diff --git a/.htaccess b/.htaccess index 6247830fa8d14..d22b5a1395cae 100644 --- a/.htaccess +++ b/.htaccess @@ -355,6 +355,15 @@ Require all denied + + + order allow,deny + deny from all + + = 2.4> + Require all denied + + # For 404s and 403s that aren't handled by the application, show plain 404 response ErrorDocument 404 /pub/errors/404.php diff --git a/.htaccess.sample b/.htaccess.sample index 3c412725f2134..c9ddff2cca4cf 100644 --- a/.htaccess.sample +++ b/.htaccess.sample @@ -332,6 +332,15 @@ Require all denied + + + order allow,deny + deny from all + + = 2.4> + Require all denied + + # For 404s and 403s that aren't handled by the application, show plain 404 response ErrorDocument 404 /pub/errors/404.php diff --git a/.php_cs.dist b/.php_cs.dist index 0f254c63283bd..84a5f88bf4355 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -5,9 +5,9 @@ */ /** - * Pre-commit hook installation: - * vendor/bin/static-review.php hook:install dev/tools/Magento/Tools/StaticReview/pre-commit .git/hooks/pre-commit + * PHP Coding Standards fixer configuration */ + $finder = PhpCsFixer\Finder::create() ->name('*.phtml') ->exclude('dev/tests/functional/generated') diff --git a/.travis.yml b/.travis.yml index dcd00f39bb810..5b1147c44135a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ addons: firefox: "46.0" hosts: - magento2.travis +services: + - rabbitmq language: php php: - 7.0 diff --git a/README.md b/README.md index c72357db26d16..b20a3738ba775 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ -[![Build Status](https://travis-ci.org/magento/magento2.svg?branch=develop)](https://travis-ci.org/magento/magento2) +[![Build Status](https://travis-ci.org/magento/magento2.svg?branch=2.3-develop)](https://travis-ci.org/magento/magento2) +[![Open Source Helpers](https://www.codetriage.com/magento/magento2/badges/users.svg)](https://www.codetriage.com/magento/magento2) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/magento/magento2?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/magento-2/localized.png)](https://crowdin.com/project/magento-2)

Welcome

diff --git a/app/code/Magento/AdminNotification/etc/db_schema.xml b/app/code/Magento/AdminNotification/etc/db_schema.xml index 6d969b3f0090a..35e6045b607d1 100644 --- a/app/code/Magento/AdminNotification/etc/db_schema.xml +++ b/app/code/Magento/AdminNotification/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> diff --git a/app/code/Magento/AdminNotification/etc/module.xml b/app/code/Magento/AdminNotification/etc/module.xml index 8a792ee8453ce..607ecbde10a26 100644 --- a/app/code/Magento/AdminNotification/etc/module.xml +++ b/app/code/Magento/AdminNotification/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/AdvancedPricingImportExport/etc/module.xml b/app/code/Magento/AdvancedPricingImportExport/etc/module.xml index ac4b8dafd0183..230fb17ae5544 100644 --- a/app/code/Magento/AdvancedPricingImportExport/etc/module.xml +++ b/app/code/Magento/AdvancedPricingImportExport/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/Amqp/Model/Config.php b/app/code/Magento/Amqp/Model/Config.php new file mode 100644 index 0000000000000..9ec9780317a9f --- /dev/null +++ b/app/code/Magento/Amqp/Model/Config.php @@ -0,0 +1,16 @@ +getPublisherConfig(), + $this->getResponseQueueNameBuilder(), + $communicationConfig, + $rpcConnectionTimeout + ); + } + + /** + * Get publisher config. + * + * @return PublisherConfig + * + * @deprecated 100.2.0 + */ + private function getPublisherConfig() + { + return \Magento\Framework\App\ObjectManager::getInstance()->get(PublisherConfig::class); + } + + /** + * Get response queue name builder. + * + * @return ResponseQueueNameBuilder + * + * @deprecated 100.2.0 + */ + private function getResponseQueueNameBuilder() + { + return \Magento\Framework\App\ObjectManager::getInstance()->get(ResponseQueueNameBuilder::class); + } +} diff --git a/app/code/Magento/Amqp/Model/Queue.php b/app/code/Magento/Amqp/Model/Queue.php new file mode 100644 index 0000000000000..ffef398352bc7 --- /dev/null +++ b/app/code/Magento/Amqp/Model/Queue.php @@ -0,0 +1,16 @@ +get(TopologyConfig::class), + \Magento\Framework\App\ObjectManager::getInstance()->get(ExchangeInstaller::class), + \Magento\Framework\App\ObjectManager::getInstance()->get(ConfigPool::class), + \Magento\Framework\App\ObjectManager::getInstance()->get(QueueInstaller::class), + \Magento\Framework\App\ObjectManager::getInstance()->get(ConnectionTypeResolver::class), + $logger + ); + } +} diff --git a/app/code/Magento/Amqp/README.md b/app/code/Magento/Amqp/README.md new file mode 100644 index 0000000000000..a21624031d619 --- /dev/null +++ b/app/code/Magento/Amqp/README.md @@ -0,0 +1,3 @@ +# Amqp + +**Amqp** provides functionality to publish/consume messages with Amqp. diff --git a/app/code/Magento/Amqp/Setup/ConfigOptionsList.php b/app/code/Magento/Amqp/Setup/ConfigOptionsList.php new file mode 100644 index 0000000000000..e4126f148d651 --- /dev/null +++ b/app/code/Magento/Amqp/Setup/ConfigOptionsList.php @@ -0,0 +1,188 @@ +connectionValidator = $connectionValidator; + } + + /** + * {@inheritdoc} + */ + public function getOptions() + { + return [ + new TextConfigOption( + self::INPUT_KEY_QUEUE_AMQP_HOST, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_QUEUE_AMQP_HOST, + 'Amqp server host', + self::DEFAULT_AMQP_HOST + ), + new TextConfigOption( + self::INPUT_KEY_QUEUE_AMQP_PORT, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_QUEUE_AMQP_PORT, + 'Amqp server port', + self::DEFAULT_AMQP_PORT + ), + new TextConfigOption( + self::INPUT_KEY_QUEUE_AMQP_USER, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_QUEUE_AMQP_USER, + 'Amqp server username', + self::DEFAULT_AMQP_USER + ), + new TextConfigOption( + self::INPUT_KEY_QUEUE_AMQP_PASSWORD, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_QUEUE_AMQP_PASSWORD, + 'Amqp server password', + self::DEFAULT_AMQP_PASSWORD + ), + new TextConfigOption( + self::INPUT_KEY_QUEUE_AMQP_VIRTUAL_HOST, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_QUEUE_AMQP_VIRTUAL_HOST, + 'Amqp virtualhost', + self::DEFAULT_AMQP_VIRTUAL_HOST + ), + new TextConfigOption( + self::INPUT_KEY_QUEUE_AMQP_SSL, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_QUEUE_AMQP_SSL, + 'Amqp SSL', + self::DEFAULT_AMQP_SSL + ), + ]; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function createConfig(array $data, DeploymentConfig $deploymentConfig) + { + $configData = new ConfigData(ConfigFilePool::APP_ENV); + + if (!$this->isDataEmpty($data, self::INPUT_KEY_QUEUE_AMQP_HOST)) { + $configData->set(self::CONFIG_PATH_QUEUE_AMQP_HOST, $data[self::INPUT_KEY_QUEUE_AMQP_HOST]); + if (!$this->isDataEmpty($data, self::INPUT_KEY_QUEUE_AMQP_PORT)) { + $configData->set(self::CONFIG_PATH_QUEUE_AMQP_PORT, $data[self::INPUT_KEY_QUEUE_AMQP_PORT]); + } + if (!$this->isDataEmpty($data, self::INPUT_KEY_QUEUE_AMQP_USER)) { + $configData->set(self::CONFIG_PATH_QUEUE_AMQP_USER, $data[self::INPUT_KEY_QUEUE_AMQP_USER]); + } + if (!$this->isDataEmpty($data, self::INPUT_KEY_QUEUE_AMQP_PASSWORD)) { + $configData->set(self::CONFIG_PATH_QUEUE_AMQP_PASSWORD, $data[self::INPUT_KEY_QUEUE_AMQP_PASSWORD]); + } + if (!$this->isDataEmpty($data, self::INPUT_KEY_QUEUE_AMQP_VIRTUAL_HOST)) { + $configData->set( + self::CONFIG_PATH_QUEUE_AMQP_VIRTUAL_HOST, + $data[self::INPUT_KEY_QUEUE_AMQP_VIRTUAL_HOST] + ); + } + if (!$this->isDataEmpty($data, self::INPUT_KEY_QUEUE_AMQP_SSL)) { + $configData->set(self::CONFIG_PATH_QUEUE_AMQP_SSL, $data[self::INPUT_KEY_QUEUE_AMQP_SSL]); + } + } + + return [$configData]; + } + + /** + * {@inheritdoc} + */ + public function validate(array $options, DeploymentConfig $deploymentConfig) + { + $errors = []; + + if (isset($options[self::INPUT_KEY_QUEUE_AMQP_HOST]) + && $options[self::INPUT_KEY_QUEUE_AMQP_HOST] !== '') { + $result = $this->connectionValidator->isConnectionValid( + $options[self::INPUT_KEY_QUEUE_AMQP_HOST], + $options[self::INPUT_KEY_QUEUE_AMQP_PORT], + $options[self::INPUT_KEY_QUEUE_AMQP_USER], + $options[self::INPUT_KEY_QUEUE_AMQP_PASSWORD], + $options[self::INPUT_KEY_QUEUE_AMQP_VIRTUAL_HOST] + ); + + if (!$result) { + $errors[] = "Could not connect to the Amqp Server."; + } + } + + return $errors; + } + + /** + * Check if data ($data) with key ($key) is empty + * + * @param array $data + * @param string $key + * @return bool + */ + private function isDataEmpty(array $data, $key) + { + if (isset($data[$key]) && $data[$key] !== '') { + return false; + } + + return true; + } +} diff --git a/app/code/Magento/Amqp/Setup/ConnectionValidator.php b/app/code/Magento/Amqp/Setup/ConnectionValidator.php new file mode 100644 index 0000000000000..eb17b3517f0e2 --- /dev/null +++ b/app/code/Magento/Amqp/Setup/ConnectionValidator.php @@ -0,0 +1,43 @@ +close(); + } catch (\Exception $e) { + return false; + } + + return true; + } +} diff --git a/app/code/Magento/Amqp/Setup/Recurring.php b/app/code/Magento/Amqp/Setup/Recurring.php new file mode 100644 index 0000000000000..cc1951d84e3d0 --- /dev/null +++ b/app/code/Magento/Amqp/Setup/Recurring.php @@ -0,0 +1,38 @@ +topologyInstaller = $topologyInstaller; + } + + /** + * {@inheritdoc} + */ + public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) + { + $this->topologyInstaller->install(); + } +} diff --git a/app/code/Magento/Amqp/Test/Unit/Setup/ConfigOptionsListTest.php b/app/code/Magento/Amqp/Test/Unit/Setup/ConfigOptionsListTest.php new file mode 100644 index 0000000000000..974be6dbff492 --- /dev/null +++ b/app/code/Magento/Amqp/Test/Unit/Setup/ConfigOptionsListTest.php @@ -0,0 +1,220 @@ +options = [ + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_HOST => 'host', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_PORT => 'port', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_USER => 'user', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_PASSWORD => 'password', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_VIRTUAL_HOST => 'virtual host', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_SSL => 'ssl', + + ]; + + $this->objectManager = new ObjectManager($this); + $this->connectionValidatorMock = $this->getMockBuilder(\Magento\Amqp\Setup\ConnectionValidator::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->deploymentConfigMock = $this->getMockBuilder(\Magento\Framework\App\DeploymentConfig::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->model = $this->objectManager->getObject( + \Magento\Amqp\Setup\ConfigOptionsList::class, + [ + 'connectionValidator' => $this->connectionValidatorMock, + ] + ); + } + + public function testGetOptions() + { + $expectedOptions = [ + new TextConfigOption( + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_HOST, + TextConfigOption::FRONTEND_WIZARD_TEXT, + ConfigOptionsList::CONFIG_PATH_QUEUE_AMQP_HOST, + 'Amqp server host', + ConfigOptionsList::DEFAULT_AMQP_HOST + ), + new TextConfigOption( + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_PORT, + TextConfigOption::FRONTEND_WIZARD_TEXT, + ConfigOptionsList::CONFIG_PATH_QUEUE_AMQP_PORT, + 'Amqp server port', + ConfigOptionsList::DEFAULT_AMQP_PORT + ), + new TextConfigOption( + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_USER, + TextConfigOption::FRONTEND_WIZARD_TEXT, + ConfigOptionsList::CONFIG_PATH_QUEUE_AMQP_USER, + 'Amqp server username', + ConfigOptionsList::DEFAULT_AMQP_USER + ), + new TextConfigOption( + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_PASSWORD, + TextConfigOption::FRONTEND_WIZARD_TEXT, + ConfigOptionsList::CONFIG_PATH_QUEUE_AMQP_PASSWORD, + 'Amqp server password', + ConfigOptionsList::DEFAULT_AMQP_PASSWORD + ), + new TextConfigOption( + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_VIRTUAL_HOST, + TextConfigOption::FRONTEND_WIZARD_TEXT, + ConfigOptionsList::CONFIG_PATH_QUEUE_AMQP_VIRTUAL_HOST, + 'Amqp virtualhost', + ConfigOptionsList::DEFAULT_AMQP_VIRTUAL_HOST + ), + new TextConfigOption( + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_SSL, + TextConfigOption::FRONTEND_WIZARD_TEXT, + ConfigOptionsList::CONFIG_PATH_QUEUE_AMQP_SSL, + 'Amqp SSL', + ConfigOptionsList::DEFAULT_AMQP_SSL + ) + ]; + $this->assertEquals($expectedOptions, $this->model->getOptions()); + } + + /** + * @param array $options + * @param array $expectedConfigData + * @dataProvider getCreateConfigDataProvider + */ + public function testCreateConfig($options, $expectedConfigData) + { + $result = $this->model->createConfig($options, $this->deploymentConfigMock); + $this->assertInternalType('array', $result); + $this->assertNotEmpty($result); + /** @var \Magento\Framework\Config\Data\ConfigData $configData */ + $configData = $result[0]; + $this->assertInstanceOf(\Magento\Framework\Config\Data\ConfigData::class, $configData); + $this->assertEquals($expectedConfigData, $configData->getData()); + } + + public function testValidateInvalidConnection() + { + $expectedResult = ['Could not connect to the Amqp Server.']; + $this->connectionValidatorMock->expects($this->once())->method('isConnectionValid')->willReturn(false); + $this->assertEquals($expectedResult, $this->model->validate($this->options, $this->deploymentConfigMock)); + } + + public function testValidateValidConnection() + { + $expectedResult = []; + $this->connectionValidatorMock->expects($this->once())->method('isConnectionValid')->willReturn(true); + $this->assertEquals($expectedResult, $this->model->validate($this->options, $this->deploymentConfigMock)); + } + + public function testValidateNoOptions() + { + $expectedResult = []; + $options = []; + $this->connectionValidatorMock->expects($this->never())->method('isConnectionValid'); + $this->assertEquals($expectedResult, $this->model->validate($options, $this->deploymentConfigMock)); + } + + public function getCreateConfigDataProvider() + { + return [ + [ + [ + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_HOST => 'host', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_PORT => 'port', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_USER => 'user', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_PASSWORD => 'password', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_VIRTUAL_HOST => 'virtual host', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_SSL => 'ssl', + ], + ['queue' => + ['amqp' => + [ + 'host' => 'host', + 'port' => 'port', + 'user' => 'user', + 'password' => 'password', + 'virtualhost' => 'virtual host', + 'ssl' => 'ssl', + ] + ] + ], + ], + [ + [ + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_HOST => 'host', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_PORT => ConfigOptionsList::DEFAULT_AMQP_PORT, + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_USER => 'user', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_PASSWORD => 'password', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_VIRTUAL_HOST => 'virtual host', + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_SSL => 'ssl', + ], + ['queue' => + ['amqp' => + [ + 'host' => 'host', + 'port' => ConfigOptionsList::DEFAULT_AMQP_PORT, + 'user' => 'user', + 'password' => 'password', + 'virtualhost' => 'virtual host', + 'ssl' => 'ssl', + ] + ] + ], + ], + [ + [ + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_HOST => ConfigOptionsList::DEFAULT_AMQP_HOST, + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_PORT => ConfigOptionsList::DEFAULT_AMQP_PORT, + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_USER => ConfigOptionsList::DEFAULT_AMQP_USER, + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_PASSWORD => ConfigOptionsList::DEFAULT_AMQP_PASSWORD, + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_VIRTUAL_HOST => + ConfigOptionsList::DEFAULT_AMQP_VIRTUAL_HOST, + ConfigOptionsList::INPUT_KEY_QUEUE_AMQP_SSL => ConfigOptionsList::DEFAULT_AMQP_SSL, + ], + [], + ], + ]; + } +} diff --git a/app/code/Magento/Amqp/composer.json b/app/code/Magento/Amqp/composer.json new file mode 100644 index 0000000000000..255fa5d55d935 --- /dev/null +++ b/app/code/Magento/Amqp/composer.json @@ -0,0 +1,26 @@ +{ + "name": "magento/module-amqp", + "description": "N/A", + "config": { + "sort-packages": true + }, + "require": { + "magento/framework": "100.3.*", + "magento/framework-amqp": "100.1.*", + "magento/framework-message-queue": "100.3.*", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "type": "magento2-module", + "version": "100.3.0-dev", + "license": [ + "proprietary" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\Amqp\\": "" + } + } +} diff --git a/app/code/Magento/Amqp/etc/di.xml b/app/code/Magento/Amqp/etc/di.xml new file mode 100644 index 0000000000000..920bb72261ef9 --- /dev/null +++ b/app/code/Magento/Amqp/etc/di.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + Magento\Framework\MessageQueue\Publisher + + + Magento\Framework\MessageQueue\Rpc\Publisher + + + + + + + + + Magento\Framework\MessageQueue\Bulk\Publisher + + + Magento\Framework\MessageQueue\Bulk\Rpc\Publisher + + + + + + + + Magento\Framework\Amqp\ConnectionTypeResolver + + + + + + + Magento\Framework\Amqp\ExchangeFactory + + + + + + + Magento\Framework\Amqp\Bulk\ExchangeFactory + + + + + + + Magento\Framework\Amqp\QueueFactory + + + + + + \Magento\Framework\Amqp\Bulk\Exchange + + + diff --git a/app/code/Magento/Amqp/etc/module.xml b/app/code/Magento/Amqp/etc/module.xml new file mode 100644 index 0000000000000..1768a9b121c81 --- /dev/null +++ b/app/code/Magento/Amqp/etc/module.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/app/code/Magento/Amqp/registration.php b/app/code/Magento/Amqp/registration.php new file mode 100644 index 0000000000000..17d8382c698e8 --- /dev/null +++ b/app/code/Magento/Amqp/registration.php @@ -0,0 +1,9 @@ +localeResolver = $localeResolver ?: + ObjectManager::getInstance()->get(\Magento\Framework\Locale\ResolverInterface::class); + parent::__construct($context, $data); + } + + /** + * Add current time zone to comment, properly translated according to locale * * @param \Magento\Framework\Data\Form\Element\AbstractElement $element * @return string @@ -19,7 +41,9 @@ class CollectionTimeLabel extends \Magento\Config\Block\System\Config\Form\Field public function render(\Magento\Framework\Data\Form\Element\AbstractElement $element) { $timeZoneCode = $this->_localeDate->getConfigTimezone(); - $getLongTimeZoneName = \IntlTimeZone::createTimeZone($timeZoneCode)->getDisplayName(); + $locale = $this->localeResolver->getLocale(); + $getLongTimeZoneName = \IntlTimeZone::createTimeZone($timeZoneCode) + ->getDisplayName(false, \IntlTimeZone::DISPLAY_LONG, $locale); $element->setData( 'comment', sprintf("%s (%s)", $getLongTimeZoneName, $timeZoneCode) diff --git a/app/code/Magento/Analytics/Setup/InstallData.php b/app/code/Magento/Analytics/Setup/InstallData.php deleted file mode 100644 index 9832849bacc04..0000000000000 --- a/app/code/Magento/Analytics/Setup/InstallData.php +++ /dev/null @@ -1,52 +0,0 @@ -getConnection()->insertMultiple( - $setup->getTable('core_config_data'), - [ - [ - 'scope' => 'default', - 'scope_id' => 0, - 'path' => 'analytics/subscription/enabled', - 'value' => 1 - ], - [ - 'scope' => 'default', - 'scope_id' => 0, - 'path' => SubscriptionHandler::CRON_STRING_PATH, - 'value' => join(' ', SubscriptionHandler::CRON_EXPR_ARRAY) - ] - ] - ); - - $setup->getConnection()->insert( - $setup->getTable('flag'), - [ - 'flag_code' => SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, - 'state' => 0, - 'flag_data' => 24, - ] - ); - } -} diff --git a/app/code/Magento/Analytics/Setup/Patch/Data/PrepareInitialConfig.php b/app/code/Magento/Analytics/Setup/Patch/Data/PrepareInitialConfig.php new file mode 100644 index 0000000000000..a352854a8b77b --- /dev/null +++ b/app/code/Magento/Analytics/Setup/Patch/Data/PrepareInitialConfig.php @@ -0,0 +1,92 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->insertMultiple( + $this->moduleDataSetup->getTable('core_config_data'), + [ + [ + 'scope' => 'default', + 'scope_id' => 0, + 'path' => 'analytics/subscription/enabled', + 'value' => 1 + ], + [ + 'scope' => 'default', + 'scope_id' => 0, + 'path' => SubscriptionHandler::CRON_STRING_PATH, + 'value' => join(' ', SubscriptionHandler::CRON_EXPR_ARRAY) + ] + ] + ); + + $this->moduleDataSetup->getConnection()->insert( + $this->moduleDataSetup->getTable('flag'), + [ + 'flag_code' => SubscriptionHandler::ATTEMPTS_REVERSE_COUNTER_FLAG_CODE, + 'state' => 0, + 'flag_data' => 24, + ] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php index a652cf6b3d548..462b3c909a7fd 100644 --- a/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php +++ b/app/code/Magento/Analytics/Test/Unit/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php @@ -9,6 +9,7 @@ use Magento\Backend\Block\Template\Context; use Magento\Framework\Data\Form; use Magento\Framework\Data\Form\Element\AbstractElement; +use Magento\Framework\Locale\ResolverInterface; use Magento\Framework\Stdlib\DateTime\TimezoneInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; @@ -34,6 +35,11 @@ class CollectionTimeLabelTest extends \PHPUnit\Framework\TestCase */ private $abstractElementMock; + /** + * @var ResolverInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $localeResolver; + protected function setUp() { $this->abstractElementMock = $this->getMockBuilder(AbstractElement::class) @@ -53,12 +59,17 @@ protected function setUp() $this->contextMock->expects($this->any()) ->method('getLocaleDate') ->willReturn($this->timeZoneMock); + $this->localeResolver = $this->getMockBuilder(ResolverInterface::class) + ->disableOriginalConstructor() + ->setMethods(['getLocale']) + ->getMockForAbstractClass(); $objectManager = new ObjectManager($this); $this->collectionTimeLabel = $objectManager->getObject( CollectionTimeLabel::class, [ - 'context' => $this->contextMock + 'context' => $this->contextMock, + 'localeResolver' => $this->localeResolver ] ); } @@ -73,6 +84,9 @@ public function testRender() $this->abstractElementMock->expects($this->any()) ->method('getComment') ->willReturn('Eastern Standard Time (America/New_York)'); + $this->localeResolver->expects($this->once()) + ->method('getLocale') + ->willReturn('en_US'); $this->assertRegexp( "/Eastern Standard Time \(America\/New_York\)/", $this->collectionTimeLabel->render($this->abstractElementMock) diff --git a/app/code/Magento/Analytics/etc/module.xml b/app/code/Magento/Analytics/etc/module.xml index 32ee5d23a4d86..24c2fbc81446e 100644 --- a/app/code/Magento/Analytics/etc/module.xml +++ b/app/code/Magento/Analytics/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php b/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php new file mode 100644 index 0000000000000..f5dd5bb13eabb --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Api/Data/BulkSummaryInterface.php @@ -0,0 +1,34 @@ +urlBuilder = $urlBuilder; + } + + /** + * Retrieve button data + * + * @return array button configuration + */ + public function getButtonData() + { + return [ + 'label' => __('Back'), + 'on_click' => sprintf("location.href = '%s';", $this->urlBuilder->getUrl('*/')), + 'class' => 'back', + 'sort_order' => 10 + ]; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Block/Adminhtml/Bulk/Details/DoneButton.php b/app/code/Magento/AsynchronousOperations/Block/Adminhtml/Bulk/Details/DoneButton.php new file mode 100644 index 0000000000000..5e30c20fd2fbf --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Block/Adminhtml/Bulk/Details/DoneButton.php @@ -0,0 +1,75 @@ +bulkStatus = $bulkStatus; + $this->request = $request; + } + + /** + * Retrieve button data + * + * @return array button configuration + */ + public function getButtonData() + { + $uuid = $this->request->getParam('uuid'); + $operationsCount = $this->bulkStatus->getOperationsCountByBulkIdAndStatus( + $uuid, + OperationInterface::STATUS_TYPE_RETRIABLY_FAILED + ); + $button = []; + + if ($this->request->getParam('buttons') && $operationsCount === 0) { + $button = [ + 'label' => __('Done'), + 'class' => 'primary', + 'sort_order' => 10, + 'on_click' => '', + 'data_attribute' => [ + 'mage-init' => [ + 'Magento_Ui/js/form/button-adapter' => [ + 'actions' => [ + [ + 'targetName' => 'notification_area.notification_area.modalContainer.modal', + 'actionName' => 'closeModal' + ], + ], + ], + ], + ], + ]; + } + + return $button; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Block/Adminhtml/Bulk/Details/RetryButton.php b/app/code/Magento/AsynchronousOperations/Block/Adminhtml/Bulk/Details/RetryButton.php new file mode 100644 index 0000000000000..9051f1ab9d428 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Block/Adminhtml/Bulk/Details/RetryButton.php @@ -0,0 +1,66 @@ +details = $details; + $this->request = $request; + $this->targetName = $targetName; + } + + /** + * {@inheritdoc} + */ + public function getButtonData() + { + $uuid = $this->request->getParam('uuid'); + $details = $this->details->getDetails($uuid); + if ($details['failed_retriable'] === 0) { + return []; + } + return [ + 'label' => __('Retry'), + 'class' => 'retry primary', + 'data_attribute' => [ + 'mage-init' => ['button' => ['event' => 'save']], + 'form-role' => 'save', + ], + ]; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Bulk/Details.php b/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Bulk/Details.php new file mode 100644 index 0000000000000..9e9dbd3dd67c5 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Bulk/Details.php @@ -0,0 +1,71 @@ +resultPageFactory = $resultPageFactory; + $this->accessValidator = $accessValidator; + $this->menuId = $menuId; + parent::__construct($context); + } + + /** + * @inheritDoc + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Logging::system_magento_logging_bulk_operations') + && $this->accessValidator->isAllowed($this->getRequest()->getParam('uuid')); + } + + /** + * Bulk details action + * + * @return \Magento\Framework\View\Result\Page + */ + public function execute() + { + $bulkId = $this->getRequest()->getParam('uuid'); + $resultPage = $this->resultPageFactory->create(); + $resultPage->initLayout(); + $this->_setActiveMenu($this->menuId); + $resultPage->getConfig()->getTitle()->prepend(__('Action Details - #' . $bulkId)); + + return $resultPage; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Bulk/Retry.php b/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Bulk/Retry.php new file mode 100644 index 0000000000000..62e6b9ba4551b --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Bulk/Retry.php @@ -0,0 +1,99 @@ +bulkManagement = $bulkManagement; + $this->notificationManagement = $notificationManagement; + $this->accessValidator = $accessValidator; + } + + /** + * @inheritDoc + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Logging::system_magento_logging_bulk_operations') + && $this->accessValidator->isAllowed($this->getRequest()->getParam('uuid')); + } + + /** + * {@inheritdoc} + */ + public function execute() + { + $bulkUuid = $this->getRequest()->getParam('uuid'); + $isAjax = $this->getRequest()->getParam('isAjax'); + $operationsToRetry = (array)$this->getRequest()->getParam('operations_to_retry', []); + $errorCodes = []; + foreach ($operationsToRetry as $operationData) { + if (isset($operationData['error_code'])) { + $errorCodes[] = (int)$operationData['error_code']; + } + } + + $affectedOperations = $this->bulkManagement->retryBulk($bulkUuid, $errorCodes); + $this->notificationManagement->ignoreBulks([$bulkUuid]); + if (!$isAjax) { + $this->messageManager->addSuccessMessage( + __('%1 item(s) have been scheduled for update."', $affectedOperations) + ); + /** @var Redirect $result */ + $result = $this->resultRedirectFactory->create(); + $result->setPath('bulk/index'); + } else { + /** @var \Magento\Framework\Controller\Result\Json $result */ + $result = $this->resultFactory->create(ResultFactory::TYPE_JSON); + $result->setHttpResponseCode(200); + $response = new \Magento\Framework\DataObject(); + $response->setError(0); + + $result->setData($response); + } + return $result; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Index/Index.php b/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Index/Index.php new file mode 100644 index 0000000000000..5a2b9c0a34e64 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Index/Index.php @@ -0,0 +1,65 @@ +resultPageFactory = $resultPageFactory; + $this->menuId = $menuId; + parent::__construct($context); + } + + /** + * @inheritDoc + */ + protected function _isAllowed() + { + return parent::_isAllowed(); + } + + /** + * Bulk list action + * + * @return \Magento\Framework\View\Result\Page + */ + public function execute() + { + $resultPage = $this->resultPageFactory->create(); + $resultPage->initLayout(); + $this->_setActiveMenu($this->menuId); + $resultPage->getConfig()->getTitle()->prepend(__('Bulk Actions Log')); + return $resultPage; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Notification/Dismiss.php b/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Notification/Dismiss.php new file mode 100644 index 0000000000000..0a71c130fb20a --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Controller/Adminhtml/Notification/Dismiss.php @@ -0,0 +1,65 @@ +notificationManagement = $notificationManagement; + } + + /** + * @inheritDoc + */ + protected function _isAllowed() + { + return $this->_authorization->isAllowed('Magento_Logging::system_magento_logging_bulk_operations'); + } + + /** + * {@inheritdoc} + */ + public function execute() + { + $bulkUuids = []; + foreach ((array)$this->getRequest()->getParam('uuid', []) as $bulkUuid) { + $bulkUuids[] = (string)$bulkUuid; + } + + $isAcknowledged = $this->notificationManagement->acknowledgeBulks($bulkUuids); + + /** @var \Magento\Framework\Controller\Result\Json $result */ + $result = $this->resultFactory->create(ResultFactory::TYPE_JSON); + if (!$isAcknowledged) { + $result->setHttpResponseCode(400); + } + + return $result; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Cron/BulkCleanup.php b/app/code/Magento/AsynchronousOperations/Cron/BulkCleanup.php new file mode 100644 index 0000000000000..7c8da3c1c4236 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Cron/BulkCleanup.php @@ -0,0 +1,77 @@ +metadataPool = $metadataPool; + $this->resourceConnection = $resourceConnection; + $this->dateTime = $dateTime; + $this->scopeConfig = $scopeConfig; + $this->date = $time; + } + + /** + * Remove all expired bulks and corresponding operations + * + * @return void + */ + public function execute() + { + $metadata = $this->metadataPool->getMetadata(BulkSummaryInterface::class); + $connection = $this->resourceConnection->getConnectionByName($metadata->getEntityConnectionName()); + + $bulkLifetime = 3600 * 24 * (int)$this->scopeConfig->getValue('system/bulk/lifetime'); + $maxBulkStartTime = $this->dateTime->formatDate($this->date->gmtTimestamp() - $bulkLifetime); + $connection->delete($metadata->getEntityTable(), ['start_time <= ?' => $maxBulkStartTime]); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/AccessValidator.php b/app/code/Magento/AsynchronousOperations/Model/AccessValidator.php new file mode 100644 index 0000000000000..a14ec254cf897 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/AccessValidator.php @@ -0,0 +1,60 @@ +userContext = $userContext; + $this->entityManager = $entityManager; + $this->bulkSummaryFactory = $bulkSummaryFactory; + } + + /** + * Check if content allowed for current user + * + * @param int $bulkUuid + * @return bool + */ + public function isAllowed($bulkUuid) + { + /** @var \Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface $bulkSummary */ + $bulkSummary = $this->entityManager->load( + $this->bulkSummaryFactory->create(), + $bulkUuid + ); + return $bulkSummary->getUserId() === $this->userContext->getUserId(); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkDescription/Options.php b/app/code/Magento/AsynchronousOperations/Model/BulkDescription/Options.php new file mode 100644 index 0000000000000..08e1a863b259d --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/BulkDescription/Options.php @@ -0,0 +1,64 @@ +bulkCollectionFactory = $bulkCollection; + $this->userContext = $userContext; + } + + /** + * {@inheritdoc} + */ + public function toOptionArray() + { + /** @var \Magento\AsynchronousOperations\Model\ResourceModel\Bulk\Collection $collection */ + $collection = $this->bulkCollectionFactory->create(); + + /** @var \Magento\Framework\DB\Select $select */ + $select = $collection->getSelect(); + $select->reset(); + $select->distinct(true); + $select->from($collection->getMainTable(), ['description']); + $select->where('user_id = ?', $this->userContext->getUserId()); + + $options = []; + + /** @var BulkSummaryInterface $item */ + foreach ($collection->getItems() as $item) { + $options[] = [ + 'value' => $item->getDescription(), + 'label' => $item->getDescription() + ]; + } + return $options; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php new file mode 100644 index 0000000000000..4f086ce8ac2ca --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/BulkManagement.php @@ -0,0 +1,205 @@ +entityManager = $entityManager; + $this->bulkSummaryFactory= $bulkSummaryFactory; + $this->operationCollectionFactory = $operationCollectionFactory; + $this->metadataPool = $metadataPool; + $this->resourceConnection = $resourceConnection; + $this->publisher = $publisher; + $this->logger = $logger; + } + + /** + * @inheritDoc + */ + public function scheduleBulk($bulkUuid, array $operations, $description, $userId = null) + { + $metadata = $this->metadataPool->getMetadata(BulkSummaryInterface::class); + $connection = $this->resourceConnection->getConnectionByName($metadata->getEntityConnectionName()); + // save bulk summary and related operations + $connection->beginTransaction(); + try { + /** @var \Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface $bulkSummary */ + $bulkSummary = $this->bulkSummaryFactory->create(); + $this->entityManager->load($bulkSummary, $bulkUuid); + $bulkSummary->setBulkId($bulkUuid); + $bulkSummary->setDescription($description); + $bulkSummary->setUserId($userId); + $bulkSummary->setOperationCount((int)$bulkSummary->getOperationCount() + count($operations)); + + $this->entityManager->save($bulkSummary); + + $connection->commit(); + } catch (\Exception $exception) { + $connection->rollBack(); + $this->logger->critical($exception->getMessage()); + return false; + } + $this->publishOperations($operations); + + return true; + } + + /** + * Retry bulk operations that failed due to given errors. + * + * @param string $bulkUuid target bulk UUID + * @param array $errorCodes list of corresponding error codes + * @return int number of affected bulk operations + */ + public function retryBulk($bulkUuid, array $errorCodes) + { + $metadata = $this->metadataPool->getMetadata(BulkSummaryInterface::class); + $connection = $this->resourceConnection->getConnectionByName($metadata->getEntityConnectionName()); + + /** @var \Magento\AsynchronousOperations\Model\ResourceModel\Operation[] $retriablyFailedOperations */ + $retriablyFailedOperations = $this->operationCollectionFactory->create() + ->addFieldToFilter('error_code', ['in' => $errorCodes]) + ->addFieldToFilter('bulk_uuid', ['eq' => $bulkUuid]) + ->getItems(); + + // remove corresponding operations from database (i.e. move them to 'open' status) + $connection->beginTransaction(); + try { + $operationIds = []; + $currentBatchSize = 0; + $maxBatchSize = 10000; + /** @var OperationInterface $operation */ + foreach ($retriablyFailedOperations as $operation) { + if ($currentBatchSize === $maxBatchSize) { + $connection->delete( + $this->resourceConnection->getTableName('magento_operation'), + $connection->quoteInto('id IN (?)', $operationIds) + ); + $operationIds = []; + $currentBatchSize = 0; + } + $currentBatchSize++; + $operationIds[] = $operation->getId(); + // Rescheduled operations must be put in queue in 'open' state (i.e. without ID) + $operation->setId(null); + } + // remove operations from the last batch + if (!empty($operationIds)) { + $connection->delete( + $this->resourceConnection->getTableName('magento_operation'), + $connection->quoteInto('id IN (?)', $operationIds) + ); + } + + $connection->commit(); + } catch (\Exception $exception) { + $connection->rollBack(); + $this->logger->critical($exception->getMessage()); + return 0; + } + $this->publishOperations($retriablyFailedOperations); + + return count($retriablyFailedOperations); + } + + /** + * Publish list of operations to the corresponding message queues. + * + * @param array $operations + * @return void + */ + private function publishOperations(array $operations) + { + $operationsByTopics = []; + foreach ($operations as $operation) { + $operationsByTopics[$operation->getTopicName()][] = $operation; + } + foreach ($operationsByTopics as $topicName => $operations) { + $this->publisher->publish($topicName, $operations); + } + } + + /** + * @inheritDoc + */ + public function deleteBulk($bulkId) + { + return $this->entityManager->delete( + $this->entityManager->load( + $this->bulkSummaryFactory->create(), + $bulkId + ) + ); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkNotificationManagement.php b/app/code/Magento/AsynchronousOperations/Model/BulkNotificationManagement.php new file mode 100644 index 0000000000000..2ba7f7fe5e3ee --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/BulkNotificationManagement.php @@ -0,0 +1,150 @@ +metadataPool = $metadataPool; + $this->resourceConnection = $resourceConnection; + $this->bulkCollectionFactory = $bulkCollectionFactory; + $this->logger = $logger; + } + + /** + * Mark given bulks as acknowledged. + * Notifications related to these bulks will not appear in notification area. + * + * @param array $bulkUuids + * @return bool true on success or false on failure + */ + public function acknowledgeBulks(array $bulkUuids) + { + $metadata = $this->metadataPool->getMetadata(BulkSummaryInterface::class); + $connection = $this->resourceConnection->getConnectionByName($metadata->getEntityConnectionName()); + + try { + $connection->insertArray( + $this->resourceConnection->getTableName('magento_acknowledged_bulk'), + ['bulk_uuid'], + $bulkUuids + ); + } catch (\Exception $exception) { + $this->logger->critical($exception->getMessage()); + return false; + } + return true; + } + + /** + * Remove given bulks from acknowledged list. + * Notifications related to these bulks will appear again in notification area. + * + * @param array $bulkUuids + * @return bool true on success or false on failure + */ + public function ignoreBulks(array $bulkUuids) + { + $metadata = $this->metadataPool->getMetadata(BulkSummaryInterface::class); + $connection = $this->resourceConnection->getConnectionByName($metadata->getEntityConnectionName()); + + try { + $connection->delete( + $this->resourceConnection->getTableName('magento_acknowledged_bulk'), + ['bulk_uuid IN(?)' => $bulkUuids] + ); + } catch (\Exception $exception) { + $this->logger->critical($exception->getMessage()); + return false; + } + return true; + } + + /** + * Retrieve all bulks that were acknowledged by given user. + * + * @param int $userId + * @return BulkSummaryInterface[] + */ + public function getAcknowledgedBulksByUser($userId) + { + $bulks = $this->bulkCollectionFactory->create() + ->join( + ['acknowledged_bulk' => $this->resourceConnection->getTableName('magento_acknowledged_bulk')], + 'main_table.uuid = acknowledged_bulk.bulk_uuid', + [] + )->addFieldToFilter('user_id', $userId) + ->addOrder('start_time', Collection::SORT_ORDER_DESC) + ->getItems(); + + return $bulks; + } + + /** + * Retrieve all bulks that were not acknowledged by given user. + * + * @param int $userId + * @return BulkSummaryInterface[] + */ + public function getIgnoredBulksByUser($userId) + { + /** @var \Magento\AsynchronousOperations\Model\ResourceModel\Bulk\Collection $bulkCollection */ + $bulkCollection = $this->bulkCollectionFactory->create(); + $bulkCollection->getSelect()->joinLeft( + ['acknowledged_bulk' => $this->resourceConnection->getTableName('magento_acknowledged_bulk')], + 'main_table.uuid = acknowledged_bulk.bulk_uuid', + ['acknowledged_bulk.bulk_uuid'] + ); + $bulks = $bulkCollection->addFieldToFilter('user_id', $userId) + ->addFieldToFilter('acknowledged_bulk.bulk_uuid', ['null' => true]) + ->addOrder('start_time', Collection::SORT_ORDER_DESC) + ->getItems(); + + return $bulks; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkStatus.php b/app/code/Magento/AsynchronousOperations/Model/BulkStatus.php new file mode 100644 index 0000000000000..c37ae0d23dd25 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/BulkStatus.php @@ -0,0 +1,200 @@ +operationCollectionFactory = $operationCollection; + $this->bulkCollectionFactory = $bulkCollection; + $this->resourceConnection = $resourceConnection; + $this->calculatedStatusSql = $calculatedStatusSql; + $this->metadataPool = $metadataPool; + } + + /** + * @inheritDoc + */ + public function getFailedOperationsByBulkId($bulkUuid, $failureType = null) + { + $failureCodes = $failureType + ? [$failureType] + : [ + OperationInterface::STATUS_TYPE_RETRIABLY_FAILED, + OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED + ]; + $operations = $this->operationCollectionFactory->create() + ->addFieldToFilter('bulk_uuid', $bulkUuid) + ->addFieldToFilter('status', $failureCodes) + ->getItems(); + return $operations; + } + + /** + * @inheritDoc + */ + public function getOperationsCountByBulkIdAndStatus($bulkUuid, $status) + { + if ($status === OperationInterface::STATUS_TYPE_OPEN) { + /** + * Total number of operations that has been scheduled within the given bulk + */ + $allOperationsQty = $this->getOperationCount($bulkUuid); + + /** + * Number of operations that has been processed (i.e. operations with any status but 'open') + */ + $allProcessedOperationsQty = (int)$this->operationCollectionFactory->create() + ->addFieldToFilter('bulk_uuid', $bulkUuid) + ->getSize(); + + return $allOperationsQty - $allProcessedOperationsQty; + } + + /** @var \Magento\AsynchronousOperations\Model\ResourceModel\Operation\Collection $collection */ + $collection = $this->operationCollectionFactory->create(); + return $collection->addFieldToFilter('bulk_uuid', $bulkUuid) + ->addFieldToFilter('status', $status) + ->getSize(); + } + + /** + * @inheritDoc + */ + public function getBulksByUser($userId) + { + /** @var ResourceModel\Bulk\Collection $collection */ + $collection = $this->bulkCollectionFactory->create(); + $operationTableName = $this->resourceConnection->getTableName('magento_operation'); + $statusesArray = [ + OperationInterface::STATUS_TYPE_RETRIABLY_FAILED, + OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED, + BulkSummaryInterface::NOT_STARTED, + OperationInterface::STATUS_TYPE_OPEN, + OperationInterface::STATUS_TYPE_COMPLETE + ]; + $select = $collection->getSelect(); + $select->columns(['status' => $this->calculatedStatusSql->get($operationTableName)]) + ->order(new \Zend_Db_Expr('FIELD(status, ' . implode(',', $statusesArray) . ')')); + $collection->addFieldToFilter('user_id', $userId) + ->addOrder('start_time'); + + return $collection->getItems(); + } + + /** + * @inheritDoc + */ + public function getBulkStatus($bulkUuid) + { + /** + * Number of operations that has been processed (i.e. operations with any status but 'open') + */ + $allProcessedOperationsQty = (int)$this->operationCollectionFactory->create() + ->addFieldToFilter('bulk_uuid', $bulkUuid) + ->getSize(); + + if ($allProcessedOperationsQty == 0) { + return BulkSummaryInterface::NOT_STARTED; + } + + /** + * Total number of operations that has been scheduled within the given bulk + */ + $allOperationsQty = $this->getOperationCount($bulkUuid); + + /** + * Number of operations that has not been started yet (i.e. operations with status 'open') + */ + $allOpenOperationsQty = $allOperationsQty - $allProcessedOperationsQty; + + /** + * Number of operations that has been completed successfully + */ + $allCompleteOperationsQty = $this->operationCollectionFactory->create() + ->addFieldToFilter('bulk_uuid', $bulkUuid)->addFieldToFilter( + 'status', + OperationInterface::STATUS_TYPE_COMPLETE + )->getSize(); + + if ($allCompleteOperationsQty == $allOperationsQty) { + return BulkSummaryInterface::FINISHED_SUCCESSFULLY; + } + + if ($allOpenOperationsQty > 0 && $allOpenOperationsQty !== $allOperationsQty) { + return BulkSummaryInterface::IN_PROGRESS; + } + + return BulkSummaryInterface::FINISHED_WITH_FAILURE; + } + + /** + * Get total number of operations that has been scheduled within the given bulk. + * + * @param string $bulkUuid + * @return int + */ + private function getOperationCount($bulkUuid) + { + $metadata = $this->metadataPool->getMetadata(BulkSummaryInterface::class); + $connection = $this->resourceConnection->getConnectionByName($metadata->getEntityConnectionName()); + + return (int)$connection->fetchOne( + $connection->select() + ->from($metadata->getEntityTable(), 'operation_count') + ->where('uuid = ?', $bulkUuid) + ); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkStatus/CalculatedStatusSql.php b/app/code/Magento/AsynchronousOperations/Model/BulkStatus/CalculatedStatusSql.php new file mode 100644 index 0000000000000..dda3ed3b6737a --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/BulkStatus/CalculatedStatusSql.php @@ -0,0 +1,33 @@ + BulkSummaryInterface::NOT_STARTED, + 'label' => 'Not Started' + ], + [ + 'value' => BulkSummaryInterface::IN_PROGRESS, + 'label' => 'In Progress' + ], + [ + 'value' => BulkSummaryInterface::FINISHED_SUCCESSFULLY, + 'label' => 'Finished Successfully' + ], + [ + 'value' => BulkSummaryInterface::FINISHED_WITH_FAILURE, + 'label' => 'Finished with Failure' + ] + ]; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/BulkSummary.php b/app/code/Magento/AsynchronousOperations/Model/BulkSummary.php new file mode 100644 index 0000000000000..e99233d076957 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/BulkSummary.php @@ -0,0 +1,118 @@ +getData(self::BULK_ID); + } + + /** + * @inheritDoc + */ + public function setBulkId($bulkUuid) + { + return $this->setData(self::BULK_ID, $bulkUuid); + } + + /** + * @inheritDoc + */ + public function getDescription() + { + return $this->getData(self::DESCRIPTION); + } + + /** + * @inheritDoc + */ + public function setDescription($description) + { + return $this->setData(self::DESCRIPTION, $description); + } + + /** + * @inheritDoc + */ + public function getStartTime() + { + return $this->getData(self::START_TIME); + } + + /** + * @inheritDoc + */ + public function setStartTime($timestamp) + { + return $this->setData(self::START_TIME, $timestamp); + } + + /** + * @inheritDoc + */ + public function getUserId() + { + return $this->getData(self::USER_ID); + } + + /** + * @inheritDoc + */ + public function setUserId($userId) + { + return $this->setData(self::USER_ID, $userId); + } + + /** + * @inheritDoc + */ + public function getOperationCount() + { + return $this->getData(self::OPERATION_COUNT); + } + + /** + * @inheritDoc + */ + public function setOperationCount($operationCount) + { + return $this->setData(self::OPERATION_COUNT, $operationCount); + } + + /** + * Retrieve existing extension attributes object. + * + * @return \Magento\AsynchronousOperations\Api\Data\BulkSummaryExtensionInterface|null + */ + public function getExtensionAttributes() + { + return $this->getData(self::EXTENSION_ATTRIBUTES_KEY); + } + + /** + * Set an extension attributes object. + * + * @param \Magento\AsynchronousOperations\Api\Data\BulkSummaryExtensionInterface $extensionAttributes + * @return $this + */ + public function setExtensionAttributes( + \Magento\AsynchronousOperations\Api\Data\BulkSummaryExtensionInterface $extensionAttributes + ) { + return $this->setData(self::EXTENSION_ATTRIBUTES_KEY, $extensionAttributes); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/Entity/BulkSummaryMapper.php b/app/code/Magento/AsynchronousOperations/Model/Entity/BulkSummaryMapper.php new file mode 100644 index 0000000000000..94ebbdca445c4 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/Entity/BulkSummaryMapper.php @@ -0,0 +1,66 @@ +metadataPool = $metadataPool; + $this->resourceConnection = $resourceConnection; + } + + /** + * {@inheritdoc} + */ + public function entityToDatabase($entityType, $data) + { + // workaround for delete/update operations that are currently using only primary key as identifier + if (!empty($data['uuid'])) { + $metadata = $this->metadataPool->getMetadata($entityType); + $connection = $this->resourceConnection->getConnectionByName($metadata->getEntityConnectionName()); + $select = $connection->select()->from($metadata->getEntityTable(), 'id')->where("uuid = ?", $data['uuid']); + $identifier = $connection->fetchOne($select); + if ($identifier !== false) { + $data['id'] = $identifier; + } + } + return $data; + } + + /** + * {@inheritdoc} + * @codeCoverageIgnore + */ + public function databaseToEntity($entityType, $data) + { + return $data; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/Operation.php b/app/code/Magento/AsynchronousOperations/Model/Operation.php new file mode 100644 index 0000000000000..dbfce3ccd8b1c --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/Operation.php @@ -0,0 +1,150 @@ +getData(self::ID); + } + + /** + * @inheritDoc + */ + public function setId($id) + { + return $this->setData(self::ID, $id); + } + + /** + * @inheritDoc + */ + public function getBulkUuid() + { + return $this->getData(self::BULK_ID); + } + + /** + * @inheritDoc + */ + public function setBulkUuid($bulkId) + { + return $this->setData(self::BULK_ID, $bulkId); + } + + /** + * @inheritDoc + */ + public function getTopicName() + { + return $this->getData(self::TOPIC_NAME); + } + + /** + * @inheritDoc + */ + public function setTopicName($topic) + { + return $this->setData(self::TOPIC_NAME, $topic); + } + + /** + * @inheritDoc + */ + public function getSerializedData() + { + return $this->getData(self::SERIALIZED_DATA); + } + + /** + * @inheritDoc + */ + public function setSerializedData($serializedData) + { + return $this->setData(self::SERIALIZED_DATA, $serializedData); + } + + /** + * @inheritDoc + */ + public function getStatus() + { + return $this->getData(self::STATUS); + } + + /** + * @inheritDoc + */ + public function setStatus($status) + { + return $this->setData(self::STATUS, $status); + } + + /** + * @inheritDoc + */ + public function getResultMessage() + { + return $this->getData(self::RESULT_MESSAGE); + } + + /** + * @inheritDoc + */ + public function setResultMessage($resultMessage) + { + return $this->setData(self::RESULT_MESSAGE, $resultMessage); + } + + /** + * @inheritDoc + */ + public function getErrorCode() + { + return $this->getData(self::ERROR_CODE); + } + + /** + * @inheritDoc + */ + public function setErrorCode($errorCode) + { + return $this->setData(self::ERROR_CODE, $errorCode); + } + + /** + * Retrieve existing extension attributes object. + * + * @return \Magento\AsynchronousOperations\Api\Data\OperationExtensionInterface|null + */ + public function getExtensionAttributes() + { + return $this->getData(self::EXTENSION_ATTRIBUTES_KEY); + } + + /** + * Set an extension attributes object. + * + * @param \Magento\AsynchronousOperations\Api\Data\OperationExtensionInterface $extensionAttributes + * @return $this + */ + public function setExtensionAttributes( + \Magento\AsynchronousOperations\Api\Data\OperationExtensionInterface $extensionAttributes + ) { + return $this->setData(self::EXTENSION_ATTRIBUTES_KEY, $extensionAttributes); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/Operation/Details.php b/app/code/Magento/AsynchronousOperations/Model/Operation/Details.php new file mode 100644 index 0000000000000..398934f093350 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/Operation/Details.php @@ -0,0 +1,77 @@ + 'operations_successful', + OperationInterface::STATUS_TYPE_RETRIABLY_FAILED => 'failed_retriable', + OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED => 'failed_not_retriable', + ]; + + /** + * @param \Magento\Framework\Bulk\BulkStatusInterface $bulkStatus + */ + public function __construct( + \Magento\Framework\Bulk\BulkStatusInterface $bulkStatus + ) { + $this->bulkStatus = $bulkStatus; + } + + /** + * Collect operations statistics for the bulk + * + * @param string $bulkUuid + * @return array + */ + public function getDetails($bulkUuid) + { + $details = [ + 'operations_total' => 0, + 'operations_successful' => 0, + 'operations_failed' => 0, + 'failed_retriable' => 0, + 'failed_not_retriable' => 0, + ]; + + if (array_key_exists($bulkUuid, $this->operationCache)) { + return $this->operationCache[$bulkUuid]; + } + + foreach ($this->statusMap as $statusCode => $readableKey) { + $details[$readableKey] = $this->bulkStatus->getOperationsCountByBulkIdAndStatus( + $bulkUuid, + $statusCode + ); + } + + // total is sum of successful, retriable, not retriable and open operations + $details['operations_total'] = array_sum($details) + $this->bulkStatus->getOperationsCountByBulkIdAndStatus( + $bulkUuid, + OperationInterface::STATUS_TYPE_OPEN + ); + $details['operations_failed'] = $details['failed_retriable'] + $details['failed_not_retriable']; + $this->operationCache[$bulkUuid] = $details; + return $details; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/OperationList.php b/app/code/Magento/AsynchronousOperations/Model/OperationList.php new file mode 100644 index 0000000000000..7de62107415b0 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/OperationList.php @@ -0,0 +1,34 @@ +items = $items; + } + + /** + * @inheritdoc + */ + public function getItems() + { + return $this->items; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/OperationManagement.php b/app/code/Magento/AsynchronousOperations/Model/OperationManagement.php new file mode 100644 index 0000000000000..54b8a76758435 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/OperationManagement.php @@ -0,0 +1,68 @@ +entityManager = $entityManager; + $this->operationFactory= $operationFactory; + $this->logger = $logger; + } + + /** + * @inheritDoc + */ + public function changeOperationStatus($operationId, $status, $errorCode = null, $message = null, $data = null) + { + try { + $operationEntity = $this->operationFactory->create(); + $this->entityManager->load($operationEntity, $operationId); + $operationEntity->setErrorCode($errorCode); + $operationEntity->setStatus($status); + $operationEntity->setResultMessage($message); + $operationEntity->setSerializedData($data); + $this->entityManager->save($operationEntity); + } catch (\Exception $exception) { + $this->logger->critical($exception->getMessage()); + return false; + } + return true; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Bulk.php b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Bulk.php new file mode 100644 index 0000000000000..d56d54359ee9a --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Bulk.php @@ -0,0 +1,23 @@ +_init('magento_bulk', 'uuid'); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Bulk/Collection.php b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Bulk/Collection.php new file mode 100644 index 0000000000000..6dd997c5333ff --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Bulk/Collection.php @@ -0,0 +1,27 @@ +_init( + \Magento\AsynchronousOperations\Model\BulkSummary::class, + \Magento\AsynchronousOperations\Model\ResourceModel\Bulk::class + ); + $this->setMainTable('magento_bulk'); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation.php b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation.php new file mode 100644 index 0000000000000..061d0917e7ab0 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation.php @@ -0,0 +1,23 @@ +_init('magento_operation', 'id'); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation/CheckIfExists.php b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation/CheckIfExists.php new file mode 100644 index 0000000000000..46c4e4bc1c2bc --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation/CheckIfExists.php @@ -0,0 +1,28 @@ +_init( + \Magento\AsynchronousOperations\Model\Operation::class, + \Magento\AsynchronousOperations\Model\ResourceModel\Operation::class + ); + $this->setMainTable('magento_operation'); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation/Create.php b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation/Create.php new file mode 100644 index 0000000000000..ce2357c6b2b4f --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/Operation/Create.php @@ -0,0 +1,85 @@ +metadataPool = $metadataPool; + $this->typeResolver = $typeResolver; + $this->resourceConnection = $resourceConnection; + } + + /** + * Save all operations from the list in one query. + * + * @param object $entity + * @param array $arguments + * @return object + * @throws \Exception + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function execute($entity, $arguments = []) + { + $entityType = $this->typeResolver->resolve($entity); + $metadata = $this->metadataPool->getMetadata($entityType); + $connection = $this->resourceConnection->getConnection($metadata->getEntityConnectionName()); + try { + $connection->beginTransaction(); + $data = []; + foreach ($entity->getItems() as $operation) { + $data[] = $operation->getData(); + } + $connection->insertOnDuplicate( + $metadata->getEntityTable(), + $data, + [ + 'status', + 'error_code', + 'result_message', + ] + ); + $connection->commit(); + } catch (\Exception $e) { + $connection->rollBack(); + throw $e; + } + return $entity; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/ResourceModel/System/Message/Collection/Synchronized/Plugin.php b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/System/Message/Collection/Synchronized/Plugin.php new file mode 100644 index 0000000000000..76c7820fa9938 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/ResourceModel/System/Message/Collection/Synchronized/Plugin.php @@ -0,0 +1,171 @@ +messageFactory = $messageFactory; + $this->bulkStatus = $bulkStatus; + $this->userContext = $userContext; + $this->operationDetails = $operationDetails; + $this->bulkNotificationManagement = $bulkNotificationManagement; + $this->authorization = $authorization; + $this->statusMapper = $statusMapper; + } + + /** + * Adding bulk related messages to notification area + * + * @param \Magento\AdminNotification\Model\ResourceModel\System\Message\Collection\Synchronized $collection + * @param array $result + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterToArray( + \Magento\AdminNotification\Model\ResourceModel\System\Message\Collection\Synchronized $collection, + $result + ) { + if (!$this->authorization->isAllowed('Magento_Logging::system_magento_logging_bulk_operations')) { + return $result; + } + $userId = $this->userContext->getUserId(); + $userBulks = $this->bulkStatus->getBulksByUser($userId); + $acknowledgedBulks = $this->getAcknowledgedBulksUuid( + $this->bulkNotificationManagement->getAcknowledgedBulksByUser($userId) + ); + $bulkMessages = []; + foreach ($userBulks as $bulk) { + $bulkUuid = $bulk->getBulkId(); + if (!in_array($bulkUuid, $acknowledgedBulks)) { + $details = $this->operationDetails->getDetails($bulkUuid); + $text = $this->getText($details); + $bulkStatus = $this->statusMapper->operationStatusToBulkSummaryStatus($bulk->getStatus()); + if ($bulkStatus === \Magento\Framework\Bulk\BulkSummaryInterface::IN_PROGRESS) { + $text = __('%1 item(s) are currently being updated.', $details['operations_total']) . $text; + } + $data = [ + 'data' => [ + 'text' => __('Task "%1": ', $bulk->getDescription()) . $text, + 'severity' => \Magento\Framework\Notification\MessageInterface::SEVERITY_MAJOR, + 'identity' => md5('bulk' . $bulkUuid), + 'uuid' => $bulkUuid, + 'status' => $bulkStatus, + 'created_at' => $bulk->getStartTime() + ] + ]; + $bulkMessages[] = $this->messageFactory->create($data)->toArray(); + } + } + + if (!empty($bulkMessages)) { + $result['totalRecords'] += count($bulkMessages); + $bulkMessages = array_slice($bulkMessages, 0, 5); + $result['items'] = array_merge($bulkMessages, $result['items']); + } + return $result; + } + + /** + * Get Bulk notification message + * + * @param array $operationDetails + * @return \Magento\Framework\Phrase|string + */ + private function getText($operationDetails) + { + if (0 == $operationDetails['operations_successful'] && 0 == $operationDetails['operations_failed']) { + return __('%1 item(s) have been scheduled for update.', $operationDetails['operations_total']); + } + + $summaryReport = ''; + if ($operationDetails['operations_successful'] > 0) { + $summaryReport .= __( + '%1 item(s) have been successfully updated.', + $operationDetails['operations_successful'] + ) ; + } + + if ($operationDetails['operations_failed'] > 0) { + $summaryReport .= '' + . __('%1 item(s) failed to update', $operationDetails['operations_failed']) + . ''; + } + return $summaryReport; + } + + /** + * Get array with acknowledgedBulksUuid + * + * @param array $acknowledgedBulks + * @return array + */ + private function getAcknowledgedBulksUuid($acknowledgedBulks) + { + $acknowledgedBulksArray = []; + foreach ($acknowledgedBulks as $bulk) { + $acknowledgedBulksArray[] = $bulk->getBulkId(); + } + return $acknowledgedBulksArray; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Model/StatusMapper.php b/app/code/Magento/AsynchronousOperations/Model/StatusMapper.php new file mode 100644 index 0000000000000..3ad260cf26a8a --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Model/StatusMapper.php @@ -0,0 +1,62 @@ + BulkSummaryInterface::FINISHED_WITH_FAILURE, + OperationInterface::STATUS_TYPE_RETRIABLY_FAILED => BulkSummaryInterface::FINISHED_WITH_FAILURE, + OperationInterface::STATUS_TYPE_COMPLETE => BulkSummaryInterface::FINISHED_SUCCESSFULLY, + OperationInterface::STATUS_TYPE_OPEN => BulkSummaryInterface::IN_PROGRESS, + BulkSummaryInterface::NOT_STARTED => BulkSummaryInterface::NOT_STARTED + ]; + + if (isset($statusMapping[$operationStatus])) { + return $statusMapping[$operationStatus]; + } + return null; + } + + /** + * Map bulk summary status to operation status + * + * @param int $bulkStatus + * @return int|null + */ + public function bulkSummaryStatusToOperationStatus($bulkStatus) + { + $statusMapping = [ + BulkSummaryInterface::FINISHED_WITH_FAILURE => [ + OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED, + OperationInterface::STATUS_TYPE_RETRIABLY_FAILED + ], + BulkSummaryInterface::FINISHED_SUCCESSFULLY => OperationInterface::STATUS_TYPE_COMPLETE, + BulkSummaryInterface::IN_PROGRESS => OperationInterface::STATUS_TYPE_OPEN, + BulkSummaryInterface::NOT_STARTED => BulkSummaryInterface::NOT_STARTED + ]; + + if (isset($statusMapping[$bulkStatus])) { + return $statusMapping[$bulkStatus]; + } + return null; + } +} diff --git a/app/code/Magento/AsynchronousOperations/README.md b/app/code/Magento/AsynchronousOperations/README.md new file mode 100644 index 0000000000000..fb7d53df1b81c --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/README.md @@ -0,0 +1 @@ + This component is designed to provide response for client who launched the bulk operation as soon as possible and postpone handling of operations moving them to background handler. \ No newline at end of file diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Block/Adminhtml/Bulk/Details/BackButtonTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Block/Adminhtml/Bulk/Details/BackButtonTest.php new file mode 100644 index 0000000000000..d6d4c5e7479f9 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Block/Adminhtml/Bulk/Details/BackButtonTest.php @@ -0,0 +1,46 @@ +urlBuilderMock = $this->getMockBuilder(\Magento\Framework\UrlInterface::class) + ->getMock(); + $this->block = new \Magento\AsynchronousOperations\Block\Adminhtml\Bulk\Details\BackButton( + $this->urlBuilderMock + ); + } + + public function testGetButtonData() + { + $backUrl = 'back url'; + $expectedResult = [ + 'label' => __('Back'), + 'on_click' => sprintf("location.href = '%s';", $backUrl), + 'class' => 'back', + 'sort_order' => 10 + ]; + + $this->urlBuilderMock->expects($this->once()) + ->method('getUrl') + ->with('*/') + ->willReturn($backUrl); + + $this->assertEquals($expectedResult, $this->block->getButtonData()); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Block/Adminhtml/Bulk/Details/DoneButtonTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Block/Adminhtml/Bulk/Details/DoneButtonTest.php new file mode 100644 index 0000000000000..10c9d898aa526 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Block/Adminhtml/Bulk/Details/DoneButtonTest.php @@ -0,0 +1,91 @@ +bulkStatusMock = $this->createMock(\Magento\Framework\Bulk\BulkStatusInterface::class); + $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) + ->getMock(); + $this->block = new \Magento\AsynchronousOperations\Block\Adminhtml\Bulk\Details\DoneButton( + $this->bulkStatusMock, + $this->requestMock + ); + } + + /** + * @param int $failedCount + * @param int $buttonsParam + * @param array $expectedResult + * @dataProvider getButtonDataProvider + */ + public function testGetButtonData($failedCount, $buttonsParam, $expectedResult) + { + $uuid = 'some standard uuid string'; + $this->requestMock->expects($this->exactly(2)) + ->method('getParam') + ->withConsecutive(['uuid'], ['buttons']) + ->willReturnOnConsecutiveCalls($uuid, $buttonsParam); + $this->bulkStatusMock->expects($this->once()) + ->method('getOperationsCountByBulkIdAndStatus') + ->with($uuid, OperationInterface::STATUS_TYPE_RETRIABLY_FAILED) + ->willReturn($failedCount); + + $this->assertEquals($expectedResult, $this->block->getButtonData()); + } + + /** + * @return array + */ + public function getButtonDataProvider() + { + return [ + [1, 0, []], + [0, 0, []], + [ + 0, + 1, + [ + 'label' => __('Done'), + 'class' => 'primary', + 'sort_order' => 10, + 'on_click' => '', + 'data_attribute' => [ + 'mage-init' => [ + 'Magento_Ui/js/form/button-adapter' => [ + 'actions' => [ + [ + 'targetName' => 'notification_area.notification_area.modalContainer.modal', + 'actionName' => 'closeModal' + ], + ], + ], + ], + ], + ] + ], + ]; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Block/Adminhtml/Bulk/Details/RetryButtonTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Block/Adminhtml/Bulk/Details/RetryButtonTest.php new file mode 100644 index 0000000000000..b7c154be09d89 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Block/Adminhtml/Bulk/Details/RetryButtonTest.php @@ -0,0 +1,79 @@ +detailsMock = $this->getMockBuilder(\Magento\AsynchronousOperations\Model\Operation\Details::class) + ->disableOriginalConstructor() + ->getMock(); + $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) + ->getMock(); + $this->block = new \Magento\AsynchronousOperations\Block\Adminhtml\Bulk\Details\RetryButton( + $this->detailsMock, + $this->requestMock + ); + } + + /** + * @param int $failedCount + * @param array $expectedResult + * @dataProvider getButtonDataProvider + */ + public function testGetButtonData($failedCount, $expectedResult) + { + $details = ['failed_retriable' => $failedCount]; + $uuid = 'some standard uuid string'; + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('uuid') + ->willReturn($uuid); + $this->detailsMock->expects($this->once()) + ->method('getDetails') + ->with($uuid) + ->willReturn($details); + + $this->assertEquals($expectedResult, $this->block->getButtonData()); + } + + /** + * @return array + */ + public function getButtonDataProvider() + { + return [ + [0, []], + [ + 20, + [ + 'label' => __('Retry'), + 'class' => 'retry primary', + 'data_attribute' => [ + 'mage-init' => ['button' => ['event' => 'save']], + 'form-role' => 'save', + ], + ] + ], + ]; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Bulk/DetailsTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Bulk/DetailsTest.php new file mode 100644 index 0000000000000..ecd33d355c223 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Bulk/DetailsTest.php @@ -0,0 +1,78 @@ +viewMock = $this->createMock(\Magento\Framework\App\ViewInterface::class); + $this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class); + $this->resultFactoryMock = $this->createMock(\Magento\Framework\View\Result\PageFactory::class); + $this->model = $objectManager->getObject( + \Magento\AsynchronousOperations\Controller\Adminhtml\Bulk\Details::class, + [ + 'request' => $this->requestMock, + 'resultPageFactory' => $this->resultFactoryMock, + 'view' => $this->viewMock, + + ] + ); + } + + public function testExecute() + { + $id = '42'; + $parameterName = 'uuid'; + $itemId = 'Magento_AsynchronousOperations::system_magento_logging_bulk_operations'; + $layoutMock = $this->createMock(\Magento\Framework\View\LayoutInterface::class); + + $blockMock = $this->createPartialMock( + \Magento\Framework\View\Element\BlockInterface::class, + ['setActive', 'getMenuModel', 'toHtml'] + ); + $menuModelMock = $this->createMock(\Magento\Backend\Model\Menu::class); + $this->viewMock->expects($this->once())->method('getLayout')->willReturn($layoutMock); + $layoutMock->expects($this->once())->method('getBlock')->willReturn($blockMock); + $blockMock->expects($this->once())->method('setActive')->with($itemId); + $blockMock->expects($this->once())->method('getMenuModel')->willReturn($menuModelMock); + $menuModelMock->expects($this->once())->method('getParentItems')->willReturn([]); + $pageMock = $this->createMock(\Magento\Framework\View\Result\Page::class); + $pageConfigMock = $this->createMock(\Magento\Framework\View\Page\Config::class); + $titleMock = $this->createMock(\Magento\Framework\View\Page\Title::class); + $this->resultFactoryMock->expects($this->once())->method('create')->willReturn($pageMock); + $this->requestMock->expects($this->once())->method('getParam')->with($parameterName)->willReturn($id); + $pageMock->expects($this->once())->method('getConfig')->willReturn($pageConfigMock); + $pageConfigMock->expects($this->once())->method('getTitle')->willReturn($titleMock); + $titleMock->expects($this->once())->method('prepend')->with($this->stringContains($id)); + $pageMock->expects($this->once())->method('initLayout'); + $this->assertEquals($pageMock, $this->model->execute()); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Bulk/RetryTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Bulk/RetryTest.php new file mode 100644 index 0000000000000..ab5e117b0225f --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Bulk/RetryTest.php @@ -0,0 +1,166 @@ +bulkManagementMock = $this->createMock(BulkManagement::class); + $this->notificationManagementMock = $this->createMock(BulkNotificationManagement::class); + $this->requestMock = $this->createMock(RequestInterface::class); + $this->resultFactoryMock = $this->createPartialMock(ResultFactory::class, ['create']); + $this->jsonResultMock = $this->createMock(Json::class); + + $this->resultRedirectFactoryMock = $this->createPartialMock(RedirectFactory::class, ['create']); + $this->resultRedirectMock = $this->createMock(Redirect::class); + + $this->model = $objectManager->getObject( + Retry::class, + [ + 'bulkManagement' => $this->bulkManagementMock, + 'notificationManagement' => $this->notificationManagementMock, + 'request' => $this->requestMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock, + 'resultFactory' => $this->resultFactoryMock, + ] + ); + } + + public function testExecute() + { + $bulkUuid = '49da7406-1ec3-4100-95ae-9654c83a6801'; + $operationsToRetry = [ + [ + 'key' => 'value', + 'error_code' => 1111, + ], + [ + 'error_code' => 2222, + ], + [ + 'error_code' => '3333', + ], + ]; + + $this->requestMock->expects($this->any()) + ->method('getParam') + ->willReturnMap([ + ['uuid', null, $bulkUuid], + ['operations_to_retry', [], $operationsToRetry], + ['isAjax', null, false], + ]); + + $this->bulkManagementMock->expects($this->once()) + ->method('retryBulk') + ->with($bulkUuid, [1111, 2222, 3333]); + + $this->notificationManagementMock->expects($this->once()) + ->method('ignoreBulks') + ->with([$bulkUuid]) + ->willReturn(true); + + $this->resultRedirectFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->resultRedirectMock); + + $this->resultRedirectMock->expects($this->once()) + ->method('setPath') + ->with('bulk/index'); + + $this->model->execute(); + } + + public function testExecuteReturnsJsonResultWhenRequestIsSentViaAjax() + { + $bulkUuid = '49da7406-1ec3-4100-95ae-9654c83a6801'; + $operationsToRetry = [ + [ + 'key' => 'value', + 'error_code' => 1111, + ], + ]; + + $this->requestMock->expects($this->any()) + ->method('getParam') + ->willReturnMap([ + ['uuid', null, $bulkUuid], + ['operations_to_retry', [], $operationsToRetry], + ['isAjax', null, true], + ]); + + $this->bulkManagementMock->expects($this->once()) + ->method('retryBulk') + ->with($bulkUuid, [1111]); + + $this->notificationManagementMock->expects($this->once()) + ->method('ignoreBulks') + ->with([$bulkUuid]) + ->willReturn(true); + + $this->resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON, []) + ->willReturn($this->jsonResultMock); + + $this->jsonResultMock->expects($this->once()) + ->method('setHttpResponseCode') + ->with(200); + + $this->assertEquals($this->jsonResultMock, $this->model->execute()); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Index/IndexTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Index/IndexTest.php new file mode 100644 index 0000000000000..98d51d8b0fd46 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Index/IndexTest.php @@ -0,0 +1,79 @@ +viewMock = $this->createMock(\Magento\Framework\App\ViewInterface::class); + $this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class); + $this->resultFactoryMock = $this->createMock(\Magento\Framework\View\Result\PageFactory::class); + + $this->model = $objectManager->getObject( + \Magento\AsynchronousOperations\Controller\Adminhtml\Index\Index::class, + [ + 'request' => $this->requestMock, + 'view' => $this->viewMock, + 'resultPageFactory' => $this->resultFactoryMock + + ] + ); + } + + public function testExecute() + { + $itemId = 'Magento_AsynchronousOperations::system_magento_logging_bulk_operations'; + $prependText = 'Bulk Actions Log'; + $layoutMock = $this->createMock(\Magento\Framework\View\LayoutInterface::class); + $menuModelMock = $this->createMock(\Magento\Backend\Model\Menu::class); + $pageMock = $this->createMock(\Magento\Framework\View\Result\Page::class); + $pageConfigMock = $this->createMock(\Magento\Framework\View\Page\Config::class); + $titleMock = $this->createMock(\Magento\Framework\View\Page\Title::class); + $this->resultFactoryMock->expects($this->once())->method('create')->willReturn($pageMock); + + $blockMock = $this->createPartialMock( + \Magento\Framework\View\Element\BlockInterface::class, + ['setActive', 'getMenuModel', 'toHtml'] + ); + + $this->viewMock->expects($this->once())->method('getLayout')->willReturn($layoutMock); + $layoutMock->expects($this->once())->method('getBlock')->willReturn($blockMock); + $blockMock->expects($this->once())->method('setActive')->with($itemId); + $blockMock->expects($this->once())->method('getMenuModel')->willReturn($menuModelMock); + $menuModelMock->expects($this->once())->method('getParentItems')->willReturn([]); + + $pageMock->expects($this->once())->method('getConfig')->willReturn($pageConfigMock); + $pageConfigMock->expects($this->once())->method('getTitle')->willReturn($titleMock); + $titleMock->expects($this->once())->method('prepend')->with($prependText); + $pageMock->expects($this->once())->method('initLayout'); + $this->model->execute(); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Notification/DismissTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Notification/DismissTest.php new file mode 100644 index 0000000000000..8ec1ec4609aa9 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Adminhtml/Notification/DismissTest.php @@ -0,0 +1,108 @@ +notificationManagementMock = $this->createMock(BulkNotificationManagement::class); + $this->requestMock = $this->createMock(RequestInterface::class); + $this->resultFactoryMock = $this->createPartialMock(ResultFactory::class, ['create']); + + $this->jsonResultMock = $this->createMock(Json::class); + + $this->model = $objectManager->getObject( + Dismiss::class, + [ + 'notificationManagement' => $this->notificationManagementMock, + 'request' => $this->requestMock, + 'resultFactory' => $this->resultFactoryMock, + ] + ); + } + + public function testExecute() + { + $bulkUuids = ['49da7406-1ec3-4100-95ae-9654c83a6801']; + + $this->requestMock->expects($this->any()) + ->method('getParam') + ->with('uuid', []) + ->willReturn($bulkUuids); + + $this->notificationManagementMock->expects($this->once()) + ->method('acknowledgeBulks') + ->with($bulkUuids) + ->willReturn(true); + + $this->resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON, []) + ->willReturn($this->jsonResultMock); + + $this->assertEquals($this->jsonResultMock, $this->model->execute()); + } + + public function testExecuteSetsBadRequestResponseStatusIfBulkWasNotAcknowledgedCorrectly() + { + $bulkUuids = ['49da7406-1ec3-4100-95ae-9654c83a6801']; + + $this->requestMock->expects($this->any()) + ->method('getParam') + ->with('uuid', []) + ->willReturn($bulkUuids); + + $this->resultFactoryMock->expects($this->once()) + ->method('create') + ->with(ResultFactory::TYPE_JSON, []) + ->willReturn($this->jsonResultMock); + + $this->notificationManagementMock->expects($this->once()) + ->method('acknowledgeBulks') + ->with($bulkUuids) + ->willReturn(false); + + $this->jsonResultMock->expects($this->once()) + ->method('setHttpResponseCode') + ->with(400); + + $this->assertEquals($this->jsonResultMock, $this->model->execute()); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Cron/BulkCleanupTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Cron/BulkCleanupTest.php new file mode 100644 index 0000000000000..be38e9181734a --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Controller/Cron/BulkCleanupTest.php @@ -0,0 +1,79 @@ +dateTimeMock = $this->createMock(\Magento\Framework\Stdlib\DateTime::class); + $this->scopeConfigMock = $this->createMock(\Magento\Framework\App\Config\ScopeConfigInterface::class); + $this->resourceConnectionMock = $this->createMock(\Magento\Framework\App\ResourceConnection::class); + $this->metadataPoolMock = $this->createMock(\Magento\Framework\EntityManager\MetadataPool::class); + $this->timeMock = $this->createMock(\Magento\Framework\Stdlib\DateTime\DateTime::class); + $this->model = new \Magento\AsynchronousOperations\Cron\BulkCleanup( + $this->metadataPoolMock, + $this->resourceConnectionMock, + $this->dateTimeMock, + $this->scopeConfigMock, + $this->timeMock + ); + } + + public function testExecute() + { + $entityType = 'BulkSummaryInterface'; + $connectionName = 'Connection'; + $bulkLifetimeMultiplier = 10; + $bulkLifetime = 3600 * 24 * $bulkLifetimeMultiplier; + + $adapterMock = $this->createMock(\Magento\Framework\DB\Adapter\AdapterInterface::class); + $entityMetadataMock = $this->createMock(\Magento\Framework\EntityManager\EntityMetadataInterface::class); + + $this->metadataPoolMock->expects($this->once())->method('getMetadata')->with($this->stringContains($entityType)) + ->willReturn($entityMetadataMock); + $entityMetadataMock->expects($this->once())->method('getEntityConnectionName')->willReturn($connectionName); + $this->resourceConnectionMock->expects($this->once())->method('getConnectionByName')->with($connectionName) + ->willReturn($adapterMock); + $this->scopeConfigMock->expects($this->once())->method('getValue')->with($this->stringContains('bulk/lifetime')) + ->willReturn($bulkLifetimeMultiplier); + $this->timeMock->expects($this->once())->method('gmtTimestamp')->willReturn($bulkLifetime*10); + $this->dateTimeMock->expects($this->once())->method('formatDate')->with($bulkLifetime*9); + $adapterMock->expects($this->once())->method('delete'); + + $this->model->execute(); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/AccessValidatorTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/AccessValidatorTest.php new file mode 100644 index 0000000000000..8eb8778a384b0 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/AccessValidatorTest.php @@ -0,0 +1,80 @@ +userContextMock = $this->createMock(\Magento\Authorization\Model\UserContextInterface::class); + $this->entityManagerMock = $this->createMock(\Magento\Framework\EntityManager\EntityManager::class); + $this->bulkSummaryFactoryMock = $this->createPartialMock( + \Magento\AsynchronousOperations\Api\Data\BulkSummaryInterfaceFactory::class, + ['create'] + ); + + $this->model = new \Magento\AsynchronousOperations\Model\AccessValidator( + $this->userContextMock, + $this->entityManagerMock, + $this->bulkSummaryFactoryMock + ); + } + + /** + * @dataProvider summaryDataProvider + * @param string $bulkUserId + * @param bool $expectedResult + */ + public function testIsAllowed($bulkUserId, $expectedResult) + { + $adminId = 1; + $uuid = 'test-001'; + $bulkSummaryMock = $this->createMock(\Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::class); + + $this->bulkSummaryFactoryMock->expects($this->once())->method('create')->willReturn($bulkSummaryMock); + $this->entityManagerMock->expects($this->once()) + ->method('load') + ->with($bulkSummaryMock, $uuid) + ->willReturn($bulkSummaryMock); + + $bulkSummaryMock->expects($this->once())->method('getUserId')->willReturn($bulkUserId); + $this->userContextMock->expects($this->once())->method('getUserId')->willReturn($adminId); + + $this->assertEquals($this->model->isAllowed($uuid), $expectedResult); + } + + /** + * @return array + */ + public static function summaryDataProvider() + { + return [ + [2, false], + [1, true] + ]; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkDescription/OptionsTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkDescription/OptionsTest.php new file mode 100644 index 0000000000000..d5835f7856dff --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkDescription/OptionsTest.php @@ -0,0 +1,73 @@ +bulkCollectionFactoryMock = $this->createPartialMock( + \Magento\AsynchronousOperations\Model\ResourceModel\Bulk\CollectionFactory::class, + ['create'] + ); + $this->userContextMock = $this->createMock(\Magento\Authorization\Model\UserContextInterface::class); + $this->model = new \Magento\AsynchronousOperations\Model\BulkDescription\Options( + $this->bulkCollectionFactoryMock, + $this->userContextMock + ); + } + + public function testToOptionsArray() + { + $userId = 100; + $collectionMock = $this->createMock(\Magento\AsynchronousOperations\Model\ResourceModel\Bulk\Collection::class); + $selectMock = $this->createMock(\Magento\Framework\DB\Select::class); + $this->bulkCollectionFactoryMock->expects($this->once())->method('create')->willReturn($collectionMock); + + $this->userContextMock->expects($this->once())->method('getUserId')->willReturn($userId); + + $collectionMock->expects($this->once())->method('getMainTable')->willReturn('table'); + + $selectMock->expects($this->once())->method('reset')->willReturnSelf(); + $selectMock->expects($this->once())->method('distinct')->with(true)->willReturnSelf(); + $selectMock->expects($this->once())->method('from')->with('table', ['description'])->willReturnSelf(); + $selectMock->expects($this->once())->method('where')->with('user_id = ?', $userId)->willReturnSelf(); + + $itemMock = $this->createPartialMock( + \Magento\AsynchronousOperations\Model\BulkSummary::class, + ['getDescription'] + ); + $itemMock->expects($this->exactly(2))->method('getDescription')->willReturn('description'); + + $collectionMock->expects($this->once())->method('getSelect')->willReturn($selectMock); + $collectionMock->expects($this->once())->method('getItems')->willReturn([$itemMock]); + + $expectedResult = [ + [ + 'value' => 'description', + 'label' => 'description' + ] + ]; + + $this->assertEquals($expectedResult, $this->model->toOptionArray()); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php new file mode 100644 index 0000000000000..3a45c34df17f8 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkManagementTest.php @@ -0,0 +1,296 @@ +entityManager = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityManager::class) + ->disableOriginalConstructor()->getMock(); + $this->bulkSummaryFactory = $this + ->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\BulkSummaryInterfaceFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->operationCollectionFactory = $this + ->getMockBuilder(\Magento\AsynchronousOperations\Model\ResourceModel\Operation\CollectionFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor() + ->getMock(); + $this->publisher = $this->getMockBuilder(\Magento\Framework\MessageQueue\BulkPublisherInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->metadataPool = $this->getMockBuilder(\Magento\Framework\EntityManager\MetadataPool::class) + ->disableOriginalConstructor()->getMock(); + $this->resourceConnection = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class) + ->disableOriginalConstructor()->getMock(); + $this->logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) + ->disableOriginalConstructor()->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->bulkManagement = $objectManager->getObject( + \Magento\AsynchronousOperations\Model\BulkManagement::class, + [ + 'entityManager' => $this->entityManager, + 'bulkSummaryFactory' => $this->bulkSummaryFactory, + 'operationCollectionFactory' => $this->operationCollectionFactory, + 'publisher' => $this->publisher, + 'metadataPool' => $this->metadataPool, + 'resourceConnection' => $this->resourceConnection, + 'logger' => $this->logger, + ] + ); + } + + /** + * Test for scheduleBulk method. + * + * @return void + */ + public function testScheduleBulk() + { + $bulkUuid = 'bulk-001'; + $description = 'Bulk summary description...'; + $userId = 1; + $connectionName = 'default'; + $topicNames = ['topic.name.0', 'topic.name.1']; + $operation = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\OperationInterface::class) + ->disableOriginalConstructor()->getMock(); + $metadata = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->metadataPool->expects($this->once())->method('getMetadata') + ->with(\Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::class) + ->willReturn($metadata); + $metadata->expects($this->once())->method('getEntityConnectionName')->willReturn($connectionName); + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->resourceConnection->expects($this->once()) + ->method('getConnectionByName')->with($connectionName)->willReturn($connection); + $connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); + $bulkSummary = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->bulkSummaryFactory->expects($this->once())->method('create')->willReturn($bulkSummary); + $this->entityManager->expects($this->once()) + ->method('load')->with($bulkSummary, $bulkUuid)->willReturn($bulkSummary); + $bulkSummary->expects($this->once())->method('setBulkId')->with($bulkUuid)->willReturnSelf(); + $bulkSummary->expects($this->once())->method('setDescription')->with($description)->willReturnSelf(); + $bulkSummary->expects($this->once())->method('setUserId')->with($userId)->willReturnSelf(); + $bulkSummary->expects($this->once())->method('getOperationCount')->willReturn(1); + $bulkSummary->expects($this->once())->method('setOperationCount')->with(3)->willReturnSelf(); + $this->entityManager->expects($this->once())->method('save')->with($bulkSummary)->willReturn($bulkSummary); + $connection->expects($this->once())->method('commit')->willReturnSelf(); + $operation->expects($this->exactly(2))->method('getTopicName') + ->willReturnOnConsecutiveCalls($topicNames[0], $topicNames[1]); + $this->publisher->expects($this->exactly(2))->method('publish') + ->withConsecutive([$topicNames[0], [$operation]], [$topicNames[1], [$operation]])->willReturn(null); + $this->assertTrue( + $this->bulkManagement->scheduleBulk($bulkUuid, [$operation, $operation], $description, $userId) + ); + } + + /** + * Test for scheduleBulk method with exception. + * + * @return void + */ + public function testScheduleBulkWithException() + { + $bulkUuid = 'bulk-001'; + $description = 'Bulk summary description...'; + $userId = 1; + $connectionName = 'default'; + $exceptionMessage = 'Exception message'; + $operation = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\OperationInterface::class) + ->disableOriginalConstructor()->getMock(); + $metadata = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->metadataPool->expects($this->once())->method('getMetadata') + ->with(\Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::class) + ->willReturn($metadata); + $metadata->expects($this->once())->method('getEntityConnectionName')->willReturn($connectionName); + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->resourceConnection->expects($this->once()) + ->method('getConnectionByName')->with($connectionName)->willReturn($connection); + $connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); + $bulkSummary = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->bulkSummaryFactory->expects($this->once())->method('create')->willReturn($bulkSummary); + $this->entityManager->expects($this->once())->method('load') + ->with($bulkSummary, $bulkUuid)->willThrowException(new \LogicException($exceptionMessage)); + $connection->expects($this->once())->method('rollBack')->willReturnSelf(); + $this->logger->expects($this->once())->method('critical')->with($exceptionMessage); + $this->publisher->expects($this->never())->method('publish'); + $this->assertFalse($this->bulkManagement->scheduleBulk($bulkUuid, [$operation], $description, $userId)); + } + + /** + * Test for retryBulk method. + * + * @return void + */ + public function testRetryBulk() + { + $bulkUuid = 'bulk-001'; + $errorCodes = ['errorCode']; + $connectionName = 'default'; + $operationId = 1; + $operationTable = 'magento_operation'; + $topicName = 'topic.name'; + $metadata = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->metadataPool->expects($this->once())->method('getMetadata') + ->with(\Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::class) + ->willReturn($metadata); + $metadata->expects($this->once())->method('getEntityConnectionName')->willReturn($connectionName); + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->resourceConnection->expects($this->once()) + ->method('getConnectionByName')->with($connectionName)->willReturn($connection); + $operationCollection = $this + ->getMockBuilder(\Magento\AsynchronousOperations\Model\ResourceModel\Operation\Collection::class) + ->disableOriginalConstructor()->getMock(); + $this->operationCollectionFactory->expects($this->once())->method('create')->willReturn($operationCollection); + $operationCollection->expects($this->exactly(2))->method('addFieldToFilter') + ->withConsecutive(['error_code', ['in' => $errorCodes]], ['bulk_uuid', ['eq' => $bulkUuid]]) + ->willReturnSelf(); + $operation = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\OperationInterface::class) + ->disableOriginalConstructor()->getMock(); + $operationCollection->expects($this->once())->method('getItems')->willReturn([$operation]); + $connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); + $operation->expects($this->once())->method('getId')->willReturn($operationId); + $operation->expects($this->once())->method('setId')->with(null)->willReturnSelf(); + $this->resourceConnection->expects($this->once()) + ->method('getTableName')->with($operationTable)->willReturn($operationTable); + $connection->expects($this->once()) + ->method('quoteInto')->with('id IN (?)', [$operationId])->willReturn('id IN (' . $operationId .')'); + $connection->expects($this->once()) + ->method('delete')->with($operationTable, 'id IN (' . $operationId .')')->willReturn(1); + $connection->expects($this->once())->method('commit')->willReturnSelf(); + $operation->expects($this->once())->method('getTopicName')->willReturn($topicName); + $this->publisher->expects($this->once())->method('publish')->with($topicName, [$operation])->willReturn(null); + $this->assertEquals(1, $this->bulkManagement->retryBulk($bulkUuid, $errorCodes)); + } + + /** + * Test for retryBulk method with exception. + * + * @return void + */ + public function testRetryBulkWithException() + { + $bulkUuid = 'bulk-001'; + $errorCodes = ['errorCode']; + $connectionName = 'default'; + $operationId = 1; + $operationTable = 'magento_operation'; + $exceptionMessage = 'Exception message'; + $metadata = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->metadataPool->expects($this->once())->method('getMetadata') + ->with(\Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::class) + ->willReturn($metadata); + $metadata->expects($this->once())->method('getEntityConnectionName')->willReturn($connectionName); + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->resourceConnection->expects($this->once()) + ->method('getConnectionByName')->with($connectionName)->willReturn($connection); + $operationCollection = $this + ->getMockBuilder(\Magento\AsynchronousOperations\Model\ResourceModel\Operation\Collection::class) + ->disableOriginalConstructor()->getMock(); + $this->operationCollectionFactory->expects($this->once())->method('create')->willReturn($operationCollection); + $operationCollection->expects($this->exactly(2))->method('addFieldToFilter') + ->withConsecutive(['error_code', ['in' => $errorCodes]], ['bulk_uuid', ['eq' => $bulkUuid]]) + ->willReturnSelf(); + $operation = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\OperationInterface::class) + ->disableOriginalConstructor()->getMock(); + $operationCollection->expects($this->once())->method('getItems')->willReturn([$operation]); + $connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); + $operation->expects($this->once())->method('getId')->willReturn($operationId); + $operation->expects($this->once())->method('setId')->with(null)->willReturnSelf(); + $this->resourceConnection->expects($this->once()) + ->method('getTableName')->with($operationTable)->willReturn($operationTable); + $connection->expects($this->once()) + ->method('quoteInto')->with('id IN (?)', [$operationId])->willReturn('id IN (' . $operationId .')'); + $connection->expects($this->once()) + ->method('delete')->with($operationTable, 'id IN (' . $operationId .')') + ->willThrowException(new \Exception($exceptionMessage)); + $connection->expects($this->once())->method('rollBack')->willReturnSelf(); + $this->logger->expects($this->once())->method('critical')->with($exceptionMessage); + $this->publisher->expects($this->never())->method('publish'); + $this->assertEquals(0, $this->bulkManagement->retryBulk($bulkUuid, $errorCodes)); + } + + /** + * Test for deleteBulk method. + * + * @return void + */ + public function testDeleteBulk() + { + $bulkUuid = 'bulk-001'; + $bulkSummary = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->bulkSummaryFactory->expects($this->once())->method('create')->willReturn($bulkSummary); + $this->entityManager->expects($this->once()) + ->method('load')->with($bulkSummary, $bulkUuid)->willReturn($bulkSummary); + $this->entityManager->expects($this->once())->method('delete')->with($bulkSummary)->willReturn(true); + $this->assertTrue($this->bulkManagement->deleteBulk($bulkUuid)); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkStatusTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkStatusTest.php new file mode 100644 index 0000000000000..cda55161ab852 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/BulkStatusTest.php @@ -0,0 +1,239 @@ +bulkCollectionFactory = $this->createPartialMock( + \Magento\AsynchronousOperations\Model\ResourceModel\Bulk\CollectionFactory::class, + ['create'] + ); + $this->operationCollectionFactory = $this->createPartialMock( + \Magento\AsynchronousOperations\Model\ResourceModel\Operation\CollectionFactory::class, + ['create'] + ); + $this->operationMock = $this->createMock(\Magento\AsynchronousOperations\Api\Data\OperationInterface::class); + $this->bulkMock = $this->createMock(\Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::class); + $this->resourceConnectionMock = $this->createMock(\Magento\Framework\App\ResourceConnection::class); + $this->calculatedStatusSqlMock = $this->createMock( + \Magento\AsynchronousOperations\Model\BulkStatus\CalculatedStatusSql::class + ); + $this->metadataPoolMock = $this->createMock(\Magento\Framework\EntityManager\MetadataPool::class); + + $this->entityMetadataMock = $this->createMock(\Magento\Framework\EntityManager\EntityMetadataInterface::class); + $this->connectionMock = $this->createMock(\Magento\Framework\DB\Adapter\AdapterInterface::class); + + $this->model = new \Magento\AsynchronousOperations\Model\BulkStatus( + $this->bulkCollectionFactory, + $this->operationCollectionFactory, + $this->resourceConnectionMock, + $this->calculatedStatusSqlMock, + $this->metadataPoolMock + ); + } + + /** + * @param int|null $failureType + * @param array $failureCodes + * @dataProvider getFailedOperationsByBulkIdDataProvider + */ + public function testGetFailedOperationsByBulkId($failureType, $failureCodes) + { + $bulkUuid = 'bulk-1'; + $operationCollection = $this->createMock( + \Magento\AsynchronousOperations\Model\ResourceModel\Operation\Collection::class + ); + $this->operationCollectionFactory->expects($this->once())->method('create')->willReturn($operationCollection); + $operationCollection + ->expects($this->at(0)) + ->method('addFieldToFilter') + ->with('bulk_uuid', $bulkUuid) + ->willReturnSelf(); + $operationCollection + ->expects($this->at(1)) + ->method('addFieldToFilter') + ->with('status', $failureCodes) + ->willReturnSelf(); + $operationCollection->expects($this->once())->method('getItems')->willReturn([$this->operationMock]); + $this->assertEquals([$this->operationMock], $this->model->getFailedOperationsByBulkId($bulkUuid, $failureType)); + } + + public function testGetOperationsCountByBulkIdAndStatus() + { + $bulkUuid = 'bulk-1'; + $status = 1354; + $size = 32; + + $operationCollection = $this->createMock( + \Magento\AsynchronousOperations\Model\ResourceModel\Operation\Collection::class + ); + $this->operationCollectionFactory->expects($this->once())->method('create')->willReturn($operationCollection); + $operationCollection + ->expects($this->at(0)) + ->method('addFieldToFilter') + ->with('bulk_uuid', $bulkUuid) + ->willReturnSelf(); + $operationCollection + ->expects($this->at(1)) + ->method('addFieldToFilter') + ->with('status', $status) + ->willReturnSelf(); + $operationCollection + ->expects($this->once()) + ->method('getSize') + ->willReturn($size); + $this->assertEquals($size, $this->model->getOperationsCountByBulkIdAndStatus($bulkUuid, $status)); + } + + public function getFailedOperationsByBulkIdDataProvider() + { + return [ + [1, [1]], + [null, + [ + OperationInterface::STATUS_TYPE_RETRIABLY_FAILED, + OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED + ] + ] + ]; + } + + public function testGetBulksByUser() + { + $userId = 1; + $selectMock = $this->createMock(\Magento\Framework\DB\Select::class); + $bulkCollection = $this->createMock(\Magento\AsynchronousOperations\Model\ResourceModel\Bulk\Collection::class); + $bulkCollection->expects($this->once())->method('getSelect')->willReturn($selectMock); + $selectMock->expects($this->once())->method('columns')->willReturnSelf(); + $selectMock->expects($this->once())->method('order')->willReturnSelf(); + $this->bulkCollectionFactory->expects($this->once())->method('create')->willReturn($bulkCollection); + $bulkCollection->expects($this->once())->method('addFieldToFilter')->with('user_id', $userId)->willReturnSelf(); + $bulkCollection->expects($this->once())->method('getItems')->willReturn([$this->bulkMock]); + $this->assertEquals([$this->bulkMock], $this->model->getBulksByUser($userId)); + } + + public function testGetBulksStatus() + { + $bulkUuid = 'bulk-1'; + $allProcessedOperationCollection = $this->createMock( + \Magento\AsynchronousOperations\Model\ResourceModel\Operation\Collection::class + ); + + $completeOperationCollection = $this->createMock( + \Magento\AsynchronousOperations\Model\ResourceModel\Operation\Collection::class + ); + + $connectionName = 'connection_name'; + $entityType = \Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::class; + $this->metadataPoolMock + ->expects($this->once()) + ->method('getMetadata') + ->with($entityType) + ->willReturn($this->entityMetadataMock); + $this->entityMetadataMock + ->expects($this->once()) + ->method('getEntityConnectionName') + ->willReturn($connectionName); + $this->resourceConnectionMock + ->expects($this->once()) + ->method('getConnectionByName') + ->with($connectionName) + ->willReturn($this->connectionMock); + + $selectMock = $this->createMock(\Magento\Framework\DB\Select::class); + $selectMock->expects($this->once())->method('from')->willReturnSelf(); + $selectMock->expects($this->once())->method('where')->with('uuid = ?', $bulkUuid)->willReturnSelf(); + $this->connectionMock->expects($this->once())->method('select')->willReturn($selectMock); + $this->connectionMock->expects($this->once())->method('fetchOne')->with($selectMock)->willReturn(10); + + $this->operationCollectionFactory + ->expects($this->at(0)) + ->method('create') + ->willReturn($allProcessedOperationCollection); + $this->operationCollectionFactory + ->expects($this->at(1)) + ->method('create') + ->willReturn($completeOperationCollection); + $allProcessedOperationCollection + ->expects($this->once()) + ->method('addFieldToFilter') + ->with('bulk_uuid', $bulkUuid) + ->willReturnSelf(); + $allProcessedOperationCollection->expects($this->once())->method('getSize')->willReturn(5); + + $completeOperationCollection + ->expects($this->at(0)) + ->method('addFieldToFilter') + ->with('bulk_uuid', $bulkUuid) + ->willReturnSelf(); + $completeOperationCollection + ->expects($this->at(1)) + ->method('addFieldToFilter') + ->with('status', OperationInterface::STATUS_TYPE_COMPLETE) + ->willReturnSelf(); + $completeOperationCollection->expects($this->any())->method('getSize')->willReturn(5); + $this->assertEquals(BulkSummaryInterface::IN_PROGRESS, $this->model->getBulkStatus($bulkUuid)); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/Entity/BulkSummaryMapperTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/Entity/BulkSummaryMapperTest.php new file mode 100644 index 0000000000000..725eae3c01ea3 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/Entity/BulkSummaryMapperTest.php @@ -0,0 +1,105 @@ +metadataPoolMock = $this->createMock(\Magento\Framework\EntityManager\MetadataPool::class); + $this->resourceConnectionMock = $this->createMock(\Magento\Framework\App\ResourceConnection::class); + $this->entityMetadataMock = $this->createMock(\Magento\Framework\EntityManager\EntityMetadataInterface::class); + $this->connectionMock = $this->createMock(\Magento\Framework\DB\Adapter\AdapterInterface::class); + $this->selectMock = $this->createMock(\Magento\Framework\DB\Select::class); + $this->model = new BulkSummaryMapper( + $this->metadataPoolMock, + $this->resourceConnectionMock + ); + } + + /** + * @param int $identifier + * @param array|false $result + * @dataProvider entityToDatabaseDataProvider + */ + public function testEntityToDatabase($identifier, $result) + { + $entityType = 'entityType'; + $data = ['uuid' => 'bulk-1']; + $connectionName = 'connection_name'; + $entityTable = 'table_name'; + $this->metadataPoolMock + ->expects($this->once()) + ->method('getMetadata') + ->with($entityType) + ->willReturn($this->entityMetadataMock); + $this->entityMetadataMock + ->expects($this->once()) + ->method('getEntityConnectionName') + ->willReturn($connectionName); + + $this->resourceConnectionMock + ->expects($this->once()) + ->method('getConnectionByName') + ->with($connectionName) + ->willReturn($this->connectionMock); + $this->connectionMock->expects($this->once())->method('select')->willReturn($this->selectMock); + $this->entityMetadataMock->expects($this->once())->method('getEntityTable')->willReturn($entityTable); + $this->selectMock->expects($this->once())->method('from')->with($entityTable, 'id')->willReturnSelf(); + $this->selectMock->expects($this->once())->method('where')->with("uuid = ?", 'bulk-1')->willReturnSelf(); + $this->connectionMock + ->expects($this->once()) + ->method('fetchOne') + ->with($this->selectMock) + ->willReturn($identifier); + + $this->assertEquals($result, $this->model->entityToDatabase($entityType, $data)); + } + + public function entityToDatabaseDataProvider() + { + return [ + [1, ['uuid' => 'bulk-1', 'id' => 1]], + [false, ['uuid' => 'bulk-1']] + ]; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/Operation/DetailsTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/Operation/DetailsTest.php new file mode 100644 index 0000000000000..7060a48e77390 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/Operation/DetailsTest.php @@ -0,0 +1,57 @@ +bulkStatusMock = $this->getMockBuilder(\Magento\Framework\Bulk\BulkStatusInterface::class) + ->getMock(); + $this->model = new \Magento\AsynchronousOperations\Model\Operation\Details($this->bulkStatusMock); + } + + public function testGetDetails() + { + $uuid = 'some_uuid_string'; + $completed = 100; + $failedRetriable = 23; + $failedNotRetriable = 45; + $open = 303; + + $expectedResult = [ + 'operations_total' => $completed + $failedRetriable + $failedNotRetriable + $open, + 'operations_successful' => $completed, + 'operations_failed' => $failedRetriable + $failedNotRetriable, + 'failed_retriable' => $failedRetriable, + 'failed_not_retriable' => $failedNotRetriable, + ]; + + $this->bulkStatusMock->method('getOperationsCountByBulkIdAndStatus') + ->willReturnMap([ + [$uuid, OperationInterface::STATUS_TYPE_COMPLETE, $completed], + [$uuid, OperationInterface::STATUS_TYPE_RETRIABLY_FAILED, $failedRetriable], + [$uuid, OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED, $failedNotRetriable], + [$uuid, OperationInterface::STATUS_TYPE_OPEN, $open], + ]); + + $result = $this->model->getDetails($uuid); + $this->assertEquals($expectedResult, $result); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/OperationManagementTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/OperationManagementTest.php new file mode 100644 index 0000000000000..32146b7b6eb19 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/OperationManagementTest.php @@ -0,0 +1,89 @@ +entityManagerMock = $this->createMock(\Magento\Framework\EntityManager\EntityManager::class); + $this->metadataPoolMock = $this->createMock(\Magento\Framework\EntityManager\MetadataPool::class); + $this->operationFactoryMock = $this->createPartialMock( + \Magento\AsynchronousOperations\Api\Data\OperationInterfaceFactory::class, + ['create'] + ); + $this->operationMock = $this->createMock(\Magento\AsynchronousOperations\Api\Data\OperationInterface::class); + $this->loggerMock = $this->createMock(\Psr\Log\LoggerInterface::class); + $this->model = new \Magento\AsynchronousOperations\Model\OperationManagement( + $this->entityManagerMock, + $this->operationFactoryMock, + $this->loggerMock + ); + } + + public function testChangeOperationStatus() + { + $operationId = 1; + $status = 1; + $message = 'Message'; + $data = 'data'; + $errorCode = 101; + $this->operationFactoryMock->expects($this->once())->method('create')->willReturn($this->operationMock); + $this->entityManagerMock->expects($this->once())->method('load')->with($this->operationMock, $operationId); + $this->operationMock->expects($this->once())->method('setStatus')->with($status)->willReturnSelf(); + $this->operationMock->expects($this->once())->method('setResultMessage')->with($message)->willReturnSelf(); + $this->operationMock->expects($this->once())->method('setSerializedData')->with($data)->willReturnSelf(); + $this->operationMock->expects($this->once())->method('setErrorCode')->with($errorCode)->willReturnSelf(); + $this->entityManagerMock->expects($this->once())->method('save')->with($this->operationMock); + $this->assertTrue($this->model->changeOperationStatus($operationId, $status, $errorCode, $message, $data)); + } + + public function testChangeOperationStatusIfExceptionWasThrown() + { + $operationId = 1; + $status = 1; + $message = 'Message'; + $data = 'data'; + $errorCode = 101; + $this->operationFactoryMock->expects($this->once())->method('create')->willReturn($this->operationMock); + $this->entityManagerMock->expects($this->once())->method('load')->with($this->operationMock, $operationId); + $this->operationMock->expects($this->once())->method('setStatus')->with($status)->willReturnSelf(); + $this->operationMock->expects($this->once())->method('setResultMessage')->with($message)->willReturnSelf(); + $this->operationMock->expects($this->once())->method('setSerializedData')->with($data)->willReturnSelf(); + $this->operationMock->expects($this->once())->method('setErrorCode')->with($errorCode)->willReturnSelf(); + $this->entityManagerMock->expects($this->once())->method('save')->willThrowException(new \Exception()); + $this->loggerMock->expects($this->once())->method('critical'); + $this->assertFalse($this->model->changeOperationStatus($operationId, $status, $errorCode, $message, $data)); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/ResourceModel/Operation/CreateTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/ResourceModel/Operation/CreateTest.php new file mode 100644 index 0000000000000..2f0fc8ceba46f --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/ResourceModel/Operation/CreateTest.php @@ -0,0 +1,134 @@ +metadataPool = $this->getMockBuilder(\Magento\Framework\EntityManager\MetadataPool::class) + ->disableOriginalConstructor()->getMock(); + $this->typeResolver = $this->getMockBuilder(\Magento\Framework\EntityManager\TypeResolver::class) + ->disableOriginalConstructor()->getMock(); + $this->resourceConnection = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class) + ->disableOriginalConstructor()->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->create = $objectManager->getObject( + \Magento\AsynchronousOperations\Model\ResourceModel\Operation\Create::class, + [ + 'metadataPool' => $this->metadataPool, + 'typeResolver' => $this->typeResolver, + 'resourceConnection' => $this->resourceConnection, + ] + ); + } + + /** + * Test for execute method. + * + * @return void + */ + public function testExecute() + { + $connectionName = 'default'; + $operationData = ['key1' => 'value1']; + $operationTable = 'magento_operation'; + $operationList = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\OperationListInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->typeResolver->expects($this->once())->method('resolve')->with($operationList) + ->willReturn(\Magento\AsynchronousOperations\Api\Data\OperationListInterface::class); + $metadata = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->metadataPool->expects($this->once())->method('getMetadata') + ->with(\Magento\AsynchronousOperations\Api\Data\OperationListInterface::class)->willReturn($metadata); + $metadata->expects($this->once())->method('getEntityConnectionName')->willReturn($connectionName); + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->resourceConnection->expects($this->once()) + ->method('getConnection')->with($connectionName)->willReturn($connection); + $connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); + $operation = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\OperationInterface::class) + ->setMethods(['getData']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $operationList->expects($this->once())->method('getItems')->willReturn([$operation]); + $operation->expects($this->once())->method('getData')->willReturn($operationData); + $metadata->expects($this->once())->method('getEntityTable')->willReturn($operationTable); + $connection->expects($this->once())->method('insertOnDuplicate') + ->with($operationTable, [$operationData], ['status', 'error_code', 'result_message'])->willReturn(1); + $connection->expects($this->once())->method('commit')->willReturnSelf(); + $this->assertEquals($operationList, $this->create->execute($operationList)); + } + + /** + * Test for execute method with exception. + * + * @return void + * @expectedException \Exception + */ + public function testExecuteWithException() + { + $connectionName = 'default'; + $operationData = ['key1' => 'value1']; + $operationTable = 'magento_operation'; + $operationList = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\OperationListInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->typeResolver->expects($this->once())->method('resolve')->with($operationList) + ->willReturn(\Magento\AsynchronousOperations\Api\Data\OperationListInterface::class); + $metadata = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->metadataPool->expects($this->once())->method('getMetadata') + ->with(\Magento\AsynchronousOperations\Api\Data\OperationListInterface::class)->willReturn($metadata); + $metadata->expects($this->once())->method('getEntityConnectionName')->willReturn($connectionName); + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->resourceConnection->expects($this->once()) + ->method('getConnection')->with($connectionName)->willReturn($connection); + $connection->expects($this->once())->method('beginTransaction')->willReturnSelf(); + $operation = $this->getMockBuilder(\Magento\AsynchronousOperations\Api\Data\OperationInterface::class) + ->setMethods(['getData']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $operationList->expects($this->once())->method('getItems')->willReturn([$operation]); + $operation->expects($this->once())->method('getData')->willReturn($operationData); + $metadata->expects($this->once())->method('getEntityTable')->willReturn($operationTable); + $connection->expects($this->once())->method('insertOnDuplicate') + ->with($operationTable, [$operationData], ['status', 'error_code', 'result_message']) + ->willThrowException(new \Exception()); + $connection->expects($this->once())->method('rollBack')->willReturnSelf(); + $this->create->execute($operationList); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/ResourceModel/System/Message/Collection/Synchronized/PluginTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/ResourceModel/System/Message/Collection/Synchronized/PluginTest.php new file mode 100644 index 0000000000000..68864d12e7672 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/ResourceModel/System/Message/Collection/Synchronized/PluginTest.php @@ -0,0 +1,169 @@ +messagefactoryMock = $this->createPartialMock( + \Magento\AdminNotification\Model\System\MessageFactory::class, + ['create'] + ); + $this->bulkStatusMock = $this->createMock(BulkStatusInterface::class); + + $this->userContextMock = $this->createMock(UserContextInterface::class); + $this->operationsDetailsMock = $this->createMock(Details::class); + $this->authorizationMock = $this->createMock(AuthorizationInterface::class); + $this->messageMock = $this->createMock(\Magento\AdminNotification\Model\System\Message::class); + $this->collectionMock = $this->createMock(Synchronized::class); + $this->bulkNotificationMock = $this->createMock(BulkNotificationManagement::class); + $this->statusMapper = $this->createMock(\Magento\AsynchronousOperations\Model\StatusMapper::class); + $this->plugin = new Plugin( + $this->messagefactoryMock, + $this->bulkStatusMock, + $this->bulkNotificationMock, + $this->userContextMock, + $this->operationsDetailsMock, + $this->authorizationMock, + $this->statusMapper + ); + } + + public function testAfterToArrayIfNotAllowed() + { + $result = []; + $this->authorizationMock + ->expects($this->once()) + ->method('isAllowed') + ->with($this->resourceName) + ->willReturn(false); + $this->assertEquals($result, $this->plugin->afterToArray($this->collectionMock, $result)); + } + + /** + * @param array $operationDetails + * @dataProvider afterToDataProvider + */ + public function testAfterTo($operationDetails) + { + $methods = ['getBulkId', 'getDescription', 'getStatus', 'getStartTime']; + $bulkMock = $this->createPartialMock(\Magento\AsynchronousOperations\Model\BulkSummary::class, $methods); + $result = ['items' =>[], 'totalRecords' => 1]; + $userBulks = [$bulkMock]; + $userId = 1; + $bulkUuid = 2; + $bulkArray = [ + 'status' => \Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface::NOT_STARTED + ]; + $bulkMock->expects($this->once())->method('getBulkId')->willReturn($bulkUuid); + $this->operationsDetailsMock + ->expects($this->once()) + ->method('getDetails') + ->with($bulkUuid) + ->willReturn($operationDetails); + $bulkMock->expects($this->once())->method('getDescription')->willReturn('Bulk Description'); + $this->messagefactoryMock->expects($this->once())->method('create')->willReturn($this->messageMock); + $this->messageMock->expects($this->once())->method('toArray')->willReturn($bulkArray); + $this->authorizationMock + ->expects($this->once()) + ->method('isAllowed') + ->with($this->resourceName) + ->willReturn(true); + $this->userContextMock->expects($this->once())->method('getUserId')->willReturn($userId); + $this->bulkNotificationMock + ->expects($this->once()) + ->method('getAcknowledgedBulksByUser') + ->with($userId) + ->willReturn([]); + $this->statusMapper->expects($this->once())->method('operationStatusToBulkSummaryStatus'); + $this->bulkStatusMock->expects($this->once())->method('getBulksByUser')->willReturn($userBulks); + $result2 = $this->plugin->afterToArray($this->collectionMock, $result); + $this->assertEquals(2, $result2['totalRecords']); + } + + public function afterToDataProvider() + { + return [ + ['operations_successful' => 0, + 'operations_failed' => 0, + 'operations_total' => 10 + ], + ['operations_successful' => 1, + 'operations_failed' => 2, + 'operations_total' => 10 + ], + ]; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Model/StatusMapperTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/StatusMapperTest.php new file mode 100644 index 0000000000000..87d2bbac3cadc --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Model/StatusMapperTest.php @@ -0,0 +1,90 @@ +model = new \Magento\AsynchronousOperations\Model\StatusMapper(); + } + + public function testOperationStatusToBulkSummaryStatus() + { + $this->assertEquals( + $this->model->operationStatusToBulkSummaryStatus(OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED), + BulkSummaryInterface::FINISHED_WITH_FAILURE + ); + + $this->assertEquals( + $this->model->operationStatusToBulkSummaryStatus(OperationInterface::STATUS_TYPE_RETRIABLY_FAILED), + BulkSummaryInterface::FINISHED_WITH_FAILURE + ); + + $this->assertEquals( + $this->model->operationStatusToBulkSummaryStatus(OperationInterface::STATUS_TYPE_COMPLETE), + BulkSummaryInterface::FINISHED_SUCCESSFULLY + ); + + $this->assertEquals( + $this->model->operationStatusToBulkSummaryStatus(OperationInterface::STATUS_TYPE_OPEN), + BulkSummaryInterface::IN_PROGRESS + ); + + $this->assertEquals( + $this->model->operationStatusToBulkSummaryStatus(0), + BulkSummaryInterface::NOT_STARTED + ); + } + + public function testOperationStatusToBulkSummaryStatusWithUnknownStatus() + { + $this->assertNull($this->model->operationStatusToBulkSummaryStatus('unknown_status')); + } + + public function testBulkSummaryStatusToOperationStatus() + { + $this->assertEquals( + $this->model->bulkSummaryStatusToOperationStatus(BulkSummaryInterface::FINISHED_SUCCESSFULLY), + OperationInterface::STATUS_TYPE_COMPLETE + ); + + $this->assertEquals( + $this->model->bulkSummaryStatusToOperationStatus(BulkSummaryInterface::IN_PROGRESS), + OperationInterface::STATUS_TYPE_OPEN + ); + + $this->assertEquals( + $this->model->bulkSummaryStatusToOperationStatus(BulkSummaryInterface::FINISHED_WITH_FAILURE), + [ + OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED, + OperationInterface::STATUS_TYPE_RETRIABLY_FAILED + ] + ); + + $this->assertEquals( + $this->model->bulkSummaryStatusToOperationStatus(BulkSummaryInterface::NOT_STARTED), + 0 + ); + } + + public function testBulkSummaryStatusToOperationStatusWithUnknownStatus() + { + $this->assertNull($this->model->bulkSummaryStatusToOperationStatus('unknown_status')); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/AdminNotification/PluginTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/AdminNotification/PluginTest.php new file mode 100644 index 0000000000000..cc0b3a3da38a7 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/AdminNotification/PluginTest.php @@ -0,0 +1,48 @@ +authorizationMock = $this->createMock(AuthorizationInterface::class); + $this->plugin = new \Magento\AsynchronousOperations\Ui\Component\AdminNotification\Plugin( + $this->authorizationMock + ); + } + + public function testAfterGetMeta() + { + $result = []; + $expectedResult = [ + 'columns' => [ + 'arguments' => [ + 'data' => [ + 'config' => [ + 'isAllowed' => true + ] + ] + ] + ] + ]; + $dataProviderMock = $this->createMock(\Magento\AdminNotification\Ui\Component\DataProvider\DataProvider::class); + $this->authorizationMock->expects($this->once())->method('isAllowed')->willReturn(true); + $this->assertEquals($expectedResult, $this->plugin->afterGetMeta($dataProviderMock, $result)); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Listing/Column/ActionsTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Listing/Column/ActionsTest.php new file mode 100644 index 0000000000000..f5cce7af943a1 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Listing/Column/ActionsTest.php @@ -0,0 +1,76 @@ +context = $this->createMock(\Magento\Framework\View\Element\UiComponent\ContextInterface::class); + $this->uiComponentFactory = $this->createMock(\Magento\Framework\View\Element\UiComponentFactory::class); + $processor = $this->createPartialMock( + \Magento\Framework\View\Element\UiComponent\Processor::class, + ['getProcessor'] + ); + $this->context->expects($this->never())->method('getProcessor')->will($this->returnValue($processor)); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->actionColumn = $objectManager->getObject( + \Magento\AsynchronousOperations\Ui\Component\Listing\Column\Actions::class, + [ + 'context' => $this->context, + 'uiComponentFactory' => $this->uiComponentFactory, + 'components' => [], + 'data' => ['name' => 'Edit'], + 'editUrl' => '' + ] + ); + } + + /** + * Test for method prepareDataSource + */ + public function testPrepareDataSource() + { + $href = 'bulk/bulk/details/id/bulk-1'; + $this->context->expects($this->once())->method('getUrl')->with( + 'bulk/bulk/details', + ['uuid' => 'bulk-1'] + )->willReturn($href); + $dataSource['data']['items']['item'] = [BulkSummary::BULK_ID => 'bulk-1']; + $actionColumn['data']['items']['item'] = [ + 'Edit' => [ + 'edit' => [ + 'href' => $href, + 'label' => __('Details'), + 'hidden' => false + ] + ] + ]; + $expectedResult = array_merge_recursive($dataSource, $actionColumn); + $this->assertEquals($expectedResult, $this->actionColumn->prepareDataSource($dataSource)); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Listing/Column/NotificationActionsTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Listing/Column/NotificationActionsTest.php new file mode 100644 index 0000000000000..a35fd82774148 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Listing/Column/NotificationActionsTest.php @@ -0,0 +1,132 @@ +context = $this->createMock(\Magento\Framework\View\Element\UiComponent\ContextInterface::class); + $this->uiComponentFactory = $this->createMock(\Magento\Framework\View\Element\UiComponentFactory::class); + $processor = $this->createPartialMock( + \Magento\Framework\View\Element\UiComponent\Processor::class, + ['getProcessor'] + ); + $this->context->expects($this->never())->method('getProcessor')->will($this->returnValue($processor)); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->actionColumn = $objectManager->getObject( + \Magento\AsynchronousOperations\Ui\Component\Listing\Column\NotificationActions::class, + [ + 'context' => $this->context, + 'uiComponentFactory' => $this->uiComponentFactory, + 'components' => [], + 'data' => ['name' => 'actions'] + ] + ); + } + + public function testPrepareDataSource() + { + $testData['data']['items'] = [ + [ + 'key' => 'value', + ], + [ + BulkSummary::BULK_ID => 'uuid-1', + 'status' => BulkSummaryInterface::FINISHED_SUCCESSFULLY, + ], + [ + BulkSummary::BULK_ID => 'uuid-2', + ], + ]; + $expectedResult['data']['items'] = [ + [ + 'key' => 'value', + ], + [ + BulkSummary::BULK_ID => 'uuid-1', + 'status' => BulkSummaryInterface::FINISHED_SUCCESSFULLY, + 'actions' => [ + 'details' => [ + 'href' => '#', + 'label' => __('View Details'), + 'callback' => [ + [ + 'provider' => 'notification_area.notification_area.modalContainer.modal.insertBulk', + 'target' => 'destroyInserted', + ], + [ + 'provider' => 'notification_area.notification_area.modalContainer.modal.insertBulk', + 'target' => 'updateData', + 'params' => [ + BulkSummary::BULK_ID => 'uuid-1', + ], + ], + [ + 'provider' => 'notification_area.notification_area.modalContainer.modal', + 'target' => 'openModal', + ], + [ + 'provider' => 'ns = notification_area, index = columns', + 'target' => 'dismiss', + 'params' => ['uuid-1'], + ], + ], + ], + ], + ], + [ + BulkSummary::BULK_ID => 'uuid-2', + 'actions' => [ + 'details' => [ + 'href' => '#', + 'label' => __('View Details'), + 'callback' => [ + [ + 'provider' => 'notification_area.notification_area.modalContainer.modal.insertBulk', + 'target' => 'destroyInserted', + ], + [ + 'provider' => 'notification_area.notification_area.modalContainer.modal.insertBulk', + 'target' => 'updateData', + 'params' => [ + BulkSummary::BULK_ID => 'uuid-2', + ], + ], + [ + 'provider' => 'notification_area.notification_area.modalContainer.modal', + 'target' => 'openModal', + ], + ], + ], + ], + ], + ]; + $this->assertEquals($expectedResult, $this->actionColumn->prepareDataSource($testData)); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Listing/Column/NotificationDismissActionsTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Listing/Column/NotificationDismissActionsTest.php new file mode 100644 index 0000000000000..cf1f0db58dfdf --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Listing/Column/NotificationDismissActionsTest.php @@ -0,0 +1,96 @@ +context = $this->createMock(\Magento\Framework\View\Element\UiComponent\ContextInterface::class); + $this->uiComponentFactory = $this->createMock(\Magento\Framework\View\Element\UiComponentFactory::class); + $processor = $this->createPartialMock( + \Magento\Framework\View\Element\UiComponent\Processor::class, + ['getProcessor'] + ); + $this->context->expects($this->never())->method('getProcessor')->will($this->returnValue($processor)); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->actionColumn = $objectManager->getObject( + \Magento\AsynchronousOperations\Ui\Component\Listing\Column\NotificationDismissActions::class, + [ + 'context' => $this->context, + 'uiComponentFactory' => $this->uiComponentFactory, + 'components' => [], + 'data' => ['name' => 'actions'] + ] + ); + } + + public function testPrepareDataSource() + { + $testData['data']['items'] = [ + [ + 'key' => 'value', + ], + [ + BulkSummary::BULK_ID => 'uuid-1', + 'status' => BulkSummaryInterface::FINISHED_SUCCESSFULLY, + ], + [ + 'status' => BulkSummaryInterface::IN_PROGRESS, + ], + ]; + $expectedResult['data']['items'] = [ + [ + 'key' => 'value', + ], + [ + BulkSummary::BULK_ID => 'uuid-1', + 'status' => BulkSummaryInterface::FINISHED_SUCCESSFULLY, + 'actions' => [ + 'dismiss' => [ + 'href' => '#', + 'label' => __('Dismiss'), + 'callback' => [ + [ + 'provider' => 'ns = notification_area, index = columns', + 'target' => 'dismiss', + 'params' => [ + 0 => 'uuid-1', + ], + ], + ], + ], + ], + ], + [ + 'status' => BulkSummaryInterface::IN_PROGRESS, + ], + ]; + $this->assertEquals($expectedResult, $this->actionColumn->prepareDataSource($testData)); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Operation/DataProviderTest.php b/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Operation/DataProviderTest.php new file mode 100644 index 0000000000000..bc1e4bcd7e3e2 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Test/Unit/Ui/Component/Operation/DataProviderTest.php @@ -0,0 +1,143 @@ +bulkCollectionFactoryMock = $this->createPartialMock( + \Magento\AsynchronousOperations\Model\ResourceModel\Bulk\CollectionFactory::class, + ['create'] + ); + $this->bulkCollectionMock = $this->createMock( + \Magento\AsynchronousOperations\Model\ResourceModel\Bulk\Collection::class + ); + $this->operationDetailsMock = $this->createMock(\Magento\AsynchronousOperations\Model\Operation\Details::class); + $this->bulkMock = $this->createMock(\Magento\AsynchronousOperations\Model\BulkSummary::class); + $this->requestMock = $this->createMock(\Magento\Framework\App\RequestInterface::class); + + $this->bulkCollectionFactoryMock + ->expects($this->once()) + ->method('create') + ->willReturn($this->bulkCollectionMock); + + $this->dataProvider = $helper->getObject( + \Magento\AsynchronousOperations\Ui\Component\Operation\DataProvider::class, + [ + 'name' => 'test-name', + 'bulkCollectionFactory' => $this->bulkCollectionFactoryMock, + 'operationDetails' => $this->operationDetailsMock, + 'request' => $this->requestMock + ] + ); + } + + public function testGetData() + { + $testData = [ + 'id' => '1', + 'uuid' => 'bulk-uuid1', + 'user_id' => '2', + 'description' => 'Description' + ]; + $testOperationData = [ + 'operations_total' => 2, + 'operations_successful' => 1, + 'operations_failed' => 2 + ]; + $testSummaryData = [ + 'summary' => '2 items selected for mass update, 1 successfully updated, 2 failed to update' + ]; + $resultData[$testData['id']] = array_merge($testData, $testOperationData, $testSummaryData); + + $this->bulkCollectionMock + ->expects($this->once()) + ->method('getItems') + ->willReturn([$this->bulkMock]); + $this->bulkMock + ->expects($this->once()) + ->method('getData') + ->willReturn($testData); + $this->operationDetailsMock + ->expects($this->once()) + ->method('getDetails') + ->with($testData['uuid']) + ->willReturn($testOperationData); + $this->bulkMock + ->expects($this->once()) + ->method('getBulkId') + ->willReturn($testData['id']); + + $expectedResult = $this->dataProvider->getData(); + $this->assertEquals($resultData, $expectedResult); + } + + public function testPrepareMeta() + { + $resultData['retriable_operations']['arguments']['data']['disabled'] = true; + $resultData['failed_operations']['arguments']['data']['disabled'] = true; + $testData = [ + 'uuid' => 'bulk-uuid1', + 'failed_retriable' => 0, + 'failed_not_retriable' => 0 + ]; + + $this->requestMock + ->expects($this->once()) + ->method('getParam') + ->willReturn($testData['uuid']); + $this->operationDetailsMock + ->expects($this->once()) + ->method('getDetails') + ->with($testData['uuid']) + ->willReturn($testData); + + $expectedResult = $this->dataProvider->prepareMeta([]); + $this->assertEquals($resultData, $expectedResult); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Ui/Component/AdminNotification/Plugin.php b/app/code/Magento/AsynchronousOperations/Ui/Component/AdminNotification/Plugin.php new file mode 100644 index 0000000000000..b5670639dce09 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Ui/Component/AdminNotification/Plugin.php @@ -0,0 +1,54 @@ +authorization = $authorization; + } + + /** + * Prepares Meta + * + * @param \Magento\AdminNotification\Ui\Component\DataProvider\DataProvider $dataProvider + * @param array $result + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterGetMeta( + \Magento\AdminNotification\Ui\Component\DataProvider\DataProvider $dataProvider, + $result + ) { + if (!isset($this->isAllowed)) { + $this->isAllowed = $this->authorization->isAllowed( + 'Magento_Logging::system_magento_logging_bulk_operations' + ); + } + $result['columns']['arguments']['data']['config']['isAllowed'] = $this->isAllowed; + return $result; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/Bulk/IdentifierResolver.php b/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/Bulk/IdentifierResolver.php new file mode 100644 index 0000000000000..b5b7da1318001 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/Bulk/IdentifierResolver.php @@ -0,0 +1,36 @@ +request = $request; + } + + /** + * @return null|string + */ + public function execute() + { + return $this->request->getParam('uuid'); + } +} diff --git a/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Failed/SearchResult.php b/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Failed/SearchResult.php new file mode 100644 index 0000000000000..aba7554c26d1d --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Failed/SearchResult.php @@ -0,0 +1,142 @@ +jsonHelper = $jsonHelper; + $this->identifierResolver = $identifierResolver; + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $mainTable, + $resourceModel, + $identifierName + ); + } + + /** + * {@inheritdoc} + */ + protected function _initSelect() + { + $bulkUuid = $this->identifierResolver->execute(); + $this->getSelect()->from(['main_table' => $this->getMainTable()], ['id', 'result_message', 'serialized_data']) + ->where('bulk_uuid=?', $bulkUuid) + ->where('status=?', OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED); + return $this; + } + + /** + * {@inheritdoc} + */ + protected function _afterLoad() + { + parent::_afterLoad(); + foreach ($this->_items as $key => $item) { + try { + $unserializedData = $this->jsonHelper->jsonDecode($item['serialized_data']); + } catch (\Exception $e) { + $this->_logger->error($e->getMessage()); + $unserializedData = []; + } + $this->_items[$key]->setData('meta_information', $this->provideMetaInfo($unserializedData)); + $this->_items[$key]->setData('link', $this->getLink($unserializedData)); + $this->_items[$key]->setData('entity_id', $this->getEntityId($unserializedData)); + } + return $this; + } + + /** + * Provide meta info by serialized data + * + * @param array $item + * @return string + */ + private function provideMetaInfo($item) + { + $metaInfo = ''; + if (isset($item['meta_information'])) { + $metaInfo = $item['meta_information']; + } + return $metaInfo; + } + + /** + * Get link from serialized data + * + * @param array $item + * @return string + */ + private function getLink($item) + { + $entityLink = ''; + if (isset($item['entity_link'])) { + $entityLink = $item['entity_link']; + } + return $entityLink; + } + + /** + * Get entity id from serialized data + * + * @param array $item + * @return string + */ + private function getEntityId($item) + { + $entityLink = ''; + if (isset($item['entity_id'])) { + $entityLink = $item['entity_id']; + } + return $entityLink; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Retriable/SearchResult.php b/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Retriable/SearchResult.php new file mode 100644 index 0000000000000..9641bd1333f9f --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Retriable/SearchResult.php @@ -0,0 +1,71 @@ +identifierResolver = $identifierResolver; + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $mainTable, + $resourceModel, + $identifierName + ); + } + + /** + * {@inheritdoc} + */ + protected function _initSelect() + { + $bulkUuid = $this->identifierResolver->execute(); + $this->getSelect()->from(['main_table' => $this->getMainTable()], ['id', 'result_message', 'error_code']) + ->where('bulk_uuid=?', $bulkUuid) + ->where('status=?', OperationInterface::STATUS_TYPE_RETRIABLY_FAILED) + ->group('error_code') + ->columns(['records_qty' => new \Zend_Db_Expr('COUNT(id)')]); + return $this; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/SearchResult.php b/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/SearchResult.php new file mode 100644 index 0000000000000..5f2fbd9ea8b11 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Ui/Component/DataProvider/SearchResult.php @@ -0,0 +1,148 @@ +userContext = $userContextInterface; + $this->statusMapper = $statusMapper; + $this->calculatedStatusSql = $calculatedStatusSql; + parent::__construct( + $entityFactory, + $logger, + $fetchStrategy, + $eventManager, + $mainTable, + $resourceModel, + $identifierName + ); + } + + /** + * {@inheritdoc} + */ + protected function _initSelect() + { + $this->getSelect()->from( + ['main_table' => $this->getMainTable()], + [ + '*', + 'status' => $this->calculatedStatusSql->get($this->getTable('magento_operation')) + ] + )->where( + 'user_id=?', + $this->userContext->getUserId() + ); + return $this; + } + + /** + * {@inheritdoc} + */ + protected function _afterLoad() + { + /** @var BulkSummaryInterface $item */ + foreach ($this->getItems() as $item) { + $item->setStatus($this->statusMapper->operationStatusToBulkSummaryStatus($item->getStatus())); + } + return parent::_afterLoad(); + } + + /** + * {@inheritdoc} + */ + public function addFieldToFilter($field, $condition = null) + { + if ($field == 'status') { + if (is_array($condition)) { + foreach ($condition as $value) { + $this->operationStatus = $this->statusMapper->bulkSummaryStatusToOperationStatus($value); + if (is_array($this->operationStatus)) { + foreach ($this->operationStatus as $statusValue) { + $this->getSelect()->orHaving('status = ?', $statusValue); + } + continue; + } + $this->getSelect()->having('status = ?', $this->operationStatus); + } + } + return $this; + } + return parent::addFieldToFilter($field, $condition); + } + + /** + * {@inheritdoc} + */ + public function getSelectCountSql() + { + $select = parent::getSelectCountSql(); + $select->columns(['status' => $this->calculatedStatusSql->get($this->getTable('magento_operation'))]); + //add grouping by status if filtering by status was executed + if (isset($this->operationStatus)) { + $select->group('status'); + } + return $select; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Ui/Component/Listing/Column/Actions.php b/app/code/Magento/AsynchronousOperations/Ui/Component/Listing/Column/Actions.php new file mode 100644 index 0000000000000..232f8ca1356be --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Ui/Component/Listing/Column/Actions.php @@ -0,0 +1,43 @@ +getData('name')]['edit'] = [ + 'href' => $this->context->getUrl( + 'bulk/bulk/details', + ['uuid' => $item['uuid']] + ), + 'label' => __('Details'), + 'hidden' => false, + ]; + } + + return $dataSource; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Ui/Component/Listing/Column/NotificationActions.php b/app/code/Magento/AsynchronousOperations/Ui/Component/Listing/Column/NotificationActions.php new file mode 100644 index 0000000000000..1886bbf430bc7 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Ui/Component/Listing/Column/NotificationActions.php @@ -0,0 +1,68 @@ +getData('name')]['details'] = [ + 'callback' => [ + [ + 'provider' => 'notification_area.notification_area.modalContainer.modal.insertBulk', + 'target' => 'destroyInserted', + ], + [ + 'provider' => 'notification_area.notification_area.modalContainer.modal.insertBulk', + 'target' => 'updateData', + 'params' => [ + 'uuid' => $item['uuid'], + ], + ], + [ + 'provider' => 'notification_area.notification_area.modalContainer.modal', + 'target' => 'openModal', + ], + ], + 'href' => '#', + 'label' => __('View Details'), + ]; + + if (isset($item['status']) + && ($item['status'] === BulkSummaryInterface::FINISHED_SUCCESSFULLY + || $item['status'] === BulkSummaryInterface::FINISHED_WITH_FAILURE) + ) { + $item[$this->getData('name')]['details']['callback'][] = [ + 'provider' => 'ns = notification_area, index = columns', + 'target' => 'dismiss', + 'params' => [ + 0 => $item['uuid'], + ], + ]; + } + } + } + + return $dataSource; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Ui/Component/Listing/Column/NotificationDismissActions.php b/app/code/Magento/AsynchronousOperations/Ui/Component/Listing/Column/NotificationDismissActions.php new file mode 100644 index 0000000000000..cae2524f92600 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Ui/Component/Listing/Column/NotificationDismissActions.php @@ -0,0 +1,50 @@ +getData('name')]['dismiss'] = [ + 'callback' => [ + [ + 'provider' => 'ns = notification_area, index = columns', + 'target' => 'dismiss', + 'params' => [ + 0 => $item['uuid'], + ], + ], + ], + 'href' => '#', + 'label' => __('Dismiss'), + ]; + } + } + + return $dataSource; + } +} diff --git a/app/code/Magento/AsynchronousOperations/Ui/Component/Operation/DataProvider.php b/app/code/Magento/AsynchronousOperations/Ui/Component/Operation/DataProvider.php new file mode 100644 index 0000000000000..89aae531fec4e --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/Ui/Component/Operation/DataProvider.php @@ -0,0 +1,124 @@ +collection = $bulkCollectionFactory->create(); + $this->operationDetails = $operationDetails; + $this->request = $request; + parent::__construct($name, $primaryFieldName, $requestFieldName, $meta, $data); + $this->meta = $this->prepareMeta($this->meta); + } + + /** + * Human readable summary for bulk + * + * @param array $operationDetails structure is implied as getOperationDetails() result + * @return string + */ + private function getSummaryReport($operationDetails) + { + if (0 == $operationDetails['operations_successful'] && 0 == $operationDetails['operations_failed']) { + return __('Pending, in queue...'); + } + + $summaryReport = __('%1 items selected for mass update', $operationDetails['operations_total'])->__toString(); + if ($operationDetails['operations_successful'] > 0) { + $summaryReport .= __(', %1 successfully updated', $operationDetails['operations_successful']); + } + + if ($operationDetails['operations_failed'] > 0) { + $summaryReport .= __(', %1 failed to update', $operationDetails['operations_failed']); + } + + return $summaryReport; + } + + /** + * Bulk summary with operation statistics + * + * @return array + */ + public function getData() + { + $data = []; + $items = $this->collection->getItems(); + if (count($items) == 0) { + return $data; + } + $bulk = array_shift($items); + /** @var \Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface $bulk */ + $data = $bulk->getData(); + $operationDetails = $this->operationDetails->getDetails($data['uuid']); + $data['summary'] = $this->getSummaryReport($operationDetails); + $data = array_merge($data, $operationDetails); + + return [$bulk->getBulkId() => $data]; + } + + /** + * Prepares Meta + * + * @param array $meta + * @return array + */ + public function prepareMeta($meta) + { + $requestId = $this->request->getParam($this->requestFieldName); + $operationDetails = $this->operationDetails->getDetails($requestId); + + if (isset($operationDetails['failed_retriable']) && !$operationDetails['failed_retriable']) { + $meta['retriable_operations']['arguments']['data']['disabled'] = true; + } + + if (isset($operationDetails['failed_not_retriable']) && !$operationDetails['failed_not_retriable']) { + $meta['failed_operations']['arguments']['data']['disabled'] = true; + } + + return $meta; + } +} diff --git a/app/code/Magento/AsynchronousOperations/composer.json b/app/code/Magento/AsynchronousOperations/composer.json new file mode 100644 index 0000000000000..7a4e7f6aad69c --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/composer.json @@ -0,0 +1,33 @@ +{ + "name": "magento/module-asynchronous-operations", + "description": "N/A", + "config": { + "sort-packages": true + }, + "require": { + "magento/framework": "100.3.*", + "magento/framework-bulk": "100.3.*", + "magento/module-authorization": "100.3.*", + "magento/module-backend": "100.3.*", + "magento/module-ui": "100.3.*", + "magento/module-user": "100.3.*", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "suggest": { + "magento/module-admin-notification": "100.3.*", + "magento/module-logging": "100.3.*" + }, + "type": "magento2-module", + "version": "100.3.0-dev", + "license": [ + "proprietary" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\AsynchronousOperations\\": "" + } + } +} diff --git a/app/code/Magento/AsynchronousOperations/etc/acl.xml b/app/code/Magento/AsynchronousOperations/etc/acl.xml new file mode 100644 index 0000000000000..42521ad40ff63 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/acl.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/app/code/Magento/AsynchronousOperations/etc/adminhtml/di.xml b/app/code/Magento/AsynchronousOperations/etc/adminhtml/di.xml new file mode 100644 index 0000000000000..26dd6a39473a6 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/adminhtml/di.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/AsynchronousOperations/etc/adminhtml/menu.xml b/app/code/Magento/AsynchronousOperations/etc/adminhtml/menu.xml new file mode 100644 index 0000000000000..2e9fe34c45cec --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/adminhtml/menu.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/app/code/Magento/AsynchronousOperations/etc/adminhtml/routes.xml b/app/code/Magento/AsynchronousOperations/etc/adminhtml/routes.xml new file mode 100644 index 0000000000000..a255af90eac8a --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/adminhtml/routes.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/code/Magento/AsynchronousOperations/etc/adminhtml/system.xml b/app/code/Magento/AsynchronousOperations/etc/adminhtml/system.xml new file mode 100644 index 0000000000000..7190b80750357 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/adminhtml/system.xml @@ -0,0 +1,20 @@ + + + + +
+ advanced + + + + + + +
+
+
diff --git a/app/code/Magento/AsynchronousOperations/etc/config.xml b/app/code/Magento/AsynchronousOperations/etc/config.xml new file mode 100644 index 0000000000000..e30c1005d0dd0 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/config.xml @@ -0,0 +1,16 @@ + + + + + + + 60 + + + + diff --git a/app/code/Magento/AsynchronousOperations/etc/crontab.xml b/app/code/Magento/AsynchronousOperations/etc/crontab.xml new file mode 100644 index 0000000000000..c55b0a886ac79 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/crontab.xml @@ -0,0 +1,14 @@ + + + + + + * * * * * + + + diff --git a/app/code/Magento/AsynchronousOperations/etc/db_schema.xml b/app/code/Magento/AsynchronousOperations/etc/db_schema.xml new file mode 100644 index 0000000000000..b986b98abf3ad --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/db_schema.xml @@ -0,0 +1,71 @@ + + + +
+ + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + +
+
diff --git a/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json b/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json new file mode 100644 index 0000000000000..22ea2da3bd73f --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/db_schema_whitelist.json @@ -0,0 +1,46 @@ +{ + "magento_bulk": { + "column": { + "id": true, + "uuid": true, + "user_id": true, + "description": true, + "operation_count": true, + "start_time": true + }, + "constraint": { + "PRIMARY": true, + "MAGENTO_BULK_USER_ID_ADMIN_USER_USER_ID": true, + "MAGENTO_BULK_UUID": true + } + }, + "magento_operation": { + "column": { + "id": true, + "bulk_uuid": true, + "topic_name": true, + "serialized_data": true, + "status": true, + "error_code": true, + "result_message": true + }, + "index": { + "MAGENTO_OPERATION_BULK_UUID_ERROR_CODE": true + }, + "constraint": { + "PRIMARY": true, + "MAGENTO_OPERATION_BULK_UUID_MAGENTO_BULK_UUID": true + } + }, + "magento_acknowledged_bulk": { + "column": { + "id": true, + "bulk_uuid": true + }, + "constraint": { + "PRIMARY": true, + "MAGENTO_ACKNOWLEDGED_BULK_BULK_UUID_MAGENTO_BULK_UUID": true, + "MAGENTO_ACKNOWLEDGED_BULK_BULK_UUID": true + } + } +} \ No newline at end of file diff --git a/app/code/Magento/AsynchronousOperations/etc/di.xml b/app/code/Magento/AsynchronousOperations/etc/di.xml new file mode 100644 index 0000000000000..3a4225347eeb3 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/di.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + magento_operation + id + + + magento_bulk + uuid + + + magento_operation + id + + + + + + + + + bulk_id + + + + + + + + Magento\AsynchronousOperations\Model\Entity\BulkSummaryMapper + + + + + + + bulkSummaryMapper + + + + + + + Magento\AsynchronousOperations\Ui\Component\DataProvider\SearchResult + Magento\AsynchronousOperations\Ui\Component\DataProvider\Operation\Failed\SearchResult + Magento\AsynchronousOperations\Ui\Component\DataProvider\Operation\Retriable\SearchResult + Magento\AsynchronousOperations\Ui\Component\DataProvider\Operation\Failed\SearchResult + Magento\AsynchronousOperations\Ui\Component\DataProvider\Operation\Retriable\SearchResult + + + + + + + + Magento\AsynchronousOperations\Model\ResourceModel\Operation\CheckIfExists + Magento\AsynchronousOperations\Model\ResourceModel\Operation\Create + + + + + + diff --git a/app/code/Magento/AsynchronousOperations/etc/module.xml b/app/code/Magento/AsynchronousOperations/etc/module.xml new file mode 100644 index 0000000000000..8f7a9e144462b --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/etc/module.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/app/code/Magento/AsynchronousOperations/i18n/en_US.csv b/app/code/Magento/AsynchronousOperations/i18n/en_US.csv new file mode 100644 index 0000000000000..44cc0a0ab7754 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/i18n/en_US.csv @@ -0,0 +1,35 @@ +Back,Back +Done,Done +Retry,Retry +"'Action Details - #' .","'Action Details - #' ." +"%1 item(s) have been scheduled for update.""","%1 item(s) have been scheduled for update.""" +"Bulk Actions Log","Bulk Actions Log" +"%1 item(s) are currently being updated.","%1 item(s) are currently being updated." +"Task ""%1"": ","Task ""%1"": " +"%1 item(s) have been scheduled for update.","%1 item(s) have been scheduled for update." +"%1 item(s) have been successfully updated.","%1 item(s) have been successfully updated." +"%1 item(s) failed to update","%1 item(s) failed to update" +Details,Details +"View Details","View Details" +Dismiss,Dismiss +"Pending, in queue...","Pending, in queue..." +"%1 items selected for mass update","%1 items selected for mass update" +", %1 successfully updated",", %1 successfully updated" +", %1 failed to update",", %1 failed to update" +"Something went wrong.","Something went wrong." +"Action Log","Action Log" +"Bulk Actions","Bulk Actions" +"Days Saved in Log","Days Saved in Log" +"Description of Operation","Description of Operation" +Summary,Summary +"Start Time","Start Time" +"Items to Retry","Items to Retry" +"To retry, select the items and click “Retry”.","To retry, select the items and click “Retry”." +"Items That Can’t Be Updated.","Items That Can’t Be Updated." +ID,ID +Status,Status +"Meta Information","Meta Information" +Error,Error +"Dismiss All Completed Tasks","Dismiss All Completed Tasks" +"Action Details - #","Action Details - #" +"Number of Records Affected","Number of Records Affected" diff --git a/app/code/Magento/AsynchronousOperations/registration.php b/app/code/Magento/AsynchronousOperations/registration.php new file mode 100644 index 0000000000000..d384df583fb5a --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/registration.php @@ -0,0 +1,9 @@ + + + + + + + + + + + diff --git a/app/code/Magento/AsynchronousOperations/view/adminhtml/layout/bulk_bulk_details_modal.xml b/app/code/Magento/AsynchronousOperations/view/adminhtml/layout/bulk_bulk_details_modal.xml new file mode 100644 index 0000000000000..946cf0a898585 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/view/adminhtml/layout/bulk_bulk_details_modal.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/app/code/Magento/AsynchronousOperations/view/adminhtml/layout/bulk_index_index.xml b/app/code/Magento/AsynchronousOperations/view/adminhtml/layout/bulk_index_index.xml new file mode 100644 index 0000000000000..d8686887bbc59 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/view/adminhtml/layout/bulk_index_index.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/app/code/Magento/AsynchronousOperations/view/adminhtml/ui_component/bulk_details_form.xml b/app/code/Magento/AsynchronousOperations/view/adminhtml/ui_component/bulk_details_form.xml new file mode 100644 index 0000000000000..19793ac82ba39 --- /dev/null +++ b/app/code/Magento/AsynchronousOperations/view/adminhtml/ui_component/bulk_details_form.xml @@ -0,0 +1,150 @@ + + +
+ + + bulk_details_form.bulk_details_form_data_source + + templates/form/collapsible + + + + +
+ + + +
+ +
+
    +
  • + + + +
  • +
+ +
+ + diff --git a/app/code/Magento/Authorization/Setup/InstallData.php b/app/code/Magento/Authorization/Setup/InstallData.php deleted file mode 100644 index b8b18706722a5..0000000000000 --- a/app/code/Magento/Authorization/Setup/InstallData.php +++ /dev/null @@ -1,101 +0,0 @@ -authFactory = $authFactory; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $roleCollection = $this->authFactory->createRoleCollection() - ->addFieldToFilter('parent_id', 0) - ->addFieldToFilter('tree_level', 1) - ->addFieldToFilter('role_type', RoleGroup::ROLE_TYPE) - ->addFieldToFilter('user_id', 0) - ->addFieldToFilter('user_type', UserContextInterface::USER_TYPE_ADMIN) - ->addFieldToFilter('role_name', 'Administrators'); - - if ($roleCollection->count() == 0) { - $admGroupRole = $this->authFactory->createRole()->setData( - [ - 'parent_id' => 0, - 'tree_level' => 1, - 'sort_order' => 1, - 'role_type' => RoleGroup::ROLE_TYPE, - 'user_id' => 0, - 'user_type' => UserContextInterface::USER_TYPE_ADMIN, - 'role_name' => 'Administrators', - ] - )->save(); - } else { - foreach ($roleCollection as $item) { - $admGroupRole = $item; - break; - } - } - - $rulesCollection = $this->authFactory->createRulesCollection() - ->addFieldToFilter('role_id', $admGroupRole->getId()) - ->addFieldToFilter('resource_id', 'all'); - - if ($rulesCollection->count() == 0) { - $this->authFactory->createRules()->setData( - [ - 'role_id' => $admGroupRole->getId(), - 'resource_id' => 'Magento_Backend::all', - 'privileges' => null, - 'permission' => 'allow', - ] - )->save(); - } else { - /** @var \Magento\Authorization\Model\Rules $rule */ - foreach ($rulesCollection as $rule) { - $rule->setData('resource_id', 'Magento_Backend::all')->save(); - } - } - - /** - * Delete rows by condition from authorization_rule - */ - $setup->startSetup(); - - $tableName = $setup->getTable('authorization_rule'); - if ($tableName) { - $setup->getConnection()->delete($tableName, ['resource_id = ?' => 'admin/system/tools/compiler']); - } - - $setup->endSetup(); - } -} diff --git a/app/code/Magento/Authorization/Setup/Patch/Data/InitializeAuthRoles.php b/app/code/Magento/Authorization/Setup/Patch/Data/InitializeAuthRoles.php new file mode 100644 index 0000000000000..84992badf65db --- /dev/null +++ b/app/code/Magento/Authorization/Setup/Patch/Data/InitializeAuthRoles.php @@ -0,0 +1,133 @@ +moduleDataSetup = $moduleDataSetup; + $this->authFactory = $authorizationFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $roleCollection = $this->authFactory->createRoleCollection() + ->addFieldToFilter('parent_id', 0) + ->addFieldToFilter('tree_level', 1) + ->addFieldToFilter('role_type', RoleGroup::ROLE_TYPE) + ->addFieldToFilter('user_id', 0) + ->addFieldToFilter('user_type', UserContextInterface::USER_TYPE_ADMIN) + ->addFieldToFilter('role_name', 'Administrators'); + + if ($roleCollection->count() == 0) { + $admGroupRole = $this->authFactory->createRole()->setData( + [ + 'parent_id' => 0, + 'tree_level' => 1, + 'sort_order' => 1, + 'role_type' => RoleGroup::ROLE_TYPE, + 'user_id' => 0, + 'user_type' => UserContextInterface::USER_TYPE_ADMIN, + 'role_name' => 'Administrators', + ] + )->save(); + } else { + /** @var \Magento\Authorization\Model\ResourceModel\Role $item */ + foreach ($roleCollection as $item) { + $admGroupRole = $item; + break; + } + } + + $rulesCollection = $this->authFactory->createRulesCollection() + ->addFieldToFilter('role_id', $admGroupRole->getId()) + ->addFieldToFilter('resource_id', 'all'); + + if ($rulesCollection->count() == 0) { + $this->authFactory->createRules()->setData( + [ + 'role_id' => $admGroupRole->getId(), + 'resource_id' => 'Magento_Backend::all', + 'privileges' => null, + 'permission' => 'allow', + ] + )->save(); + } else { + /** @var \Magento\Authorization\Model\Rules $rule */ + foreach ($rulesCollection as $rule) { + $rule->setData('resource_id', 'Magento_Backend::all')->save(); + } + } + + /** + * Delete rows by condition from authorization_rule + */ + $tableName = $this->moduleDataSetup->getTable('authorization_rule'); + if ($tableName) { + $this->moduleDataSetup->getConnection()->delete( + $tableName, + ['resource_id = ?' => 'admin/system/tools/compiler'] + ); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Authorization/etc/db_schema.xml b/app/code/Magento/Authorization/etc/db_schema.xml index ef615b4508a89..45c02128bfc99 100644 --- a/app/code/Magento/Authorization/etc/db_schema.xml +++ b/app/code/Magento/Authorization/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> diff --git a/app/code/Magento/Authorization/etc/module.xml b/app/code/Magento/Authorization/etc/module.xml index 357e36d937e50..145b1ba10d0f8 100644 --- a/app/code/Magento/Authorization/etc/module.xml +++ b/app/code/Magento/Authorization/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Authorizenet/etc/module.xml b/app/code/Magento/Authorizenet/etc/module.xml index 6d05f14d21318..a30fd34927746 100644 --- a/app/code/Magento/Authorizenet/etc/module.xml +++ b/app/code/Magento/Authorizenet/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Date.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Date.php index 40a5d92c56b6f..632603d389d21 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Date.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Date.php @@ -127,7 +127,7 @@ public function getHtml() /** * @param string|null $index - * @return string + * @return array|string|int|float|null */ public function getEscapedValue($index = null) { @@ -138,6 +138,11 @@ public function getEscapedValue($index = null) $this->_localeDate->getDateFormat(\IntlDateFormatter::SHORT) ); } + + if (is_string($value)) { + return $this->escapeHtml($value); + } + return $value; } diff --git a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Datetime.php b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Datetime.php index 96b3471db845e..88d1560026cbd 100644 --- a/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Datetime.php +++ b/app/code/Magento/Backend/Block/Widget/Grid/Column/Filter/Datetime.php @@ -140,8 +140,8 @@ public function getHtml() /** * Return escaped value for calendar * - * @param string $index - * @return string + * @param string|null $index + * @return array|string|int|float|null */ public function getEscapedValue($index = null) { @@ -150,6 +150,11 @@ public function getEscapedValue($index = null) if ($value instanceof \DateTimeInterface) { return $this->_localeDate->formatDateTime($value); } + + if (is_string($value)) { + return $this->escapeHtml($value); + } + return $value; } diff --git a/app/code/Magento/Backend/Model/Auth/StorageInterface.php b/app/code/Magento/Backend/Model/Auth/StorageInterface.php index 52b2b089c71e1..e643165a93317 100644 --- a/app/code/Magento/Backend/Model/Auth/StorageInterface.php +++ b/app/code/Magento/Backend/Model/Auth/StorageInterface.php @@ -23,7 +23,7 @@ interface StorageInterface public function processLogin(); /** - * Perform login specific actions + * Perform logout specific actions * * @return $this * @abstract diff --git a/app/code/Magento/Backend/Model/Menu/Item/Validator.php b/app/code/Magento/Backend/Model/Menu/Item/Validator.php index d79752b296e5f..7b72b355f551d 100644 --- a/app/code/Magento/Backend/Model/Menu/Item/Validator.php +++ b/app/code/Magento/Backend/Model/Menu/Item/Validator.php @@ -74,34 +74,86 @@ public function __construct() * @throws \BadMethodCallException */ public function validate($data) + { + if ($this->checkMenuItemIsRemoved($data)) { + return; + } + + $this->assertContainsRequiredParameters($data); + $this->assertIdentifierIsNotUsed($data['id']); + + foreach ($data as $param => $value) { + $this->validateMenuItemParameter($param, $value); + } + $this->_ids[] = $data['id']; + } + + /** + * Check that menu item is not deleted + * + * @param array $data + * @return bool + */ + private function checkMenuItemIsRemoved($data) + { + return isset($data['id'], $data['removed']) && $data['removed'] === true; + } + + /** + * Check that menu item contains all required data + * @param array $data + * + * @throws \BadMethodCallException + */ + private function assertContainsRequiredParameters($data) { foreach ($this->_required as $param) { if (!isset($data[$param])) { throw new \BadMethodCallException('Missing required param ' . $param); } } + } - if (array_search($data['id'], $this->_ids) !== false) { - throw new \InvalidArgumentException('Item with id ' . $data['id'] . ' already exists'); + /** + * Check that menu item id is not used + * + * @param string $id + * @throws \InvalidArgumentException + */ + private function assertIdentifierIsNotUsed($id) + { + if (array_search($id, $this->_ids) !== false) { + throw new \InvalidArgumentException('Item with id ' . $id . ' already exists'); } + } - foreach ($data as $param => $value) { - if ($data[$param] !== null - && isset( - $this->_validators[$param] - ) && !$this->_validators[$param]->isValid( - $value - ) - ) { - throw new \InvalidArgumentException( - "Param " . $param . " doesn't pass validation: " . implode( - '; ', - $this->_validators[$param]->getMessages() - ) - ); - } + /** + * Validate menu item parameter value + * + * @param string $param + * @param mixed $value + * @throws \InvalidArgumentException + */ + private function validateMenuItemParameter($param, $value) + { + if ($value === null) { + return; } - $this->_ids[] = $data['id']; + if (!isset($this->_validators[$param])) { + return; + } + + $validator = $this->_validators[$param]; + if ($validator->isValid($value)) { + return; + } + + throw new \InvalidArgumentException( + "Param " . $param . " doesn't pass validation: " . implode( + '; ', + $validator->getMessages() + ) + ); } /** diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DateTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DateTest.php index 355d11b561317..2848c9b23d2b7 100644 --- a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DateTest.php +++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DateTest.php @@ -30,6 +30,12 @@ class DateTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $localeDateMock; + /** @var \Magento\Framework\Escaper|\PHPUnit_Framework_MockObject_MockObject */ + private $escaperMock; + + /** @var \Magento\Backend\Block\Context|\PHPUnit_Framework_MockObject_MockObject */ + private $contextMock; + protected function setUp() { $this->mathRandomMock = $this->getMockBuilder(\Magento\Framework\Math\Random::class) @@ -58,6 +64,17 @@ protected function setUp() ->setMethods([]) ->getMock(); + $this->escaperMock = $this->getMockBuilder(\Magento\Framework\Escaper::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->contextMock = $this->getMockBuilder(\Magento\Backend\Block\Context::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->contextMock->expects($this->once())->method('getEscaper')->willReturn($this->escaperMock); + $this->contextMock->expects($this->once())->method('getLocaleDate')->willReturn($this->localeDateMock); + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->model = $objectManagerHelper->getObject( \Magento\Backend\Block\Widget\Grid\Column\Filter\Date::class, @@ -65,7 +82,8 @@ protected function setUp() 'mathRandom' => $this->mathRandomMock, 'localeResolver' => $this->localeResolverMock, 'dateTimeFormatter' => $this->dateTimeFormatterMock, - 'localeDate' => $this->localeDateMock + 'localeDate' => $this->localeDateMock, + 'context' => $this->contextMock, ] ); $this->model->setColumn($this->columnMock); @@ -98,4 +116,16 @@ public function testGetHtmlSuccessfulTimestamp() $this->assertContains('id="' . $uniqueHash . '_from" value="' . $yesterday->getTimestamp(), $output); $this->assertContains('id="' . $uniqueHash . '_to" value="' . $tomorrow->getTimestamp(), $output); } + + public function testGetEscapedValueEscapeString() + { + $value = "\">"; + $array = [ + 'orig_from' => $value, + 'from' => $value, + ]; + $this->model->setValue($array); + $this->escaperMock->expects($this->once())->method('escapeHtml')->with($value); + $this->model->getEscapedValue('from'); + } } diff --git a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DatetimeTest.php b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DatetimeTest.php index 1e692f890a94e..cdb88b6735f15 100644 --- a/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DatetimeTest.php +++ b/app/code/Magento/Backend/Test/Unit/Block/Widget/Grid/Column/Filter/DatetimeTest.php @@ -30,6 +30,12 @@ class DatetimeTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $localeDateMock; + /** @var \Magento\Framework\Escaper|\PHPUnit_Framework_MockObject_MockObject */ + private $escaperMock; + + /** @var \Magento\Backend\Block\Context|\PHPUnit_Framework_MockObject_MockObject */ + private $contextMock; + protected function setUp() { $this->mathRandomMock = $this->getMockBuilder(\Magento\Framework\Math\Random::class) @@ -50,7 +56,7 @@ protected function setUp() $this->columnMock = $this->getMockBuilder(\Magento\Backend\Block\Widget\Grid\Column::class) ->disableOriginalConstructor() - ->setMethods(['getTimezone', 'getHtmlId', 'getId']) + ->setMethods(['getTimezone', 'getHtmlId', 'getId', 'getFilterTime']) ->getMock(); $this->localeDateMock = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class) @@ -58,6 +64,17 @@ protected function setUp() ->setMethods([]) ->getMock(); + $this->escaperMock = $this->getMockBuilder(\Magento\Framework\Escaper::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->contextMock = $this->getMockBuilder(\Magento\Backend\Block\Context::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->contextMock->expects($this->once())->method('getEscaper')->willReturn($this->escaperMock); + $this->contextMock->expects($this->once())->method('getLocaleDate')->willReturn($this->localeDateMock); + $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->model = $objectManagerHelper->getObject( \Magento\Backend\Block\Widget\Grid\Column\Filter\Datetime::class, @@ -65,7 +82,8 @@ protected function setUp() 'mathRandom' => $this->mathRandomMock, 'localeResolver' => $this->localeResolverMock, 'dateTimeFormatter' => $this->dateTimeFormatterMock, - 'localeDate' => $this->localeDateMock + 'localeDate' => $this->localeDateMock, + 'context' => $this->contextMock, ] ); $this->model->setColumn($this->columnMock); @@ -98,4 +116,17 @@ public function testGetHtmlSuccessfulTimestamp() $this->assertContains('id="' . $uniqueHash . '_from" value="' . $yesterday->getTimestamp(), $output); $this->assertContains('id="' . $uniqueHash . '_to" value="' . $tomorrow->getTimestamp(), $output); } + + public function testGetEscapedValueEscapeString() + { + $value = "\">"; + $array = [ + 'orig_from' => $value, + 'from' => $value, + ]; + $this->model->setValue($array); + $this->escaperMock->expects($this->once())->method('escapeHtml')->with($value); + $this->columnMock->expects($this->once())->method('getFilterTime')->willReturn(true); + $this->model->getEscapedValue('from'); + } } diff --git a/app/code/Magento/Backend/etc/module.xml b/app/code/Magento/Backend/etc/module.xml index 57e00489391f2..6d1691a0e5603 100644 --- a/app/code/Magento/Backend/etc/module.xml +++ b/app/code/Magento/Backend/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Backend/view/adminhtml/templates/page/report.phtml b/app/code/Magento/Backend/view/adminhtml/templates/page/report.phtml index 3a3dbd99bfba9..4ef6d378cc4a4 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/page/report.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/page/report.phtml @@ -8,5 +8,7 @@ ?> getBugreportUrl()): ?> - + + + diff --git a/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php b/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php index ee0370c8ecb29..27770182a6db6 100644 --- a/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php +++ b/app/code/Magento/Backup/Controller/Adminhtml/Index/Create.php @@ -12,14 +12,14 @@ class Create extends \Magento\Backup\Controller\Adminhtml\Index { /** - * Create backup action + * Create backup action. * * @return void|\Magento\Backend\App\Action * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function execute() { - if (!$this->getRequest()->isAjax()) { + if (!$this->isRequestAllowed()) { return $this->_redirect('*/*/index'); } @@ -106,4 +106,14 @@ public function execute() $this->getResponse()->representJson($response->toJson()); } + + /** + * Check if request is allowed. + * + * @return bool + */ + private function isRequestAllowed() + { + return $this->getRequest()->isAjax() && $this->getRequest()->isPost(); + } } diff --git a/app/code/Magento/Backup/Test/Unit/Controller/Adminhtml/Index/CreateTest.php b/app/code/Magento/Backup/Test/Unit/Controller/Adminhtml/Index/CreateTest.php new file mode 100644 index 0000000000000..80477d9f6f9e4 --- /dev/null +++ b/app/code/Magento/Backup/Test/Unit/Controller/Adminhtml/Index/CreateTest.php @@ -0,0 +1,240 @@ +objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManagerInterface::class) + ->getMock(); + $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) + ->disableOriginalConstructor() + ->setMethods(['isAjax', 'isPost', 'getParam']) + ->getMock(); + $this->responseMock = $this->getMockBuilder(\Magento\Framework\App\Response\Http::class) + ->disableOriginalConstructor() + ->setMethods(['representJson', 'setRedirect']) + ->getMock(); + $this->sessionMock = $this->getMockBuilder(\Magento\Backend\Model\Session::class) + ->disableOriginalConstructor() + ->getMock(); + $this->backupFactoryMock = $this->getMockBuilder(\Magento\Framework\Backup\Factory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->backupModelMock = $this->getMockBuilder(\Magento\Backup\Model\Backup::class) + ->disableOriginalConstructor() + ->setMethods(['setBackupExtension', 'setTime', 'setBackupsDir', 'setName', 'create']) + ->getMock(); + $this->dataBackendHelperMock = $this->getMockBuilder(\Magento\Backend\Helper\Data::class) + ->disableOriginalConstructor() + ->setMethods(['getUrl']) + ->getMock(); + $this->dataBackupHelperMock = $this->getMockBuilder(\Magento\Backup\Helper\Data::class) + ->disableOriginalConstructor() + ->setMethods(['getExtensionByType', 'getBackupsDir']) + ->getMock(); + $this->maintenanceModeMock = $this->getMockBuilder(\Magento\Framework\App\MaintenanceMode::class) + ->disableOriginalConstructor() + ->setMethods(['set']) + ->getMock(); + $this->fileFactoryMock = $this->getMockBuilder(\Magento\Framework\App\Response\Http\FileFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManager = new ObjectManager($this); + $this->context = $this->objectManager->getObject( + \Magento\Backend\App\Action\Context::class, + [ + 'objectManager' => $this->objectManagerMock, + 'request' => $this->requestMock, + 'response' => $this->responseMock, + 'session' => $this->sessionMock, + 'helper' => $this->dataBackendHelperMock, + 'maintenanceMode' => $this->maintenanceModeMock, + ] + ); + $this->createController = $this->objectManager->getObject( + \Magento\Backup\Controller\Adminhtml\Index\Create::class, + [ + 'context' => $this->context, + 'backupFactory' => $this->backupFactoryMock, + 'fileFactory' => $this->fileFactoryMock, + ] + ); + } + + /** + * @covers \Magento\Backup\Controller\Adminhtml\Index\Create::execute + * @return void + */ + public function testExecuteNotPost() + { + $redirectUrl = '*/*/index'; + $redirectUrlBackup = 'backup/index/index'; + + $this->requestMock->expects($this->any()) + ->method('isAjax') + ->willReturn(true); + $this->requestMock->expects($this->any()) + ->method('isPost') + ->willReturn(false); + $this->dataBackendHelperMock->expects($this->any()) + ->method('getUrl') + ->with($redirectUrl, []) + ->willReturn($redirectUrlBackup); + $this->responseMock->expects($this->any()) + ->method('setRedirect') + ->with($redirectUrlBackup) + ->willReturnSelf(); + + $this->assertSame($this->responseMock, $this->createController->execute()); + } + + /** + * @covers \Magento\Backup\Controller\Adminhtml\Index\Create::execute + * @return void + */ + public function testExecutePermission() + { + $redirectUrl = '*/*/index'; + $redirectUrlBackup = 'backup/index/index'; + $backupType = 'db'; + $backupName = 'backup1'; + $response = '{"redirect_url":"backup\/index\/index"}'; + + $this->requestMock->expects($this->any()) + ->method('isAjax') + ->willReturn(true); + $this->requestMock->expects($this->any()) + ->method('isPost') + ->willReturn(true); + $this->requestMock->expects($this->any()) + ->method('getParam') + ->willReturnMap([ + ['type', null, $backupType], + ['backup_name', null, $backupName], + ]); + $this->dataBackendHelperMock->expects($this->any()) + ->method('getUrl') + ->with($redirectUrl, []) + ->willReturn($redirectUrlBackup); + $this->responseMock->expects($this->any()) + ->method('representJson') + ->with($response) + ->willReturnSelf(); + $this->maintenanceModeMock->expects($this->any()) + ->method('set') + ->with(true) + ->willReturn(false); + $this->backupFactoryMock->expects($this->any()) + ->method('create') + ->with($backupType) + ->willReturn($this->backupModelMock); + $this->backupModelMock->expects($this->any()) + ->method('setBackupExtension') + ->with($backupType) + ->willReturnSelf(); + $this->backupModelMock->expects($this->any()) + ->method('setBackupsDir') + ->willReturnSelf(); + $this->backupModelMock->expects($this->any()) + ->method('setTime') + ->willReturnSelf(); + $this->backupModelMock->expects($this->any()) + ->method('setName') + ->with($backupName) + ->willReturnSelf(); + $this->backupModelMock->expects($this->once()) + ->method('create') + ->willReturnSelf(); + $this->objectManagerMock->expects($this->any()) + ->method('get') + ->with(\Magento\Backup\Helper\Data::class) + ->willReturn($this->dataBackupHelperMock); + $this->dataBackupHelperMock->expects($this->any()) + ->method('getExtensionByType') + ->with($backupType) + ->willReturn($backupType); + $this->dataBackupHelperMock->expects($this->any()) + ->method('getBackupsDir') + ->willReturn('dir'); + + $this->assertNull($this->createController->execute()); + } +} diff --git a/app/code/Magento/Backup/etc/module.xml b/app/code/Magento/Backup/etc/module.xml index 667ec9d8a7461..3e9906a5ecd74 100644 --- a/app/code/Magento/Backup/etc/module.xml +++ b/app/code/Magento/Backup/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Braintree/Setup/Patch/Data/ConvertSerializedDataToJson.php b/app/code/Magento/Braintree/Setup/Patch/Data/ConvertSerializedDataToJson.php new file mode 100644 index 0000000000000..a0704002842ea --- /dev/null +++ b/app/code/Magento/Braintree/Setup/Patch/Data/ConvertSerializedDataToJson.php @@ -0,0 +1,111 @@ +moduleDataSetup = $moduleDataSetup; + $this->fieldDataConverterFactory = $fieldDataConverterFactory; + $this->queryModifierFactory = $queryModifierFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->convertSerializedDataToJson(); + } + + /** + * Upgrade data to version 2.0.1, converts row data in the core_config_data table that uses the path + * payment/braintree/countrycreditcard from serialized to JSON + * + * @return void + */ + private function convertSerializedDataToJson() + { + $fieldDataConverter = $this->fieldDataConverterFactory->create( + \Magento\Framework\DB\DataConverter\SerializedToJson::class + ); + + $queryModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'path' => ['payment/braintree/countrycreditcard'] + ] + ] + ); + + $fieldDataConverter->convert( + $this->moduleDataSetup->getConnection(), + $this->moduleDataSetup->getTable('core_config_data'), + 'config_id', + 'value', + $queryModifier + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Braintree/Setup/UpgradeData.php b/app/code/Magento/Braintree/Setup/UpgradeData.php deleted file mode 100644 index a7b39f12273e2..0000000000000 --- a/app/code/Magento/Braintree/Setup/UpgradeData.php +++ /dev/null @@ -1,83 +0,0 @@ -fieldDataConverterFactory = $fieldDataConverterFactory; - $this->queryModifierFactory = $queryModifierFactory; - } - - /** - * Upgrades data for Braintree module - * - * @param ModuleDataSetupInterface $setup - * @param ModuleContextInterface $context - * @return void - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $this->convertSerializedDataToJson($setup); - } - } - - /** - * Upgrade data to version 2.0.1, converts row data in the core_config_data table that uses the path - * payment/braintree/countrycreditcard from serialized to JSON - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function convertSerializedDataToJson(ModuleDataSetupInterface $setup) - { - $fieldDataConverter = $this->fieldDataConverterFactory->create( - \Magento\Framework\DB\DataConverter\SerializedToJson::class - ); - - $queryModifier = $this->queryModifierFactory->create( - 'in', - [ - 'values' => [ - 'path' => ['payment/braintree/countrycreditcard'] - ] - ] - ); - - $fieldDataConverter->convert( - $setup->getConnection(), - $setup->getTable('core_config_data'), - 'config_id', - 'value', - $queryModifier - ); - } -} diff --git a/app/code/Magento/Braintree/etc/module.xml b/app/code/Magento/Braintree/etc/module.xml index e3415c4935ff6..8be79268e7b58 100644 --- a/app/code/Magento/Braintree/etc/module.xml +++ b/app/code/Magento/Braintree/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/hosted-fields.js b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/hosted-fields.js index d2faac6ed792f..05c09abdb7b2e 100644 --- a/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/hosted-fields.js +++ b/app/code/Magento/Braintree/view/frontend/web/js/view/payment/method-renderer/hosted-fields.js @@ -61,7 +61,7 @@ define([ }, /** - * @returns {Bool} + * @returns {Boolean} */ isVaultEnabled: function () { return this.vaultEnabler.isVaultEnabled(); @@ -142,11 +142,20 @@ define([ return true; }, + /** + * Returns state of place order button + * @returns {Boolean} + */ + isButtonActive: function () { + return this.isActive() && this.isPlaceOrderActionAllowed(); + }, + /** * Trigger order placing */ placeOrderClick: function () { if (this.validateCardType()) { + this.isPlaceOrderActionAllowed(false); $(this.getSelector('submit')).trigger('click'); } }, diff --git a/app/code/Magento/Braintree/view/frontend/web/template/payment/form.html b/app/code/Magento/Braintree/view/frontend/web/template/payment/form.html index d30186c8fb309..819b06ca75788 100644 --- a/app/code/Magento/Braintree/view/frontend/web/template/payment/form.html +++ b/app/code/Magento/Braintree/view/frontend/web/template/payment/form.html @@ -141,8 +141,7 @@ data-bind=" click: placeOrderClick, attr: {title: $t('Place Order')}, - css: {disabled: !isPlaceOrderActionAllowed()}, - enable: isActive() + enable: isButtonActive() " disabled> diff --git a/app/code/Magento/Bundle/Model/OptionRepository.php b/app/code/Magento/Bundle/Model/OptionRepository.php index b4b3c84b88ef3..b5e5244a11fda 100644 --- a/app/code/Magento/Bundle/Model/OptionRepository.php +++ b/app/code/Magento/Bundle/Model/OptionRepository.php @@ -201,10 +201,10 @@ public function save( /** @var \Magento\Bundle\Model\Option $existingOption */ $existingOption = $optionCollection->getFirstItem(); - if (!$optionId) { - $option->setOptionId(null); - } if (!$optionId || $existingOption->getParentId() != $parentId) { + //If option ID is empty or existing option's parent ID is different + //we'd need a new ID for the option. + $option->setOptionId(null); $option->setDefaultTitle($option->getTitle()); if (is_array($option->getProductLinks())) { $linksToAdd = $option->getProductLinks(); diff --git a/app/code/Magento/Bundle/Model/Product/SaveHandler.php b/app/code/Magento/Bundle/Model/Product/SaveHandler.php index de11df62cbb05..8517cec6aff6d 100644 --- a/app/code/Magento/Bundle/Model/Product/SaveHandler.php +++ b/app/code/Magento/Bundle/Model/Product/SaveHandler.php @@ -5,6 +5,7 @@ */ namespace Magento\Bundle\Model\Product; +use Magento\Bundle\Api\Data\OptionInterface; use Magento\Catalog\Api\Data\ProductInterface; use Magento\Bundle\Api\ProductOptionRepositoryInterface as OptionRepository; use Magento\Bundle\Api\ProductLinkManagementInterface; @@ -49,42 +50,58 @@ public function __construct( ?: ObjectManager::getInstance()->get(MetadataPool::class); } + /** + * @param ProductInterface $bundle + * @param OptionInterface[] $currentOptions + * + * @return void + */ + private function removeOldOptions( + ProductInterface $bundle, + array $currentOptions + ) { + $oldOptions = $this->optionRepository->getList($bundle->getSku()); + if ($oldOptions) { + $remainingOptions = []; + $metadata + = $this->metadataPool->getMetadata(ProductInterface::class); + $productId = $bundle->getData($metadata->getLinkField()); + + foreach ($currentOptions as $option) { + $remainingOptions[] = $option->getOptionId(); + } + foreach ($oldOptions as $option) { + if (!in_array($option->getOptionId(), $remainingOptions)) { + $option->setParentId($productId); + $this->removeOptionLinks($bundle->getSku(), $option); + $this->optionRepository->delete($option); + } + } + } + } + /** * @param object $entity * @param array $arguments - * @return \Magento\Catalog\Api\Data\ProductInterface|object + * + * @return ProductInterface|object + * * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function execute($entity, $arguments = []) { /** @var \Magento\Bundle\Api\Data\OptionInterface[] $options */ $options = $entity->getExtensionAttributes()->getBundleProductOptions() ?: []; - + //Only processing bundle products. if ($entity->getTypeId() !== 'bundle' || empty($options)) { return $entity; } - + /** @var ProductInterface $entity */ + //Removing old options if (!$entity->getCopyFromView()) { - $updatedOptions = []; - $oldOptions = $this->optionRepository->getList($entity->getSku()); - - $metadata = $this->metadataPool->getMetadata(ProductInterface::class); - - $productId = $entity->getData($metadata->getLinkField()); - - foreach ($options as $option) { - $updatedOptions[$option->getOptionId()][$productId] = (bool)$option->getOptionId(); - } - - foreach ($oldOptions as $option) { - if (!isset($updatedOptions[$option->getOptionId()][$productId])) { - $option->setParentId($productId); - $this->removeOptionLinks($entity->getSku(), $option); - $this->optionRepository->delete($option); - } - } + $this->removeOldOptions($entity, $options); } - + //Saving active options. foreach ($options as $option) { $this->optionRepository->save($entity, $option); } diff --git a/app/code/Magento/Bundle/Setup/InstallData.php b/app/code/Magento/Bundle/Setup/InstallData.php deleted file mode 100644 index 6a3ff08c4d781..0000000000000 --- a/app/code/Magento/Bundle/Setup/InstallData.php +++ /dev/null @@ -1,208 +0,0 @@ -eavSetupFactory = $eavSetupFactory; - } - - /** - * {@inheritdoc} - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - $fieldList = [ - 'price', - 'special_price', - 'special_from_date', - 'special_to_date', - 'minimal_price', - 'cost', - 'tier_price', - 'weight', - ]; - foreach ($fieldList as $field) { - $applyTo = explode( - ',', - $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field, 'apply_to') - ); - if (!in_array('bundle', $applyTo)) { - $applyTo[] = 'bundle'; - $eavSetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - $field, - 'apply_to', - implode(',', $applyTo) - ); - } - } - - $applyTo = explode(',', $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'cost', 'apply_to')); - unset($applyTo[array_search('bundle', $applyTo)]); - $eavSetup->updateAttribute(\Magento\Catalog\Model\Product::ENTITY, 'cost', 'apply_to', implode(',', $applyTo)); - - /** - * Add attributes to the eav/attribute - */ - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'price_type', - [ - 'type' => 'int', - 'backend' => '', - 'frontend' => '', - 'label' => '', - 'input' => '', - 'class' => '', - 'source' => '', - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, - 'visible' => true, - 'required' => true, - 'user_defined' => false, - 'default' => '', - 'searchable' => false, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'used_in_product_listing' => true, - 'unique' => false, - 'apply_to' => 'bundle' - ] - ); - - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'sku_type', - [ - 'type' => 'int', - 'backend' => '', - 'frontend' => '', - 'label' => '', - 'input' => '', - 'class' => '', - 'source' => '', - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, - 'visible' => false, - 'required' => true, - 'user_defined' => false, - 'default' => '', - 'searchable' => false, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'unique' => false, - 'apply_to' => 'bundle' - ] - ); - - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'weight_type', - [ - 'type' => 'int', - 'backend' => '', - 'frontend' => '', - 'label' => '', - 'input' => '', - 'class' => '', - 'source' => '', - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, - 'visible' => false, - 'required' => true, - 'user_defined' => false, - 'default' => '', - 'searchable' => false, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'used_in_product_listing' => true, - 'unique' => false, - 'apply_to' => 'bundle' - ] - ); - - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'price_view', - [ - 'group' => 'Advanced Pricing', - 'type' => 'int', - 'backend' => '', - 'frontend' => '', - 'label' => 'Price View', - 'input' => 'select', - 'class' => '', - 'source' => \Magento\Bundle\Model\Product\Attribute\Source\Price\View::class, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, - 'visible' => true, - 'required' => true, - 'user_defined' => false, - 'default' => '', - 'searchable' => false, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'used_in_product_listing' => true, - 'unique' => false, - 'apply_to' => 'bundle' - ] - ); - - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'shipment_type', - [ - 'type' => 'int', - 'backend' => '', - 'frontend' => '', - 'label' => 'Shipment', - 'input' => '', - 'class' => '', - 'source' => '', - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, - 'visible' => false, - 'required' => true, - 'user_defined' => false, - 'default' => '', - 'searchable' => false, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'used_in_product_listing' => true, - 'unique' => false, - 'apply_to' => 'bundle' - ] - ); - } -} diff --git a/app/code/Magento/Bundle/Setup/Patch/Data/ApplyAttributesUpdate.php b/app/code/Magento/Bundle/Setup/Patch/Data/ApplyAttributesUpdate.php new file mode 100644 index 0000000000000..d8ad1757ab2e6 --- /dev/null +++ b/app/code/Magento/Bundle/Setup/Patch/Data/ApplyAttributesUpdate.php @@ -0,0 +1,241 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function apply() + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + $fieldList = [ + 'price', + 'special_price', + 'special_from_date', + 'special_to_date', + 'minimal_price', + 'cost', + 'tier_price', + 'weight', + ]; + foreach ($fieldList as $field) { + $applyTo = explode( + ',', + $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field, 'apply_to') + ); + if (!in_array('bundle', $applyTo)) { + $applyTo[] = 'bundle'; + $eavSetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + $field, + 'apply_to', + implode(',', $applyTo) + ); + } + } + + $applyTo = explode(',', $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'cost', 'apply_to')); + unset($applyTo[array_search('bundle', $applyTo)]); + $eavSetup->updateAttribute(\Magento\Catalog\Model\Product::ENTITY, 'cost', 'apply_to', implode(',', $applyTo)); + + /** + * Add attributes to the eav/attribute + */ + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'price_type', + [ + 'type' => 'int', + 'backend' => '', + 'frontend' => '', + 'label' => '', + 'input' => '', + 'class' => '', + 'source' => '', + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, + 'visible' => true, + 'required' => true, + 'user_defined' => false, + 'default' => '', + 'searchable' => false, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'used_in_product_listing' => true, + 'unique' => false, + 'apply_to' => 'bundle' + ] + ); + + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'sku_type', + [ + 'type' => 'int', + 'backend' => '', + 'frontend' => '', + 'label' => '', + 'input' => '', + 'class' => '', + 'source' => '', + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, + 'visible' => false, + 'required' => true, + 'user_defined' => false, + 'default' => '', + 'searchable' => false, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'unique' => false, + 'apply_to' => 'bundle' + ] + ); + + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'weight_type', + [ + 'type' => 'int', + 'backend' => '', + 'frontend' => '', + 'label' => '', + 'input' => '', + 'class' => '', + 'source' => '', + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, + 'visible' => false, + 'required' => true, + 'user_defined' => false, + 'default' => '', + 'searchable' => false, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'used_in_product_listing' => true, + 'unique' => false, + 'apply_to' => 'bundle' + ] + ); + + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'price_view', + [ + 'group' => 'Advanced Pricing', + 'type' => 'int', + 'backend' => '', + 'frontend' => '', + 'label' => 'Price View', + 'input' => 'select', + 'class' => '', + 'source' => \Magento\Bundle\Model\Product\Attribute\Source\Price\View::class, + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, + 'visible' => true, + 'required' => true, + 'user_defined' => false, + 'default' => '', + 'searchable' => false, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'used_in_product_listing' => true, + 'unique' => false, + 'apply_to' => 'bundle' + ] + ); + + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'shipment_type', + [ + 'type' => 'int', + 'backend' => '', + 'frontend' => '', + 'label' => 'Shipment', + 'input' => '', + 'class' => '', + 'source' => '', + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, + 'visible' => false, + 'required' => true, + 'user_defined' => false, + 'default' => '', + 'searchable' => false, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'used_in_product_listing' => true, + 'unique' => false, + 'apply_to' => 'bundle' + ] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Bundle/Setup/Patch/Data/UpdateBundleRelatedEntityTytpes.php b/app/code/Magento/Bundle/Setup/Patch/Data/UpdateBundleRelatedEntityTytpes.php new file mode 100644 index 0000000000000..44647ea76a1c2 --- /dev/null +++ b/app/code/Magento/Bundle/Setup/Patch/Data/UpdateBundleRelatedEntityTytpes.php @@ -0,0 +1,204 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var \Magento\Eav\Setup\EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + + $attributeSetId = $eavSetup->getDefaultAttributeSetId(ProductAttributeInterface::ENTITY_TYPE_CODE); + $eavSetup->addAttributeGroup( + ProductAttributeInterface::ENTITY_TYPE_CODE, + $attributeSetId, + 'Bundle Items', + 16 + ); + $this->upgradePriceType($eavSetup); + $this->upgradeSkuType($eavSetup); + $this->upgradeWeightType($eavSetup); + $this->upgradeShipmentType($eavSetup); + } + + /** + * Upgrade Dynamic Price attribute + * + * @param EavSetup $eavSetup + * @return void + */ + private function upgradePriceType(EavSetup $eavSetup) + { + $eavSetup->updateAttribute( + ProductAttributeInterface::ENTITY_TYPE_CODE, + 'price_type', + 'frontend_input', + 'boolean', + 31 + ); + $eavSetup->updateAttribute( + ProductAttributeInterface::ENTITY_TYPE_CODE, + 'price_type', + 'frontend_label', + 'Dynamic Price' + ); + $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'price_type', 'default_value', 0); + } + + /** + * Upgrade Dynamic Sku attribute + * + * @param EavSetup $eavSetup + * @return void + */ + private function upgradeSkuType(EavSetup $eavSetup) + { + $eavSetup->updateAttribute( + ProductAttributeInterface::ENTITY_TYPE_CODE, + 'sku_type', + 'frontend_input', + 'boolean', + 21 + ); + $eavSetup->updateAttribute( + ProductAttributeInterface::ENTITY_TYPE_CODE, + 'sku_type', + 'frontend_label', + 'Dynamic SKU' + ); + $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'sku_type', 'default_value', 0); + $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'sku_type', 'is_visible', 1); + } + + /** + * Upgrade Dynamic Weight attribute + * + * @param EavSetup $eavSetup + * @return void + */ + private function upgradeWeightType(EavSetup $eavSetup) + { + $eavSetup->updateAttribute( + ProductAttributeInterface::ENTITY_TYPE_CODE, + 'weight_type', + 'frontend_input', + 'boolean', + 71 + ); + $eavSetup->updateAttribute( + ProductAttributeInterface::ENTITY_TYPE_CODE, + 'weight_type', + 'frontend_label', + 'Dynamic Weight' + ); + $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'weight_type', 'default_value', 0); + $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'weight_type', 'is_visible', 1); + } + + /** + * Upgrade Ship Bundle Items attribute + * + * @param EavSetup $eavSetup + * @return void + */ + private function upgradeShipmentType(EavSetup $eavSetup) + { + $attributeSetId = $eavSetup->getDefaultAttributeSetId(ProductAttributeInterface::ENTITY_TYPE_CODE); + $eavSetup->addAttributeToGroup( + ProductAttributeInterface::ENTITY_TYPE_CODE, + $attributeSetId, + 'Bundle Items', + 'shipment_type', + 1 + ); + $eavSetup->updateAttribute( + ProductAttributeInterface::ENTITY_TYPE_CODE, + 'shipment_type', + 'frontend_input', + 'select' + ); + $eavSetup->updateAttribute( + ProductAttributeInterface::ENTITY_TYPE_CODE, + 'shipment_type', + 'frontend_label', + 'Ship Bundle Items' + ); + $eavSetup->updateAttribute( + ProductAttributeInterface::ENTITY_TYPE_CODE, + 'shipment_type', + 'source_model', + \Magento\Bundle\Model\Product\Attribute\Source\Shipment\Type::class + ); + $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'shipment_type', 'default_value', 0); + $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'shipment_type', 'is_visible', 1); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + ApplyAttributesUpdate::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.2'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Bundle/Setup/Patch/Schema/UpdateBundleRelatedSchema.php b/app/code/Magento/Bundle/Setup/Patch/Schema/UpdateBundleRelatedSchema.php new file mode 100644 index 0000000000000..94bf1d11fb4aa --- /dev/null +++ b/app/code/Magento/Bundle/Setup/Patch/Schema/UpdateBundleRelatedSchema.php @@ -0,0 +1,159 @@ +schemaSetup = $schemaSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->schemaSetup->startSetup(); + // Updating data of the 'catalog_product_bundle_option_value' table. + $tableName = $this->schemaSetup->getTable('catalog_product_bundle_option_value'); + + $select = $this->schemaSetup->getConnection()->select() + ->from( + ['values' => $tableName], + ['value_id'] + )->joinLeft( + [ + 'options' => $this->schemaSetup->getTable( + 'catalog_product_bundle_option' + ) + ], + 'values.option_id = options.option_id', + ['parent_product_id' => 'parent_id'] + ); + + $this->schemaSetup->getConnection()->query( + $this->schemaSetup->getConnection()->insertFromSelect( + $select, + $tableName, + ['value_id', 'parent_product_id'], + \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE + ) + ); + + // Updating data of the 'catalog_product_bundle_selection_price' table. + $tableName = $this->schemaSetup->getTable( + 'catalog_product_bundle_selection_price' + ); + $tmpTableName = $this->schemaSetup->getTable( + 'catalog_product_bundle_selection_price_tmp' + ); + + $existingForeignKeys = $this->schemaSetup->getConnection()->getForeignKeys($tableName); + + foreach ($existingForeignKeys as $key) { + $this->schemaSetup->getConnection()->dropForeignKey($key['TABLE_NAME'], $key['FK_NAME']); + } + + $this->schemaSetup->getConnection()->createTable( + $this->schemaSetup->getConnection()->createTableByDdl($tableName, $tmpTableName) + ); + + foreach ($existingForeignKeys as $key) { + $this->schemaSetup->getConnection()->addForeignKey( + $key['FK_NAME'], + $key['TABLE_NAME'], + $key['COLUMN_NAME'], + $key['REF_TABLE_NAME'], + $key['REF_COLUMN_NAME'], + $key['ON_DELETE'] + ); + } + + $this->schemaSetup->getConnection()->query( + $this->schemaSetup->getConnection()->insertFromSelect( + $this->schemaSetup->getConnection()->select()->from($tableName), + $tmpTableName + ) + ); + + $this->schemaSetup->getConnection()->truncateTable($tableName); + + $columnsToSelect = []; + + foreach ($this->schemaSetup->getConnection()->describeTable($tmpTableName) as $column) { + $alias = $column['COLUMN_NAME'] == 'parent_product_id' ? 'selections.' : 'prices.'; + + $columnsToSelect[] = $alias . $column['COLUMN_NAME']; + } + + $select = $this->schemaSetup->getConnection()->select() + ->from( + ['prices' => $tmpTableName], + [] + )->joinLeft( + [ + 'selections' => $this->schemaSetup->getTable( + 'catalog_product_bundle_selection' + ) + ], + 'prices.selection_id = selections.selection_id', + [] + )->columns($columnsToSelect); + + $this->schemaSetup->getConnection()->query( + $this->schemaSetup->getConnection()->insertFromSelect($select, $tableName) + ); + + $this->schemaSetup->getConnection()->dropTable($tmpTableName); + + $this->schemaSetup->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.4'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Bundle/Setup/UpgradeData.php b/app/code/Magento/Bundle/Setup/UpgradeData.php deleted file mode 100644 index 750bc79d84801..0000000000000 --- a/app/code/Magento/Bundle/Setup/UpgradeData.php +++ /dev/null @@ -1,255 +0,0 @@ -eavSetupFactory = $eavSetupFactory; - } - - /** - * {@inheritdoc} - * - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - - if (version_compare($context->getVersion(), '2.0.2', '<')) { - /** @var \Magento\Eav\Setup\EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - - $attributeSetId = $eavSetup->getDefaultAttributeSetId(ProductAttributeInterface::ENTITY_TYPE_CODE); - $eavSetup->addAttributeGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - $attributeSetId, - 'Bundle Items', - 16 - ); - - $this->upgradePriceType($eavSetup); - $this->upgradeSkuType($eavSetup); - $this->upgradeWeightType($eavSetup); - $this->upgradeShipmentType($eavSetup); - } - - if (version_compare($context->getVersion(), '2.0.4', '<')) { - // Updating data of the 'catalog_product_bundle_option_value' table. - $tableName = $setup->getTable('catalog_product_bundle_option_value'); - - $select = $setup->getConnection()->select() - ->from( - ['values' => $tableName], - ['value_id'] - )->joinLeft( - ['options' => $setup->getTable('catalog_product_bundle_option')], - 'values.option_id = options.option_id', - ['parent_product_id' => 'parent_id'] - ); - - $setup->getConnection()->query( - $setup->getConnection()->insertFromSelect( - $select, - $tableName, - ['value_id', 'parent_product_id'], - \Magento\Framework\DB\Adapter\AdapterInterface::INSERT_ON_DUPLICATE - ) - ); - - // Updating data of the 'catalog_product_bundle_selection_price' table. - $tableName = $setup->getTable('catalog_product_bundle_selection_price'); - $tmpTableName = $setup->getTable('catalog_product_bundle_selection_price_tmp'); - - $existingForeignKeys = $setup->getConnection()->getForeignKeys($tableName); - - foreach ($existingForeignKeys as $key) { - $setup->getConnection()->dropForeignKey($key['TABLE_NAME'], $key['FK_NAME']); - } - - $setup->getConnection()->createTable( - $setup->getConnection()->createTableByDdl($tableName, $tmpTableName) - ); - - foreach ($existingForeignKeys as $key) { - $setup->getConnection()->addForeignKey( - $key['FK_NAME'], - $key['TABLE_NAME'], - $key['COLUMN_NAME'], - $key['REF_TABLE_NAME'], - $key['REF_COLUMN_NAME'], - $key['ON_DELETE'] - ); - } - - $setup->getConnection()->query( - $setup->getConnection()->insertFromSelect( - $setup->getConnection()->select()->from($tableName), - $tmpTableName - ) - ); - - $setup->getConnection()->truncateTable($tableName); - - $columnsToSelect = []; - - foreach ($setup->getConnection()->describeTable($tmpTableName) as $column) { - $alias = $column['COLUMN_NAME'] == 'parent_product_id' ? 'selections.' : 'prices.'; - - $columnsToSelect[] = $alias . $column['COLUMN_NAME']; - } - - $select = $setup->getConnection()->select() - ->from( - ['prices' => $tmpTableName], - [] - )->joinLeft( - ['selections' => $setup->getTable('catalog_product_bundle_selection')], - 'prices.selection_id = selections.selection_id', - [] - )->columns($columnsToSelect); - - $setup->getConnection()->query( - $setup->getConnection()->insertFromSelect($select, $tableName) - ); - - $setup->getConnection()->dropTable($tmpTableName); - } - - $setup->endSetup(); - } - - /** - * Upgrade Dynamic Price attribute - * - * @param EavSetup $eavSetup - * @return void - */ - private function upgradePriceType(EavSetup $eavSetup) - { - $eavSetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'price_type', - 'frontend_input', - 'boolean', - 31 - ); - $eavSetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'price_type', - 'frontend_label', - 'Dynamic Price' - ); - $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'price_type', 'default_value', 0); - } - - /** - * Upgrade Dynamic Sku attribute - * - * @param EavSetup $eavSetup - * @return void - */ - private function upgradeSkuType(EavSetup $eavSetup) - { - $eavSetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'sku_type', - 'frontend_input', - 'boolean', - 21 - ); - $eavSetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'sku_type', - 'frontend_label', - 'Dynamic SKU' - ); - $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'sku_type', 'default_value', 0); - $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'sku_type', 'is_visible', 1); - } - - /** - * Upgrade Dynamic Weight attribute - * - * @param EavSetup $eavSetup - * @return void - */ - private function upgradeWeightType(EavSetup $eavSetup) - { - $eavSetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'weight_type', - 'frontend_input', - 'boolean', - 71 - ); - $eavSetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'weight_type', - 'frontend_label', - 'Dynamic Weight' - ); - $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'weight_type', 'default_value', 0); - $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'weight_type', 'is_visible', 1); - } - - /** - * Upgrade Ship Bundle Items attribute - * - * @param EavSetup $eavSetup - * @return void - */ - private function upgradeShipmentType(EavSetup $eavSetup) - { - $attributeSetId = $eavSetup->getDefaultAttributeSetId(ProductAttributeInterface::ENTITY_TYPE_CODE); - $eavSetup->addAttributeToGroup( - ProductAttributeInterface::ENTITY_TYPE_CODE, - $attributeSetId, - 'Bundle Items', - 'shipment_type', - 1 - ); - $eavSetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'shipment_type', - 'frontend_input', - 'select' - ); - $eavSetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'shipment_type', - 'frontend_label', - 'Ship Bundle Items' - ); - $eavSetup->updateAttribute( - ProductAttributeInterface::ENTITY_TYPE_CODE, - 'shipment_type', - 'source_model', - \Magento\Bundle\Model\Product\Attribute\Source\Shipment\Type::class - ); - $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'shipment_type', 'default_value', 0); - $eavSetup->updateAttribute(ProductAttributeInterface::ENTITY_TYPE_CODE, 'shipment_type', 'is_visible', 1); - } -} diff --git a/app/code/Magento/Bundle/etc/config.xml b/app/code/Magento/Bundle/etc/config.xml deleted file mode 100644 index 152f04e251c35..0000000000000 --- a/app/code/Magento/Bundle/etc/config.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - diff --git a/app/code/Magento/Bundle/etc/db_schema.xml b/app/code/Magento/Bundle/etc/db_schema.xml index 5f9e1902697e5..8092f34c533fa 100644 --- a/app/code/Magento/Bundle/etc/db_schema.xml +++ b/app/code/Magento/Bundle/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
- - - - diff --git a/app/code/Magento/Bundle/etc/module.xml b/app/code/Magento/Bundle/etc/module.xml index 8027f3c67c927..9e4e2a166a7b8 100644 --- a/app/code/Magento/Bundle/etc/module.xml +++ b/app/code/Magento/Bundle/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/BundleGraphQl/etc/module.xml b/app/code/Magento/BundleGraphQl/etc/module.xml index 34e721bf02e8e..d6c45dd617a1a 100644 --- a/app/code/Magento/BundleGraphQl/etc/module.xml +++ b/app/code/Magento/BundleGraphQl/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php b/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php index 9b8518a41ffff..4004a3e5f1933 100644 --- a/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php +++ b/app/code/Magento/BundleImportExport/Model/Export/RowCustomizer.php @@ -242,7 +242,8 @@ protected function getFormattedBundleSelections($optionValues, SelectionCollecti 'price' => $selection->getSelectionPriceValue(), 'default' => $selection->getIsDefault(), 'default_qty' => $selection->getSelectionQty(), - 'price_type' => $this->getPriceTypeValue($selection->getSelectionPriceType()) + 'price_type' => $this->getPriceTypeValue($selection->getSelectionPriceType()), + 'can_change_qty' => $selection->getSelectionCanChangeQty(), ]; $bundleData .= $optionValues . ImportModel::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR diff --git a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php index bc32483b41680..8e59c866e162a 100644 --- a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php +++ b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php @@ -299,6 +299,7 @@ protected function populateSelectionTemplate($selection, $optionId, $parentId, $ } else { $productId = $selection['product_id']; } + $populatedSelection = [ 'selection_id' => null, 'option_id' => (int)$optionId, @@ -310,7 +311,8 @@ protected function populateSelectionTemplate($selection, $optionId, $parentId, $ ? self::SELECTION_PRICE_TYPE_FIXED : self::SELECTION_PRICE_TYPE_PERCENT, 'selection_price_value' => (isset($selection['price'])) ? (float)$selection['price'] : 0.0, 'selection_qty' => (isset($selection['default_qty'])) ? (float)$selection['default_qty'] : 1.0, - 'selection_can_change_qty' => 1, + 'selection_can_change_qty' => isset($selection['can_change_qty']) + ? ($selection['can_change_qty'] ? 1 : 0) : 1, ]; if (isset($selection['selection_id'])) { $populatedSelection['selection_id'] = $selection['selection_id']; diff --git a/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php b/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php index e76e9e1ba565f..849158122e8be 100644 --- a/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php +++ b/app/code/Magento/BundleImportExport/Test/Unit/Model/Export/Product/RowCustomizerTest.php @@ -105,12 +105,20 @@ protected function setUp() ); $this->selection = $this->createPartialMock( \Magento\Catalog\Model\Product::class, - ['getSku', 'getSelectionPriceValue', 'getIsDefault', 'getSelectionQty', 'getSelectionPriceType'] + [ + 'getSku', + 'getSelectionPriceValue', + 'getIsDefault', + 'getSelectionQty', + 'getSelectionPriceType', + 'getSelectionCanChangeQty' + ] ); $this->selection->expects($this->any())->method('getSku')->willReturn(1); $this->selection->expects($this->any())->method('getSelectionPriceValue')->willReturn(1); $this->selection->expects($this->any())->method('getSelectionQty')->willReturn(1); $this->selection->expects($this->any())->method('getSelectionPriceType')->willReturn(1); + $this->selection->expects($this->any())->method('getSelectionCanChangeQty')->willReturn(1); $this->selectionsCollection = $this->createPartialMock( \Magento\Bundle\Model\ResourceModel\Selection\Collection::class, ['getIterator', 'addAttributeToSort'] @@ -168,6 +176,19 @@ public function testAddData() 'additional_attributes' => $attributes ]; $preparedRow = $preparedData->addData($dataRow, 1); + + $bundleValues = [ + 'name=title', + 'type=1', + 'required=1', + 'sku=1', + 'price=1', + 'default=', + 'default_qty=1', + 'price_type=percent', + 'can_change_qty=1', + ]; + $expected = [ 'sku' => 'sku1', 'additional_attributes' => 'attribute=1,attribute2="Text",attribute3=One,Two,Three', @@ -176,7 +197,7 @@ public function testAddData() 'bundle_sku_type' => 'fixed', 'bundle_price_view' => 'As low as', 'bundle_weight_type' => 'fixed', - 'bundle_values' => 'name=title,type=1,required=1,sku=1,price=1,default=,default_qty=1,price_type=percent' + 'bundle_values' => implode(',', $bundleValues) ]; $this->assertEquals($expected, $preparedRow); } diff --git a/app/code/Magento/BundleImportExport/etc/module.xml b/app/code/Magento/BundleImportExport/etc/module.xml index e324145cabcca..44b09e4c5fb88 100644 --- a/app/code/Magento/BundleImportExport/etc/module.xml +++ b/app/code/Magento/BundleImportExport/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/CacheInvalidate/etc/module.xml b/app/code/Magento/CacheInvalidate/etc/module.xml index dda90ba8b38ab..789b74480b44e 100644 --- a/app/code/Magento/CacheInvalidate/etc/module.xml +++ b/app/code/Magento/CacheInvalidate/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Captcha/etc/db_schema.xml b/app/code/Magento/Captcha/etc/db_schema.xml index 25aef55c606f1..fa9a14abb8963 100644 --- a/app/code/Magento/Captcha/etc/db_schema.xml +++ b/app/code/Magento/Captcha/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Captcha/etc/module.xml b/app/code/Magento/Captcha/etc/module.xml index 03ab6dbee3991..36a44a6543066 100644 --- a/app/code/Magento/Captcha/etc/module.xml +++ b/app/code/Magento/Captcha/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Catalog/Api/Data/CategoryInterface.php b/app/code/Magento/Catalog/Api/Data/CategoryInterface.php index b65cdafbe26f4..b9a23e9d08ec3 100644 --- a/app/code/Magento/Catalog/Api/Data/CategoryInterface.php +++ b/app/code/Magento/Catalog/Api/Data/CategoryInterface.php @@ -14,6 +14,37 @@ */ interface CategoryInterface extends \Magento\Framework\Api\CustomAttributesDataInterface { + /**#@+ + * Constants defined for keys of data array + */ + const KEY_PARENT_ID = 'parent_id'; + const KEY_NAME = 'name'; + const KEY_IS_ACTIVE = 'is_active'; + const KEY_POSITION = 'position'; + const KEY_LEVEL = 'level'; + const KEY_UPDATED_AT = 'updated_at'; + const KEY_CREATED_AT = 'created_at'; + const KEY_PATH = 'path'; + const KEY_AVAILABLE_SORT_BY = 'available_sort_by'; + const KEY_INCLUDE_IN_MENU = 'include_in_menu'; + const KEY_PRODUCT_COUNT = 'product_count'; + const KEY_CHILDREN_DATA = 'children_data'; + + const ATTRIBUTES = [ + 'id', + self::KEY_PARENT_ID, + self::KEY_NAME, + self::KEY_IS_ACTIVE, + self::KEY_POSITION, + self::KEY_LEVEL, + self::KEY_UPDATED_AT, + self::KEY_CREATED_AT, + self::KEY_AVAILABLE_SORT_BY, + self::KEY_INCLUDE_IN_MENU, + self::KEY_CHILDREN_DATA, + ]; + /**#@-*/ + /** * @return int|null */ diff --git a/app/code/Magento/Catalog/Api/Data/ProductAttributeInterface.php b/app/code/Magento/Catalog/Api/Data/ProductAttributeInterface.php index 12adf5b08938f..590c23a0aa0b1 100644 --- a/app/code/Magento/Catalog/Api/Data/ProductAttributeInterface.php +++ b/app/code/Magento/Catalog/Api/Data/ProductAttributeInterface.php @@ -32,4 +32,9 @@ interface ProductAttributeInterface extends \Magento\Catalog\Api\Data\EavAttribu const CODE_TIER_PRICE_FIELD_VALUE_TYPE = 'value_type'; const CODE_SEO_FIELD_META_DESCRIPTION = 'meta_description'; const CODE_WEIGHT = 'weight'; + + /** + * @return \Magento\Eav\Api\Data\AttributeExtensionInterface|null + */ + public function getExtensionAttributes(); } diff --git a/app/code/Magento/Catalog/Api/Data/ProductInterface.php b/app/code/Magento/Catalog/Api/Data/ProductInterface.php index a79c76fd8e2b6..4968f49fd20dc 100644 --- a/app/code/Magento/Catalog/Api/Data/ProductInterface.php +++ b/app/code/Magento/Catalog/Api/Data/ProductInterface.php @@ -36,6 +36,24 @@ interface ProductInterface extends \Magento\Framework\Api\CustomAttributesDataIn const UPDATED_AT = 'updated_at'; + const MEDIA_GALLERY = 'media_gallery'; + + const TIER_PRICE = 'tier_price'; + + const ATTRIBUTES = [ + self::SKU, + self::NAME, + self::PRICE, + self::WEIGHT, + self::STATUS, + self::VISIBILITY, + self::ATTRIBUTE_SET_ID, + self::TYPE_ID, + self::CREATED_AT, + self::UPDATED_AT, + self::MEDIA_GALLERY, + self::TIER_PRICE, + ]; /**#@-*/ /** diff --git a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Set/Main.php b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Set/Main.php index c6e48c02805a6..6760b44c22ee1 100644 --- a/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Set/Main.php +++ b/app/code/Magento/Catalog/Block/Adminhtml/Product/Attribute/Set/Main.php @@ -233,7 +233,7 @@ public function getGroupTreeJson() /* @var $node \Magento\Eav\Model\Entity\Attribute\Group */ foreach ($groups as $node) { $item = []; - $item['text'] = $node->getAttributeGroupName(); + $item['text'] = $this->escapeHtml($node->getAttributeGroupName()); $item['id'] = $node->getAttributeGroupId(); $item['cls'] = 'folder'; $item['allowDrop'] = true; @@ -280,7 +280,7 @@ public function getAttributeTreeJson() foreach ($attributes as $child) { $attr = [ - 'text' => $child->getAttributeCode(), + 'text' => $this->escapeHtml($child->getAttributeCode()), 'id' => $child->getAttributeId(), 'cls' => 'leaf', 'allowDrop' => false, diff --git a/app/code/Magento/Catalog/Block/Product/ImageBuilder.php b/app/code/Magento/Catalog/Block/Product/ImageBuilder.php index 04d30270cbb62..b752000f5a19d 100644 --- a/app/code/Magento/Catalog/Block/Product/ImageBuilder.php +++ b/app/code/Magento/Catalog/Block/Product/ImageBuilder.php @@ -6,6 +6,7 @@ namespace Magento\Catalog\Block\Product; use Magento\Catalog\Helper\ImageFactory as HelperFactory; +use Magento\Catalog\Model\Product; use Magento\Catalog\Model\Product\Image\NotLoadInfoImageException; class ImageBuilder @@ -21,7 +22,7 @@ class ImageBuilder protected $helperFactory; /** - * @var \Magento\Catalog\Model\Product + * @var Product */ protected $product; @@ -50,10 +51,10 @@ public function __construct( /** * Set product * - * @param \Magento\Catalog\Model\Product $product + * @param Product $product * @return $this */ - public function setProduct(\Magento\Catalog\Model\Product $product) + public function setProduct(Product $product) { $this->product = $product; return $this; @@ -79,9 +80,7 @@ public function setImageId($imageId) */ public function setAttributes(array $attributes) { - if ($attributes) { - $this->attributes = $attributes; - } + $this->attributes = $attributes; return $this; } diff --git a/app/code/Magento/Catalog/Block/Product/ListProduct.php b/app/code/Magento/Catalog/Block/Product/ListProduct.php index 4a7d28c383d8b..ee63d3400ade5 100644 --- a/app/code/Magento/Catalog/Block/Product/ListProduct.php +++ b/app/code/Magento/Catalog/Block/Product/ListProduct.php @@ -9,11 +9,20 @@ use Magento\Catalog\Api\CategoryRepositoryInterface; use Magento\Catalog\Block\Product\ProductList\Toolbar; use Magento\Catalog\Model\Category; +use Magento\Catalog\Model\Config; +use Magento\Catalog\Model\Layer; +use Magento\Catalog\Model\Layer\Resolver; use Magento\Catalog\Model\Product; use Magento\Catalog\Model\ResourceModel\Product\Collection; +use Magento\Catalog\Pricing\Price\FinalPrice; use Magento\Eav\Model\Entity\Collection\AbstractCollection; +use Magento\Framework\App\ActionInterface; +use Magento\Framework\App\Config\Element; +use Magento\Framework\Data\Helper\PostHelper; use Magento\Framework\DataObject\IdentityInterface; use Magento\Framework\Exception\NoSuchEntityException; +use Magento\Framework\Pricing\Render; +use Magento\Framework\Url\Helper\Data; /** * Product list @@ -40,17 +49,17 @@ class ListProduct extends AbstractProduct implements IdentityInterface /** * Catalog layer * - * @var \Magento\Catalog\Model\Layer + * @var Layer */ protected $_catalogLayer; /** - * @var \Magento\Framework\Data\Helper\PostHelper + * @var PostHelper */ protected $_postDataHelper; /** - * @var \Magento\Framework\Url\Helper\Data + * @var Data */ protected $urlHelper; @@ -61,18 +70,18 @@ class ListProduct extends AbstractProduct implements IdentityInterface /** * @param Context $context - * @param \Magento\Framework\Data\Helper\PostHelper $postDataHelper - * @param \Magento\Catalog\Model\Layer\Resolver $layerResolver + * @param PostHelper $postDataHelper + * @param Resolver $layerResolver * @param CategoryRepositoryInterface $categoryRepository - * @param \Magento\Framework\Url\Helper\Data $urlHelper + * @param Data $urlHelper * @param array $data */ public function __construct( - \Magento\Catalog\Block\Product\Context $context, - \Magento\Framework\Data\Helper\PostHelper $postDataHelper, - \Magento\Catalog\Model\Layer\Resolver $layerResolver, + Context $context, + PostHelper $postDataHelper, + Resolver $layerResolver, CategoryRepositoryInterface $categoryRepository, - \Magento\Framework\Url\Helper\Data $urlHelper, + Data $urlHelper, array $data = [] ) { $this->_catalogLayer = $layerResolver->get(); @@ -113,7 +122,7 @@ protected function _getProductCollection() /** * Get catalog layer model * - * @return \Magento\Catalog\Model\Layer + * @return Layer */ public function getLayer() { @@ -137,7 +146,35 @@ public function getLoadedProductCollection() */ public function getMode() { - return $this->getChildBlock('toolbar')->getCurrentMode(); + if ($this->getChildBlock('toolbar')) { + return $this->getChildBlock('toolbar')->getCurrentMode(); + } + + return $this->getDefaultListingMode(); + } + + /** + * Get listing mode for products if toolbar is removed from layout. + * Use the general configuration for product list mode from config path catalog/frontend/list_mode as default value + * or mode data from block declaration from layout. + * + * @return string + */ + private function getDefaultListingMode() + { + // default Toolbar when the toolbar layout is not used + $defaultToolbar = $this->getToolbarBlock(); + $availableModes = $defaultToolbar->getModes(); + + // layout config mode + $mode = $this->getData('mode'); + + if (!$mode || !isset($availableModes[$mode])) { + // default config mode + $mode = $defaultToolbar->getCurrentMode(); + } + + return $mode; } /** @@ -148,28 +185,60 @@ public function getMode() protected function _beforeToHtml() { $collection = $this->_getProductCollection(); - $this->configureToolbar($this->getToolbarBlock(), $collection); + + $this->addToolbarBlock($collection); + $collection->load(); return parent::_beforeToHtml(); } /** - * Retrieve Toolbar block + * Add toolbar block from product listing layout + * + * @param Collection $collection + */ + private function addToolbarBlock(Collection $collection) + { + $toolbarLayout = $this->getToolbarFromLayout(); + + if ($toolbarLayout) { + $this->configureToolbar($toolbarLayout, $collection); + } + } + + /** + * Retrieve Toolbar block from layout or a default Toolbar * * @return Toolbar */ public function getToolbarBlock() + { + $block = $this->getToolbarFromLayout(); + + if (!$block) { + $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime())); + } + + return $block; + } + + /** + * Get toolbar block from layout + * + * @return bool|Toolbar + */ + private function getToolbarFromLayout() { $blockName = $this->getToolbarBlockName(); + + $toolbarLayout = false; + if ($blockName) { - $block = $this->getLayout()->getBlock($blockName); - if ($block) { - return $block; - } + $toolbarLayout = $this->getLayout()->getBlock($blockName); } - $block = $this->getLayout()->createBlock($this->_defaultToolbarBlock, uniqid(microtime())); - return $block; + + return $toolbarLayout; } /** @@ -203,7 +272,7 @@ public function setCollection($collection) } /** - * @param array|string|integer|\Magento\Framework\App\Config\Element $code + * @param array|string|integer| Element $code * @return $this */ public function addAttribute($code) @@ -223,7 +292,7 @@ public function getPriceBlockTemplate() /** * Retrieve Catalog Config object * - * @return \Magento\Catalog\Model\Config + * @return Config */ protected function _getConfig() { @@ -233,8 +302,8 @@ protected function _getConfig() /** * Prepare Sort By fields from Category Data * - * @param \Magento\Catalog\Model\Category $category - * @return \Magento\Catalog\Block\Product\ListProduct + * @param Category $category + * @return $this */ public function prepareSortableFieldsByCategory($category) { @@ -286,38 +355,38 @@ public function getIdentities() /** * Get post parameters * - * @param \Magento\Catalog\Model\Product $product + * @param Product $product * @return string */ - public function getAddToCartPostParams(\Magento\Catalog\Model\Product $product) + public function getAddToCartPostParams(Product $product) { $url = $this->getAddToCartUrl($product); return [ 'action' => $url, 'data' => [ 'product' => $product->getEntityId(), - \Magento\Framework\App\ActionInterface::PARAM_NAME_URL_ENCODED => $this->urlHelper->getEncodedUrl($url), + ActionInterface::PARAM_NAME_URL_ENCODED => $this->urlHelper->getEncodedUrl($url), ] ]; } /** - * @param \Magento\Catalog\Model\Product $product + * @param Product $product * @return string */ - public function getProductPrice(\Magento\Catalog\Model\Product $product) + public function getProductPrice(Product $product) { $priceRender = $this->getPriceRender(); $price = ''; if ($priceRender) { $price = $priceRender->render( - \Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE, + FinalPrice::PRICE_CODE, $product, [ 'include_container' => true, 'display_minimal_price' => true, - 'zone' => \Magento\Framework\Pricing\Render::ZONE_ITEM_LIST, + 'zone' => Render::ZONE_ITEM_LIST, 'list_category_page' => true ] ); @@ -330,7 +399,7 @@ public function getProductPrice(\Magento\Catalog\Model\Product $product) * Specifies that price rendering should be done for the list of products * i.e. rendering happens in the scope of product list, but not single product * - * @return \Magento\Framework\Pricing\Render + * @return Render */ protected function getPriceRender() { @@ -356,7 +425,7 @@ protected function getPriceRender() private function initializeProductCollection() { $layer = $this->getLayer(); - /* @var $layer \Magento\Catalog\Model\Layer */ + /* @var $layer Layer */ if ($this->getShowRootCategory()) { $this->setCategoryId($this->_storeManager->getStore()->getRootCategoryId()); } @@ -395,8 +464,7 @@ private function initializeProductCollection() $layer->setCurrentCategory($origCategory); } - $toolbar = $this->getToolbarBlock(); - $this->configureToolbar($toolbar, $collection); + $this->addToolbarBlock($collection); $this->_eventManager->dispatch( 'catalog_block_product_list_collection', diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php index 6ba0348b45986..bcc7d468fd0f4 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php @@ -127,8 +127,7 @@ public function execute() return $resultRedirect->setPath('catalog/*/', ['_current' => true, 'id' => null]); } - $data['general'] = $this->getRequest()->getPostValue(); - $categoryPostData = $data['general']; + $categoryPostData = $this->getRequest()->getPostValue(); $isNewCategory = !isset($categoryPostData['entity_id']); $categoryPostData = $this->stringToBoolConverting($categoryPostData); diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php index f0ba9b518fa5e..6a9abe0a4c64e 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Attribute/Save.php @@ -202,8 +202,6 @@ public function execute() } } - $data = $this->presentation->convertPresentationDataToInputType($data); - if ($attributeId) { if (!$model->getId()) { $this->messageManager->addErrorMessage(__('This attribute no longer exists.')); @@ -218,6 +216,7 @@ public function execute() $data['attribute_code'] = $model->getAttributeCode(); $data['is_user_defined'] = $model->getIsUserDefined(); + $data['frontend_input'] = $model->getFrontendInput(); } else { /** * @todo add to helper and specify all relations for properties @@ -230,6 +229,8 @@ public function execute() ); } + $data = $this->presentation->convertPresentationDataToInputType($data); + $data += ['is_filterable' => 0, 'is_filterable_in_search' => 0]; if ($model->getIsUserDefined() === null || $model->getIsUserDefined() != 0) { diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php index ff840635e4c70..9b05b8edeee79 100644 --- a/app/code/Magento/Catalog/Model/Category.php +++ b/app/code/Magento/Catalog/Model/Category.php @@ -6,8 +6,12 @@ namespace Magento\Catalog\Model; use Magento\Catalog\Api\CategoryRepositoryInterface; +use Magento\Catalog\Api\Data\CategoryInterface; +use Magento\Catalog\Model\Entity\GetCategoryCustomAttributeCodes; use Magento\CatalogUrlRewrite\Model\CategoryUrlRewriteGenerator; +use Magento\Eav\Model\Entity\GetCustomAttributeCodesInterface; use Magento\Framework\Api\AttributeValueFactory; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Convert\ConvertArray; use Magento\Framework\Exception\NoSuchEntityException; use Magento\Framework\Profiler; @@ -69,23 +73,6 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements const CACHE_TAG = 'cat_c'; - /**#@+ - * Constants - */ - const KEY_PARENT_ID = 'parent_id'; - const KEY_NAME = 'name'; - const KEY_IS_ACTIVE = 'is_active'; - const KEY_POSITION = 'position'; - const KEY_LEVEL = 'level'; - const KEY_UPDATED_AT = 'updated_at'; - const KEY_CREATED_AT = 'created_at'; - const KEY_PATH = 'path'; - const KEY_AVAILABLE_SORT_BY = 'available_sort_by'; - const KEY_INCLUDE_IN_MENU = 'include_in_menu'; - const KEY_PRODUCT_COUNT = 'product_count'; - const KEY_CHILDREN_DATA = 'children_data'; - /**#@-*/ - /**#@-*/ protected $_eventPrefix = 'catalog_category'; @@ -110,6 +97,11 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements */ protected $_url; + /** + * @var ResourceModel\Category + */ + protected $_resource; + /** * URL rewrite model * @@ -142,21 +134,11 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements /** * Attributes are that part of interface * + * @deprecated + * @see CategoryInterface::ATTRIBUTES * @var array */ - protected $interfaceAttributes = [ - 'id', - self::KEY_PARENT_ID, - self::KEY_NAME, - self::KEY_IS_ACTIVE, - self::KEY_POSITION, - self::KEY_LEVEL, - self::KEY_UPDATED_AT, - self::KEY_CREATED_AT, - self::KEY_AVAILABLE_SORT_BY, - self::KEY_INCLUDE_IN_MENU, - self::KEY_CHILDREN_DATA, - ]; + protected $interfaceAttributes = CategoryInterface::ATTRIBUTES; /** * Category tree model @@ -230,6 +212,11 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements */ protected $metadataService; + /** + * @var GetCustomAttributeCodesInterface + */ + private $getCustomAttributeCodes; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -252,6 +239,7 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data + * @param GetCustomAttributeCodesInterface|null $getCustomAttributeCodes * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -275,7 +263,8 @@ public function __construct( CategoryRepositoryInterface $categoryRepository, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] + array $data = [], + GetCustomAttributeCodesInterface $getCustomAttributeCodes = null ) { $this->metadataService = $metadataService; $this->_treeModel = $categoryTreeResource; @@ -290,6 +279,9 @@ public function __construct( $this->urlFinder = $urlFinder; $this->indexerRegistry = $indexerRegistry; $this->categoryRepository = $categoryRepository; + $this->getCustomAttributeCodes = $getCustomAttributeCodes ?? ObjectManager::getInstance()->get( + GetCategoryCustomAttributeCodes::class + ); parent::__construct( $context, $registry, @@ -323,11 +315,17 @@ protected function _construct() */ protected function getCustomAttributesCodes() { - if ($this->customAttributesCodes === null) { - $this->customAttributesCodes = $this->getEavAttributesCodes($this->metadataService); - $this->customAttributesCodes = array_diff($this->customAttributesCodes, $this->interfaceAttributes); - } - return $this->customAttributesCodes; + return $this->getCustomAttributeCodes->execute($this->metadataService); + } + + /** + * @throws \Magento\Framework\Exception\LocalizedException + * @return \Magento\Catalog\Model\ResourceModel\Category + * @deprecated because resource models should be used directly + */ + protected function _getResource() + { + return parent::_getResource(); } /** @@ -667,9 +665,22 @@ public function getImageUrl($attributeCode = 'image') $image = $this->getData($attributeCode); if ($image) { if (is_string($image)) { - $url = $this->_storeManager->getStore()->getBaseUrl( + $store = $this->_storeManager->getStore(); + + $isRelativeUrl = substr($image, 0, 1) === '/'; + + $mediaBaseUrl = $store->getBaseUrl( \Magento\Framework\UrlInterface::URL_TYPE_MEDIA - ) . 'catalog/category/' . $image; + ); + + if ($isRelativeUrl) { + $url = $image; + } else { + $url = $mediaBaseUrl + . ltrim(\Magento\Catalog\Model\Category\FileInfo::ENTITY_MEDIA_PATH, '/') + . '/' + . $image; + } } else { throw new \Magento\Framework\Exception\LocalizedException( __('Something went wrong while getting the image url.') diff --git a/app/code/Magento/Catalog/Model/Category/Attribute.php b/app/code/Magento/Catalog/Model/Category/Attribute.php index 968db224c01f5..b1803a0db947e 100644 --- a/app/code/Magento/Catalog/Model/Category/Attribute.php +++ b/app/code/Magento/Catalog/Model/Category/Attribute.php @@ -29,14 +29,15 @@ class Attribute extends \Magento\Catalog\Model\Entity\Attribute implements */ public function getApplyTo() { - if ($this->getData(self::APPLY_TO)) { - if (is_array($this->getData(self::APPLY_TO))) { - return $this->getData(self::APPLY_TO); + $applyTo = $this->_getData(self::APPLY_TO); + if ($applyTo) { + if (is_array($applyTo)) { + return $applyTo; } - return explode(',', $this->getData(self::APPLY_TO)); - } else { - return []; + return explode(',', $applyTo); } + + return []; } /** @@ -59,7 +60,7 @@ public function setApplyTo($applyTo) */ public function getIsWysiwygEnabled() { - return $this->getData(self::IS_WYSIWYG_ENABLED); + return $this->_getData(self::IS_WYSIWYG_ENABLED); } /** @@ -70,7 +71,7 @@ public function getIsWysiwygEnabled() */ public function setIsWysiwygEnabled($isWysiwygEnabled) { - return $this->getData(self::IS_WYSIWYG_ENABLED, $isWysiwygEnabled); + return $this->setData(self::IS_WYSIWYG_ENABLED, $isWysiwygEnabled); } /** @@ -78,7 +79,7 @@ public function setIsWysiwygEnabled($isWysiwygEnabled) */ public function getIsHtmlAllowedOnFront() { - return $this->getData(self::IS_HTML_ALLOWED_ON_FRONT); + return $this->_getData(self::IS_HTML_ALLOWED_ON_FRONT); } /** @@ -97,7 +98,7 @@ public function setIsHtmlAllowedOnFront($isHtmlAllowedOnFront) */ public function getUsedForSortBy() { - return $this->getData(self::USED_FOR_SORT_BY); + return $this->_getData(self::USED_FOR_SORT_BY); } /** @@ -116,7 +117,7 @@ public function setUsedForSortBy($usedForSortBy) */ public function getIsFilterable() { - return $this->getData(self::IS_FILTERABLE); + return $this->_getData(self::IS_FILTERABLE); } /** @@ -135,7 +136,7 @@ public function setIsFilterable($isFilterable) */ public function getIsFilterableInSearch() { - return $this->getData(self::IS_FILTERABLE_IN_SEARCH); + return $this->_getData(self::IS_FILTERABLE_IN_SEARCH); } /** @@ -143,7 +144,7 @@ public function getIsFilterableInSearch() */ public function getIsUsedInGrid() { - return (bool)$this->getData(self::IS_USED_IN_GRID); + return (bool)$this->_getData(self::IS_USED_IN_GRID); } /** @@ -151,7 +152,7 @@ public function getIsUsedInGrid() */ public function getIsVisibleInGrid() { - return (bool)$this->getData(self::IS_VISIBLE_IN_GRID); + return (bool)$this->_getData(self::IS_VISIBLE_IN_GRID); } /** @@ -159,7 +160,7 @@ public function getIsVisibleInGrid() */ public function getIsFilterableInGrid() { - return (bool)$this->getData(self::IS_FILTERABLE_IN_GRID); + return (bool)$this->_getData(self::IS_FILTERABLE_IN_GRID); } /** @@ -170,7 +171,7 @@ public function getIsFilterableInGrid() */ public function setIsFilterableInSearch($isFilterableInSearch) { - return $this->getData(self::IS_FILTERABLE_IN_SEARCH, $isFilterableInSearch); + return $this->setData(self::IS_FILTERABLE_IN_SEARCH, $isFilterableInSearch); } /** @@ -178,7 +179,7 @@ public function setIsFilterableInSearch($isFilterableInSearch) */ public function getPosition() { - return $this->getData(self::POSITION); + return $this->_getData(self::POSITION); } /** @@ -197,7 +198,7 @@ public function setPosition($position) */ public function getIsSearchable() { - return $this->getData(self::IS_SEARCHABLE); + return $this->_getData(self::IS_SEARCHABLE); } /** @@ -216,7 +217,7 @@ public function setIsSearchable($isSearchable) */ public function getIsVisibleInAdvancedSearch() { - return $this->getData(self::IS_VISIBLE_IN_ADVANCED_SEARCH); + return $this->_getData(self::IS_VISIBLE_IN_ADVANCED_SEARCH); } /** @@ -235,7 +236,7 @@ public function setIsVisibleInAdvancedSearch($isVisibleInAdvancedSearch) */ public function getIsComparable() { - return $this->getData(self::IS_COMPARABLE); + return $this->_getData(self::IS_COMPARABLE); } /** @@ -254,7 +255,7 @@ public function setIsComparable($isComparable) */ public function getIsUsedForPromoRules() { - return $this->getData(self::IS_USED_FOR_PROMO_RULES); + return $this->_getData(self::IS_USED_FOR_PROMO_RULES); } /** @@ -273,7 +274,7 @@ public function setIsUsedForPromoRules($isUsedForPromoRules) */ public function getIsVisibleOnFront() { - return $this->getData(self::IS_VISIBLE_ON_FRONT); + return $this->_getData(self::IS_VISIBLE_ON_FRONT); } /** @@ -292,7 +293,7 @@ public function setIsVisibleOnFront($isVisibleOnFront) */ public function getUsedInProductListing() { - return $this->getData(self::USED_IN_PRODUCT_LISTING); + return $this->_getData(self::USED_IN_PRODUCT_LISTING); } /** @@ -311,7 +312,7 @@ public function setUsedInProductListing($usedInProductListing) */ public function getIsVisible() { - return $this->getData(self::IS_VISIBLE); + return $this->_getData(self::IS_VISIBLE); } /** @@ -332,7 +333,7 @@ public function setIsVisible($isVisible) */ public function getScope() { - $scope = $this->getData(self::KEY_IS_GLOBAL); + $scope = $this->_getData(self::KEY_IS_GLOBAL); if ($scope == self::SCOPE_GLOBAL) { return self::SCOPE_GLOBAL_TEXT; } elseif ($scope == self::SCOPE_WEBSITE) { diff --git a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php index 19587ce56f592..a2dff83173b37 100644 --- a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php +++ b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php @@ -5,6 +5,8 @@ */ namespace Magento\Catalog\Model\Category\Attribute\Backend; +use Magento\Framework\App\Filesystem\DirectoryList; + /** * Catalog category image attribute backend model * @@ -95,6 +97,11 @@ public function beforeSave($object) $attributeName = $this->getAttribute()->getName(); $value = $object->getData($attributeName); + if ($this->fileResidesOutsideCategoryDir($value)) { + // use relative path for image attribute so we know it's outside of category dir when we fetch it + $value[0]['name'] = $value[0]['url']; + } + if ($imageName = $this->getUploadedImageName($value)) { $object->setData($this->additionalData . $attributeName, $value); $object->setData($attributeName, $imageName); @@ -131,6 +138,26 @@ private function isTmpFileAvailable($value) return is_array($value) && isset($value[0]['tmp_name']); } + /** + * Check for file path resides outside of category media dir. The URL will be a path including pub/media if true + * + * @param array|null $value + * @return bool + */ + private function fileResidesOutsideCategoryDir($value) + { + if (!is_array($value) || !isset($value[0]['url'])) { + return false; + } + + $fileUrl = ltrim($value[0]['url'], '/'); + $baseMediaDir = $this->_filesystem->getUri(DirectoryList::MEDIA); + + $usingPathRelativeToBase = strpos($fileUrl, $baseMediaDir) === 0; + + return $usingPathRelativeToBase; + } + /** * Save uploaded file and set its name to category * @@ -148,6 +175,7 @@ public function afterSave($object) $this->_logger->critical($e); } } + return $this; } } diff --git a/app/code/Magento/Catalog/Model/Category/DataProvider.php b/app/code/Magento/Catalog/Model/Category/DataProvider.php index 803c89a2504fb..a4127c9a97ffd 100644 --- a/app/code/Magento/Catalog/Model/Category/DataProvider.php +++ b/app/code/Magento/Catalog/Model/Category/DataProvider.php @@ -492,12 +492,20 @@ private function convertValues($category, $categoryData) unset($categoryData[$attributeCode]); $fileName = $category->getData($attributeCode); - if ($this->getFileInfo()->isExist($fileName)) { - $stat = $this->getFileInfo()->getStat($fileName); - $mime = $this->getFileInfo()->getMimeType($fileName); + $fileInfo = $this->getFileInfo(); + + if ($fileInfo->isExist($fileName)) { + $stat = $fileInfo->getStat($fileName); + $mime = $fileInfo->getMimeType($fileName); + + $categoryData[$attributeCode][0]['name'] = basename($fileName); + + if ($fileInfo->isBeginsWithMediaDirectoryPath($fileName)) { + $categoryData[$attributeCode][0]['url'] = $fileName; + } else { + $categoryData[$attributeCode][0]['url'] = $category->getImageUrl($attributeCode); + } - $categoryData[$attributeCode][0]['name'] = $fileName; - $categoryData[$attributeCode][0]['url'] = $category->getImageUrl($attributeCode); $categoryData[$attributeCode][0]['size'] = isset($stat) ? $stat['size'] : 0; $categoryData[$attributeCode][0]['type'] = $mime; } diff --git a/app/code/Magento/Catalog/Model/Category/FileInfo.php b/app/code/Magento/Catalog/Model/Category/FileInfo.php index b26036ff9832c..9715bb2b1616e 100644 --- a/app/code/Magento/Catalog/Model/Category/FileInfo.php +++ b/app/code/Magento/Catalog/Model/Category/FileInfo.php @@ -9,6 +9,7 @@ use Magento\Framework\File\Mime; use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Directory\WriteInterface; +use Magento\Framework\Filesystem\Directory\ReadInterface; /** * Class FileInfo @@ -37,6 +38,11 @@ class FileInfo */ private $mediaDirectory; + /** + * @var ReadInterface + */ + private $baseDirectory; + /** * @param Filesystem $filesystem * @param Mime $mime @@ -62,6 +68,20 @@ private function getMediaDirectory() return $this->mediaDirectory; } + /** + * Get Base Directory read instance + * + * @return ReadInterface + */ + private function getBaseDirectory() + { + if (!isset($this->baseDirectory)) { + $this->baseDirectory = $this->filesystem->getDirectoryRead(DirectoryList::ROOT); + } + + return $this->baseDirectory; + } + /** * Retrieve MIME type of requested file * @@ -70,7 +90,7 @@ private function getMediaDirectory() */ public function getMimeType($fileName) { - $filePath = self::ENTITY_MEDIA_PATH . '/' . ltrim($fileName, '/'); + $filePath = $this->getFilePath($fileName); $absoluteFilePath = $this->getMediaDirectory()->getAbsolutePath($filePath); $result = $this->mime->getMimeType($absoluteFilePath); @@ -85,7 +105,7 @@ public function getMimeType($fileName) */ public function getStat($fileName) { - $filePath = self::ENTITY_MEDIA_PATH . '/' . ltrim($fileName, '/'); + $filePath = $this->getFilePath($fileName); $result = $this->getMediaDirectory()->stat($filePath); return $result; @@ -99,9 +119,65 @@ public function getStat($fileName) */ public function isExist($fileName) { - $filePath = self::ENTITY_MEDIA_PATH . '/' . ltrim($fileName, '/'); + $filePath = $this->getFilePath($fileName); $result = $this->getMediaDirectory()->isExist($filePath); return $result; } + + /** + * Construct and return file subpath based on filename relative to media directory + * + * @param string $fileName + * @return string + */ + private function getFilePath($fileName) + { + $filePath = ltrim($fileName, '/'); + + $mediaDirectoryRelativeSubpath = $this->getMediaDirectoryPathRelativeToBaseDirectoryPath(); + $isFileNameBeginsWithMediaDirectoryPath = $this->isBeginsWithMediaDirectoryPath($fileName); + + // if the file is not using a relative path, it resides in the catalog/category media directory + $fileIsInCategoryMediaDir = !$isFileNameBeginsWithMediaDirectoryPath; + + if ($fileIsInCategoryMediaDir) { + $filePath = self::ENTITY_MEDIA_PATH . '/' . $filePath; + } else { + $filePath = substr($filePath, strlen($mediaDirectoryRelativeSubpath)); + } + + return $filePath; + } + + /** + * Checks for whether $fileName string begins with media directory path + * + * @param string $fileName + * @return bool + */ + public function isBeginsWithMediaDirectoryPath($fileName) + { + $filePath = ltrim($fileName, '/'); + + $mediaDirectoryRelativeSubpath = $this->getMediaDirectoryPathRelativeToBaseDirectoryPath(); + $isFileNameBeginsWithMediaDirectoryPath = strpos($filePath, $mediaDirectoryRelativeSubpath) === 0; + + return $isFileNameBeginsWithMediaDirectoryPath; + } + + /** + * Get media directory subpath relative to base directory path + * + * @return string + */ + private function getMediaDirectoryPathRelativeToBaseDirectoryPath() + { + $baseDirectoryPath = $this->getBaseDirectory()->getAbsolutePath(); + $mediaDirectoryPath = $this->getMediaDirectory()->getAbsolutePath(); + + $mediaDirectoryRelativeSubpath = substr($mediaDirectoryPath, strlen($baseDirectoryPath)); + + return $mediaDirectoryRelativeSubpath; + } } diff --git a/app/code/Magento/Catalog/Model/Entity/GetCategoryCustomAttributeCodes.php b/app/code/Magento/Catalog/Model/Entity/GetCategoryCustomAttributeCodes.php new file mode 100644 index 0000000000000..b2b9199cc56b4 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Entity/GetCategoryCustomAttributeCodes.php @@ -0,0 +1,37 @@ +baseCustomAttributeCodes = $baseCustomAttributeCodes; + } + + /** + * @inheritdoc + */ + public function execute(MetadataServiceInterface $metadataService): array + { + $customAttributesCodes = $this->baseCustomAttributeCodes->execute($metadataService); + return array_diff($customAttributesCodes, CategoryInterface::ATTRIBUTES); + } +} diff --git a/app/code/Magento/Catalog/Model/Entity/GetProductCustomAttributeCodes.php b/app/code/Magento/Catalog/Model/Entity/GetProductCustomAttributeCodes.php new file mode 100644 index 0000000000000..23678ffcf48b7 --- /dev/null +++ b/app/code/Magento/Catalog/Model/Entity/GetProductCustomAttributeCodes.php @@ -0,0 +1,37 @@ +baseCustomAttributeCodes = $baseCustomAttributeCodes; + } + + /** + * @inheritdoc + */ + public function execute(MetadataServiceInterface $metadataService): array + { + $customAttributesCodes = $this->baseCustomAttributeCodes->execute($metadataService); + return array_diff($customAttributesCodes, ProductInterface::ATTRIBUTES); + } +} diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php index ae0c3554c0d32..54a4ff8239d5f 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Action/Full.php @@ -87,6 +87,21 @@ public function __construct( $this->activeTableSwitcher = $activeTableSwitcher ?: $objectManager->get(ActiveTableSwitcher::class); } + /** + * + * Clear the table we'll be writing de-normalized data into + * to prevent archived data getting in the way of actual data. + * + * @return void + */ + private function clearCurrentTable() + { + $this->connection->delete( + $this->activeTableSwitcher + ->getAdditionalTableName($this->getMainTable()) + ); + } + /** * Refresh entities index * @@ -94,6 +109,7 @@ public function __construct( */ public function execute() { + $this->clearCurrentTable(); $this->reindex(); $this->activeTableSwitcher->switchTable($this->connection, [$this->getMainTable()]); return $this; @@ -103,6 +119,9 @@ public function execute() * Return select for remove unnecessary data * * @return \Magento\Framework\DB\Select + * + * @deprecated Not used anymore. + * @see clearCurrentTable() */ protected function getSelectUnnecessaryData() { @@ -127,12 +146,14 @@ protected function getSelectUnnecessaryData() * Remove unnecessary data * * @return void + * + * @deprecated Not used anymore. + * @see clearCurrentTable() */ protected function removeUnnecessaryData() { - $this->connection->query( - $this->connection->deleteFromSelect($this->getSelectUnnecessaryData(), $this->getMainTable()) - ); + //Called for backward compatibility. + $this->getSelectUnnecessaryData(); } /** @@ -233,6 +254,7 @@ private function reindexCategoriesBySelect(\Magento\Framework\DB\Select $basicSe ) ); $this->publishData(); + //Called for backward compatibility. $this->removeUnnecessaryData(); } } diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php index cb5669a4bb42e..9bb3562a8b1c0 100644 --- a/app/code/Magento/Catalog/Model/Product.php +++ b/app/code/Magento/Catalog/Model/Product.php @@ -9,9 +9,12 @@ use Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterface; use Magento\Catalog\Api\Data\ProductInterface; use Magento\Catalog\Api\ProductLinkRepositoryInterface; +use Magento\Catalog\Model\Entity\GetProductCustomAttributeCodes; use Magento\Catalog\Model\Product\Attribute\Backend\Media\EntryConverterPool; +use Magento\Eav\Model\Entity\GetCustomAttributeCodesInterface; use Magento\Framework\Api\AttributeValueFactory; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\ObjectManager; use Magento\Framework\DataObject\IdentityInterface; use Magento\Framework\Pricing\SaleableInterface; @@ -117,6 +120,11 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements */ protected $_urlModel = null; + /** + * @var ResourceModel\Product + */ + protected $_resource; + /** * @var string */ @@ -305,22 +313,12 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements /** * List of attributes in ProductInterface + * + * @deprecated + * @see ProductInterface::ATTRIBUTES * @var array */ - protected $interfaceAttributes = [ - ProductInterface::SKU, - ProductInterface::NAME, - ProductInterface::PRICE, - ProductInterface::WEIGHT, - ProductInterface::STATUS, - ProductInterface::VISIBILITY, - ProductInterface::ATTRIBUTE_SET_ID, - ProductInterface::TYPE_ID, - ProductInterface::CREATED_AT, - ProductInterface::UPDATED_AT, - 'media_gallery', - 'tier_price', - ]; + protected $interfaceAttributes = ProductInterface::ATTRIBUTES; /** * @var \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface @@ -346,6 +344,11 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements */ protected $linkTypeProvider; + /** + * @var GetCustomAttributeCodesInterface + */ + private $getCustomAttributeCodes; + /** * Product constructor. * @param \Magento\Framework\Model\Context $context @@ -383,7 +386,7 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements * @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper * @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor * @param array $data - * + * @param GetCustomAttributeCodesInterface|null $getCustomAttributeCodes * @SuppressWarnings(PHPMD.ExcessiveParameterList) * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ @@ -422,7 +425,8 @@ public function __construct( EntryConverterPool $mediaGalleryEntryConverterPool, \Magento\Framework\Api\DataObjectHelper $dataObjectHelper, \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $joinProcessor, - array $data = [] + array $data = [], + GetCustomAttributeCodesInterface $getCustomAttributeCodes = null ) { $this->metadataService = $metadataService; $this->_itemOptionFactory = $itemOptionFactory; @@ -451,6 +455,9 @@ public function __construct( $this->mediaGalleryEntryConverterPool = $mediaGalleryEntryConverterPool; $this->dataObjectHelper = $dataObjectHelper; $this->joinProcessor = $joinProcessor; + $this->getCustomAttributeCodes = $getCustomAttributeCodes ?? ObjectManager::getInstance()->get( + GetProductCustomAttributeCodes::class + ); parent::__construct( $context, $registry, @@ -473,16 +480,24 @@ protected function _construct() $this->_init(\Magento\Catalog\Model\ResourceModel\Product::class); } + /** + * Get resource instance + * + * @throws \Magento\Framework\Exception\LocalizedException + * @return \Magento\Catalog\Model\ResourceModel\Product + * @deprecated because resource models should be used directly + */ + protected function _getResource() + { + return parent::_getResource(); + } + /** * {@inheritdoc} */ protected function getCustomAttributesCodes() { - if ($this->customAttributesCodes === null) { - $this->customAttributesCodes = $this->getEavAttributesCodes($this->metadataService); - $this->customAttributesCodes = array_diff($this->customAttributesCodes, $this->interfaceAttributes); - } - return $this->customAttributesCodes; + return $this->getCustomAttributeCodes->execute($this->metadataService); } /** diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Frontend/Image.php b/app/code/Magento/Catalog/Model/Product/Attribute/Frontend/Image.php index 6173a76eca421..cdd6da7019da5 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Frontend/Image.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Frontend/Image.php @@ -9,23 +9,28 @@ * * @author Magento Core Team */ + namespace Magento\Catalog\Model\Product\Attribute\Frontend; -class Image extends \Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend +use Magento\Eav\Model\Entity\Attribute\Frontend\AbstractFrontend; +use Magento\Framework\UrlInterface; +use Magento\Store\Model\StoreManagerInterface; + +class Image extends AbstractFrontend { /** * Store manager * - * @var \Magento\Store\Model\StoreManagerInterface + * @var StoreManagerInterface */ protected $_storeManager; /** * Construct * - * @param \Magento\Store\Model\StoreManagerInterface $storeManager + * @param StoreManagerInterface $storeManager */ - public function __construct(\Magento\Store\Model\StoreManagerInterface $storeManager) + public function __construct(StoreManagerInterface $storeManager) { $this->_storeManager = $storeManager; } @@ -42,9 +47,9 @@ public function getUrl($product) $image = $product->getData($this->getAttribute()->getAttributeCode()); $url = false; if (!empty($image)) { - $url = $this->_storeManager->getStore($product->getStore()) - ->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA) - . 'catalog/product/' . $image; + $url = $this->_storeManager + ->getStore($product->getStore()) + ->getBaseUrl(UrlInterface::URL_TYPE_MEDIA) . 'catalog/product/' . ltrim($image, '/'); } return $url; } diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Source/Inputtype.php b/app/code/Magento/Catalog/Model/Product/Attribute/Source/Inputtype.php index adbd6579e6828..07a8c4cc4d1a7 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Source/Inputtype.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Source/Inputtype.php @@ -28,13 +28,16 @@ class Inputtype extends \Magento\Eav\Model\Adminhtml\System\Config\Source\Inputt /** * @param \Magento\Framework\Event\ManagerInterface $eventManager * @param \Magento\Framework\Registry $coreRegistry + * @param array $optionsArray */ public function __construct( \Magento\Framework\Event\ManagerInterface $eventManager, - \Magento\Framework\Registry $coreRegistry + \Magento\Framework\Registry $coreRegistry, + array $optionsArray = [] ) { $this->_eventManager = $eventManager; $this->_coreRegistry = $coreRegistry; + parent::__construct($optionsArray); } /** diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php b/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php index 7879c629970ab..d882ad078b97f 100644 --- a/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php +++ b/app/code/Magento/Catalog/Model/ResourceModel/Eav/Attribute.php @@ -21,7 +21,6 @@ * @method int setSearchWeight(int $value) * @method bool getIsUsedForPriceRules() * @method int setIsUsedForPriceRules(int $value) - * @method \Magento\Eav\Api\Data\AttributeExtensionInterface getExtensionAttributes() * * @author Magento Core Team * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -80,6 +79,11 @@ class Attribute extends \Magento\Eav\Model\Entity\Attribute implements */ protected $_indexerEavProcessor; + /** + * @var \Magento\Eav\Api\Data\AttributeExtensionFactory + */ + private $eavAttributeFactory; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -101,9 +105,10 @@ class Attribute extends \Magento\Eav\Model\Entity\Attribute implements * @param \Magento\Catalog\Model\Indexer\Product\Eav\Processor $indexerEavProcessor * @param \Magento\Catalog\Helper\Product\Flat\Indexer $productFlatIndexerHelper * @param LockValidatorInterface $lockValidator - * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource - * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection + * @param \Magento\Framework\Model\ResourceModel\AbstractResource|null $resource + * @param \Magento\Framework\Data\Collection\AbstractDb|null $resourceCollection * @param array $data + * @param \Magento\Eav\Api\Data\AttributeExtensionFactory|null $eavAttributeFactory * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -129,12 +134,15 @@ public function __construct( LockValidatorInterface $lockValidator, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] + array $data = [], + \Magento\Eav\Api\Data\AttributeExtensionFactory $eavAttributeFactory = null ) { $this->_indexerEavProcessor = $indexerEavProcessor; $this->_productFlatIndexerProcessor = $productFlatIndexerProcessor; $this->_productFlatIndexerHelper = $productFlatIndexerHelper; $this->attrLockValidator = $lockValidator; + $this->eavAttributeFactory = $eavAttributeFactory ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Eav\Api\Data\AttributeExtensionFactory::class); parent::__construct( $context, $registry, @@ -247,11 +255,11 @@ public function isEnabledInFlat() */ protected function _isEnabledInFlat() { - return $this->getData('backend_type') == 'static' + return $this->_getData('backend_type') == 'static' || $this->_productFlatIndexerHelper->isAddFilterableAttributes() - && $this->getData('is_filterable') > 0 - || $this->getData('used_in_product_listing') == 1 - || $this->getData('used_for_sort_by') == 1; + && $this->_getData('is_filterable') > 0 + || $this->_getData('used_in_product_listing') == 1 + || $this->_getData('used_for_sort_by') == 1; } /** @@ -349,7 +357,7 @@ public function getStoreId() if ($dataObject) { return $dataObject->getStoreId(); } - return $this->getData('store_id'); + return $this->_getData('store_id'); } /** @@ -374,7 +382,7 @@ public function getApplyTo() */ public function getSourceModel() { - $model = $this->getData('source_model'); + $model = $this->_getData('source_model'); if (empty($model)) { if ($this->getBackendType() == 'int' && $this->getFrontendInput() == 'select') { return $this->_getDefaultSourceModel(); @@ -504,7 +512,7 @@ public function getIndexType() */ public function getIsWysiwygEnabled() { - return $this->getData(self::IS_WYSIWYG_ENABLED); + return $this->_getData(self::IS_WYSIWYG_ENABLED); } /** @@ -512,7 +520,7 @@ public function getIsWysiwygEnabled() */ public function getIsHtmlAllowedOnFront() { - return $this->getData(self::IS_HTML_ALLOWED_ON_FRONT); + return $this->_getData(self::IS_HTML_ALLOWED_ON_FRONT); } /** @@ -520,7 +528,7 @@ public function getIsHtmlAllowedOnFront() */ public function getUsedForSortBy() { - return $this->getData(self::USED_FOR_SORT_BY); + return $this->_getData(self::USED_FOR_SORT_BY); } /** @@ -528,7 +536,7 @@ public function getUsedForSortBy() */ public function getIsFilterable() { - return $this->getData(self::IS_FILTERABLE); + return $this->_getData(self::IS_FILTERABLE); } /** @@ -536,7 +544,7 @@ public function getIsFilterable() */ public function getIsFilterableInSearch() { - return $this->getData(self::IS_FILTERABLE_IN_SEARCH); + return $this->_getData(self::IS_FILTERABLE_IN_SEARCH); } /** @@ -544,7 +552,7 @@ public function getIsFilterableInSearch() */ public function getIsUsedInGrid() { - return (bool)$this->getData(self::IS_USED_IN_GRID); + return (bool)$this->_getData(self::IS_USED_IN_GRID); } /** @@ -552,7 +560,7 @@ public function getIsUsedInGrid() */ public function getIsVisibleInGrid() { - return (bool)$this->getData(self::IS_VISIBLE_IN_GRID); + return (bool)$this->_getData(self::IS_VISIBLE_IN_GRID); } /** @@ -560,7 +568,7 @@ public function getIsVisibleInGrid() */ public function getIsFilterableInGrid() { - return (bool)$this->getData(self::IS_FILTERABLE_IN_GRID); + return (bool)$this->_getData(self::IS_FILTERABLE_IN_GRID); } /** @@ -568,7 +576,7 @@ public function getIsFilterableInGrid() */ public function getPosition() { - return $this->getData(self::POSITION); + return $this->_getData(self::POSITION); } /** @@ -576,7 +584,7 @@ public function getPosition() */ public function getIsSearchable() { - return $this->getData(self::IS_SEARCHABLE); + return $this->_getData(self::IS_SEARCHABLE); } /** @@ -584,7 +592,7 @@ public function getIsSearchable() */ public function getIsVisibleInAdvancedSearch() { - return $this->getData(self::IS_VISIBLE_IN_ADVANCED_SEARCH); + return $this->_getData(self::IS_VISIBLE_IN_ADVANCED_SEARCH); } /** @@ -592,7 +600,7 @@ public function getIsVisibleInAdvancedSearch() */ public function getIsComparable() { - return $this->getData(self::IS_COMPARABLE); + return $this->_getData(self::IS_COMPARABLE); } /** @@ -600,7 +608,7 @@ public function getIsComparable() */ public function getIsUsedForPromoRules() { - return $this->getData(self::IS_USED_FOR_PROMO_RULES); + return $this->_getData(self::IS_USED_FOR_PROMO_RULES); } /** @@ -608,7 +616,7 @@ public function getIsUsedForPromoRules() */ public function getIsVisibleOnFront() { - return $this->getData(self::IS_VISIBLE_ON_FRONT); + return $this->_getData(self::IS_VISIBLE_ON_FRONT); } /** @@ -616,7 +624,7 @@ public function getIsVisibleOnFront() */ public function getUsedInProductListing() { - return $this->getData(self::USED_IN_PRODUCT_LISTING); + return $this->_getData(self::USED_IN_PRODUCT_LISTING); } /** @@ -624,7 +632,7 @@ public function getUsedInProductListing() */ public function getIsVisible() { - return $this->getData(self::IS_VISIBLE); + return $this->_getData(self::IS_VISIBLE); } //@codeCoverageIgnoreEnd @@ -887,4 +895,18 @@ public function setIsFilterableInGrid($isFilterableInGrid) $this->setData(self::IS_FILTERABLE_IN_GRID, $isFilterableInGrid); return $this; } + + /** + * @return \Magento\Eav\Api\Data\AttributeExtensionInterface + */ + public function getExtensionAttributes() + { + $extensionAttributes = $this->_getExtensionAttributes(); + if (null === $extensionAttributes) { + /** @var \Magento\Eav\Api\Data\AttributeExtensionInterface $extensionAttributes */ + $extensionAttributes = $this->eavAttributeFactory->create(); + $this->setExtensionAttributes($extensionAttributes); + } + return $extensionAttributes; + } } diff --git a/app/code/Magento/Catalog/Setup/CategorySetup.php b/app/code/Magento/Catalog/Setup/CategorySetup.php index f85407a9a9d7a..271387932829b 100644 --- a/app/code/Magento/Catalog/Setup/CategorySetup.php +++ b/app/code/Magento/Catalog/Setup/CategorySetup.php @@ -7,13 +7,51 @@ */ namespace Magento\Catalog\Setup; +use Magento\Catalog\Block\Adminhtml\Category\Helper\Pricestep; +use Magento\Catalog\Block\Adminhtml\Category\Helper\Sortby\Available; +use Magento\Catalog\Block\Adminhtml\Category\Helper\Sortby\DefaultSortby; +use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\BaseImage; +use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Category as CategoryFormHelper; +use Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Weight as WeightFormHelper; +use Magento\Catalog\Model\Attribute\Backend\Customlayoutupdate; +use Magento\Catalog\Model\Attribute\Backend\Startdate; +use Magento\Catalog\Model\Category\Attribute\Backend\Image; +use Magento\Catalog\Model\Category\Attribute\Backend\Sortby as SortbyBackendModel; +use Magento\Catalog\Model\Category\Attribute\Source\Layout; +use Magento\Catalog\Model\Category\Attribute\Source\Mode; +use Magento\Catalog\Model\Category\Attribute\Source\Page; +use Magento\Catalog\Model\Category\Attribute\Source\Sortby; use Magento\Catalog\Model\CategoryFactory; +use Magento\Catalog\Model\Entity\Product\Attribute\Design\Options\Container; +use Magento\Catalog\Model\Product\Attribute\Backend\Category as CategoryBackendAttribute; +use Magento\Catalog\Model\Product\Attribute\Backend\Price; +use Magento\Catalog\Model\Product\Attribute\Backend\Sku; +use Magento\Catalog\Model\Product\Attribute\Backend\Stock; +use Magento\Catalog\Model\Product\Attribute\Backend\Tierprice; +use Magento\Catalog\Model\Product\Attribute\Backend\Weight; +use Magento\Catalog\Model\Product\Attribute\Frontend\Image as ImageFrontendModel; +use Magento\Catalog\Model\Product\Attribute\Source\Countryofmanufacture; +use Magento\Catalog\Model\Product\Attribute\Source\Layout as LayoutModel; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Visibility; +use Magento\Catalog\Model\ResourceModel\Category; +use Magento\Catalog\Model\ResourceModel\Category\Attribute\Collection; +use Magento\Catalog\Model\ResourceModel\Eav\Attribute; +use Magento\Catalog\Model\ResourceModel\Product; +use Magento\CatalogInventory\Block\Adminhtml\Form\Field\Stock as StockField; +use Magento\CatalogInventory\Model\Source\Stock as StockSourceModel; +use Magento\CatalogInventory\Model\Stock as StockModel; +use Magento\Eav\Model\Entity\Attribute\Backend\Datetime; +use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface; +use Magento\Eav\Model\Entity\Attribute\Source\Boolean; use Magento\Eav\Model\Entity\Setup\Context; use Magento\Eav\Model\ResourceModel\Entity\Attribute\Group\CollectionFactory; use Magento\Eav\Setup\EavSetup; use Magento\Framework\App\CacheInterface; +use Magento\Framework\App\ResourceConnection; use Magento\Framework\Setup\ModuleDataSetupInterface; use Magento\Catalog\Model\Product\Type; +use Magento\Theme\Model\Theme\Source\Theme; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -80,28 +118,28 @@ public function getDefaultEntities() return [ 'catalog_category' => [ 'entity_type_id' => self::CATEGORY_ENTITY_TYPE_ID, - 'entity_model' => \Magento\Catalog\Model\ResourceModel\Category::class, - 'attribute_model' => \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class, + 'entity_model' => Category::class, + 'attribute_model' => Attribute::class, 'table' => 'catalog_category_entity', 'additional_attribute_table' => 'catalog_eav_attribute', 'entity_attribute_collection' => - \Magento\Catalog\Model\ResourceModel\Category\Attribute\Collection::class, + Collection::class, 'attributes' => [ 'name' => [ 'type' => 'varchar', 'label' => 'Name', 'input' => 'text', 'sort_order' => 1, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'General Information', ], 'is_active' => [ 'type' => 'int', 'label' => 'Is Active', 'input' => 'select', - 'source' => \Magento\Eav\Model\Entity\Attribute\Source\Boolean::class, + 'source' => Boolean::class, 'sort_order' => 2, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'General Information', ], 'description' => [ @@ -110,7 +148,7 @@ public function getDefaultEntities() 'input' => 'textarea', 'required' => false, 'sort_order' => 4, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'wysiwyg_enabled' => true, 'is_html_allowed_on_front' => true, 'group' => 'General Information', @@ -119,10 +157,10 @@ public function getDefaultEntities() 'type' => 'varchar', 'label' => 'Image', 'input' => 'image', - 'backend' => \Magento\Catalog\Model\Category\Attribute\Backend\Image::class, + 'backend' => Image::class, 'required' => false, 'sort_order' => 5, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'General Information', ], 'meta_title' => [ @@ -131,7 +169,7 @@ public function getDefaultEntities() 'input' => 'text', 'required' => false, 'sort_order' => 6, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'General Information', ], 'meta_keywords' => [ @@ -140,7 +178,7 @@ public function getDefaultEntities() 'input' => 'textarea', 'required' => false, 'sort_order' => 7, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'General Information', ], 'meta_description' => [ @@ -149,34 +187,34 @@ public function getDefaultEntities() 'input' => 'textarea', 'required' => false, 'sort_order' => 8, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'General Information', ], 'display_mode' => [ 'type' => 'varchar', 'label' => 'Display Mode', 'input' => 'select', - 'source' => \Magento\Catalog\Model\Category\Attribute\Source\Mode::class, + 'source' => Mode::class, 'required' => false, 'sort_order' => 10, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Display Settings', ], 'landing_page' => [ 'type' => 'int', 'label' => 'CMS Block', 'input' => 'select', - 'source' => \Magento\Catalog\Model\Category\Attribute\Source\Page::class, + 'source' => Page::class, 'required' => false, 'sort_order' => 20, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Display Settings', ], 'is_anchor' => [ 'type' => 'int', 'label' => 'Is Anchor', 'input' => 'select', - 'source' => \Magento\Eav\Model\Entity\Attribute\Source\Boolean::class, + 'source' => Boolean::class, 'required' => false, 'sort_order' => 30, 'group' => 'Display Settings', @@ -222,50 +260,50 @@ public function getDefaultEntities() 'type' => 'varchar', 'label' => 'Custom Design', 'input' => 'select', - 'source' => \Magento\Theme\Model\Theme\Source\Theme::class, + 'source' => Theme::class, 'required' => false, 'sort_order' => 10, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Custom Design', ], 'custom_design_from' => [ 'type' => 'datetime', 'label' => 'Active From', 'input' => 'date', - 'backend' => \Magento\Catalog\Model\Attribute\Backend\Startdate::class, + 'backend' => Startdate::class, 'required' => false, 'sort_order' => 30, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Custom Design', ], 'custom_design_to' => [ 'type' => 'datetime', 'label' => 'Active To', 'input' => 'date', - 'backend' => \Magento\Eav\Model\Entity\Attribute\Backend\Datetime::class, + 'backend' => Datetime::class, 'required' => false, 'sort_order' => 40, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Custom Design', ], 'page_layout' => [ 'type' => 'varchar', 'label' => 'Page Layout', 'input' => 'select', - 'source' => \Magento\Catalog\Model\Category\Attribute\Source\Layout::class, + 'source' => Layout::class, 'required' => false, 'sort_order' => 50, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Custom Design', ], 'custom_layout_update' => [ 'type' => 'text', 'label' => 'Custom Layout Update', 'input' => 'textarea', - 'backend' => \Magento\Catalog\Model\Attribute\Backend\Customlayoutupdate::class, + 'backend' => Customlayoutupdate::class, 'required' => false, 'sort_order' => 60, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Custom Design', ], 'level' => [ @@ -288,53 +326,53 @@ public function getDefaultEntities() 'type' => 'text', 'label' => 'Available Product Listing Sort By', 'input' => 'multiselect', - 'source' => \Magento\Catalog\Model\Category\Attribute\Source\Sortby::class, - 'backend' => \Magento\Catalog\Model\Category\Attribute\Backend\Sortby::class, + 'source' => Sortby::class, + 'backend' => SortbyBackendModel::class, 'sort_order' => 40, - 'input_renderer' => \Magento\Catalog\Block\Adminhtml\Category\Helper\Sortby\Available::class, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'input_renderer' => Available::class, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Display Settings', ], 'default_sort_by' => [ 'type' => 'varchar', 'label' => 'Default Product Listing Sort By', 'input' => 'select', - 'source' => \Magento\Catalog\Model\Category\Attribute\Source\Sortby::class, - 'backend' => \Magento\Catalog\Model\Category\Attribute\Backend\Sortby::class, + 'source' => Sortby::class, + 'backend' => SortbyBackendModel::class, 'sort_order' => 50, 'input_renderer' => - \Magento\Catalog\Block\Adminhtml\Category\Helper\Sortby\DefaultSortby::class, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + DefaultSortby::class, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Display Settings', ], 'include_in_menu' => [ 'type' => 'int', 'label' => 'Include in Navigation Menu', 'input' => 'select', - 'source' => \Magento\Eav\Model\Entity\Attribute\Source\Boolean::class, + 'source' => Boolean::class, 'default' => '1', 'sort_order' => 10, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'General Information', ], 'custom_use_parent_settings' => [ 'type' => 'int', 'label' => 'Use Parent Category Settings', 'input' => 'select', - 'source' => \Magento\Eav\Model\Entity\Attribute\Source\Boolean::class, + 'source' => Boolean::class, 'required' => false, 'sort_order' => 5, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Custom Design', ], 'custom_apply_to_products' => [ 'type' => 'int', 'label' => 'Apply To Products', 'input' => 'select', - 'source' => \Magento\Eav\Model\Entity\Attribute\Source\Boolean::class, + 'source' => Boolean::class, 'required' => false, 'sort_order' => 6, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Custom Design', ], 'filter_price_range' => [ @@ -343,20 +381,20 @@ public function getDefaultEntities() 'input' => 'text', 'required' => false, 'sort_order' => 51, - 'input_renderer' => \Magento\Catalog\Block\Adminhtml\Category\Helper\Pricestep::class, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'input_renderer' => Pricestep::class, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Display Settings', ], ], ], 'catalog_product' => [ 'entity_type_id' => self::CATALOG_PRODUCT_ENTITY_TYPE_ID, - 'entity_model' => \Magento\Catalog\Model\ResourceModel\Product::class, - 'attribute_model' => \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class, + 'entity_model' => Product::class, + 'attribute_model' => Attribute::class, 'table' => 'catalog_product_entity', 'additional_attribute_table' => 'catalog_eav_attribute', 'entity_attribute_collection' => - \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection::class, + Product\Attribute\Collection::class, 'attributes' => [ 'name' => [ 'type' => 'varchar', @@ -364,7 +402,7 @@ public function getDefaultEntities() 'input' => 'text', 'frontend_class' => 'validate-length maximum-length-255', 'sort_order' => 1, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'searchable' => true, 'visible_in_advanced_search' => true, 'used_in_product_listing' => true, @@ -375,7 +413,7 @@ public function getDefaultEntities() 'label' => 'SKU', 'input' => 'text', 'frontend_class' => 'validate-length maximum-length-64', - 'backend' => \Magento\Catalog\Model\Product\Attribute\Backend\Sku::class, + 'backend' => Sku::class, 'unique' => true, 'sort_order' => 2, 'searchable' => true, @@ -387,7 +425,7 @@ public function getDefaultEntities() 'label' => 'Description', 'input' => 'textarea', 'sort_order' => 3, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'searchable' => true, 'comparable' => true, 'wysiwyg_enabled' => true, @@ -399,7 +437,7 @@ public function getDefaultEntities() 'label' => 'Short Description', 'input' => 'textarea', 'sort_order' => 4, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'searchable' => true, 'comparable' => true, 'wysiwyg_enabled' => true, @@ -414,9 +452,9 @@ public function getDefaultEntities() 'type' => 'decimal', 'label' => 'Price', 'input' => 'price', - 'backend' => \Magento\Catalog\Model\Product\Attribute\Backend\Price::class, + 'backend' => Price::class, 'sort_order' => 1, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'global' => ScopedAttributeInterface::SCOPE_WEBSITE, 'searchable' => true, 'filterable' => true, 'visible_in_advanced_search' => true, @@ -429,10 +467,10 @@ public function getDefaultEntities() 'type' => 'decimal', 'label' => 'Special Price', 'input' => 'price', - 'backend' => \Magento\Catalog\Model\Product\Attribute\Backend\Price::class, + 'backend' => Price::class, 'required' => false, 'sort_order' => 3, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'global' => ScopedAttributeInterface::SCOPE_WEBSITE, 'used_in_product_listing' => true, 'apply_to' => 'simple,virtual', 'group' => 'Prices', @@ -444,10 +482,10 @@ public function getDefaultEntities() 'type' => 'datetime', 'label' => 'Special Price From Date', 'input' => 'date', - 'backend' => \Magento\Catalog\Model\Attribute\Backend\Startdate::class, + 'backend' => Startdate::class, 'required' => false, 'sort_order' => 4, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'global' => ScopedAttributeInterface::SCOPE_WEBSITE, 'used_in_product_listing' => true, 'apply_to' => 'simple,virtual', 'group' => 'Prices', @@ -459,10 +497,10 @@ public function getDefaultEntities() 'type' => 'datetime', 'label' => 'Special Price To Date', 'input' => 'date', - 'backend' => \Magento\Eav\Model\Entity\Attribute\Backend\Datetime::class, + 'backend' => Datetime::class, 'required' => false, 'sort_order' => 5, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'global' => ScopedAttributeInterface::SCOPE_WEBSITE, 'used_in_product_listing' => true, 'apply_to' => 'simple,virtual', 'group' => 'Prices', @@ -474,11 +512,11 @@ public function getDefaultEntities() 'type' => 'decimal', 'label' => 'Cost', 'input' => 'price', - 'backend' => \Magento\Catalog\Model\Product\Attribute\Backend\Price::class, + 'backend' => Price::class, 'required' => false, 'user_defined' => true, 'sort_order' => 6, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'global' => ScopedAttributeInterface::SCOPE_WEBSITE, 'apply_to' => 'simple,virtual', 'group' => 'Prices', 'is_used_in_grid' => true, @@ -489,8 +527,8 @@ public function getDefaultEntities() 'type' => 'decimal', 'label' => 'Weight', 'input' => 'weight', - 'backend' => \Magento\Catalog\Model\Product\Attribute\Backend\Weight::class, - 'input_renderer' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Weight::class, + 'backend' => Weight::class, + 'input_renderer' => WeightFormHelper::class, 'sort_order' => 5, 'apply_to' => 'simple,virtual', 'is_used_in_grid' => true, @@ -518,7 +556,7 @@ public function getDefaultEntities() 'input' => 'text', 'required' => false, 'sort_order' => 20, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Meta Information', 'is_used_in_grid' => true, 'is_visible_in_grid' => false, @@ -530,7 +568,7 @@ public function getDefaultEntities() 'input' => 'textarea', 'required' => false, 'sort_order' => 30, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Meta Information', 'is_used_in_grid' => true, 'is_visible_in_grid' => false, @@ -544,7 +582,7 @@ public function getDefaultEntities() 'note' => 'Maximum 255 chars', 'class' => 'validate-length maximum-length-255', 'sort_order' => 40, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Meta Information', 'is_used_in_grid' => true, 'is_visible_in_grid' => false, @@ -554,11 +592,11 @@ public function getDefaultEntities() 'type' => 'varchar', 'label' => 'Base Image', 'input' => 'media_image', - 'frontend' => \Magento\Catalog\Model\Product\Attribute\Frontend\Image::class, - 'input_renderer' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\BaseImage::class, + 'frontend' => ImageFrontendModel::class, + 'input_renderer' => BaseImage::class, 'required' => false, 'sort_order' => 0, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'used_in_product_listing' => true, 'group' => 'General', ], @@ -566,10 +604,10 @@ public function getDefaultEntities() 'type' => 'varchar', 'label' => 'Small Image', 'input' => 'media_image', - 'frontend' => \Magento\Catalog\Model\Product\Attribute\Frontend\Image::class, + 'frontend' => ImageFrontendModel::class, 'required' => false, 'sort_order' => 2, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'used_in_product_listing' => true, 'group' => 'Images', ], @@ -577,10 +615,10 @@ public function getDefaultEntities() 'type' => 'varchar', 'label' => 'Thumbnail', 'input' => 'media_image', - 'frontend' => \Magento\Catalog\Model\Product\Attribute\Frontend\Image::class, + 'frontend' => ImageFrontendModel::class, 'required' => false, 'sort_order' => 3, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'used_in_product_listing' => true, 'group' => 'Images', ], @@ -588,7 +626,7 @@ public function getDefaultEntities() 'type' => 'varchar', 'label' => 'Media Gallery', 'input' => 'gallery', - 'backend' => \Magento\Catalog\Model\Product\Attribute\Backend\Media::class, + 'backend' => Media::class, 'required' => false, 'sort_order' => 4, 'group' => 'Images', @@ -598,10 +636,10 @@ public function getDefaultEntities() 'type' => 'decimal', 'label' => 'Tier Price', 'input' => 'text', - 'backend' => \Magento\Catalog\Model\Product\Attribute\Backend\Tierprice::class, + 'backend' => Tierprice::class, 'required' => false, 'sort_order' => 7, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'global' => ScopedAttributeInterface::SCOPE_WEBSITE, 'apply_to' => 'simple,virtual', 'group' => 'Prices', ], @@ -624,10 +662,10 @@ public function getDefaultEntities() 'type' => 'datetime', 'label' => 'Set Product as New from Date', 'input' => 'date', - 'backend' => \Magento\Catalog\Model\Attribute\Backend\Startdate::class, + 'backend' => Startdate::class, 'required' => false, 'sort_order' => 7, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'global' => ScopedAttributeInterface::SCOPE_WEBSITE, 'used_in_product_listing' => true, 'is_used_in_grid' => true, 'is_visible_in_grid' => false, @@ -637,10 +675,10 @@ public function getDefaultEntities() 'type' => 'datetime', 'label' => 'Set Product as New to Date', 'input' => 'date', - 'backend' => \Magento\Eav\Model\Entity\Attribute\Backend\Datetime::class, + 'backend' => Datetime::class, 'required' => false, 'sort_order' => 8, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'global' => ScopedAttributeInterface::SCOPE_WEBSITE, 'used_in_product_listing' => true, 'is_used_in_grid' => true, 'is_visible_in_grid' => false, @@ -658,9 +696,9 @@ public function getDefaultEntities() 'type' => 'int', 'label' => 'Status', 'input' => 'select', - 'source' => \Magento\Catalog\Model\Product\Attribute\Source\Status::class, + 'source' => Status::class, 'sort_order' => 9, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'global' => ScopedAttributeInterface::SCOPE_WEBSITE, 'searchable' => true, 'used_in_product_listing' => true, ], @@ -670,7 +708,7 @@ public function getDefaultEntities() 'input' => 'price', 'required' => false, 'sort_order' => 8, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'visible' => false, 'apply_to' => 'simple,virtual', 'group' => 'Prices', @@ -679,19 +717,19 @@ public function getDefaultEntities() 'type' => 'int', 'label' => 'Visibility', 'input' => 'select', - 'source' => \Magento\Catalog\Model\Product\Visibility::class, + 'source' => Visibility::class, 'default' => '4', 'sort_order' => 12, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, ], 'custom_design' => [ 'type' => 'varchar', 'label' => 'Custom Design', 'input' => 'select', - 'source' => \Magento\Theme\Model\Theme\Source\Theme::class, + 'source' => Theme::class, 'required' => false, 'sort_order' => 1, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Design', 'is_used_in_grid' => true, 'is_visible_in_grid' => false, @@ -701,10 +739,10 @@ public function getDefaultEntities() 'type' => 'datetime', 'label' => 'Active From', 'input' => 'date', - 'backend' => \Magento\Catalog\Model\Attribute\Backend\Startdate::class, + 'backend' => Startdate::class, 'required' => false, 'sort_order' => 2, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Design', 'is_used_in_grid' => true, 'is_visible_in_grid' => false, @@ -714,10 +752,10 @@ public function getDefaultEntities() 'type' => 'datetime', 'label' => 'Active To', 'input' => 'date', - 'backend' => \Magento\Eav\Model\Entity\Attribute\Backend\Datetime::class, + 'backend' => Datetime::class, 'required' => false, 'sort_order' => 3, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Design', 'is_used_in_grid' => true, 'is_visible_in_grid' => false, @@ -727,20 +765,20 @@ public function getDefaultEntities() 'type' => 'text', 'label' => 'Custom Layout Update', 'input' => 'textarea', - 'backend' => \Magento\Catalog\Model\Attribute\Backend\Customlayoutupdate::class, + 'backend' => Customlayoutupdate::class, 'required' => false, 'sort_order' => 4, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Design', ], 'page_layout' => [ 'type' => 'varchar', 'label' => 'Page Layout', 'input' => 'select', - 'source' => \Magento\Catalog\Model\Product\Attribute\Source\Layout::class, + 'source' => LayoutModel::class, 'required' => false, 'sort_order' => 5, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Design', 'is_used_in_grid' => true, 'is_visible_in_grid' => false, @@ -749,9 +787,9 @@ public function getDefaultEntities() 'category_ids' => [ 'type' => 'static', 'label' => 'Categories', - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, - 'backend' => \Magento\Catalog\Model\Product\Attribute\Backend\Category::class, - 'input_renderer' => \Magento\Catalog\Block\Adminhtml\Product\Helper\Form\Category::class, + 'global' => ScopedAttributeInterface::SCOPE_GLOBAL, + 'backend' => CategoryBackendAttribute::class, + 'input_renderer' => CategoryFormHelper::class, 'required' => false, 'sort_order' => 9, 'visible' => true, @@ -764,11 +802,11 @@ public function getDefaultEntities() 'type' => 'varchar', 'label' => 'Display Product Options In', 'input' => 'select', - 'source' => \Magento\Catalog\Model\Entity\Product\Attribute\Design\Options\Container::class, + 'source' => Container::class, 'required' => false, 'default' => 'container2', 'sort_order' => 6, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'group' => 'Design', ], 'required_options' => [ @@ -792,7 +830,7 @@ public function getDefaultEntities() 'input' => 'text', 'required' => false, 'sort_order' => 16, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'visible' => false, 'used_in_product_listing' => true, ], @@ -802,7 +840,7 @@ public function getDefaultEntities() 'input' => 'text', 'required' => false, 'sort_order' => 17, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'visible' => false, 'used_in_product_listing' => true, ], @@ -812,7 +850,7 @@ public function getDefaultEntities() 'input' => 'text', 'required' => false, 'sort_order' => 18, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'global' => ScopedAttributeInterface::SCOPE_STORE, 'visible' => false, 'used_in_product_listing' => true, ], @@ -832,9 +870,9 @@ public function getDefaultEntities() 'type' => 'varchar', 'label' => 'Country of Manufacture', 'input' => 'select', - 'source' => \Magento\Catalog\Model\Product\Attribute\Source\Countryofmanufacture::class, + 'source' => Countryofmanufacture::class, 'required' => false, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'global' => ScopedAttributeInterface::SCOPE_WEBSITE, 'visible' => true, 'user_defined' => false, 'searchable' => false, @@ -851,13 +889,13 @@ public function getDefaultEntities() 'quantity_and_stock_status' => [ 'group' => 'General', 'type' => 'int', - 'backend' => \Magento\Catalog\Model\Product\Attribute\Backend\Stock::class, + 'backend' => Stock::class, 'label' => 'Quantity', 'input' => 'select', - 'input_renderer' => \Magento\CatalogInventory\Block\Adminhtml\Form\Field\Stock::class, - 'source' => \Magento\CatalogInventory\Model\Source\Stock::class, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, - 'default' => \Magento\CatalogInventory\Model\Stock::STOCK_IN_STOCK, + 'input_renderer' => StockField::class, + 'source' => StockSourceModel::class, + 'global' => ScopedAttributeInterface::SCOPE_GLOBAL, + 'default' => StockModel::STOCK_IN_STOCK, 'user_defined' => false, 'visible' => true, 'required' => false, diff --git a/app/code/Magento/Catalog/Setup/InstallData.php b/app/code/Magento/Catalog/Setup/InstallData.php deleted file mode 100644 index 5b1a10b098eb5..0000000000000 --- a/app/code/Magento/Catalog/Setup/InstallData.php +++ /dev/null @@ -1,340 +0,0 @@ -defaultCategory === null) { - $this->defaultCategory = \Magento\Framework\App\ObjectManager::getInstance() - ->get(DefaultCategory::class); - } - return $this->defaultCategory; - } - - /** - * Init - * - * @param CategorySetupFactory $categorySetupFactory - */ - public function __construct(CategorySetupFactory $categorySetupFactory) - { - $this->categorySetupFactory = $categorySetupFactory; - } - - /** - * {@inheritdoc} - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */ - $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); - $rootCategoryId = \Magento\Catalog\Model\Category::TREE_ROOT_ID; - $defaultCategoryId = $this->getDefaultCategory()->getId(); - - $categorySetup->installEntities(); - // Create Root Catalog Node - $categorySetup->createCategory() - ->load($rootCategoryId) - ->setId($rootCategoryId) - ->setStoreId(0) - ->setPath($rootCategoryId) - ->setLevel(0) - ->setPosition(0) - ->setChildrenCount(0) - ->setName('Root Catalog') - ->setInitialSetupFlag(true) - ->save(); - - // Create Default Catalog Node - $category = $categorySetup->createCategory(); - $category->load($defaultCategoryId) - ->setId($defaultCategoryId) - ->setStoreId(0) - ->setPath($rootCategoryId . '/' . $defaultCategoryId) - ->setName('Default Category') - ->setDisplayMode('PRODUCTS') - ->setIsActive(1) - ->setLevel(1) - ->setInitialSetupFlag(true) - ->setAttributeSetId($category->getDefaultAttributeSetId()) - ->save(); - - $data = [ - 'scope' => 'default', - 'scope_id' => 0, - 'path' => \Magento\Catalog\Helper\Category::XML_PATH_CATEGORY_ROOT_ID, - 'value' => $category->getId(), - ]; - $setup->getConnection() - ->insertOnDuplicate($setup->getTable('core_config_data'), $data, ['value']); - - $categorySetup->addAttributeGroup(\Magento\Catalog\Model\Product::ENTITY, 'Default', 'Design', 6); - - $entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Category::ENTITY); - $attributeSetId = $categorySetup->getDefaultAttributeSetId($entityTypeId); - $attributeGroupId = $categorySetup->getDefaultAttributeGroupId($entityTypeId, $attributeSetId); - - // update General Group - $categorySetup->updateAttributeGroup($entityTypeId, $attributeSetId, $attributeGroupId, 'sort_order', '10'); - - $groups = [ - 'display' => ['name' => 'Display Settings', 'code' => 'display-settings', 'sort' => 20, 'id' => null], - 'design' => ['name' => 'Custom Design', 'code' => 'custom-design', 'sort' => 30, 'id' => null], - ]; - - foreach ($groups as $k => $groupProp) { - $categorySetup->addAttributeGroup($entityTypeId, $attributeSetId, $groupProp['name'], $groupProp['sort']); - $groups[$k]['id'] = $categorySetup->getAttributeGroupId($entityTypeId, $attributeSetId, $groupProp['code']); - } - - // update attributes group and sort - $attributes = [ - 'custom_design' => ['group' => 'design', 'sort' => 10], - // 'custom_design_apply' => array('group' => 'design', 'sort' => 20), - 'custom_design_from' => ['group' => 'design', 'sort' => 30], - 'custom_design_to' => ['group' => 'design', 'sort' => 40], - 'page_layout' => ['group' => 'design', 'sort' => 50], - 'custom_layout_update' => ['group' => 'design', 'sort' => 60], - 'display_mode' => ['group' => 'display', 'sort' => 10], - 'landing_page' => ['group' => 'display', 'sort' => 20], - 'is_anchor' => ['group' => 'display', 'sort' => 30], - 'available_sort_by' => ['group' => 'display', 'sort' => 40], - 'default_sort_by' => ['group' => 'display', 'sort' => 50], - ]; - - foreach ($attributes as $attributeCode => $attributeProp) { - $categorySetup->addAttributeToGroup( - $entityTypeId, - $attributeSetId, - $groups[$attributeProp['group']]['id'], - $attributeCode, - $attributeProp['sort'] - ); - } - - /** - * Install product link types - */ - $data = [ - ['link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_RELATED, 'code' => 'relation'], - ['link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_UPSELL, 'code' => 'up_sell'], - ['link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_CROSSSELL, 'code' => 'cross_sell'], - ]; - - foreach ($data as $bind) { - $setup->getConnection() - ->insertForce($setup->getTable('catalog_product_link_type'), $bind); - } - - /** - * install product link attributes - */ - $data = [ - [ - 'link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_RELATED, - 'product_link_attribute_code' => 'position', - 'data_type' => 'int', - ], - [ - 'link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_UPSELL, - 'product_link_attribute_code' => 'position', - 'data_type' => 'int' - ], - [ - 'link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_CROSSSELL, - 'product_link_attribute_code' => 'position', - 'data_type' => 'int' - ], - ]; - - $setup->getConnection() - ->insertMultiple($setup->getTable('catalog_product_link_attribute'), $data); - - /** - * Remove Catalog specified attribute options (columns) from eav/attribute table - * - */ - $describe = $setup->getConnection() - ->describeTable($setup->getTable('catalog_eav_attribute')); - foreach ($describe as $columnData) { - if ($columnData['COLUMN_NAME'] == 'attribute_id') { - continue; - } - $setup->getConnection() - ->dropColumn($setup->getTable('eav_attribute'), $columnData['COLUMN_NAME']); - } - - $newGeneralTabName = 'Product Details'; - $newPriceTabName = 'Advanced Pricing'; - $newImagesTabName = 'Image Management'; - $newMetaTabName = 'Search Engine Optimization'; - $autosettingsTabName = 'Autosettings'; - $tabNames = [ - 'General' => [ - 'attribute_group_name' => $newGeneralTabName, - 'attribute_group_code' => $categorySetup->convertToAttributeGroupCode($newGeneralTabName), - 'tab_group_code' => 'basic', - 'sort_order' => 10, - ], - 'Images' => [ - 'attribute_group_name' => $newImagesTabName, - 'attribute_group_code' => $categorySetup->convertToAttributeGroupCode($newImagesTabName), - 'tab_group_code' => 'basic', - 'sort_order' => 20, - ], - 'Meta Information' => [ - 'attribute_group_name' => $newMetaTabName, - 'attribute_group_code' => $categorySetup->convertToAttributeGroupCode($newMetaTabName), - 'tab_group_code' => 'basic', - 'sort_order' => 30, - ], - 'Prices' => [ - 'attribute_group_name' => $newPriceTabName, - 'attribute_group_code' => $categorySetup->convertToAttributeGroupCode($newPriceTabName), - 'tab_group_code' => 'advanced', - 'sort_order' => 40, - ], - 'Design' => ['attribute_group_code' => 'design', 'tab_group_code' => 'advanced', 'sort_order' => 50], - ]; - - $entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); - $attributeSetId = $categorySetup->getAttributeSetId($entityTypeId, 'Default'); - - //Rename attribute tabs - foreach ($tabNames as $tabName => $tab) { - $groupId = $categorySetup->getAttributeGroupId($entityTypeId, $attributeSetId, $tabName); - if ($groupId) { - foreach ($tab as $propertyName => $propertyValue) { - $categorySetup->updateAttributeGroup( - $entityTypeId, - $attributeSetId, - $groupId, - $propertyName, - $propertyValue - ); - } - } - } - - //Add new tab - $categorySetup->addAttributeGroup($entityTypeId, $attributeSetId, $autosettingsTabName, 60); - $categorySetup->updateAttributeGroup( - $entityTypeId, - $attributeSetId, - 'Autosettings', - 'attribute_group_code', - 'autosettings' - ); - $categorySetup->updateAttributeGroup( - $entityTypeId, - $attributeSetId, - 'Autosettings', - 'tab_group_code', - 'advanced' - ); - - //New attributes order and properties - $properties = ['is_required', 'default_value', 'frontend_input_renderer']; - $attributesOrder = [ - //Product Details tab - 'name' => [$newGeneralTabName => 10], - 'sku' => [$newGeneralTabName => 20], - 'price' => [$newGeneralTabName => 30], - 'image' => [$newGeneralTabName => 50], - 'weight' => [$newGeneralTabName => 70, 'is_required' => 0], - 'category_ids' => [$newGeneralTabName => 80], - 'description' => [$newGeneralTabName => 90, 'is_required' => 0], - 'status' => [ - $newGeneralTabName => 100, - 'is_required' => 0, - 'default_value' => 1, - 'frontend_input_renderer' => \Magento\Framework\Data\Form\Element\Hidden::class, - ], - //Autosettings tab - 'short_description' => [$autosettingsTabName => 0, 'is_required' => 0], - 'visibility' => [$autosettingsTabName => 20, 'is_required' => 0], - 'news_from_date' => [$autosettingsTabName => 30], - 'news_to_date' => [$autosettingsTabName => 40], - 'country_of_manufacture' => [$autosettingsTabName => 50], - ]; - - foreach ($attributesOrder as $key => $value) { - $attribute = $categorySetup->getAttribute($entityTypeId, $key); - if ($attribute) { - foreach ($value as $propertyName => $propertyValue) { - if (in_array($propertyName, $properties)) { - $categorySetup->updateAttribute( - $entityTypeId, - $attribute['attribute_id'], - $propertyName, - $propertyValue - ); - } else { - $categorySetup->addAttributeToGroup( - $entityTypeId, - $attributeSetId, - $propertyName, - $attribute['attribute_id'], - $propertyValue - ); - } - } - } - } - - foreach (['status', 'visibility'] as $attributeCode) { - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - $attributeCode, - 'is_required_in_admin_store', - '1' - ); - } - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Category::ENTITY, - 'custom_design_from', - 'attribute_model', - \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class - ); - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Category::ENTITY, - 'custom_design_from', - 'frontend_model', - \Magento\Eav\Model\Entity\Attribute\Frontend\Datetime::class - ); - } -} diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/ChangePriceAttributeDefaultScope.php b/app/code/Magento/Catalog/Setup/Patch/Data/ChangePriceAttributeDefaultScope.php new file mode 100644 index 0000000000000..9698e2e049f26 --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/ChangePriceAttributeDefaultScope.php @@ -0,0 +1,100 @@ +moduleDataSetup = $moduleDataSetup; + $this->categorySetupFactory = $categorySetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var CategorySetup $categorySetup */ + $categorySetup = $this->categorySetupFactory->create(['setup' => $this->moduleDataSetup]); + $this->changePriceAttributeDefaultScope($categorySetup); + } + + /** + * @param CategorySetup $categorySetup + * @return void + */ + private function changePriceAttributeDefaultScope($categorySetup) + { + $entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); + foreach (['price', 'cost', 'special_price'] as $attributeCode) { + $attribute = $categorySetup->getAttribute($entityTypeId, $attributeCode); + if (isset($attribute['attribute_id'])) { + $categorySetup->updateAttribute( + $entityTypeId, + $attribute['attribute_id'], + 'is_global', + \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL + ); + } + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateProductMetaDescription::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.1.3'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/DisallowUsingHtmlForProductName.php b/app/code/Magento/Catalog/Setup/Patch/Data/DisallowUsingHtmlForProductName.php new file mode 100644 index 0000000000000..ea8f6bbf39b31 --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/DisallowUsingHtmlForProductName.php @@ -0,0 +1,86 @@ +moduleDataSetup = $moduleDataSetup; + $this->categorySetupFactory = $categorySetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $categorySetup = $this->categorySetupFactory->create(['setup' => $this->moduleDataSetup]); + $entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); + $attribute = $categorySetup->getAttribute($entityTypeId, 'name'); + + $this->moduleDataSetup->getConnection()->update( + $this->moduleDataSetup->getTable('catalog_eav_attribute'), + ['is_html_allowed_on_front' => 0], + $this->moduleDataSetup->getConnection()->quoteInto('attribute_id = ?', $attribute['attribute_id']) + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + ChangePriceAttributeDefaultScope::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.1.5'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/InstallDefaultCategories.php b/app/code/Magento/Catalog/Setup/Patch/Data/InstallDefaultCategories.php new file mode 100644 index 0000000000000..f1d836a5862f6 --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/InstallDefaultCategories.php @@ -0,0 +1,377 @@ +moduleDataSetup = $moduleDataSetup; + $this->categorySetupFactory = $categorySetupFactory; + $this->defaultCategoryFactory = $defaultCategoryFactory; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function apply() + { + /** @var \Magento\Catalog\Setup\CategorySetup $categorySetup */ + $categorySetup = $this->categorySetupFactory->create(['setup' => $this->moduleDataSetup]); + $rootCategoryId = \Magento\Catalog\Model\Category::TREE_ROOT_ID; + $defaultCategory = $this->defaultCategoryFactory->create(); + $defaultCategoryId = $defaultCategory->getId(); + + $categorySetup->installEntities(); + // Create Root Catalog Node + $categorySetup->createCategory() + ->load($rootCategoryId) + ->setId($rootCategoryId) + ->setStoreId(0) + ->setPath($rootCategoryId) + ->setLevel(0) + ->setPosition(0) + ->setChildrenCount(0) + ->setName('Root Catalog') + ->setInitialSetupFlag(true) + ->save(); + + // Create Default Catalog Node + $category = $categorySetup->createCategory(); + $category->load($defaultCategoryId) + ->setId($defaultCategoryId) + ->setStoreId(0) + ->setPath($rootCategoryId . '/' . $defaultCategoryId) + ->setName('Default Category') + ->setDisplayMode('PRODUCTS') + ->setIsActive(1) + ->setLevel(1) + ->setInitialSetupFlag(true) + ->setAttributeSetId($category->getDefaultAttributeSetId()) + ->save(); + + $data = [ + 'scope' => 'default', + 'scope_id' => 0, + 'path' => \Magento\Catalog\Helper\Category::XML_PATH_CATEGORY_ROOT_ID, + 'value' => $category->getId(), + ]; + $this->moduleDataSetup->getConnection()->insertOnDuplicate( + $this->moduleDataSetup->getTable('core_config_data'), + $data, + ['value'] + ); + + $categorySetup->addAttributeGroup(\Magento\Catalog\Model\Product::ENTITY, 'Default', 'Design', 6); + + $entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Category::ENTITY); + $attributeSetId = $categorySetup->getDefaultAttributeSetId($entityTypeId); + $attributeGroupId = $categorySetup->getDefaultAttributeGroupId($entityTypeId, $attributeSetId); + + // update General Group + $categorySetup->updateAttributeGroup($entityTypeId, $attributeSetId, $attributeGroupId, 'sort_order', '10'); + + $groups = [ + 'display' => ['name' => 'Display Settings', 'code' => 'display-settings', 'sort' => 20, 'id' => null], + 'design' => ['name' => 'Custom Design', 'code' => 'custom-design', 'sort' => 30, 'id' => null], + ]; + + foreach ($groups as $k => $groupProp) { + $categorySetup->addAttributeGroup($entityTypeId, $attributeSetId, $groupProp['name'], $groupProp['sort']); + $groups[$k]['id'] = $categorySetup->getAttributeGroupId($entityTypeId, $attributeSetId, $groupProp['code']); + } + + // update attributes group and sort + $attributes = [ + 'custom_design' => ['group' => 'design', 'sort' => 10], + // 'custom_design_apply' => array('group' => 'design', 'sort' => 20), + 'custom_design_from' => ['group' => 'design', 'sort' => 30], + 'custom_design_to' => ['group' => 'design', 'sort' => 40], + 'page_layout' => ['group' => 'design', 'sort' => 50], + 'custom_layout_update' => ['group' => 'design', 'sort' => 60], + 'display_mode' => ['group' => 'display', 'sort' => 10], + 'landing_page' => ['group' => 'display', 'sort' => 20], + 'is_anchor' => ['group' => 'display', 'sort' => 30], + 'available_sort_by' => ['group' => 'display', 'sort' => 40], + 'default_sort_by' => ['group' => 'display', 'sort' => 50], + ]; + + foreach ($attributes as $attributeCode => $attributeProp) { + $categorySetup->addAttributeToGroup( + $entityTypeId, + $attributeSetId, + $groups[$attributeProp['group']]['id'], + $attributeCode, + $attributeProp['sort'] + ); + } + + /** + * Install product link types + */ + $data = [ + ['link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_RELATED, 'code' => 'relation'], + ['link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_UPSELL, 'code' => 'up_sell'], + ['link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_CROSSSELL, 'code' => 'cross_sell'], + ]; + + foreach ($data as $bind) { + $this->moduleDataSetup->getConnection()->insertForce( + $this->moduleDataSetup->getTable( + 'catalog_product_link_type' + ), + $bind + ); + } + + /** + * install product link attributes + */ + $data = [ + [ + 'link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_RELATED, + 'product_link_attribute_code' => 'position', + 'data_type' => 'int', + ], + [ + 'link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_UPSELL, + 'product_link_attribute_code' => 'position', + 'data_type' => 'int' + ], + [ + 'link_type_id' => \Magento\Catalog\Model\Product\Link::LINK_TYPE_CROSSSELL, + 'product_link_attribute_code' => 'position', + 'data_type' => 'int' + ], + ]; + + $this->moduleDataSetup->getConnection()->insertMultiple( + $this->moduleDataSetup->getTable('catalog_product_link_attribute'), + $data + ); + + /** + * Remove Catalog specified attribute options (columns) from eav/attribute table + * + */ + $describe = $this->moduleDataSetup->getConnection() + ->describeTable($this->moduleDataSetup->getTable('catalog_eav_attribute')); + foreach ($describe as $columnData) { + if ($columnData['COLUMN_NAME'] == 'attribute_id') { + continue; + } + $this->moduleDataSetup->getConnection()->dropColumn( + $this->moduleDataSetup->getTable('eav_attribute'), + $columnData['COLUMN_NAME'] + ); + } + + $newGeneralTabName = 'Product Details'; + $newPriceTabName = 'Advanced Pricing'; + $newImagesTabName = 'Image Management'; + $newMetaTabName = 'Search Engine Optimization'; + $autosettingsTabName = 'Autosettings'; + $tabNames = [ + 'General' => [ + 'attribute_group_name' => $newGeneralTabName, + 'attribute_group_code' => $categorySetup->convertToAttributeGroupCode($newGeneralTabName), + 'tab_group_code' => 'basic', + 'sort_order' => 10, + ], + 'Images' => [ + 'attribute_group_name' => $newImagesTabName, + 'attribute_group_code' => $categorySetup->convertToAttributeGroupCode($newImagesTabName), + 'tab_group_code' => 'basic', + 'sort_order' => 20, + ], + 'Meta Information' => [ + 'attribute_group_name' => $newMetaTabName, + 'attribute_group_code' => $categorySetup->convertToAttributeGroupCode($newMetaTabName), + 'tab_group_code' => 'basic', + 'sort_order' => 30, + ], + 'Prices' => [ + 'attribute_group_name' => $newPriceTabName, + 'attribute_group_code' => $categorySetup->convertToAttributeGroupCode($newPriceTabName), + 'tab_group_code' => 'advanced', + 'sort_order' => 40, + ], + 'Design' => ['attribute_group_code' => 'design', 'tab_group_code' => 'advanced', 'sort_order' => 50], + ]; + + $entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); + $attributeSetId = $categorySetup->getAttributeSetId($entityTypeId, 'Default'); + + //Rename attribute tabs + foreach ($tabNames as $tabName => $tab) { + $groupId = $categorySetup->getAttributeGroupId($entityTypeId, $attributeSetId, $tabName); + if ($groupId) { + foreach ($tab as $propertyName => $propertyValue) { + $categorySetup->updateAttributeGroup( + $entityTypeId, + $attributeSetId, + $groupId, + $propertyName, + $propertyValue + ); + } + } + } + + //Add new tab + $categorySetup->addAttributeGroup($entityTypeId, $attributeSetId, $autosettingsTabName, 60); + $categorySetup->updateAttributeGroup( + $entityTypeId, + $attributeSetId, + 'Autosettings', + 'attribute_group_code', + 'autosettings' + ); + $categorySetup->updateAttributeGroup( + $entityTypeId, + $attributeSetId, + 'Autosettings', + 'tab_group_code', + 'advanced' + ); + + //New attributes order and properties + $properties = ['is_required', 'default_value', 'frontend_input_renderer']; + $attributesOrder = [ + //Product Details tab + 'name' => [$newGeneralTabName => 10], + 'sku' => [$newGeneralTabName => 20], + 'price' => [$newGeneralTabName => 30], + 'image' => [$newGeneralTabName => 50], + 'weight' => [$newGeneralTabName => 70, 'is_required' => 0], + 'category_ids' => [$newGeneralTabName => 80], + 'description' => [$newGeneralTabName => 90, 'is_required' => 0], + 'status' => [ + $newGeneralTabName => 100, + 'is_required' => 0, + 'default_value' => 1, + 'frontend_input_renderer' => \Magento\Framework\Data\Form\Element\Hidden::class, + ], + //Autosettings tab + 'short_description' => [$autosettingsTabName => 0, 'is_required' => 0], + 'visibility' => [$autosettingsTabName => 20, 'is_required' => 0], + 'news_from_date' => [$autosettingsTabName => 30], + 'news_to_date' => [$autosettingsTabName => 40], + 'country_of_manufacture' => [$autosettingsTabName => 50], + ]; + + foreach ($attributesOrder as $key => $value) { + $attribute = $categorySetup->getAttribute($entityTypeId, $key); + if ($attribute) { + foreach ($value as $propertyName => $propertyValue) { + if (in_array($propertyName, $properties)) { + $categorySetup->updateAttribute( + $entityTypeId, + $attribute['attribute_id'], + $propertyName, + $propertyValue + ); + } else { + $categorySetup->addAttributeToGroup( + $entityTypeId, + $attributeSetId, + $propertyName, + $attribute['attribute_id'], + $propertyValue + ); + } + } + } + } + + foreach (['status', 'visibility'] as $attributeCode) { + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + $attributeCode, + 'is_required_in_admin_store', + '1' + ); + } + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Category::ENTITY, + 'custom_design_from', + 'attribute_model', + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class + ); + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Category::ENTITY, + 'custom_design_from', + 'frontend_model', + \Magento\Eav\Model\Entity\Attribute\Frontend\Datetime::class + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/SetNewResourceModelsPaths.php b/app/code/Magento/Catalog/Setup/Patch/Data/SetNewResourceModelsPaths.php new file mode 100644 index 0000000000000..d59347f501de1 --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/SetNewResourceModelsPaths.php @@ -0,0 +1,116 @@ +moduleDataSetup = $moduleDataSetup; + $this->categorySetupFactory = $categorySetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + // set new resource model paths + /** @var CategorySetup $categorySetup */ + $categorySetup = $this->categorySetupFactory->create(['setup' => $this->moduleDataSetup]); + $categorySetup->updateEntityType( + \Magento\Catalog\Model\Category::ENTITY, + 'entity_model', + \Magento\Catalog\Model\ResourceModel\Category::class + ); + $categorySetup->updateEntityType( + \Magento\Catalog\Model\Category::ENTITY, + 'attribute_model', + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class + ); + $categorySetup->updateEntityType( + \Magento\Catalog\Model\Category::ENTITY, + 'entity_attribute_collection', + \Magento\Catalog\Model\ResourceModel\Category\Attribute\Collection::class + ); + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Category::ENTITY, + 'custom_design_from', + 'attribute_model', + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class + ); + $categorySetup->updateEntityType( + \Magento\Catalog\Model\Product::ENTITY, + 'entity_model', + \Magento\Catalog\Model\ResourceModel\Product::class + ); + $categorySetup->updateEntityType( + \Magento\Catalog\Model\Product::ENTITY, + 'attribute_model', + \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class + ); + $categorySetup->updateEntityType( + \Magento\Catalog\Model\Product::ENTITY, + 'entity_attribute_collection', + \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection::class + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + InstallDefaultCategories::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.2'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/UpdateDefaultAttributeValue.php b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateDefaultAttributeValue.php new file mode 100644 index 0000000000000..1d58de1994a11 --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateDefaultAttributeValue.php @@ -0,0 +1,80 @@ +moduleDataSetup = $moduleDataSetup; + $this->categorySetupFactory = $categorySetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var CategorySetup $categorySetup */ + $categorySetup = $this->categorySetupFactory->create(['setup' => $this->moduleDataSetup]); + $categorySetup->updateAttribute(3, 54, 'default_value', 1); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + SetNewResourceModelsPaths::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.3'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/UpdateMediaAttributesBackendTypes.php b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateMediaAttributesBackendTypes.php new file mode 100644 index 0000000000000..43665c569c0c9 --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateMediaAttributesBackendTypes.php @@ -0,0 +1,93 @@ +moduleDataSetup = $moduleDataSetup; + $this->categorySetupFactory = $categorySetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $mediaBackendType = 'static'; + $mediaBackendModel = null; + /** @var CategorySetup $categorySetup */ + $categorySetup = $this->categorySetupFactory->create(['setup' => $this->moduleDataSetup]); + $categorySetup->updateAttribute( + 'catalog_product', + 'media_gallery', + 'backend_type', + $mediaBackendType + ); + $categorySetup->updateAttribute( + 'catalog_product', + 'media_gallery', + 'backend_model', + $mediaBackendModel + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateDefaultAttributeValue::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.4'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/UpdateProductAttributes.php b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateProductAttributes.php new file mode 100644 index 0000000000000..d02753d44adee --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateProductAttributes.php @@ -0,0 +1,266 @@ +moduleDataSetup = $moduleDataSetup; + $this->categorySetupFactory = $categorySetupFactory; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function apply() + { + /** @var CategorySetup $categorySetup */ + $categorySetup = $this->categorySetupFactory->create(['setup' => $this->moduleDataSetup]); + + //Product Details tab + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'status', + 'frontend_label', + 'Enable Product', + 5 + ); + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'name', + 'frontend_label', + 'Product Name' + ); + $attributeSetId = $categorySetup->getDefaultAttributeSetId(\Magento\Catalog\Model\Product::ENTITY); + $categorySetup->addAttributeToGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Product Details', + 'visibility', + 80 + ); + $categorySetup->addAttributeToGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Product Details', + 'news_from_date', + 90 + ); + $categorySetup->addAttributeToGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Product Details', + 'news_to_date', + 100 + ); + $categorySetup->addAttributeToGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Product Details', + 'country_of_manufacture', + 110 + ); + + //Content tab + $categorySetup->addAttributeGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Content', + 15 + ); + $categorySetup->updateAttributeGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Content', + 'tab_group_code', + 'basic' + ); + $categorySetup->addAttributeToGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Content', + 'description' + ); + $categorySetup->addAttributeToGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Content', + 'short_description', + 100 + ); + + //Images tab + $groupId = (int)$categorySetup->getAttributeGroupByCode( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'image-management', + 'attribute_group_id' + ); + $categorySetup->addAttributeToGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + $groupId, + 'image', + 1 + ); + $categorySetup->updateAttributeGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + $groupId, + 'attribute_group_name', + 'Images' + ); + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'image', + 'frontend_label', + 'Base' + ); + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'small_image', + 'frontend_label', + 'Small' + ); + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'image', + 'frontend_input_renderer', + null + ); + + //Design tab + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'page_layout', + 'frontend_label', + 'Layout' + ); + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'custom_layout_update', + 'frontend_label', + 'Layout Update XML', + 10 + ); + + //Schedule Design Update tab + $categorySetup->addAttributeGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Schedule Design Update', + 55 + ); + $categorySetup->updateAttributeGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Schedule Design Update', + 'tab_group_code', + 'advanced' + ); + $categorySetup->addAttributeToGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Schedule Design Update', + 'custom_design_from', + 20 + ); + $categorySetup->addAttributeToGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Schedule Design Update', + 'custom_design_to', + 30 + ); + $categorySetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'custom_design', + 'frontend_label', + 'New Theme', + 40 + ); + $categorySetup->addAttributeToGroup( + \Magento\Catalog\Model\Product::ENTITY, + $attributeSetId, + 'Schedule Design Update', + 'custom_design' + ); + $categorySetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'custom_layout', + [ + 'type' => 'varchar', + 'label' => 'New Layout', + 'input' => 'select', + 'source' => \Magento\Catalog\Model\Product\Attribute\Source\Layout::class, + 'required' => false, + 'sort_order' => 50, + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'group' => 'Schedule Design Update', + 'is_used_in_grid' => true, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => false + ] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateMediaAttributesBackendTypes::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.5'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/UpdateProductMetaDescription.php b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateProductMetaDescription.php new file mode 100644 index 0000000000000..0c8f248d1d5c5 --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/UpdateProductMetaDescription.php @@ -0,0 +1,88 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + + $eavSetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'meta_description', + [ + 'note' => 'Maximum 255 chars. Meta Description should optimally be between 150-160 characters' + ] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateProductAttributes::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.7'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Catalog/Setup/UpgradeWebsiteAttributes.php b/app/code/Magento/Catalog/Setup/Patch/Data/UpgradeWebsiteAttributes.php similarity index 79% rename from app/code/Magento/Catalog/Setup/UpgradeWebsiteAttributes.php rename to app/code/Magento/Catalog/Setup/Patch/Data/UpgradeWebsiteAttributes.php index 3d300d9c849a9..f9d6abbc37493 100644 --- a/app/code/Magento/Catalog/Setup/UpgradeWebsiteAttributes.php +++ b/app/code/Magento/Catalog/Setup/Patch/Data/UpgradeWebsiteAttributes.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Catalog\Setup; +namespace Magento\Catalog\Setup\Patch\Data; use Magento\Catalog\Api\Data\CategoryInterface; use Magento\Catalog\Api\Data\ProductInterface; @@ -12,14 +12,16 @@ use Magento\Framework\EntityManager\MetadataPool; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; /** * Class UpgradeWebsiteAttributes - * @package Magento\Catalog\Setup + * @package Magento\Catalog\Setup\Patch * * IMPORTANT: This class const/methods can not be reused because it needs to be isolated */ -class UpgradeWebsiteAttributes +class UpgradeWebsiteAttributes implements DataPatchInterface, PatchVersionInterface { /** * ATTENTION: These constants must not be reused anywhere outside @@ -79,48 +81,55 @@ class UpgradeWebsiteAttributes */ private $linkFields = []; + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + /** * UpgradeWebsiteAttributes constructor. * @param Generator $batchQueryGenerator * @param MetadataPool $metadataPool + * @param ModuleDataSetupInterface $moduleDataSetup */ - public function __construct(Generator $batchQueryGenerator, MetadataPool $metadataPool) - { + public function __construct( + Generator $batchQueryGenerator, + MetadataPool $metadataPool, + ModuleDataSetupInterface $moduleDataSetup + ) { $this->batchQueryGenerator = $batchQueryGenerator; $this->metaDataPool = $metadataPool; + $this->moduleDataSetup = $moduleDataSetup; } /** - * @param ModuleDataSetupInterface $setup - * @return void + * {@inheritdoc} */ - public function upgrade(ModuleDataSetupInterface $setup) + public function apply() { foreach (array_keys($this->tableMetaDataClass) as $tableName) { - $this->upgradeTable($setup, $tableName); + $this->upgradeTable($tableName); } } /** - * @param ModuleDataSetupInterface $setup * @param string $tableName * @return void */ - private function upgradeTable(ModuleDataSetupInterface $setup, $tableName) + private function upgradeTable($tableName) { - foreach ($this->fetchAttributeValues($setup, $tableName) as $attributeValueItems) { - $this->processAttributeValues($setup, $attributeValueItems, $tableName); + foreach ($this->fetchAttributeValues($tableName) as $attributeValueItems) { + $this->processAttributeValues($attributeValueItems, $tableName); } } /** * Aligns website attribute values - * @param ModuleDataSetupInterface $setup * @param array $attributeValueItems * @param string $tableName * @return void */ - private function processAttributeValues(ModuleDataSetupInterface $setup, array $attributeValueItems, $tableName) + private function processAttributeValues(array $attributeValueItems, $tableName) { $this->resetProcessedAttributeValues(); @@ -129,9 +138,9 @@ private function processAttributeValues(ModuleDataSetupInterface $setup, array $ continue; } - $insertions = $this->generateAttributeValueInsertions($setup, $attributeValueItem, $tableName); + $insertions = $this->generateAttributeValueInsertions($attributeValueItem, $tableName); if (!empty($insertions)) { - $this->executeInsertions($setup, $insertions, $tableName); + $this->executeInsertions($insertions, $tableName); } $this->markAttributeValueProcessed($attributeValueItem, $tableName); @@ -141,32 +150,31 @@ private function processAttributeValues(ModuleDataSetupInterface $setup, array $ /** * Yields batch of AttributeValues * - * @param ModuleDataSetupInterface $setup * @param string $tableName * @yield array - * @return void + * @return \Generator */ - private function fetchAttributeValues(ModuleDataSetupInterface $setup, $tableName) + private function fetchAttributeValues($tableName) { - $connection = $setup->getConnection(); + $connection = $this->moduleDataSetup->getConnection(); $batchSelectIterator = $this->batchQueryGenerator->generate( 'value_id', $connection ->select() ->from( - ['cpei' => $setup->getTable($tableName)], + ['cpei' => $this->moduleDataSetup->getTable($tableName)], '*' ) ->join( [ - 'cea' => $setup->getTable('catalog_eav_attribute'), + 'cea' => $this->moduleDataSetup->getTable('catalog_eav_attribute'), ], 'cpei.attribute_id = cea.attribute_id', '' ) ->join( [ - 'st' => $setup->getTable('store'), + 'st' => $this->moduleDataSetup->getTable('store'), ], 'st.store_id = cpei.store_id', 'st.website_id' @@ -187,20 +195,19 @@ private function fetchAttributeValues(ModuleDataSetupInterface $setup, $tableNam } /** - * @param ModuleDataSetupInterface $setup * @return array */ - private function getGroupedStoreViews(ModuleDataSetupInterface $setup) + private function getGroupedStoreViews() { if (!empty($this->groupedStoreViews)) { return $this->groupedStoreViews; } - $connection = $setup->getConnection(); + $connection = $this->moduleDataSetup->getConnection(); $query = $connection ->select() ->from( - $setup->getTable('store'), + $this->moduleDataSetup->getTable('store'), '*' ); @@ -274,17 +281,15 @@ private function getAttributeValueKey($entityId, $attributeId, $websiteId) } /** - * @param ModuleDataSetupInterface $setup * @param array $attributeValue * @param string $tableName * @return array|null */ private function generateAttributeValueInsertions( - ModuleDataSetupInterface $setup, array $attributeValue, $tableName ) { - $groupedStoreViews = $this->getGroupedStoreViews($setup); + $groupedStoreViews = $this->getGroupedStoreViews(); if (empty($groupedStoreViews[$attributeValue['website_id']])) { return null; } @@ -305,12 +310,11 @@ private function generateAttributeValueInsertions( } /** - * @param ModuleDataSetupInterface $setup * @param array $insertions * @param string $tableName * @return void */ - private function executeInsertions(ModuleDataSetupInterface $setup, array $insertions, $tableName) + private function executeInsertions(array $insertions, $tableName) { $rawQuery = sprintf( 'INSERT INTO @@ -318,12 +322,12 @@ private function executeInsertions(ModuleDataSetupInterface $setup, array $inser VALUES %s ON duplicate KEY UPDATE `value` = VALUES(`value`)', - $setup->getTable($tableName), + $this->moduleDataSetup->getTable($tableName), $this->getTableLinkField($tableName), $this->prepareInsertValuesStatement($insertions) ); - $setup->getConnection()->query($rawQuery, $this->getPlaceholderValues($insertions)); + $this->moduleDataSetup->getConnection()->query($rawQuery, $this->getPlaceholderValues($insertions)); } /** @@ -386,4 +390,30 @@ private function getTableLinkField($tableName) return $this->linkFields[$tableName]; } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpgradeWidgetData::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.2.2'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } } diff --git a/app/code/Magento/Catalog/Setup/Patch/Data/UpgradeWidgetData.php b/app/code/Magento/Catalog/Setup/Patch/Data/UpgradeWidgetData.php new file mode 100644 index 0000000000000..8f72f94319971 --- /dev/null +++ b/app/code/Magento/Catalog/Setup/Patch/Data/UpgradeWidgetData.php @@ -0,0 +1,162 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetup = $eavSetupFactory->create(['setup' => $moduleDataSetup]); + $this->queryModifierFactory = $queryModifierFactory; + $this->aggregatedFieldDataConverter = $aggregatedFieldDataConverter; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $categoryTypeId = $this->eavSetup->getEntityTypeId(\Magento\Catalog\Model\Category::ENTITY); + $categoryLayoutUpdateAttribute = $this->eavSetup->getAttribute($categoryTypeId, 'custom_layout_update'); + $categoryLayoutUpdateAttributeModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'attribute_id' => $categoryLayoutUpdateAttribute['attribute_id'] + ] + ] + ); + $layoutUpdateValueModifier = $this->queryModifierFactory->create( + 'like', + [ + 'values' => [ + 'value' => '%conditions_encoded%' + ] + ] + ); + $categoryLayoutUpdateModifier = $this->queryModifierFactory->create( + 'composite', + [ + 'queryModifiers' => [ + $categoryLayoutUpdateAttributeModifier, + $layoutUpdateValueModifier + ] + ] + ); + $productTypeId = $this->eavSetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); + $productLayoutUpdateAttribute = $this->eavSetup->getAttribute($productTypeId, 'custom_layout_update'); + $productLayoutUpdateAttributeModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'attribute_id' => $productLayoutUpdateAttribute['attribute_id'] + ] + ] + ); + $productLayoutUpdateModifier = $this->queryModifierFactory->create( + 'composite', + [ + 'queryModifiers' => [ + $productLayoutUpdateAttributeModifier, + $layoutUpdateValueModifier + ] + ] + ); + $this->aggregatedFieldDataConverter->convert( + [ + new FieldToConvert( + LayoutUpdateConverter::class, + $this->eavSetup->getSetup()->getTable('catalog_category_entity_text'), + 'value_id', + 'value', + $categoryLayoutUpdateModifier + ), + new FieldToConvert( + LayoutUpdateConverter::class, + $this->eavSetup->getSetup()->getTable('catalog_product_entity_text'), + 'value_id', + 'value', + $productLayoutUpdateModifier + ), + ], + $this->eavSetup->getSetup()->getConnection() + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + DisallowUsingHtmlForProductName::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.2.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Catalog/Setup/UpgradeData.php b/app/code/Magento/Catalog/Setup/UpgradeData.php deleted file mode 100644 index a290d4870bd49..0000000000000 --- a/app/code/Magento/Catalog/Setup/UpgradeData.php +++ /dev/null @@ -1,439 +0,0 @@ -categorySetupFactory = $categorySetupFactory; - $this->eavSetupFactory = $eavSetupFactory; - $this->upgradeWidgetData = $upgradeWidgetData; - $this->upgradeWebsiteAttributes = $upgradeWebsiteAttributes; - } - - /** - * {@inheritdoc} - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - if ($context->getVersion() - && version_compare($context->getVersion(), '2.0.1') < 0 - ) { - $select = $setup->getConnection()->select() - ->from( - $setup->getTable('catalog_product_entity_group_price'), - [ - 'entity_id', - 'all_groups', - 'customer_group_id', - new \Zend_Db_Expr('1'), - 'value', - 'website_id' - ] - ); - $select = $setup->getConnection()->insertFromSelect( - $select, - $setup->getTable('catalog_product_entity_tier_price'), - [ - 'entity_id', - 'all_groups', - 'customer_group_id', - 'qty', - 'value', - 'website_id' - ] - ); - $setup->getConnection()->query($select); - - $categorySetupManager = $this->categorySetupFactory->create(); - $categorySetupManager->removeAttribute(\Magento\Catalog\Model\Product::ENTITY, 'group_price'); - } - - if (version_compare($context->getVersion(), '2.0.2') < 0) { - // set new resource model paths - /** @var CategorySetup $categorySetup */ - $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); - $categorySetup->updateEntityType( - \Magento\Catalog\Model\Category::ENTITY, - 'entity_model', - \Magento\Catalog\Model\ResourceModel\Category::class - ); - $categorySetup->updateEntityType( - \Magento\Catalog\Model\Category::ENTITY, - 'attribute_model', - \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class - ); - $categorySetup->updateEntityType( - \Magento\Catalog\Model\Category::ENTITY, - 'entity_attribute_collection', - \Magento\Catalog\Model\ResourceModel\Category\Attribute\Collection::class - ); - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Category::ENTITY, - 'custom_design_from', - 'attribute_model', - \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class - ); - $categorySetup->updateEntityType( - \Magento\Catalog\Model\Product::ENTITY, - 'entity_model', - \Magento\Catalog\Model\ResourceModel\Product::class - ); - $categorySetup->updateEntityType( - \Magento\Catalog\Model\Product::ENTITY, - 'attribute_model', - \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class - ); - $categorySetup->updateEntityType( - \Magento\Catalog\Model\Product::ENTITY, - 'entity_attribute_collection', - \Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection::class - ); - } - - if (version_compare($context->getVersion(), '2.0.3') < 0) { - /** @var CategorySetup $categorySetup */ - $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); - $categorySetup->updateAttribute(3, 54, 'default_value', 1); - } - - if (version_compare($context->getVersion(), '2.0.4') < 0) { - $mediaBackendType = 'static'; - $mediaBackendModel = null; - /** @var CategorySetup $categorySetup */ - $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); - $categorySetup->updateAttribute( - 'catalog_product', - 'media_gallery', - 'backend_type', - $mediaBackendType - ); - $categorySetup->updateAttribute( - 'catalog_product', - 'media_gallery', - 'backend_model', - $mediaBackendModel - ); - } - - if (version_compare($context->getVersion(), '2.0.5', '<')) { - /** @var CategorySetup $categorySetup */ - $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); - - //Product Details tab - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'status', - 'frontend_label', - 'Enable Product', - 5 - ); - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'name', - 'frontend_label', - 'Product Name' - ); - $attributeSetId = $categorySetup->getDefaultAttributeSetId(\Magento\Catalog\Model\Product::ENTITY); - $categorySetup->addAttributeToGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Product Details', - 'visibility', - 80 - ); - $categorySetup->addAttributeToGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Product Details', - 'news_from_date', - 90 - ); - $categorySetup->addAttributeToGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Product Details', - 'news_to_date', - 100 - ); - $categorySetup->addAttributeToGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Product Details', - 'country_of_manufacture', - 110 - ); - - //Content tab - $categorySetup->addAttributeGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Content', - 15 - ); - $categorySetup->updateAttributeGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Content', - 'tab_group_code', - 'basic' - ); - $categorySetup->addAttributeToGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Content', - 'description' - ); - $categorySetup->addAttributeToGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Content', - 'short_description', - 100 - ); - - //Images tab - $groupId = (int)$categorySetup->getAttributeGroupByCode( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'image-management', - 'attribute_group_id' - ); - $categorySetup->addAttributeToGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - $groupId, - 'image', - 1 - ); - $categorySetup->updateAttributeGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - $groupId, - 'attribute_group_name', - 'Images' - ); - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'image', - 'frontend_label', - 'Base' - ); - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'small_image', - 'frontend_label', - 'Small' - ); - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'image', - 'frontend_input_renderer', - null - ); - - //Design tab - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'page_layout', - 'frontend_label', - 'Layout' - ); - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'custom_layout_update', - 'frontend_label', - 'Layout Update XML', - 10 - ); - - //Schedule Design Update tab - $categorySetup->addAttributeGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Schedule Design Update', - 55 - ); - $categorySetup->updateAttributeGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Schedule Design Update', - 'tab_group_code', - 'advanced' - ); - $categorySetup->addAttributeToGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Schedule Design Update', - 'custom_design_from', - 20 - ); - $categorySetup->addAttributeToGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Schedule Design Update', - 'custom_design_to', - 30 - ); - $categorySetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'custom_design', - 'frontend_label', - 'New Theme', - 40 - ); - $categorySetup->addAttributeToGroup( - \Magento\Catalog\Model\Product::ENTITY, - $attributeSetId, - 'Schedule Design Update', - 'custom_design' - ); - $categorySetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'custom_layout', - [ - 'type' => 'varchar', - 'label' => 'New Layout', - 'input' => 'select', - 'source' => \Magento\Catalog\Model\Product\Attribute\Source\Layout::class, - 'required' => false, - 'sort_order' => 50, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, - 'group' => 'Schedule Design Update', - 'is_used_in_grid' => true, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => false - ] - ); - } - - if (version_compare($context->getVersion(), '2.0.7') < 0) { - /** @var EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - - $eavSetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'meta_description', - [ - 'note' => 'Maximum 255 chars. Meta Description should optimally be between 150-160 characters' - ] - ); - } - - if (version_compare($context->getVersion(), '2.1.3') < 0) { - /** @var CategorySetup $categorySetup */ - $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); - $this->changePriceAttributeDefaultScope($categorySetup); - } - - if (version_compare($context->getVersion(), '2.1.5') < 0) { - $this->disallowUsingHtmlForProductName($setup); - } - - if ($context->getVersion() && version_compare($context->getVersion(), '2.2.1') < 0) { - $this->upgradeWidgetData->upgrade(); - } - - if (version_compare($context->getVersion(), '2.2.2') < 0) { - $this->upgradeWebsiteAttributes->upgrade($setup); - } - - $setup->endSetup(); - } - - /** - * Set to 'No' 'Is Allowed Html on Store Front' option on product name attribute, because product name - * is multi entity field (used in order, quote) and cannot be conditionally escaped in all places - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function disallowUsingHtmlForProductName(ModuleDataSetupInterface $setup) - { - /** @var CategorySetup $categorySetup */ - $categorySetup = $this->categorySetupFactory->create(['setup' => $setup]); - $entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); - $attribute = $categorySetup->getAttribute($entityTypeId, 'name'); - - $setup->getConnection() - ->update( - $setup->getTable('catalog_eav_attribute'), - ['is_html_allowed_on_front' => 0], - $setup->getConnection()->quoteInto('attribute_id = ?', $attribute['attribute_id']) - ); - } - - /** - * @param CategorySetup $categorySetup - * @return void - */ - private function changePriceAttributeDefaultScope($categorySetup) - { - $entityTypeId = $categorySetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); - foreach (['price', 'cost', 'special_price'] as $attributeCode) { - $attribute = $categorySetup->getAttribute($entityTypeId, $attributeCode); - if (isset($attribute['attribute_id'])) { - $categorySetup->updateAttribute( - $entityTypeId, - $attribute['attribute_id'], - 'is_global', - \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL - ); - } - } - } -} diff --git a/app/code/Magento/Catalog/Setup/UpgradeWidgetData.php b/app/code/Magento/Catalog/Setup/UpgradeWidgetData.php deleted file mode 100644 index f9eba413f5416..0000000000000 --- a/app/code/Magento/Catalog/Setup/UpgradeWidgetData.php +++ /dev/null @@ -1,120 +0,0 @@ -eavSetup = $eavSetup; - $this->queryModifierFactory = $queryModifierFactory; - $this->aggregatedFieldDataConverter = $aggregatedFieldDataConverter; - } - - /** - * Convert category and product layout update - * - * @return void - * @throws \InvalidArgumentException - */ - public function upgrade() - { - $categoryTypeId = $this->eavSetup->getEntityTypeId(\Magento\Catalog\Model\Category::ENTITY); - $categoryLayoutUpdateAttribute = $this->eavSetup->getAttribute($categoryTypeId, 'custom_layout_update'); - $categoryLayoutUpdateAttributeModifier = $this->queryModifierFactory->create( - 'in', - [ - 'values' => [ - 'attribute_id' => $categoryLayoutUpdateAttribute['attribute_id'] - ] - ] - ); - $layoutUpdateValueModifier = $this->queryModifierFactory->create( - 'like', - [ - 'values' => [ - 'value' => '%conditions_encoded%' - ] - ] - ); - $categoryLayoutUpdateModifier = $this->queryModifierFactory->create( - 'composite', - [ - 'queryModifiers' => [ - $categoryLayoutUpdateAttributeModifier, - $layoutUpdateValueModifier - ] - ] - ); - $productTypeId = $this->eavSetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); - $productLayoutUpdateAttribute = $this->eavSetup->getAttribute($productTypeId, 'custom_layout_update'); - $productLayoutUpdateAttributeModifier = $this->queryModifierFactory->create( - 'in', - [ - 'values' => [ - 'attribute_id' => $productLayoutUpdateAttribute['attribute_id'] - ] - ] - ); - $productLayoutUpdateModifier = $this->queryModifierFactory->create( - 'composite', - [ - 'queryModifiers' => [ - $productLayoutUpdateAttributeModifier, - $layoutUpdateValueModifier - ] - ] - ); - $this->aggregatedFieldDataConverter->convert( - [ - new FieldToConvert( - LayoutUpdateConverter::class, - $this->eavSetup->getSetup()->getTable('catalog_category_entity_text'), - 'value_id', - 'value', - $categoryLayoutUpdateModifier - ), - new FieldToConvert( - LayoutUpdateConverter::class, - $this->eavSetup->getSetup()->getTable('catalog_product_entity_text'), - 'value_id', - 'value', - $productLayoutUpdateModifier - ), - ], - $this->eavSetup->getSetup()->getConnection() - ); - } -} diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/ImageBuilderTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/ImageBuilderTest.php index e0b5d6ef3992a..dc152aaf05867 100644 --- a/app/code/Magento/Catalog/Test/Unit/Block/Product/ImageBuilderTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/ImageBuilderTest.php @@ -5,49 +5,43 @@ */ namespace Magento\Catalog\Test\Unit\Block\Product; +use Magento\Catalog\Block\Product\ImageBuilder; +use Magento\Catalog\Block\Product\ImageFactory; +use Magento\Catalog\Helper\Image; +use Magento\Catalog\Model\Product; + class ImageBuilderTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Catalog\Block\Product\ImageBuilder + * @var ImageBuilder */ - protected $model; + private $model; /** * @var \Magento\Catalog\Helper\ImageFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $helperFactory; + private $helperFactory; /** - * @var \Magento\Catalog\Block\Product\ImageFactory|\PHPUnit_Framework_MockObject_MockObject + * @var ImageFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $imageFactory; + private $imageFactory; protected function setUp() { - $this->helperFactory = $this->getMockBuilder(\Magento\Catalog\Helper\ImageFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - - $this->imageFactory = $this->getMockBuilder(\Magento\Catalog\Block\Product\ImageFactory::class) - ->disableOriginalConstructor() - ->setMethods(['create']) - ->getMock(); - - $this->model = new \Magento\Catalog\Block\Product\ImageBuilder( - $this->helperFactory, - $this->imageFactory - ); + $this->helperFactory = $this->createPartialMock(\Magento\Catalog\Helper\ImageFactory::class, ['create']); + + $this->imageFactory = $this->createPartialMock(ImageFactory::class, ['create']); + + $this->model = new ImageBuilder($this->helperFactory, $this->imageFactory); } public function testSetProduct() { - $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) - ->disableOriginalConstructor() - ->getMock(); + $productMock = $this->createMock(Product::class); $this->assertInstanceOf( - \Magento\Catalog\Block\Product\ImageBuilder::class, + ImageBuilder::class, $this->model->setProduct($productMock) ); } @@ -57,7 +51,7 @@ public function testSetImageId() $imageId = 'test_image_id'; $this->assertInstanceOf( - \Magento\Catalog\Block\Product\ImageBuilder::class, + ImageBuilder::class, $this->model->setImageId($imageId) ); } @@ -68,7 +62,7 @@ public function testSetAttributes() 'name' => 'value', ]; $this->assertInstanceOf( - \Magento\Catalog\Block\Product\ImageBuilder::class, + ImageBuilder::class, $this->model->setAttributes($attributes) ); } @@ -81,13 +75,9 @@ public function testCreate($data, $expected) { $imageId = 'test_image_id'; - $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class) - ->disableOriginalConstructor() - ->getMock(); + $productMock = $this->createMock(Product::class); - $helperMock = $this->getMockBuilder(\Magento\Catalog\Helper\Image::class) - ->disableOriginalConstructor() - ->getMock(); + $helperMock = $this->createMock(Image::class); $helperMock->expects($this->once()) ->method('init') ->with($productMock, $imageId) @@ -116,9 +106,7 @@ public function testCreate($data, $expected) ->method('create') ->willReturn($helperMock); - $imageMock = $this->getMockBuilder(\Magento\Catalog\Block\Product\Image::class) - ->disableOriginalConstructor() - ->getMock(); + $imageMock = $this->createMock(\Magento\Catalog\Block\Product\Image::class); $this->imageFactory->expects($this->once()) ->method('create') @@ -131,61 +119,173 @@ public function testCreate($data, $expected) $this->assertInstanceOf(\Magento\Catalog\Block\Product\Image::class, $this->model->create()); } + /** + * Check if custom attributes will be overridden when builder used few times + * @param array $data + * @dataProvider createMultipleCallsDataProvider + */ + public function testCreateMultipleCalls($data) + { + list ($firstCall, $secondCall) = array_values($data); + + $imageId = 'test_image_id'; + + $productMock = $this->createMock(Product::class); + + $helperMock = $this->createMock(Image::class); + $helperMock->expects($this->exactly(2)) + ->method('init') + ->with($productMock, $imageId) + ->willReturnSelf(); + + $helperMock->expects($this->exactly(2)) + ->method('getFrame') + ->willReturnOnConsecutiveCalls($firstCall['data']['frame'], $secondCall['data']['frame']); + $helperMock->expects($this->exactly(2)) + ->method('getUrl') + ->willReturnOnConsecutiveCalls($firstCall['data']['url'], $secondCall['data']['url']); + $helperMock->expects($this->exactly(4)) + ->method('getWidth') + ->willReturnOnConsecutiveCalls( + $firstCall['data']['width'], + $firstCall['data']['width'], + $secondCall['data']['width'], + $secondCall['data']['width'] + ); + $helperMock->expects($this->exactly(4)) + ->method('getHeight') + ->willReturnOnConsecutiveCalls( + $firstCall['data']['height'], + $firstCall['data']['height'], + $secondCall['data']['height'], + $secondCall['data']['height'] + ); + $helperMock->expects($this->exactly(2)) + ->method('getLabel') + ->willReturnOnConsecutiveCalls($firstCall['data']['label'], $secondCall['data']['label']); + $helperMock->expects($this->exactly(2)) + ->method('getResizedImageInfo') + ->willReturnOnConsecutiveCalls($firstCall['data']['imagesize'], $secondCall['data']['imagesize']); + $this->helperFactory->expects($this->exactly(2)) + ->method('create') + ->willReturn($helperMock); + + $imageMock = $this->createMock(\Magento\Catalog\Block\Product\Image::class); + + $this->imageFactory->expects($this->at(0)) + ->method('create') + ->with($firstCall['expected']) + ->willReturn($imageMock); + + $this->imageFactory->expects($this->at(1)) + ->method('create') + ->with($secondCall['expected']) + ->willReturn($imageMock); + + $this->model->setProduct($productMock); + $this->model->setImageId($imageId); + $this->model->setAttributes($firstCall['data']['custom_attributes']); + + $this->assertInstanceOf(\Magento\Catalog\Block\Product\Image::class, $this->model->create()); + + $this->model->setProduct($productMock); + $this->model->setImageId($imageId); + $this->model->setAttributes($secondCall['data']['custom_attributes']); + $this->assertInstanceOf(\Magento\Catalog\Block\Product\Image::class, $this->model->create()); + } + + /** + * @return array + */ + public function createDataProvider(): array + { + return [ + $this->getTestDataWithoutAttributes(), + $this->getTestDataWithAttributes(), + ]; + } + /** * @return array */ - public function createDataProvider() + public function createMultipleCallsDataProvider(): array { return [ [ + [ + 'without_attributes' => $this->getTestDataWithoutAttributes(), + 'with_attributes' => $this->getTestDataWithAttributes(), + ], + ], + [ + [ + 'with_attributes' => $this->getTestDataWithAttributes(), + 'without_attributes' => $this->getTestDataWithoutAttributes(), + ], + ], + ]; + } + + /** + * @return array + */ + private function getTestDataWithoutAttributes(): array + { + return [ + 'data' => [ + 'frame' => 0, + 'url' => 'test_url_1', + 'width' => 100, + 'height' => 100, + 'label' => 'test_label', + 'custom_attributes' => [], + 'imagesize' => [100, 100], + ], + 'expected' => [ 'data' => [ - 'frame' => 0, - 'url' => 'test_url_1', + 'template' => 'Magento_Catalog::product/image_with_borders.phtml', + 'image_url' => 'test_url_1', 'width' => 100, 'height' => 100, 'label' => 'test_label', - 'custom_attributes' => [], - 'imagesize' => [100, 100], + 'ratio' => 1, + 'custom_attributes' => '', + 'resized_image_width' => 100, + 'resized_image_height' => 100, ], - 'expected' => [ - 'data' => [ - 'template' => 'Magento_Catalog::product/image_with_borders.phtml', - 'image_url' => 'test_url_1', - 'width' => 100, - 'height' => 100, - 'label' => 'test_label', - 'ratio' => 1, - 'custom_attributes' => '', - 'resized_image_width' => 100, - 'resized_image_height' => 100, - ], + ], + ]; + } + + /** + * @return array + */ + private function getTestDataWithAttributes(): array + { + return [ + 'data' => [ + 'frame' => 1, + 'url' => 'test_url_2', + 'width' => 100, + 'height' => 50, + 'label' => 'test_label_2', + 'custom_attributes' => [ + 'name_1' => 'value_1', + 'name_2' => 'value_2', ], + 'imagesize' => [120, 70], ], - [ + 'expected' => [ 'data' => [ - 'frame' => 1, - 'url' => 'test_url_2', + 'template' => 'Magento_Catalog::product/image.phtml', + 'image_url' => 'test_url_2', 'width' => 100, 'height' => 50, 'label' => 'test_label_2', - 'custom_attributes' => [ - 'name_1' => 'value_1', - 'name_2' => 'value_2', - ], - 'imagesize' => [120, 70], - ], - 'expected' => [ - 'data' => [ - 'template' => 'Magento_Catalog::product/image.phtml', - 'image_url' => 'test_url_2', - 'width' => 100, - 'height' => 50, - 'label' => 'test_label_2', - 'ratio' => 0.5, - 'custom_attributes' => 'name_1="value_1" name_2="value_2"', - 'resized_image_width' => 120, - 'resized_image_height' => 70, - ], + 'ratio' => 0.5, + 'custom_attributes' => 'name_1="value_1" name_2="value_2"', + 'resized_image_width' => 120, + 'resized_image_height' => 70, ], ], ]; diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php index d4e09714d0522..aef9d761c61ba 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php @@ -5,6 +5,8 @@ */ namespace Magento\Catalog\Test\Unit\Model\Category\Attribute\Backend; +use Magento\Framework\App\Filesystem\DirectoryList; + class ImageTest extends \PHPUnit\Framework\TestCase { /** @@ -27,6 +29,11 @@ class ImageTest extends \PHPUnit\Framework\TestCase */ private $logger; + /** + * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject + */ + private $filesystem; + protected function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -59,6 +66,9 @@ protected function setUp() \Magento\Catalog\Model\ImageUploader::class, ['moveFileFromTmp'] ); + + $this->filesystem = $this->getMockBuilder(\Magento\Framework\Filesystem::class)->disableOriginalConstructor() + ->getMock(); } /** @@ -144,6 +154,38 @@ public function testBeforeSaveAttributeFileName() $this->assertEquals('test123.jpg', $object->getTestAttribute()); } + public function testBeforeSaveAttributeFileNameOutsideOfCategoryDir() + { + $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class, [ + 'filesystem' => $this->filesystem + ]); + + $model->setAttribute($this->attribute); + + $this->filesystem + ->expects($this->once()) + ->method('getUri') + ->with(DirectoryList::MEDIA) + ->willReturn('pub/media'); + + $object = new \Magento\Framework\DataObject([ + 'test_attribute' => [ + [ + 'name' => '/test123.jpg', + 'url' => '/pub/media/wysiwyg/test123.jpg', + ] + ] + ]); + + $model->beforeSave($object); + + $this->assertEquals('/pub/media/wysiwyg/test123.jpg', $object->getTestAttribute()); + $this->assertEquals( + [['name' => '/pub/media/wysiwyg/test123.jpg', 'url' => '/pub/media/wysiwyg/test123.jpg']], + $object->getData('_additional_data_test_attribute') + ); + } + public function testBeforeSaveTemporaryAttribute() { $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/FileInfoTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/FileInfoTest.php index 0e8777b5c6f9e..8ca823127e66c 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Category/FileInfoTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/FileInfoTest.php @@ -10,6 +10,7 @@ use Magento\Framework\File\Mime; use Magento\Framework\Filesystem; use Magento\Framework\Filesystem\Directory\WriteInterface; +use Magento\Framework\Filesystem\Directory\ReadInterface; class FileInfoTest extends \PHPUnit\Framework\TestCase { @@ -28,6 +29,11 @@ class FileInfoTest extends \PHPUnit\Framework\TestCase */ private $mediaDirectory; + /** + * @var ReadInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $baseDirectory; + /** * @var FileInfo */ @@ -38,6 +44,9 @@ protected function setUp() $this->mediaDirectory = $this->getMockBuilder(WriteInterface::class) ->getMockForAbstractClass(); + $this->baseDirectory = $this->getMockBuilder(ReadInterface::class) + ->getMockForAbstractClass(); + $this->filesystem = $this->getMockBuilder(Filesystem::class) ->disableOriginalConstructor() ->getMock(); @@ -46,10 +55,20 @@ protected function setUp() ->with(DirectoryList::MEDIA) ->willReturn($this->mediaDirectory); + $this->filesystem->expects($this->any()) + ->method('getDirectoryRead') + ->with(DirectoryList::ROOT) + ->willReturn($this->baseDirectory); + $this->mime = $this->getMockBuilder(Mime::class) ->disableOriginalConstructor() ->getMock(); + $this->baseDirectory->expects($this->any()) + ->method('getAbsolutePath') + ->with(null) + ->willReturn('/a/b/c'); + $this->model = new FileInfo( $this->filesystem, $this->mime @@ -58,16 +77,24 @@ protected function setUp() public function testGetMimeType() { - $mediaPath = '/catalog/category'; - $fileName = '/filename.ext1'; - $absoluteFilePath = '/absolute_path/catalog/category/filename.ext1'; + $absoluteFilePath = '/a/b/c/pub/media/catalog/category/filename.ext1'; $expected = 'ext1'; - $this->mediaDirectory->expects($this->once()) + $this->mediaDirectory->expects($this->at(0)) + ->method('getAbsolutePath') + ->with(null) + ->willReturn('/a/b/c/pub/media'); + + $this->mediaDirectory->expects($this->at(1)) + ->method('getAbsolutePath') + ->with(null) + ->willReturn('/a/b/c/pub/media'); + + $this->mediaDirectory->expects($this->at(2)) ->method('getAbsolutePath') - ->with($mediaPath. '/' . ltrim($fileName, '/')) + ->with('/catalog/category/filename.ext1') ->willReturn($absoluteFilePath); $this->mime->expects($this->once()) @@ -86,6 +113,11 @@ public function testGetStat() $expected = ['size' => 1]; + $this->mediaDirectory->expects($this->any()) + ->method('getAbsolutePath') + ->with(null) + ->willReturn('/a/b/c/pub/media'); + $this->mediaDirectory->expects($this->once()) ->method('stat') ->with($mediaPath . $fileName) @@ -104,6 +136,11 @@ public function testIsExist() $fileName = '/filename.ext1'; + $this->mediaDirectory->expects($this->any()) + ->method('getAbsolutePath') + ->with(null) + ->willReturn('/a/b/c/pub/media'); + $this->mediaDirectory->expects($this->once()) ->method('isExist') ->with($mediaPath . $fileName) diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php index d96ac4bfaab0a..51521db53312e 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php @@ -7,7 +7,7 @@ namespace Magento\Catalog\Test\Unit\Model; use Magento\Catalog\Model\Indexer; -use Magento\Catalog\Model\Category; +use Magento\Eav\Model\Entity\GetCustomAttributeCodesInterface; /** * @SuppressWarnings(PHPMD.TooManyFields) @@ -120,6 +120,11 @@ class CategoryTest extends \PHPUnit\Framework\TestCase */ private $objectManager; + /** + * @var GetCustomAttributeCodesInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $getCustomAttributeCodes; + protected function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); @@ -160,6 +165,10 @@ protected function setUp() ); $this->attributeValueFactory = $this->getMockBuilder(\Magento\Framework\Api\AttributeValueFactory::class) ->disableOriginalConstructor()->getMock(); + $this->getCustomAttributeCodes = $this->getMockBuilder(GetCustomAttributeCodesInterface::class) + ->setMethods(['execute']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); $this->category = $this->getCategoryModel(); } @@ -309,6 +318,7 @@ protected function getCategoryModel() 'indexerRegistry' => $this->indexerRegistry, 'metadataService' => $this->metadataServiceMock, 'customAttributeFactory' => $this->attributeValueFactory, + 'getCustomAttributeCodes' => $this->getCustomAttributeCodes ] ); } @@ -431,43 +441,39 @@ public function testReindexFlatDisabled( public function testGetCustomAttributes() { - $nameAttributeCode = 'name'; - $descriptionAttributeCode = 'description'; - $interfaceAttribute = $this->createMock(\Magento\Framework\Api\MetadataObjectInterface::class); - $interfaceAttribute->expects($this->once()) - ->method('getAttributeCode') - ->willReturn($nameAttributeCode); - $descriptionAttribute = $this->createMock(\Magento\Framework\Api\MetadataObjectInterface::class); - $descriptionAttribute->expects($this->once()) - ->method('getAttributeCode') - ->willReturn($descriptionAttributeCode); - $customAttributesMetadata = [$interfaceAttribute, $descriptionAttribute]; - - $this->metadataServiceMock->expects($this->once()) - ->method('getCustomAttributesMetadata') - ->willReturn($customAttributesMetadata); - $this->category->setData($nameAttributeCode, "sub"); - - //The color attribute is not set, expect empty custom attribute array + $interfaceAttributeCode = 'name'; + $customAttributeCode = 'description'; + $initialCustomAttributeValue = 'initial description'; + $newCustomAttributeValue = 'new description'; + + $this->getCustomAttributeCodes->expects($this->exactly(3)) + ->method('execute') + ->willReturn([$customAttributeCode]); + $this->category->setData($interfaceAttributeCode, "sub"); + + //The description attribute is not set, expect empty custom attribute array $this->assertEquals([], $this->category->getCustomAttributes()); - //Set the color attribute; - $this->category->setData($descriptionAttributeCode, "description"); + //Set the description attribute; + $this->category->setData($customAttributeCode, $initialCustomAttributeValue); $attributeValue = new \Magento\Framework\Api\AttributeValue(); $attributeValue2 = new \Magento\Framework\Api\AttributeValue(); $this->attributeValueFactory->expects($this->exactly(2))->method('create') ->willReturnOnConsecutiveCalls($attributeValue, $attributeValue2); $this->assertEquals(1, count($this->category->getCustomAttributes())); - $this->assertNotNull($this->category->getCustomAttribute($descriptionAttributeCode)); - $this->assertEquals("description", $this->category->getCustomAttribute($descriptionAttributeCode)->getValue()); + $this->assertNotNull($this->category->getCustomAttribute($customAttributeCode)); + $this->assertEquals( + $initialCustomAttributeValue, + $this->category->getCustomAttribute($customAttributeCode)->getValue() + ); //Change the attribute value, should reflect in getCustomAttribute - $this->category->setData($descriptionAttributeCode, "new description"); + $this->category->setData($customAttributeCode, $newCustomAttributeValue); $this->assertEquals(1, count($this->category->getCustomAttributes())); - $this->assertNotNull($this->category->getCustomAttribute($descriptionAttributeCode)); + $this->assertNotNull($this->category->getCustomAttribute($customAttributeCode)); $this->assertEquals( - "new description", - $this->category->getCustomAttribute($descriptionAttributeCode)->getValue() + $newCustomAttributeValue, + $this->category->getCustomAttribute($customAttributeCode)->getValue() ); } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetCategoryCustomAttributeCodesTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetCategoryCustomAttributeCodesTest.php new file mode 100644 index 0000000000000..465063dccd3d5 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetCategoryCustomAttributeCodesTest.php @@ -0,0 +1,66 @@ +baseCustomAttributeCodes = $this->getMockBuilder(GetCustomAttributeCodesInterface::class) + ->disableOriginalConstructor() + ->setMethods(['execute']) + ->getMockForAbstractClass(); + $objectManager = new ObjectManager($this); + $this->getCategoryCustomAttributeCodes = $objectManager->getObject( + GetCategoryCustomAttributeCodes::class, + ['baseCustomAttributeCodes' => $this->baseCustomAttributeCodes] + ); + } + + /** + * Test GetCategoryCustomAttributeCodes::execute() will return only custom category attribute codes. + */ + public function testExecute() + { + /** @var MetadataServiceInterface|\PHPUnit_Framework_MockObject_MockObject $metadataService */ + $metadataService = $this->getMockBuilder(MetadataServiceInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->baseCustomAttributeCodes->expects($this->once()) + ->method('execute') + ->with($this->identicalTo($metadataService)) + ->willReturn(['test_custom_attribute_code', 'name']); + $this->assertEquals( + ['test_custom_attribute_code'], + $this->getCategoryCustomAttributeCodes->execute($metadataService) + ); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetProductCustomAttributeCodesTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetProductCustomAttributeCodesTest.php new file mode 100644 index 0000000000000..a37e1c6df0908 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Entity/GetProductCustomAttributeCodesTest.php @@ -0,0 +1,66 @@ +baseCustomAttributeCodes = $this->getMockBuilder(GetCustomAttributeCodesInterface::class) + ->disableOriginalConstructor() + ->setMethods(['execute']) + ->getMockForAbstractClass(); + $objectManager = new ObjectManager($this); + $this->getProductCustomAttributeCodes = $objectManager->getObject( + GetProductCustomAttributeCodes::class, + ['baseCustomAttributeCodes' => $this->baseCustomAttributeCodes] + ); + } + + /** + * Test GetProductCustomAttributeCodes::execute() will return only custom product attribute codes. + */ + public function testExecute() + { + /** @var MetadataServiceInterface|\PHPUnit_Framework_MockObject_MockObject $metadataService */ + $metadataService = $this->getMockBuilder(MetadataServiceInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->baseCustomAttributeCodes->expects($this->once()) + ->method('execute') + ->with($this->identicalTo($metadataService)) + ->willReturn(['test_custom_attribute_code', 'name']); + $this->assertEquals( + ['test_custom_attribute_code'], + $this->getProductCustomAttributeCodes->execute($metadataService) + ); + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Frontend/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Frontend/ImageTest.php index 115a333a38b5b..3ceedddc2b713 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Frontend/ImageTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Frontend/ImageTest.php @@ -3,45 +3,71 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Catalog\Test\Unit\Model\Product\Attribute\Frontend; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Frontend\Image; +use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Store\Model\Store; +use Magento\Store\Model\StoreManagerInterface; +use PHPUnit\Framework\TestCase; -class ImageTest extends \PHPUnit\Framework\TestCase +class ImageTest extends TestCase { /** - * @var \Magento\Catalog\Model\Product\Attribute\Frontend\Image + * @var Image */ private $model; - public function testGetUrl() + /** + * @dataProvider getUrlDataProvider + * @param string $expectedImage + * @param string $productImage + */ + public function testGetUrl(string $expectedImage, string $productImage) + { + $this->assertEquals($expectedImage, $this->model->getUrl($this->getMockedProduct($productImage))); + } + + /** + * Data provider for testGetUrl + * + * @return array + */ + public function getUrlDataProvider(): array { - $this->assertEquals('catalog/product/img.jpg', $this->model->getUrl($this->getMockedProduct())); + return [ + ['catalog/product/img.jpg', 'img.jpg'], + ['catalog/product/img.jpg', '/img.jpg'], + ]; } protected function setUp() { $helper = new ObjectManager($this); $this->model = $helper->getObject( - \Magento\Catalog\Model\Product\Attribute\Frontend\Image::class, + Image::class, ['storeManager' => $this->getMockedStoreManager()] ); $this->model->setAttribute($this->getMockedAttribute()); } /** - * @return \Magento\Catalog\Model\Product + * @param string $productImage + * @return Product */ - private function getMockedProduct() + private function getMockedProduct(string $productImage): Product { - $mockBuilder = $this->getMockBuilder(\Magento\Catalog\Model\Product::class); + $mockBuilder = $this->getMockBuilder(Product::class); $mock = $mockBuilder->setMethods(['getData', 'getStore', '__wakeup']) ->disableOriginalConstructor() ->getMock(); $mock->expects($this->any()) ->method('getData') - ->will($this->returnValue('img.jpg')); + ->will($this->returnValue($productImage)); $mock->expects($this->any()) ->method('getStore'); @@ -50,13 +76,13 @@ private function getMockedProduct() } /** - * @return \Magento\Store\Model\StoreManagerInterface + * @return StoreManagerInterface */ - private function getMockedStoreManager() + private function getMockedStoreManager(): StoreManagerInterface { $mockedStore = $this->getMockedStore(); - $mockBuilder = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class); + $mockBuilder = $this->getMockBuilder(StoreManagerInterface::class); $mock = $mockBuilder->setMethods(['getStore']) ->disableOriginalConstructor() ->getMockForAbstractClass(); @@ -69,11 +95,11 @@ private function getMockedStoreManager() } /** - * @return \Magento\Store\Model\Store + * @return Store */ - private function getMockedStore() + private function getMockedStore(): Store { - $mockBuilder = $this->getMockBuilder(\Magento\Store\Model\Store::class); + $mockBuilder = $this->getMockBuilder(Store::class); $mock = $mockBuilder->setMethods(['getBaseUrl', '__wakeup']) ->disableOriginalConstructor() ->getMockForAbstractClass(); @@ -86,11 +112,11 @@ private function getMockedStore() } /** - * @return \Magento\Eav\Model\Entity\Attribute\AbstractAttribute + * @return AbstractAttribute */ - private function getMockedAttribute() + private function getMockedAttribute(): AbstractAttribute { - $mockBuilder = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class); + $mockBuilder = $this->getMockBuilder(AbstractAttribute::class); $mockBuilder->setMethods(['getAttributeCode', '__wakeup']); $mockBuilder->disableOriginalConstructor(); $mock = $mockBuilder->getMockForAbstractClass(); diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Source/InputtypeTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Source/InputtypeTest.php index f5c71e45a6647..0246ba337dbc9 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Source/InputtypeTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Attribute/Source/InputtypeTest.php @@ -27,27 +27,37 @@ protected function setUp() $this->inputtypeModel = $this->objectManagerHelper->getObject( \Magento\Catalog\Model\Product\Attribute\Source\Inputtype::class, [ - 'coreRegistry' => $this->registry + 'coreRegistry' => $this->registry, + 'optionsArray' => $this->getInputTypeSet() ] ); } public function testToOptionArray() { - $inputTypesSet = [ + + $extraValues = [ + ['value' => 'price', 'label' => 'Price'], + ['value' => 'media_image', 'label' => 'Media Image'] + ]; + $inputTypesSet = $this->getInputTypeSet(); + $inputTypesSet = array_merge($inputTypesSet, $extraValues); + + $this->registry->expects($this->once())->method('registry'); + $this->registry->expects($this->once())->method('register'); + $this->assertEquals($inputTypesSet, $this->inputtypeModel->toOptionArray()); + } + + private function getInputTypeSet() + { + return [ ['value' => 'text', 'label' => 'Text Field'], ['value' => 'textarea', 'label' => 'Text Area'], ['value' => 'texteditor', 'label' => 'Text Editor'], ['value' => 'date', 'label' => 'Date'], ['value' => 'boolean', 'label' => 'Yes/No'], ['value' => 'multiselect', 'label' => 'Multiple Select'], - ['value' => 'select', 'label' => 'Dropdown'], - ['value' => 'price', 'label' => 'Price'], - ['value' => 'media_image', 'label' => 'Media Image'], + ['value' => 'select', 'label' => 'Dropdown'] ]; - - $this->registry->expects($this->once())->method('registry'); - $this->registry->expects($this->once())->method('register'); - $this->assertEquals($inputTypesSet, $this->inputtypeModel->toOptionArray()); } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php index 8d7e3dfb3f2fd..1ba35dde7ad2f 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php @@ -9,6 +9,7 @@ use Magento\Catalog\Api\Data\ProductExtensionFactory; use Magento\Catalog\Api\Data\ProductExtensionInterface; use Magento\Catalog\Model\Product; +use Magento\Eav\Model\Entity\GetCustomAttributeCodesInterface; use Magento\Framework\Api\Data\ImageContentInterface; use Magento\Framework\Api\ExtensibleDataInterface; use Magento\Framework\Api\ExtensionAttributesFactory; @@ -198,6 +199,11 @@ class ProductTest extends \PHPUnit\Framework\TestCase */ private $extensionAttributes; + /** + * @var GetCustomAttributeCodesInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $getCustomAttributeCodes; + /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ @@ -369,6 +375,10 @@ protected function setUp() ->expects($this->any()) ->method('create') ->willReturn($this->extensionAttributes); + $this->getCustomAttributeCodes = $this->getMockBuilder(GetCustomAttributeCodesInterface::class) + ->disableOriginalConstructor() + ->setMethods(['execute']) + ->getMockForAbstractClass(); $this->objectManagerHelper = new ObjectManagerHelper($this); $this->model = $this->objectManagerHelper->getObject( @@ -398,7 +408,8 @@ protected function setUp() 'catalogProductMediaConfig' => $this->mediaConfig, '_filesystem' => $this->filesystemMock, '_collectionFactory' => $this->collectionFactoryMock, - 'data' => ['id' => 1] + 'data' => ['id' => 1], + 'getCustomAttributeCodes' => $this->getCustomAttributeCodes ] ); } @@ -1267,41 +1278,40 @@ public function testGetMediaGalleryImagesMerging() public function testGetCustomAttributes() { - $priceCode = 'price'; - $colorAttributeCode = 'color'; - $interfaceAttribute = $this->createMock(\Magento\Framework\Api\MetadataObjectInterface::class); - $interfaceAttribute->expects($this->once()) - ->method('getAttributeCode') - ->willReturn($priceCode); - $colorAttribute = $this->createMock(\Magento\Framework\Api\MetadataObjectInterface::class); - $colorAttribute->expects($this->once()) - ->method('getAttributeCode') - ->willReturn($colorAttributeCode); - $customAttributesMetadata = [$interfaceAttribute, $colorAttribute]; - - $this->metadataServiceMock->expects($this->once()) - ->method('getCustomAttributesMetadata') - ->willReturn($customAttributesMetadata); - $this->model->setData($priceCode, 10); + $interfaceAttributeCode = 'price'; + $customAttributeCode = 'color'; + $initialCustomAttributeValue = 'red'; + $newCustomAttributeValue = 'blue'; + + $this->getCustomAttributeCodes->expects($this->exactly(3)) + ->method('execute') + ->willReturn([$customAttributeCode]); + $this->model->setData($interfaceAttributeCode, 10); //The color attribute is not set, expect empty custom attribute array $this->assertEquals([], $this->model->getCustomAttributes()); //Set the color attribute; - $this->model->setData($colorAttributeCode, "red"); + $this->model->setData($customAttributeCode, $initialCustomAttributeValue); $attributeValue = new \Magento\Framework\Api\AttributeValue(); $attributeValue2 = new \Magento\Framework\Api\AttributeValue(); $this->attributeValueFactory->expects($this->exactly(2))->method('create') ->willReturnOnConsecutiveCalls($attributeValue, $attributeValue2); $this->assertEquals(1, count($this->model->getCustomAttributes())); - $this->assertNotNull($this->model->getCustomAttribute($colorAttributeCode)); - $this->assertEquals("red", $this->model->getCustomAttribute($colorAttributeCode)->getValue()); + $this->assertNotNull($this->model->getCustomAttribute($customAttributeCode)); + $this->assertEquals( + $initialCustomAttributeValue, + $this->model->getCustomAttribute($customAttributeCode)->getValue() + ); //Change the attribute value, should reflect in getCustomAttribute - $this->model->setData($colorAttributeCode, "blue"); + $this->model->setData($customAttributeCode, $newCustomAttributeValue); $this->assertEquals(1, count($this->model->getCustomAttributes())); - $this->assertNotNull($this->model->getCustomAttribute($colorAttributeCode)); - $this->assertEquals("blue", $this->model->getCustomAttribute($colorAttributeCode)->getValue()); + $this->assertNotNull($this->model->getCustomAttribute($customAttributeCode)); + $this->assertEquals( + $newCustomAttributeValue, + $this->model->getCustomAttribute($customAttributeCode)->getValue() + ); } /** diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php index ee6d483c9d4fb..3dc95b02b751c 100755 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav.php @@ -31,6 +31,7 @@ use Magento\Ui\Component\Form\Fieldset; use Magento\Ui\DataProvider\Mapper\FormElement as FormElementMapper; use Magento\Ui\DataProvider\Mapper\MetaProperties as MetaPropertiesMapper; +use Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Eav\CompositeConfigProcessor; /** * Class Eav @@ -187,6 +188,11 @@ class Eav extends AbstractModifier */ private $localeCurrency; + /** + * @var CompositeConfigProcessor + */ + private $wysiwygConfigProcessor; + /** * @param LocatorInterface $locator * @param CatalogEavValidationRules $catalogEavValidationRules @@ -207,6 +213,7 @@ class Eav extends AbstractModifier * @param DataPersistorInterface $dataPersistor * @param array $attributesToDisable * @param array $attributesToEliminate + * @param CompositeConfigProcessor|null $wysiwygConfigProcessor * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -228,7 +235,8 @@ public function __construct( ScopeOverriddenValue $scopeOverriddenValue, DataPersistorInterface $dataPersistor, $attributesToDisable = [], - $attributesToEliminate = [] + $attributesToEliminate = [], + CompositeConfigProcessor $wysiwygConfigProcessor = null ) { $this->locator = $locator; $this->catalogEavValidationRules = $catalogEavValidationRules; @@ -249,6 +257,8 @@ public function __construct( $this->dataPersistor = $dataPersistor; $this->attributesToDisable = $attributesToDisable; $this->attributesToEliminate = $attributesToEliminate; + $this->wysiwygConfigProcessor = $wysiwygConfigProcessor ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(CompositeConfigProcessor::class); } /** @@ -779,13 +789,7 @@ private function customizeWysiwyg(ProductAttributeInterface $attribute, array $m $meta['arguments']['data']['config']['formElement'] = WysiwygElement::NAME; $meta['arguments']['data']['config']['wysiwyg'] = true; - $meta['arguments']['data']['config']['wysiwygConfigData'] = [ - 'add_variables' => false, - 'add_widgets' => false, - 'add_directives' => true, - 'use_container' => true, - 'container_class' => 'hor-scroll', - ]; + $meta['arguments']['data']['config']['wysiwygConfigData'] = $this->wysiwygConfigProcessor->process($attribute); return $meta; } diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav/CompositeConfigProcessor.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav/CompositeConfigProcessor.php new file mode 100644 index 0000000000000..5513af9d98e7d --- /dev/null +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav/CompositeConfigProcessor.php @@ -0,0 +1,58 @@ +logger = $logger; + $this->eavWysiwygDataProcessors = $eavWysiwygDataProcessors; + } + + /** + * {@inheritdoc} + */ + public function process(\Magento\Catalog\Api\Data\ProductAttributeInterface $attribute) + { + $wysiwygConfigData = []; + + foreach ($this->eavWysiwygDataProcessors as $processor) { + if (!$processor instanceof WysiwygConfigDataProcessorInterface) { + $this->logger->critical( + __( + 'Processor %1 doesn\'t implement WysiwygConfigDataProcessorInterface. It will be skipped', + get_class($processor) + ) + ); + continue; + } + + $wysiwygConfigData = array_merge_recursive($wysiwygConfigData, $processor->process($attribute)); + } + + return $wysiwygConfigData; + } +} diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav/WysiwygConfigDataProcessor.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav/WysiwygConfigDataProcessor.php new file mode 100644 index 0000000000000..d301a45d14ff5 --- /dev/null +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav/WysiwygConfigDataProcessor.php @@ -0,0 +1,29 @@ + false, + 'add_widgets' => false, + 'add_directives' => true, + 'use_container' => true, + 'container_class' => 'hor-scroll', + ]; + } +} diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav/WysiwygConfigDataProcessorInterface.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav/WysiwygConfigDataProcessorInterface.php new file mode 100644 index 0000000000000..64faef7ba2761 --- /dev/null +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/Eav/WysiwygConfigDataProcessorInterface.php @@ -0,0 +1,23 @@ + + + + + Magento\Catalog\Ui\DataProvider\Product\Form\Modifier\Eav\WysiwygConfigDataProcessor + + + diff --git a/app/code/Magento/Catalog/etc/db_schema.xml b/app/code/Magento/Catalog/etc/db_schema.xml index 5160eeff9abff..f39a78d922f9f 100644 --- a/app/code/Magento/Catalog/etc/db_schema.xml +++ b/app/code/Magento/Catalog/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index 29b1cdfc7d15a..a7502d12e1f7b 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -143,6 +143,12 @@ Magento\Catalog\Model\Product\Attribute\Source\Status\Proxy Magento\Catalog\Model\Product\Link\Proxy + Magento\Catalog\Model\Entity\GetProductCustomAttributeCodes + + + + + Magento\Catalog\Model\Entity\GetCategoryCustomAttributeCodes diff --git a/app/code/Magento/Catalog/etc/module.xml b/app/code/Magento/Catalog/etc/module.xml index 26ed173420adb..96deaa08bbfae 100644 --- a/app/code/Magento/Catalog/etc/module.xml +++ b/app/code/Magento/Catalog/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml index d5dfe845e54c2..54b945b48c104 100644 --- a/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml +++ b/app/code/Magento/Catalog/view/adminhtml/templates/catalog/product/attribute/set/main.phtml @@ -315,7 +315,7 @@ }, validateGroupName : function(name, exceptNodeId) { - name = name.strip(); + name = name.strip().escapeHTML(); var result = true; if (name === '') { result = false; diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml index 9096cb1458bf9..1d587e21313b7 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/category_form.xml @@ -151,32 +151,35 @@ true - + category - ui/form/element/uploader/uploader + ui/form/element/uploader/image string true false - + false Magento_Catalog/image-preview + Media Gallery + jpg jpeg gif png + 4194304 - + - + diff --git a/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml b/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml index 96055b73d363b..1e60823929770 100644 --- a/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml +++ b/app/code/Magento/Catalog/view/adminhtml/ui_component/design_config_form.xml @@ -22,10 +22,10 @@ Allowed file types: jpeg, gif, png. - fileUploader + imageUploader - + jpg jpeg gif png 2097152 @@ -33,7 +33,7 @@ theme/design_config_fileUploader/save - + @@ -80,12 +80,11 @@ - Allowed file types: jpeg, gif, png. - fileUploader + imageUploader - + jpg jpeg gif png 2097152 @@ -93,7 +92,7 @@ theme/design_config_fileUploader/save - + @@ -140,12 +139,11 @@ - Allowed file types: jpeg, gif, png. - fileUploader + imageUploader - + jpg jpeg gif png 2097152 @@ -153,7 +151,7 @@ theme/design_config_fileUploader/save - + diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/field-wysiwyg.html b/app/code/Magento/Catalog/view/adminhtml/web/template/field-wysiwyg.html deleted file mode 100644 index c9340eab2f2e6..0000000000000 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/field-wysiwyg.html +++ /dev/null @@ -1,46 +0,0 @@ - -
- -
- - -
- - - - -
- - - - - -
-
- - diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/image-preview.html b/app/code/Magento/Catalog/view/adminhtml/web/template/image-preview.html index a6a1b3e5b05e8..04b4990f9cace 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/template/image-preview.html +++ b/app/code/Magento/Catalog/view/adminhtml/web/template/image-preview.html @@ -5,8 +5,9 @@ */ -->
-
- +
+ +
@@ -30,7 +32,7 @@
- x + x,
diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml index b3f59991bed57..cad2b3aaa013b 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml @@ -77,7 +77,7 @@ $_helper = $this->helper('Magento\Catalog\Helper\Output');
> isSaleable()): ?> getAddToCartPostParams($_product); ?> -
+ getBlockHtml('formkey') ?> diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml index c8c915a3140da..4d7005dfe6cb2 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml @@ -16,7 +16,7 @@ getProduct(); ?>
- getOptions()): ?> enctype="multipart/form-data"> diff --git a/app/code/Magento/CatalogAnalytics/etc/module.xml b/app/code/Magento/CatalogAnalytics/etc/module.xml index 7974598e17a59..613af18d1832c 100644 --- a/app/code/Magento/CatalogAnalytics/etc/module.xml +++ b/app/code/Magento/CatalogAnalytics/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/CatalogGraphQl/etc/module.xml b/app/code/Magento/CatalogGraphQl/etc/module.xml index e183010353532..1f7aca7667425 100644 --- a/app/code/Magento/CatalogGraphQl/etc/module.xml +++ b/app/code/Magento/CatalogGraphQl/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Product.php b/app/code/Magento/CatalogImportExport/Model/Import/Product.php index cf8707b472156..58e2b13b192aa 100644 --- a/app/code/Magento/CatalogImportExport/Model/Import/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Import/Product.php @@ -1712,7 +1712,7 @@ protected function _saveProducts() foreach ($rowImages as $column => $columnImages) { foreach ($columnImages as $columnImageKey => $columnImage) { if (!isset($uploadedImages[$columnImage])) { - $uploadedFile = $this->uploadMediaFiles($columnImage, true); + $uploadedFile = $this->uploadMediaFiles($columnImage); $uploadedFile = $uploadedFile ?: $this->getSystemFile($columnImage); if ($uploadedFile) { $uploadedImages[$columnImage] = $uploadedFile; diff --git a/app/code/Magento/CatalogImportExport/etc/module.xml b/app/code/Magento/CatalogImportExport/etc/module.xml index 517ffc0fa393d..9e2c801d27b46 100644 --- a/app/code/Magento/CatalogImportExport/etc/module.xml +++ b/app/code/Magento/CatalogImportExport/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php index 1e7c800ea1c38..85fee62eb4303 100644 --- a/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php +++ b/app/code/Magento/CatalogInventory/Model/Indexer/Stock/AbstractAction.php @@ -10,6 +10,7 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\App\ResourceConnection; +use Magento\Framework\EntityManager\MetadataPool; /** * Abstract action reindex class @@ -70,25 +71,33 @@ abstract class AbstractAction */ private $cacheCleaner; + /** + * @var MetadataPool + */ + private $metadataPool; + /** * @param ResourceConnection $resource * @param \Magento\CatalogInventory\Model\ResourceModel\Indexer\StockFactory $indexerFactory * @param \Magento\Catalog\Model\Product\Type $catalogProductType * @param \Magento\Framework\Indexer\CacheContext $cacheContext * @param \Magento\Framework\Event\ManagerInterface $eventManager + * @param MetadataPool|null $metadataPool */ public function __construct( ResourceConnection $resource, \Magento\CatalogInventory\Model\ResourceModel\Indexer\StockFactory $indexerFactory, \Magento\Catalog\Model\Product\Type $catalogProductType, \Magento\Framework\Indexer\CacheContext $cacheContext, - \Magento\Framework\Event\ManagerInterface $eventManager + \Magento\Framework\Event\ManagerInterface $eventManager, + MetadataPool $metadataPool = null ) { $this->_resource = $resource; $this->_indexerFactory = $indexerFactory; $this->_catalogProductType = $catalogProductType; $this->cacheContext = $cacheContext; $this->eventManager = $eventManager; + $this->metadataPool = $metadataPool ?: ObjectManager::getInstance()->get(MetadataPool::class); } /** @@ -154,10 +163,15 @@ protected function _getTable($entityName) public function getRelationsByChild($childIds) { $connection = $this->_getConnection(); - $select = $connection->select() - ->from($this->_getTable('catalog_product_relation'), 'parent_id') - ->where('child_id IN(?)', $childIds); - + $linkField = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class) + ->getLinkField(); + $select = $connection->select()->from( + ['cpe' => $this->_getTable('catalog_product_entity')], + 'entity_id' + )->join( + ['relation' => $this->_getTable('catalog_product_relation')], + 'relation.parent_id = cpe.' . $linkField + )->where('child_id IN(?)', $childIds); return $connection->fetchCol($select); } @@ -230,7 +244,8 @@ protected function _reindexRows($productIds = []) if (!is_array($productIds)) { $productIds = [$productIds]; } - + $parentIds = $this->getRelationsByChild($productIds); + $productIds = $parentIds ? array_unique(array_merge($parentIds, $productIds)) : $productIds; $this->getCacheCleaner()->clean($productIds, function () use ($productIds) { $this->doReindex($productIds); }); @@ -248,13 +263,10 @@ private function doReindex($productIds = []) { $connection = $this->_getConnection(); - $parentIds = $this->getRelationsByChild($productIds); - $processIds = $parentIds ? array_merge($parentIds, $productIds) : $productIds; - // retrieve product types by processIds $select = $connection->select() ->from($this->_getTable('catalog_product_entity'), ['entity_id', 'type_id']) - ->where('entity_id IN(?)', $processIds); + ->where('entity_id IN(?)', $productIds); $pairs = $connection->fetchPairs($select); $byType = []; diff --git a/app/code/Magento/CatalogInventory/Model/Plugin/ReindexUpdatedProducts.php b/app/code/Magento/CatalogInventory/Model/Plugin/ReindexUpdatedProducts.php new file mode 100644 index 0000000000000..f10afcd4ea329 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Model/Plugin/ReindexUpdatedProducts.php @@ -0,0 +1,46 @@ +indexerProcessor = $indexerProcessor; + } + + /** + * Reindex on product attribute mass change + * + * @param ProductAction $subject + * @param ProductAction $action + * @param array $productIds + * @return ProductAction + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterUpdateAttributes( + ProductAction $subject, + ProductAction $action, + $productIds + ) { + $this->indexerProcessor->reindexList(array_unique($productIds)); + return $action; + } +} diff --git a/app/code/Magento/CatalogInventory/Setup/InstallData.php b/app/code/Magento/CatalogInventory/Setup/InstallData.php deleted file mode 100644 index 6fd1745574266..0000000000000 --- a/app/code/Magento/CatalogInventory/Setup/InstallData.php +++ /dev/null @@ -1,60 +0,0 @@ -eavSetupFactory = $eavSetupFactory; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->getConnection() - ->insertForce( - $setup->getTable('cataloginventory_stock'), - ['stock_id' => 1, 'stock_name' => 'Default'] - ); - - /** @var EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - $groupName = 'Product Details'; - $entityTypeId = $eavSetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); - $attributeSetId = $eavSetup->getAttributeSetId($entityTypeId, 'Default'); - - $attribute = $eavSetup->getAttribute($entityTypeId, 'quantity_and_stock_status'); - if ($attribute) { - $eavSetup->addAttributeToGroup($entityTypeId, $attributeSetId, $groupName, $attribute['attribute_id'], 60); - $eavSetup->updateAttribute($entityTypeId, $attribute['attribute_id'], 'default_value', 1); - } - } -} diff --git a/app/code/Magento/CatalogInventory/Setup/Patch/Data/ConvertSerializedDataToJson.php b/app/code/Magento/CatalogInventory/Setup/Patch/Data/ConvertSerializedDataToJson.php new file mode 100644 index 0000000000000..d0ea3da59c51d --- /dev/null +++ b/app/code/Magento/CatalogInventory/Setup/Patch/Data/ConvertSerializedDataToJson.php @@ -0,0 +1,127 @@ +moduleDataSetup = $moduleDataSetup; + $this->fieldDataConverterFactory = $fieldDataConverterFactory; + $this->queryModifierFactory = $queryModifierFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $select = $this->moduleDataSetup->getConnection() + ->select() + ->from( + $this->moduleDataSetup->getTable('core_config_data'), + ['config_id', 'value'] + ) + ->where('path = ?', 'cataloginventory/item_options/min_sale_qty'); + + $rows = $this->moduleDataSetup->getConnection()->fetchAssoc($select); + $serializedRows = array_filter($rows, function ($row) { + return $this->isSerialized($row['value']); + }); + + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $queryModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'config_id' => array_keys($serializedRows) + ] + ] + ); + + $fieldDataConverter->convert( + $this->moduleDataSetup->getConnection(), + $this->moduleDataSetup->getTable('core_config_data'), + 'config_id', + 'value', + $queryModifier + ); + } + + /** + * Check if value is a serialized string + * + * @param string $value + * @return boolean + */ + private function isSerialized($value) + { + return (boolean) preg_match('/^((s|i|d|b|a|O|C):|N;)/', $value); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateStockItemsWebsite::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.2.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/CatalogInventory/Setup/Patch/Data/CreateDefaultStock.php b/app/code/Magento/CatalogInventory/Setup/Patch/Data/CreateDefaultStock.php new file mode 100644 index 0000000000000..ceb353a8091a7 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Setup/Patch/Data/CreateDefaultStock.php @@ -0,0 +1,91 @@ +moduleDataSetup = $resourceConnection; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection() + ->insertForce( + $this->moduleDataSetup->getTable('cataloginventory_stock'), + ['stock_id' => 1, 'stock_name' => 'Default'] + ); + + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + $groupName = 'Product Details'; + $entityTypeId = $eavSetup->getEntityTypeId(\Magento\Catalog\Model\Product::ENTITY); + $attributeSetId = $eavSetup->getAttributeSetId($entityTypeId, 'Default'); + $attribute = $eavSetup->getAttribute($entityTypeId, 'quantity_and_stock_status'); + if ($attribute) { + $eavSetup->addAttributeToGroup($entityTypeId, $attributeSetId, $groupName, $attribute['attribute_id'], 60); + $eavSetup->updateAttribute($entityTypeId, $attribute['attribute_id'], 'default_value', 1); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/CatalogInventory/Setup/Patch/Data/UpdateStockItemsWebsite.php b/app/code/Magento/CatalogInventory/Setup/Patch/Data/UpdateStockItemsWebsite.php new file mode 100644 index 0000000000000..9c73da8915b64 --- /dev/null +++ b/app/code/Magento/CatalogInventory/Setup/Patch/Data/UpdateStockItemsWebsite.php @@ -0,0 +1,98 @@ +moduleDataSetup = $moduleDataSetup; + $this->stockConfiguration = $stockConfiguration; + $this->storeManager = $storeManager; + $this->indexerProcessor = $indexerProcessor; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->update( + $this->moduleDataSetup->getTable('cataloginventory_stock_item'), + ['website_id' => $this->stockConfiguration->getDefaultScopeId()], + ['website_id = ?' => $this->storeManager->getWebsite()->getId()] + ); + $this->indexerProcessor->getIndexer()->invalidate(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + CreateDefaultStock::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.2.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/CatalogInventory/Setup/UpgradeData.php b/app/code/Magento/CatalogInventory/Setup/UpgradeData.php deleted file mode 100644 index 8c99861308ba1..0000000000000 --- a/app/code/Magento/CatalogInventory/Setup/UpgradeData.php +++ /dev/null @@ -1,152 +0,0 @@ -configuration = $configuration; - $this->storeManager = $storeManager; - $this->indexerProcessor = $indexerProcessor; - $this->fieldDataConverterFactory = $fieldDataConverterFactory; - $this->queryModifierFactory = $queryModifierFactory; - } - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - if (version_compare($context->getVersion(), '2.2.0') < 0) { - $this->upgradeCatalogInventoryStockItem($setup); - } - - if (version_compare($context->getVersion(), '2.2.1', '<')) { - $this->convertSerializedDataToJson($setup); - } - $setup->endSetup(); - } - - /** - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function upgradeCatalogInventoryStockItem($setup) - { - $setup->getConnection()->update( - $setup->getTable('cataloginventory_stock_item'), - ['website_id' => $this->configuration->getDefaultScopeId()], - ['website_id = ?' => $this->storeManager->getWebsite()->getId()] - ); - $this->indexerProcessor->getIndexer()->invalidate(); - } - - /** - * Upgrade data to version 2.2.1, converts row data in the core_config_data table that uses the - * path cataloginventory/item_options/min_sale_qty from serialized to JSON. Stored value may not be - * serialized, so validate data format before executing update. - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function convertSerializedDataToJson(ModuleDataSetupInterface $setup) - { - $select = $setup->getConnection() - ->select() - ->from( - $setup->getTable('core_config_data'), - ['config_id', 'value'] - ) - ->where('path = ?', 'cataloginventory/item_options/min_sale_qty'); - - $rows = $setup->getConnection()->fetchAssoc($select); - $serializedRows = array_filter($rows, function ($row) { - return $this->isSerialized($row['value']); - }); - - $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); - $queryModifier = $this->queryModifierFactory->create( - 'in', - [ - 'values' => [ - 'config_id' => array_keys($serializedRows) - ] - ] - ); - - $fieldDataConverter->convert( - $setup->getConnection(), - $setup->getTable('core_config_data'), - 'config_id', - 'value', - $queryModifier - ); - } - - /** - * Check if value is a serialized string - * - * @param string $value - * @return boolean - */ - private function isSerialized($value) - { - return (boolean) preg_match('/^((s|i|d|b|a|O|C):|N;)/', $value); - } -} diff --git a/app/code/Magento/CatalogInventory/etc/db_schema.xml b/app/code/Magento/CatalogInventory/etc/db_schema.xml index a5395ae0a2c85..82372f7f60552 100644 --- a/app/code/Magento/CatalogInventory/etc/db_schema.xml +++ b/app/code/Magento/CatalogInventory/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml index 04935b11ce02b..65bc277121429 100644 --- a/app/code/Magento/CatalogInventory/etc/di.xml +++ b/app/code/Magento/CatalogInventory/etc/di.xml @@ -78,6 +78,9 @@ + + + Magento\CatalogInventory\Model\Indexer\Stock\Processor diff --git a/app/code/Magento/CatalogInventory/etc/module.xml b/app/code/Magento/CatalogInventory/etc/module.xml index b9cddf838b9f2..d643c5015130f 100644 --- a/app/code/Magento/CatalogInventory/etc/module.xml +++ b/app/code/Magento/CatalogInventory/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/CatalogRule/Setup/InstallData.php b/app/code/Magento/CatalogRule/Setup/InstallData.php deleted file mode 100644 index 47591f838d185..0000000000000 --- a/app/code/Magento/CatalogRule/Setup/InstallData.php +++ /dev/null @@ -1,45 +0,0 @@ -createMigrationSetup(); - $setup->startSetup(); - - $installer->appendClassAliasReplace( - 'catalogrule', - 'conditions_serialized', - \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_MODEL, - \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_SERIALIZED, - ['rule_id'] - ); - $installer->appendClassAliasReplace( - 'catalogrule', - 'actions_serialized', - \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_MODEL, - \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_SERIALIZED, - ['rule_id'] - ); - - $installer->doUpdateClassAliases(); - - $setup->endSetup(); - } -} diff --git a/app/code/Magento/CatalogRule/Setup/Patch/Data/ConvertSerializedDataToJson.php b/app/code/Magento/CatalogRule/Setup/Patch/Data/ConvertSerializedDataToJson.php new file mode 100644 index 0000000000000..111d7acd53099 --- /dev/null +++ b/app/code/Magento/CatalogRule/Setup/Patch/Data/ConvertSerializedDataToJson.php @@ -0,0 +1,101 @@ +moduleDataSetup = $moduleDataSetup; + $this->metadataPool = $metadataPool; + $this->aggregatedFieldDataConverter = $aggregatedFieldDataConverter; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $metadata = $this->metadataPool->getMetadata(RuleInterface::class); + $this->aggregatedFieldDataConverter->convert( + [ + new FieldToConvert( + SerializedToJson::class, + $this->moduleDataSetup->getTable('catalogrule'), + $metadata->getLinkField(), + 'conditions_serialized' + ), + new FieldToConvert( + SerializedToJson::class, + $this->moduleDataSetup->getTable('catalogrule'), + $metadata->getLinkField(), + 'actions_serialized' + ), + ], + $this->moduleDataSetup->getConnection() + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateClassAliasesForCatalogRules::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.3'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/CatalogRule/Setup/Patch/Data/UpdateClassAliasesForCatalogRules.php b/app/code/Magento/CatalogRule/Setup/Patch/Data/UpdateClassAliasesForCatalogRules.php new file mode 100644 index 0000000000000..ce1d76876f690 --- /dev/null +++ b/app/code/Magento/CatalogRule/Setup/Patch/Data/UpdateClassAliasesForCatalogRules.php @@ -0,0 +1,80 @@ +dataSetup = $dataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $installer = $this->dataSetup->createMigrationSetup(); + $installer->appendClassAliasReplace( + 'catalogrule', + 'conditions_serialized', + \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_MODEL, + \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_SERIALIZED, + ['rule_id'] + ); + $installer->appendClassAliasReplace( + 'catalogrule', + 'actions_serialized', + \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_MODEL, + \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_SERIALIZED, + ['rule_id'] + ); + $installer->doUpdateClassAliases(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/CatalogRule/Setup/UpgradeData.php b/app/code/Magento/CatalogRule/Setup/UpgradeData.php deleted file mode 100644 index 7f75b7e41dfac..0000000000000 --- a/app/code/Magento/CatalogRule/Setup/UpgradeData.php +++ /dev/null @@ -1,86 +0,0 @@ -aggregatedFieldConverter = $aggregatedFieldConverter; - $this->metadataPool = $metadataPool; - } - - /** - * @inheritdoc - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - - if (version_compare($context->getVersion(), '2.0.3', '<')) { - $this->convertSerializedDataToJson($setup); - } - - $setup->endSetup(); - } - - /** - * Convert metadata from serialized to JSON format: - * - * @param ModuleDataSetupInterface $setup - * - * @return void - */ - public function convertSerializedDataToJson($setup) - { - $metadata = $this->metadataPool->getMetadata(RuleInterface::class); - $this->aggregatedFieldConverter->convert( - [ - new FieldToConvert( - SerializedToJson::class, - $setup->getTable('catalogrule'), - $metadata->getLinkField(), - 'conditions_serialized' - ), - new FieldToConvert( - SerializedToJson::class, - $setup->getTable('catalogrule'), - $metadata->getLinkField(), - 'actions_serialized' - ), - ], - $setup->getConnection() - ); - } -} diff --git a/app/code/Magento/CatalogRule/etc/db_schema.xml b/app/code/Magento/CatalogRule/etc/db_schema.xml index 726c92e252f6c..883a992d8c730 100644 --- a/app/code/Magento/CatalogRule/etc/db_schema.xml +++ b/app/code/Magento/CatalogRule/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/CatalogRule/etc/module.xml b/app/code/Magento/CatalogRule/etc/module.xml index 1dc0f27b137bc..c2acce2ff995d 100644 --- a/app/code/Magento/CatalogRule/etc/module.xml +++ b/app/code/Magento/CatalogRule/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/CatalogRuleConfigurable/etc/module.xml b/app/code/Magento/CatalogRuleConfigurable/etc/module.xml index 3552af8ceb337..0f4d5742fb778 100644 --- a/app/code/Magento/CatalogRuleConfigurable/etc/module.xml +++ b/app/code/Magento/CatalogRuleConfigurable/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/CatalogSearch/Model/Autocomplete/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Autocomplete/DataProvider.php index c4413d002e19c..c1c9997bc83ea 100644 --- a/app/code/Magento/CatalogSearch/Model/Autocomplete/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Autocomplete/DataProvider.php @@ -10,9 +10,16 @@ use Magento\Search\Model\QueryFactory; use Magento\Search\Model\Autocomplete\DataProviderInterface; use Magento\Search\Model\Autocomplete\ItemFactory; +use Magento\Framework\App\Config\ScopeConfigInterface as ScopeConfig; +use Magento\Store\Model\ScopeInterface; class DataProvider implements DataProviderInterface { + /** + * Autocomplete limit + */ + const CONFIG_AUTOCOMPLETE_LIMIT = 'catalog/search/autocomplete_limit'; + /** * Query factory * @@ -27,16 +34,29 @@ class DataProvider implements DataProviderInterface */ protected $itemFactory; + /** + * Limit + * + * @var int + */ + protected $limit; + /** * @param QueryFactory $queryFactory * @param ItemFactory $itemFactory */ public function __construct( QueryFactory $queryFactory, - ItemFactory $itemFactory + ItemFactory $itemFactory, + ScopeConfig $scopeConfig ) { $this->queryFactory = $queryFactory; $this->itemFactory = $itemFactory; + + $this->limit = (int) $scopeConfig->getValue( + self::CONFIG_AUTOCOMPLETE_LIMIT, + ScopeInterface::SCOPE_STORE + ); } /** @@ -58,7 +78,7 @@ public function getItems() $result[] = $resultItem; } } - return $result; + return ($this->limit) ? array_splice($result, 0, $this->limit) : $result; } /** diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php index 708f8b9163a38..f276849804739 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/DataProvider.php @@ -6,10 +6,14 @@ namespace Magento\CatalogSearch\Model\Indexer\Fulltext\Action; use Magento\Catalog\Api\Data\ProductInterface; +use Magento\Catalog\Model\Product\Attribute\Source\Status; use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Select; +use Magento\Store\Model\Store; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyFields) * @api * @since 100.0.3 */ @@ -101,6 +105,23 @@ class DataProvider */ private $attributeOptions = []; + /** + * Cache searchable attributes by backend type + * + * @var array + */ + private $searchableAttributesByBackendType = []; + + /** + * Adjusts a size of filtered rows for searchable products. Filtered rows counts by the following condition: + * entity_id > X AND entity_id < X + BatchSize * antiGapMultiplier + * It will help in case a lot of gaps between entity_id in product table, when selected amount of products will be + * less than batch size + * + * @var int + */ + private $antiGapMultiplier; + /** * @param ResourceConnection $resource * @param \Magento\Catalog\Model\Product\Type $catalogProductType @@ -110,6 +131,7 @@ class DataProvider * @param \Magento\Framework\Event\ManagerInterface $eventManager * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool + * @param int $antiGapMultiplier */ public function __construct( ResourceConnection $resource, @@ -119,7 +141,8 @@ public function __construct( \Magento\CatalogSearch\Model\ResourceModel\EngineProvider $engineProvider, \Magento\Framework\Event\ManagerInterface $eventManager, \Magento\Store\Model\StoreManagerInterface $storeManager, - \Magento\Framework\EntityManager\MetadataPool $metadataPool + \Magento\Framework\EntityManager\MetadataPool $metadataPool, + int $antiGapMultiplier = 5 ) { $this->resource = $resource; $this->connection = $resource->getConnection(); @@ -130,6 +153,7 @@ public function __construct( $this->storeManager = $storeManager; $this->engine = $engineProvider->get(); $this->metadata = $metadataPool->getMetadata(ProductInterface::class); + $this->antiGapMultiplier = $antiGapMultiplier; } /** @@ -150,7 +174,7 @@ private function getTable($table) * @param array $staticFields * @param array|int $productIds * @param int $lastProductId - * @param int $limit + * @param int $batch * @return array * @since 100.0.3 */ @@ -159,9 +183,47 @@ public function getSearchableProducts( array $staticFields, $productIds = null, $lastProductId = 0, - $limit = 100 + $batch = 100 + ) { + + $select = $this->getSelectForSearchableProducts($storeId, $staticFields, $productIds, $lastProductId, $batch); + if ($productIds === null) { + $select->where( + 'e.entity_id < ?', + $lastProductId ? $this->antiGapMultiplier * $batch + $lastProductId + 1 : $batch + 1 + ); + } + $products = $this->connection->fetchAll($select); + if ($productIds === null && !$products) { + // try to search without limit entity_id by batch size for cover case with a big gap between entity ids + $products = $this->connection->fetchAll( + $this->getSelectForSearchableProducts($storeId, $staticFields, $productIds, $lastProductId, $batch) + ); + } + + return $products; + } + + /** + * Get Select object for searchable products + * + * @param int $storeId + * @param array $staticFields + * @param array|int $productIds + * @param int $lastProductId + * @param int $batch + * @return Select + */ + private function getSelectForSearchableProducts( + $storeId, + array $staticFields, + $productIds, + $lastProductId, + $batch ) { $websiteId = $this->storeManager->getStore($storeId)->getWebsiteId(); + $lastProductId = (int) $lastProductId; + $select = $this->connection->select() ->useStraightJoin(true) ->from( @@ -174,15 +236,65 @@ public function getSearchableProducts( [] ); + $this->joinAttribute($select, 'visibility', $storeId, $this->engine->getAllowedVisibility()); + $this->joinAttribute($select, 'status', $storeId, [Status::STATUS_ENABLED]); + if ($productIds !== null) { $select->where('e.entity_id IN (?)', $productIds); } + $select->where('e.entity_id > ?', $lastProductId); + $select->order('e.entity_id'); + $select->limit($batch); - $select->where('e.entity_id > ?', $lastProductId)->limit($limit)->order('e.entity_id'); + return $select; + } - $result = $this->connection->fetchAll($select); + /** + * Join attribute to searchable product for filtration + * + * @param Select $select + * @param string $attributeCode + * @param int $storeId + * @param array $whereValue + */ + private function joinAttribute(Select $select, $attributeCode, $storeId, array $whereValue) + { + $linkField = $this->metadata->getLinkField(); + $attribute = $this->getSearchableAttribute($attributeCode); + $attributeTable = $this->getTable('catalog_product_entity_' . $attribute->getBackendType()); + $defaultAlias = $attributeCode . '_default'; + $storeAlias = $attributeCode . '_store'; + + $whereCondition = $this->connection->getCheckSql( + $storeAlias . '.value_id > 0', + $storeAlias . '.value', + $defaultAlias . '.value' + ); - return $result; + $select->join( + [$defaultAlias => $attributeTable], + $this->connection->quoteInto( + $defaultAlias . '.' . $linkField . '= e.' . $linkField . ' AND ' . $defaultAlias . '.attribute_id = ?', + $attribute->getAttributeId() + ) . $this->connection->quoteInto( + ' AND ' . $defaultAlias . '.store_id = ?', + Store::DEFAULT_STORE_ID + ), + [] + )->joinLeft( + [$storeAlias => $attributeTable], + $this->connection->quoteInto( + $storeAlias . '.' . $linkField . '= e.' . $linkField . ' AND ' . $storeAlias . '.attribute_id = ?', + $attribute->getAttributeId() + ) . $this->connection->quoteInto( + ' AND ' . $storeAlias . '.store_id = ?', + $storeId + ), + [] + )->where( + $whereCondition . ' IN (?)', + $whereValue + ); } /** @@ -219,20 +331,23 @@ public function getSearchableAttributes($backendType = null) foreach ($attributes as $attribute) { $attribute->setEntity($entity); + $this->searchableAttributes[$attribute->getAttributeId()] = $attribute; + $this->searchableAttributes[$attribute->getAttributeCode()] = $attribute; } - - $this->searchableAttributes = $attributes; } if ($backendType !== null) { - $attributes = []; - foreach ($this->searchableAttributes as $attributeId => $attribute) { + if (isset($this->searchableAttributesByBackendType[$backendType])) { + return $this->searchableAttributesByBackendType[$backendType]; + } + $this->searchableAttributesByBackendType[$backendType] = []; + foreach ($this->searchableAttributes as $attribute) { if ($attribute->getBackendType() == $backendType) { - $attributes[$attributeId] = $attribute; + $this->searchableAttributesByBackendType[$backendType][$attribute->getAttributeId()] = $attribute; } } - return $attributes; + return $this->searchableAttributesByBackendType[$backendType]; } return $this->searchableAttributes; @@ -248,16 +363,8 @@ public function getSearchableAttributes($backendType = null) public function getSearchableAttribute($attribute) { $attributes = $this->getSearchableAttributes(); - if (is_numeric($attribute)) { - if (isset($attributes[$attribute])) { - return $attributes[$attribute]; - } - } elseif (is_string($attribute)) { - foreach ($attributes as $attributeModel) { - if ($attributeModel->getAttributeCode() == $attribute) { - return $attributeModel; - } - } + if (isset($attributes[$attribute])) { + return $attributes[$attribute]; } return $this->eavConfig->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attribute); @@ -333,7 +440,7 @@ public function getProductAttributes($storeId, array $productIds, array $attribu } if ($selects) { - $select = $this->connection->select()->union($selects, \Magento\Framework\DB\Select::SQL_UNION_ALL); + $select = $this->connection->select()->union($selects, Select::SQL_UNION_ALL); $query = $this->connection->query($select); while ($row = $query->fetch()) { $entityId = $productLinkFieldsToEntityIdMap[$row[$linkField]]; @@ -448,7 +555,6 @@ public function prepareProductIndex($indexData, $productData, $storeId) } } } - foreach ($indexData as $entityId => $attributeData) { foreach ($attributeData as $attributeId => $attributeValue) { $value = $this->getAttributeValue($attributeId, $attributeValue, $storeId); @@ -490,33 +596,58 @@ private function getAttributeValue($attributeId, $valueId, $storeId) { $attribute = $this->getSearchableAttribute($attributeId); $value = $this->engine->processAttributeValue($attribute, $valueId); + if (false !== $value) { + $optionValue = $this->getAttributeOptionValue($attributeId, $valueId, $storeId); + if (null === $optionValue) { + $value = $this->filterAttributeValue($value); + } else { + $value = implode($this->separator, array_filter([$value, $optionValue])); + } + } - if (false !== $value - && $attribute->getIsSearchable() - && $attribute->usesSource() - && $this->engine->allowAdvancedIndex() + return $value; + } + + /** + * Get attribute option value + * + * @param int $attributeId + * @param int $valueId + * @param int $storeId + * @return null|string + */ + private function getAttributeOptionValue($attributeId, $valueId, $storeId) + { + $optionKey = $attributeId . '-' . $storeId; + if (!array_key_exists($optionKey, $this->attributeOptions) ) { - if (!isset($this->attributeOptions[$attributeId][$storeId])) { + $attribute = $this->getSearchableAttribute($attributeId); + if ($this->engine->allowAdvancedIndex() + && $attribute->getIsSearchable() + && $attribute->usesSource() + ) { $attribute->setStoreId($storeId); $options = $attribute->getSource()->toOptionArray(); - $this->attributeOptions[$attributeId][$storeId] = array_combine( - array_column($options, 'value'), - array_column($options, 'label') - ); - } - - $valueText = ''; - if (isset($this->attributeOptions[$attributeId][$storeId][$valueId])) { - $valueText = $this->attributeOptions[$attributeId][$storeId][$valueId]; + $this->attributeOptions[$optionKey] = array_column($options, 'label', 'value'); + $this->attributeOptions[$optionKey] = array_map(function ($value) { + return $this->filterAttributeValue($value); + }, $this->attributeOptions[$optionKey]); + } else { + $this->attributeOptions[$optionKey] = null; } - - $pieces = array_filter(array_merge([$value], [$valueText])); - - $value = implode($this->separator, $pieces); } - $value = preg_replace('/\\s+/siu', ' ', trim(strip_tags($value))); + return $this->attributeOptions[$optionKey][$valueId] ?? null; + } - return $value; + /** + * Remove whitespaces and tags from attribute value + * + * @param string $value + * @return string + */ + private function filterAttributeValue($value) + { + return preg_replace('/\s+/iu', ' ', trim(strip_tags($value))); } } diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php index 639c0e8ca66f0..a8208404d0451 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php @@ -197,6 +197,13 @@ class Full */ private $dataProvider; + /** + * Batch size for searchable product ids + * + * @var int + */ + private $batchSize; + /** * @param ResourceConnection $resource * @param \Magento\Catalog\Model\Product\Type $catalogProductType @@ -218,6 +225,7 @@ class Full * @param \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\IndexIteratorFactory $indexIteratorFactory * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool * @param DataProvider $dataProvider + * @param int $batchSize * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -240,7 +248,8 @@ public function __construct( \Magento\Framework\Indexer\ConfigInterface $indexerConfig, \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\IndexIteratorFactory $indexIteratorFactory, \Magento\Framework\EntityManager\MetadataPool $metadataPool = null, - DataProvider $dataProvider = null + DataProvider $dataProvider = null, + $batchSize = 500 ) { $this->resource = $resource; $this->connection = $resource->getConnection(); @@ -264,6 +273,7 @@ public function __construct( $this->metadataPool = $metadataPool ?: ObjectManager::getInstance() ->get(\Magento\Framework\EntityManager\MetadataPool::class); $this->dataProvider = $dataProvider ?: ObjectManager::getInstance()->get(DataProvider::class); + $this->batchSize = $batchSize; } /** @@ -354,7 +364,7 @@ public function rebuildStoreIndex($storeId, $productIds = null) $lastProductId = 0; $products = $this->dataProvider - ->getSearchableProducts($storeId, $staticFields, $productIds, $lastProductId); + ->getSearchableProducts($storeId, $staticFields, $productIds, $lastProductId, $this->batchSize); while (count($products) > 0) { $productsIds = array_column($products, 'entity_id'); $relatedProducts = $this->getRelatedProducts($products); @@ -365,12 +375,6 @@ public function rebuildStoreIndex($storeId, $productIds = null) foreach ($products as $productData) { $lastProductId = $productData['entity_id']; - if (!$this->isProductVisible($productData['entity_id'], $productsAttributes) || - !$this->isProductEnabled($productData['entity_id'], $productsAttributes) - ) { - continue; - } - $productIndex = [$productData['entity_id'] => $productsAttributes[$productData['entity_id']]]; if (isset($relatedProducts[$productData['entity_id']])) { $childProductsIndex = $this->getChildProductsIndex( @@ -388,7 +392,7 @@ public function rebuildStoreIndex($storeId, $productIds = null) yield $productData['entity_id'] => $index; } $products = $this->dataProvider - ->getSearchableProducts($storeId, $staticFields, $productIds, $lastProductId); + ->getSearchableProducts($storeId, $staticFields, $productIds, $lastProductId, $this->batchSize); }; } @@ -412,25 +416,6 @@ private function getRelatedProducts($products) return array_filter($relatedProducts); } - /** - * Performs check that product is visible on Store Front - * - * Check that product is visible on Store Front using visibility attribute - * and allowed visibility values. - * - * @param int $productId - * @param array $productsAttributes - * @return bool - */ - private function isProductVisible($productId, array $productsAttributes) - { - $visibility = $this->dataProvider->getSearchableAttribute('visibility'); - $allowedVisibility = $this->engine->getAllowedVisibility(); - return isset($productsAttributes[$productId]) && - isset($productsAttributes[$productId][$visibility->getId()]) && - in_array($productsAttributes[$productId][$visibility->getId()], $allowedVisibility); - } - /** * Performs check that product is enabled on Store Front * @@ -445,8 +430,7 @@ private function isProductEnabled($productId, array $productsAttributes) { $status = $this->dataProvider->getSearchableAttribute('status'); $allowedStatuses = $this->catalogProductStatus->getVisibleStatusIds(); - return isset($productsAttributes[$productId]) && - isset($productsAttributes[$productId][$status->getId()]) && + return isset($productsAttributes[$productId][$status->getId()]) && in_array($productsAttributes[$productId][$status->getId()], $allowedStatuses); } diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandler.php b/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandler.php index ea5bb8be17c74..931d7571a9014 100644 --- a/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandler.php +++ b/app/code/Magento/CatalogSearch/Model/Indexer/IndexerHandler.php @@ -75,7 +75,7 @@ public function __construct( Batch $batch, IndexScopeResolverInterface $indexScopeResolver, array $data, - $batchSize = 100 + $batchSize = 500 ) { $this->indexScopeResolver = $indexScopeResolver; $this->indexStructure = $indexStructure; diff --git a/app/code/Magento/CatalogSearch/Model/ResourceModel/Engine.php b/app/code/Magento/CatalogSearch/Model/ResourceModel/Engine.php index 4212912af9930..ffba417eb3ac7 100644 --- a/app/code/Magento/CatalogSearch/Model/ResourceModel/Engine.php +++ b/app/code/Magento/CatalogSearch/Model/ResourceModel/Engine.php @@ -70,6 +70,13 @@ public function allowAdvancedIndex() return true; } + /** + * Is attribute filterable as term cache + * + * @var array + */ + private $termFilterableAttributeAttributeCache = []; + /** * Is Attribute Filterable as Term * @@ -78,10 +85,16 @@ public function allowAdvancedIndex() */ private function isTermFilterableAttribute($attribute) { - return ($attribute->getIsVisibleInAdvancedSearch() - || $attribute->getIsFilterable() - || $attribute->getIsFilterableInSearch()) - && in_array($attribute->getFrontendInput(), ['select', 'multiselect']); + $attributeId = $attribute->getAttributeId(); + if (!isset($this->termFilterableAttributeAttributeCache[$attributeId])) { + $this->termFilterableAttributeAttributeCache[$attributeId] = + in_array($attribute->getFrontendInput(), ['select', 'multiselect'], true) + && ($attribute->getIsVisibleInAdvancedSearch() + || $attribute->getIsFilterable() + || $attribute->getIsFilterableInSearch()); + } + + return $this->termFilterableAttributeAttributeCache[$attributeId]; } /** diff --git a/app/code/Magento/CatalogSearch/Setup/InstallData.php b/app/code/Magento/CatalogSearch/Setup/InstallData.php deleted file mode 100644 index 8a2754f1903c5..0000000000000 --- a/app/code/Magento/CatalogSearch/Setup/InstallData.php +++ /dev/null @@ -1,73 +0,0 @@ -indexerFactory = $indexerFactory; - $this->attributeRepository = $attributeRepository; - } - - /** - * Installs data for a module - * - * @param ModuleDataSetupInterface $setup - * @param ModuleContextInterface $context - * @return void - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $this->setWeight('sku', 6); - $this->setWeight('name', 5); - $this->getIndexer('catalogsearch_fulltext')->reindexAll(); - } - - /** - * @param string $indexerId - * @return \Magento\Framework\Indexer\IndexerInterface - */ - private function getIndexer($indexerId) - { - return $this->indexerFactory->create()->load($indexerId); - } - - /** - * @param string $attributeCode - * @param int $weight - * @return void - */ - private function setWeight($attributeCode, $weight) - { - $attribute = $this->attributeRepository->get($attributeCode); - $attribute->setSearchWeight($weight); - $this->attributeRepository->save($attribute); - } -} diff --git a/app/code/Magento/CatalogSearch/Setup/Patch/Data/SetInitialSearchWeightForAttributes.php b/app/code/Magento/CatalogSearch/Setup/Patch/Data/SetInitialSearchWeightForAttributes.php new file mode 100644 index 0000000000000..e266e67804e88 --- /dev/null +++ b/app/code/Magento/CatalogSearch/Setup/Patch/Data/SetInitialSearchWeightForAttributes.php @@ -0,0 +1,88 @@ +indexerFactory = $indexerFactory; + $this->attributeRepository = $attributeRepository; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->setWeight('sku', 6); + $this->setWeight('name', 5); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Set attribute search weight. + * + * @param $attributeCode + * @param $weight + */ + private function setWeight($attributeCode, $weight) + { + $attribute = $this->attributeRepository->get($attributeCode); + $attribute->setSearchWeight($weight); + $this->attributeRepository->save($attribute); + } +} diff --git a/app/code/Magento/CatalogSearch/Setup/RecurringData.php b/app/code/Magento/CatalogSearch/Setup/RecurringData.php new file mode 100644 index 0000000000000..0c2aee800b6f1 --- /dev/null +++ b/app/code/Magento/CatalogSearch/Setup/RecurringData.php @@ -0,0 +1,62 @@ +indexerInterfaceFactory = $indexerInterfaceFactory; + $this->state = $state; + } + + /** + * {@inheritdoc} + */ + public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $this->state->emulateAreaCode( + \Magento\Framework\App\Area::AREA_CRONTAB, + [$this, 'reindex'] + ); + } + + /** + * Run reindex. + * + * @return void + */ + public function reindex() + { + $this->indexerInterfaceFactory->create()->load('catalogsearch_fulltext')->reindexAll(); + } +} diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Autocomplete/DataProviderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Autocomplete/DataProviderTest.php index 75daf438f7bf2..bb8fc848bb2b7 100644 --- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Autocomplete/DataProviderTest.php +++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Autocomplete/DataProviderTest.php @@ -30,6 +30,11 @@ class DataProviderTest extends \PHPUnit\Framework\TestCase */ private $suggestCollection; + /** + * @var integer + */ + private $limit = 3; + protected function setUp() { $helper = new ObjectManager($this); @@ -60,11 +65,20 @@ protected function setUp() ->setMethods(['create']) ->getMock(); + $scopeConfig = $this->getMockBuilder(\Magento\Framework\App\Config\ScopeConfigInterface::class) + ->setMethods(['getValue']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $scopeConfig->expects($this->any()) + ->method('getValue') + ->willReturn($this->limit); + $this->model = $helper->getObject( \Magento\CatalogSearch\Model\Autocomplete\DataProvider::class, [ 'queryFactory' => $queryFactory, - 'itemFactory' => $this->itemFactory + 'itemFactory' => $this->itemFactory, + 'scopeConfig' => $scopeConfig ] ); } @@ -103,8 +117,10 @@ public function testGetItems() ->will($this->returnValue($expected)); $this->itemFactory->expects($this->any())->method('create')->willReturn($itemMock); + $result = $this->model->getItems(); $this->assertEquals($expected, $result[0]->toArray()); + $this->assertEquals($this->limit, count($result)); } private function buildCollection(array $data) diff --git a/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml b/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml index f5ebd3c6c9dc4..18d2cdf542799 100644 --- a/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml +++ b/app/code/Magento/CatalogSearch/etc/adminhtml/system.xml @@ -32,6 +32,10 @@ Number of popular search terms to be cached for faster response. Use “0” to cache all results after a term is searched for the second time. validate-digits + + + validate-digits + diff --git a/app/code/Magento/CatalogSearch/etc/config.xml b/app/code/Magento/CatalogSearch/etc/config.xml index 9fb0118701d10..d2b50fe9f5336 100644 --- a/app/code/Magento/CatalogSearch/etc/config.xml +++ b/app/code/Magento/CatalogSearch/etc/config.xml @@ -16,6 +16,7 @@ 1 128 100 + 8 diff --git a/app/code/Magento/CatalogSearch/etc/db_schema.xml b/app/code/Magento/CatalogSearch/etc/db_schema.xml index 2f6c0ba2b72b7..ae9217b0632a7 100644 --- a/app/code/Magento/CatalogSearch/etc/db_schema.xml +++ b/app/code/Magento/CatalogSearch/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/CatalogSearch/etc/module.xml b/app/code/Magento/CatalogSearch/etc/module.xml index fd31faa083926..db530edbdd7ef 100644 --- a/app/code/Magento/CatalogSearch/etc/module.xml +++ b/app/code/Magento/CatalogSearch/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/CatalogUrlRewrite/Setup/InstallData.php b/app/code/Magento/CatalogUrlRewrite/Setup/InstallData.php deleted file mode 100644 index bbc5f497843b0..0000000000000 --- a/app/code/Magento/CatalogUrlRewrite/Setup/InstallData.php +++ /dev/null @@ -1,101 +0,0 @@ -eavSetupFactory = $eavSetupFactory; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - $eavSetup->addAttribute( - \Magento\Catalog\Model\Category::ENTITY, - 'url_key', - [ - 'type' => 'varchar', - 'label' => 'URL Key', - 'input' => 'text', - 'required' => false, - 'sort_order' => 3, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, - 'group' => 'General Information', - ] - ); - - $eavSetup->addAttribute( - \Magento\Catalog\Model\Category::ENTITY, - 'url_path', - [ - 'type' => 'varchar', - 'required' => false, - 'sort_order' => 17, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, - 'visible' => false, - 'group' => 'General Information', - ] - ); - - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'url_key', - [ - 'type' => 'varchar', - 'label' => 'URL Key', - 'input' => 'text', - 'required' => false, - 'sort_order' => 10, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, - 'used_in_product_listing' => true, - 'group' => 'Search Engine Optimization', - 'is_used_in_grid' => true, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => true, - ] - ); - - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'url_path', - [ - 'type' => 'varchar', - 'required' => false, - 'sort_order' => 11, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, - 'visible' => false, - ] - ); - } -} diff --git a/app/code/Magento/CatalogUrlRewrite/Setup/Patch/Data/CreateUrlAttributes.php b/app/code/Magento/CatalogUrlRewrite/Setup/Patch/Data/CreateUrlAttributes.php new file mode 100644 index 0000000000000..22e87174e1f11 --- /dev/null +++ b/app/code/Magento/CatalogUrlRewrite/Setup/Patch/Data/CreateUrlAttributes.php @@ -0,0 +1,131 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + $eavSetup->addAttribute( + \Magento\Catalog\Model\Category::ENTITY, + 'url_key', + [ + 'type' => 'varchar', + 'label' => 'URL Key', + 'input' => 'text', + 'required' => false, + 'sort_order' => 3, + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'group' => 'General Information', + ] + ); + + $eavSetup->addAttribute( + \Magento\Catalog\Model\Category::ENTITY, + 'url_path', + [ + 'type' => 'varchar', + 'required' => false, + 'sort_order' => 17, + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'visible' => false, + 'group' => 'General Information', + ] + ); + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'url_key', + [ + 'type' => 'varchar', + 'label' => 'URL Key', + 'input' => 'text', + 'required' => false, + 'sort_order' => 10, + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'used_in_product_listing' => true, + 'group' => 'Search Engine Optimization', + 'is_used_in_grid' => true, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => true, + ] + ); + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'url_path', + [ + 'type' => 'varchar', + 'required' => false, + 'sort_order' => 11, + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'visible' => false, + ] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/CatalogUrlRewrite/etc/db_schema.xml b/app/code/Magento/CatalogUrlRewrite/etc/db_schema.xml index bb83af6a75c97..174173fa2019f 100644 --- a/app/code/Magento/CatalogUrlRewrite/etc/db_schema.xml +++ b/app/code/Magento/CatalogUrlRewrite/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
- + diff --git a/app/code/Magento/CatalogUrlRewriteGraphQl/etc/module.xml b/app/code/Magento/CatalogUrlRewriteGraphQl/etc/module.xml index d17a3cdb45c76..be4bb9fcd7010 100644 --- a/app/code/Magento/CatalogUrlRewriteGraphQl/etc/module.xml +++ b/app/code/Magento/CatalogUrlRewriteGraphQl/etc/module.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/app/code/Magento/CatalogWidget/etc/module.xml b/app/code/Magento/CatalogWidget/etc/module.xml index 8954f11f954f7..b3724d4b91f79 100644 --- a/app/code/Magento/CatalogWidget/etc/module.xml +++ b/app/code/Magento/CatalogWidget/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Checkout/Block/Cart/Shipping.php b/app/code/Magento/Checkout/Block/Cart/Shipping.php index 7b0ab1bc03e5b..c52b7fe18814f 100644 --- a/app/code/Magento/Checkout/Block/Cart/Shipping.php +++ b/app/code/Magento/Checkout/Block/Cart/Shipping.php @@ -74,7 +74,8 @@ public function getJsLayout() foreach ($this->layoutProcessors as $processor) { $this->jsLayout = $processor->process($this->jsLayout); } - return $this->serializer->serialize($this->jsLayout); + + return json_encode($this->jsLayout, JSON_HEX_TAG); } /** @@ -94,6 +95,6 @@ public function getBaseUrl() */ public function getSerializedCheckoutConfig() { - return $this->serializer->serialize($this->getCheckoutConfig()); + return json_encode($this->getCheckoutConfig(), JSON_HEX_TAG); } } diff --git a/app/code/Magento/Checkout/Block/Cart/Totals.php b/app/code/Magento/Checkout/Block/Cart/Totals.php index d3d3adbe40f38..375c564f29059 100644 --- a/app/code/Magento/Checkout/Block/Cart/Totals.php +++ b/app/code/Magento/Checkout/Block/Cart/Totals.php @@ -69,7 +69,8 @@ public function getJsLayout() foreach ($this->layoutProcessors as $processor) { $this->jsLayout = $processor->process($this->jsLayout); } - return parent::getJsLayout(); + + return json_encode($this->jsLayout, JSON_HEX_TAG); } /** diff --git a/app/code/Magento/Checkout/Block/Onepage.php b/app/code/Magento/Checkout/Block/Onepage.php index bc3cd43a024a6..ca6b045ddbb5d 100644 --- a/app/code/Magento/Checkout/Block/Onepage.php +++ b/app/code/Magento/Checkout/Block/Onepage.php @@ -77,7 +77,8 @@ public function getJsLayout() foreach ($this->layoutProcessors as $processor) { $this->jsLayout = $processor->process($this->jsLayout); } - return $this->serializer->serialize($this->jsLayout); + + return json_encode($this->jsLayout, JSON_HEX_TAG); } /** @@ -119,6 +120,6 @@ public function getBaseUrl() */ public function getSerializedCheckoutConfig() { - return $this->serializer->serialize($this->getCheckoutConfig()); + return json_encode($this->getCheckoutConfig(), JSON_HEX_TAG); } } diff --git a/app/code/Magento/Checkout/CustomerData/DefaultItem.php b/app/code/Magento/Checkout/CustomerData/DefaultItem.php index 6e917366c9cd2..9351685405a60 100644 --- a/app/code/Magento/Checkout/CustomerData/DefaultItem.php +++ b/app/code/Magento/Checkout/CustomerData/DefaultItem.php @@ -6,6 +6,8 @@ namespace Magento\Checkout\CustomerData; +use Magento\Framework\App\ObjectManager; + /** * Default item */ @@ -36,12 +38,20 @@ class DefaultItem extends AbstractItem */ protected $checkoutHelper; + /** + * Escaper + * + * @var \Magento\Framework\Escaper + */ + private $escaper; + /** * @param \Magento\Catalog\Helper\Image $imageHelper * @param \Magento\Msrp\Helper\Data $msrpHelper * @param \Magento\Framework\UrlInterface $urlBuilder * @param \Magento\Catalog\Helper\Product\ConfigurationPool $configurationPool * @param \Magento\Checkout\Helper\Data $checkoutHelper + * @param \Magento\Framework\Escaper|null $escaper * @codeCoverageIgnore */ public function __construct( @@ -49,13 +59,15 @@ public function __construct( \Magento\Msrp\Helper\Data $msrpHelper, \Magento\Framework\UrlInterface $urlBuilder, \Magento\Catalog\Helper\Product\ConfigurationPool $configurationPool, - \Magento\Checkout\Helper\Data $checkoutHelper + \Magento\Checkout\Helper\Data $checkoutHelper, + \Magento\Framework\Escaper $escaper = null ) { $this->configurationPool = $configurationPool; $this->imageHelper = $imageHelper; $this->msrpHelper = $msrpHelper; $this->urlBuilder = $urlBuilder; $this->checkoutHelper = $checkoutHelper; + $this->escaper = $escaper ?: ObjectManager::getInstance()->get(\Magento\Framework\Escaper::class); } /** @@ -64,6 +76,8 @@ public function __construct( protected function doGetItemData() { $imageHelper = $this->imageHelper->init($this->getProductForThumbnail(), 'mini_cart_product_thumbnail'); + $productName = $this->escaper->escapeHtml($this->item->getProduct()->getName()); + return [ 'options' => $this->getOptionList(), 'qty' => $this->item->getQty() * 1, @@ -71,7 +85,7 @@ protected function doGetItemData() 'configure_url' => $this->getConfigureUrl(), 'is_visible_in_site_visibility' => $this->item->getProduct()->isVisibleInSiteVisibility(), 'product_id' => $this->item->getProduct()->getId(), - 'product_name' => $this->item->getProduct()->getName(), + 'product_name' => $productName, 'product_sku' => $this->item->getProduct()->getSku(), 'product_url' => $this->getProductUrl(), 'product_has_url' => $this->hasProductUrl(), diff --git a/app/code/Magento/Checkout/Setup/InstallData.php b/app/code/Magento/Checkout/Setup/InstallData.php deleted file mode 100644 index 38879e06d65ac..0000000000000 --- a/app/code/Magento/Checkout/Setup/InstallData.php +++ /dev/null @@ -1,826 +0,0 @@ -eavSetupFactory = $eavSetupFactory; - $this->customerAddress = $customerAddress; - } - - /** - * {@inheritdoc} - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - - $setup->startSetup(); - - $connection = $setup->getConnection(); - - $select = $connection->select()->from( - $setup->getTable('core_config_data'), - 'COUNT(*)' - )->where( - 'path=?', - 'customer/address/prefix_show' - )->where( - 'value NOT LIKE ?', - '0' - ); - $showPrefix = (bool)$this->customerAddress->getConfig('prefix_show') - || $connection->fetchOne($select) > 0; - - $select = $connection->select()->from( - $setup->getTable('core_config_data'), - 'COUNT(*)' - )->where( - 'path=?', - 'customer/address/middlename_show' - )->where( - 'value NOT LIKE ?', - '0' - ); - $showMiddlename = (bool)$this->customerAddress->getConfig( - 'middlename_show' - ) || $connection->fetchOne( - $select - ) > 0; - - $select = $connection->select()->from( - $setup->getTable('core_config_data'), - 'COUNT(*)' - )->where( - 'path=?', - 'customer/address/suffix_show' - )->where( - 'value NOT LIKE ?', - '0' - ); - $showSuffix = (bool)$this->customerAddress->getConfig('suffix_show') - || $connection->fetchOne($select) > 0; - - $select = $connection->select()->from( - $setup->getTable('core_config_data'), - 'COUNT(*)' - )->where( - 'path=?', - 'customer/address/dob_show' - )->where( - 'value NOT LIKE ?', - '0' - ); - $showDob = (bool)$this->customerAddress->getConfig('dob_show') - || $connection->fetchOne($select) > 0; - - $select = $connection->select()->from( - $setup->getTable('core_config_data'), - 'COUNT(*)' - )->where( - 'path=?', - 'customer/address/taxvat_show' - )->where( - 'value NOT LIKE ?', - '0' - ); - $showTaxVat = (bool)$this->customerAddress->getConfig('taxvat_show') - || $connection->fetchOne($select) > 0; - - $customerEntityTypeId = $eavSetup->getEntityTypeId('customer'); - $addressEntityTypeId = $eavSetup->getEntityTypeId('customer_address'); - - /** - ***************************************************************************** - * checkout/onepage/register - ***************************************************************************** - */ - - $connection->insert( - $setup->getTable('eav_form_type'), - [ - 'code' => 'checkout_onepage_register', - 'label' => 'checkout_onepage_register', - 'is_system' => 1, - 'theme' => '', - 'store_id' => 0 - ] - ); - $formTypeId = $connection->lastInsertId($setup->getTable('eav_form_type')); - - $connection->insert( - $setup->getTable('eav_form_type_entity'), - ['type_id' => $formTypeId, 'entity_type_id' => $customerEntityTypeId] - ); - $connection->insert( - $setup->getTable('eav_form_type_entity'), - ['type_id' => $formTypeId, 'entity_type_id' => $addressEntityTypeId] - ); - - $elementSort = 0; - if ($showPrefix) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'prefix'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'firstname'), - 'sort_order' => $elementSort++ - ] - ); - if ($showMiddlename) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'middlename'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'lastname'), - 'sort_order' => $elementSort++ - ] - ); - if ($showSuffix) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'suffix'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'company'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'email'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'street'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'city'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'region'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'postcode'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'country_id'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'telephone'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'fax'), - 'sort_order' => $elementSort++ - ] - ); - if ($showDob) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'dob'), - 'sort_order' => $elementSort++ - ] - ); - } - if ($showTaxVat) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'taxvat'), - 'sort_order' => $elementSort++ - ] - ); - } - - /** - ***************************************************************************** - * checkout/onepage/register_guest - ***************************************************************************** - */ - - $connection->insert( - $setup->getTable('eav_form_type'), - [ - 'code' => 'checkout_onepage_register_guest', - 'label' => 'checkout_onepage_register_guest', - 'is_system' => 1, - 'theme' => '', - 'store_id' => 0 - ] - ); - $formTypeId = $connection->lastInsertId($setup->getTable('eav_form_type')); - - $connection->insert( - $setup->getTable('eav_form_type_entity'), - ['type_id' => $formTypeId, 'entity_type_id' => $customerEntityTypeId] - ); - $connection->insert( - $setup->getTable('eav_form_type_entity'), - ['type_id' => $formTypeId, 'entity_type_id' => $addressEntityTypeId] - ); - - $elementSort = 0; - if ($showPrefix) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'prefix'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'firstname'), - 'sort_order' => $elementSort++ - ] - ); - if ($showMiddlename) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'middlename'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'lastname'), - 'sort_order' => $elementSort++ - ] - ); - if ($showSuffix) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'suffix'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'company'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'email'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'street'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'city'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'region'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'postcode'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'country_id'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'telephone'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'fax'), - 'sort_order' => $elementSort++ - ] - ); - if ($showDob) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'dob'), - 'sort_order' => $elementSort++ - ] - ); - } - if ($showTaxVat) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'taxvat'), - 'sort_order' => $elementSort++ - ] - ); - } - - /** - ***************************************************************************** - * checkout/onepage/billing_address - ***************************************************************************** - */ - - $connection->insert( - $setup->getTable('eav_form_type'), - [ - 'code' => 'checkout_onepage_billing_address', - 'label' => 'checkout_onepage_billing_address', - 'is_system' => 1, - 'theme' => '', - 'store_id' => 0 - ] - ); - $formTypeId = $connection->lastInsertId($setup->getTable('eav_form_type')); - - $connection->insert( - $setup->getTable('eav_form_type_entity'), - ['type_id' => $formTypeId, 'entity_type_id' => $addressEntityTypeId] - ); - - $elementSort = 0; - if ($showPrefix) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'prefix'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'firstname'), - 'sort_order' => $elementSort++ - ] - ); - if ($showMiddlename) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'middlename'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'lastname'), - 'sort_order' => $elementSort++ - ] - ); - if ($showSuffix) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'suffix'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'company'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'street'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'city'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'region'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'postcode'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'country_id'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'telephone'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'fax'), - 'sort_order' => $elementSort++ - ] - ); - - /** - ***************************************************************************** - * checkout/onepage/shipping_address - ***************************************************************************** - */ - - $connection->insert( - $setup->getTable('eav_form_type'), - [ - 'code' => 'checkout_onepage_shipping_address', - 'label' => 'checkout_onepage_shipping_address', - 'is_system' => 1, - 'theme' => '', - 'store_id' => 0 - ] - ); - $formTypeId = $connection->lastInsertId($setup->getTable('eav_form_type')); - - $connection->insert( - $setup->getTable('eav_form_type_entity'), - ['type_id' => $formTypeId, 'entity_type_id' => $addressEntityTypeId] - ); - - $elementSort = 0; - if ($showPrefix) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'prefix'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'firstname'), - 'sort_order' => $elementSort++ - ] - ); - if ($showMiddlename) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'middlename'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'lastname'), - 'sort_order' => $elementSort++ - ] - ); - if ($showSuffix) { - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'suffix'), - 'sort_order' => $elementSort++ - ] - ); - } - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'company'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'street'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'city'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'region'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'postcode'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'country_id'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'telephone'), - 'sort_order' => $elementSort++ - ] - ); - $connection->insert( - $setup->getTable('eav_form_element'), - [ - 'type_id' => $formTypeId, - 'fieldset_id' => null, - 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'fax'), - 'sort_order' => $elementSort++ - ] - ); - - $table = $setup->getTable('core_config_data'); - - $select = $connection->select()->from( - $table, - ['config_id', 'value'] - )->where( - 'path = ?', - 'checkout/options/onepage_checkout_disabled' - ); - - $data = $connection->fetchAll($select); - - if ($data) { - try { - $connection->beginTransaction(); - - foreach ($data as $value) { - $bind = ['path' => 'checkout/options/onepage_checkout_enabled', 'value' => !(bool)$value['value']]; - $where = 'config_id = ' . $value['config_id']; - $connection->update($table, $bind, $where); - } - - $connection->commit(); - } catch (\Exception $e) { - $connection->rollback(); - throw $e; - } - } - - $setup->endSetup(); - } -} diff --git a/app/code/Magento/Checkout/Setup/Patch/Data/PrepareInitialCheckoutConfiguration.php b/app/code/Magento/Checkout/Setup/Patch/Data/PrepareInitialCheckoutConfiguration.php new file mode 100644 index 0000000000000..bc38809d070b2 --- /dev/null +++ b/app/code/Magento/Checkout/Setup/Patch/Data/PrepareInitialCheckoutConfiguration.php @@ -0,0 +1,851 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + $this->customerAddress = $customerAddress; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function apply() + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + + $this->moduleDataSetup->getConnection()->startSetup(); + + $connection = $this->moduleDataSetup->getConnection(); + + $select = $connection->select()->from( + $this->moduleDataSetup->getTable('core_config_data'), + 'COUNT(*)' + )->where( + 'path=?', + 'customer/address/prefix_show' + )->where( + 'value NOT LIKE ?', + '0' + ); + $showPrefix = (bool)$this->customerAddress->getConfig('prefix_show') + || $connection->fetchOne($select) > 0; + + $select = $connection->select()->from( + $this->moduleDataSetup->getTable('core_config_data'), + 'COUNT(*)' + )->where( + 'path=?', + 'customer/address/middlename_show' + )->where( + 'value NOT LIKE ?', + '0' + ); + $showMiddlename = (bool)$this->customerAddress->getConfig('middlename_show') + || $connection->fetchOne($select) > 0; + + $select = $connection->select()->from( + $this->moduleDataSetup->getTable('core_config_data'), + 'COUNT(*)' + )->where( + 'path=?', + 'customer/address/suffix_show' + )->where( + 'value NOT LIKE ?', + '0' + ); + $showSuffix = (bool)$this->customerAddress->getConfig('suffix_show') + || $connection->fetchOne($select) > 0; + + $select = $connection->select()->from( + $this->moduleDataSetup->getTable('core_config_data'), + 'COUNT(*)' + )->where( + 'path=?', + 'customer/address/dob_show' + )->where( + 'value NOT LIKE ?', + '0' + ); + $showDob = (bool)$this->customerAddress->getConfig('dob_show') + || $connection->fetchOne($select) > 0; + + $select = $connection->select()->from( + $this->moduleDataSetup->getTable('core_config_data'), + 'COUNT(*)' + )->where( + 'path=?', + 'customer/address/taxvat_show' + )->where( + 'value NOT LIKE ?', + '0' + ); + $showTaxVat = (bool)$this->customerAddress->getConfig('taxvat_show') + || $connection->fetchOne($select) > 0; + + $customerEntityTypeId = $eavSetup->getEntityTypeId('customer'); + $addressEntityTypeId = $eavSetup->getEntityTypeId('customer_address'); + + /** + ***************************************************************************** + * checkout/onepage/register + ***************************************************************************** + */ + + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_type'), + [ + 'code' => 'checkout_onepage_register', + 'label' => 'checkout_onepage_register', + 'is_system' => 1, + 'theme' => '', + 'store_id' => 0 + ] + ); + $formTypeId = $connection->lastInsertId($this->moduleDataSetup->getTable('eav_form_type')); + + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_type_entity'), + ['type_id' => $formTypeId, 'entity_type_id' => $customerEntityTypeId] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_type_entity'), + ['type_id' => $formTypeId, 'entity_type_id' => $addressEntityTypeId] + ); + + $elementSort = 0; + if ($showPrefix) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'prefix'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'firstname'), + 'sort_order' => $elementSort++ + ] + ); + if ($showMiddlename) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'middlename'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'lastname'), + 'sort_order' => $elementSort++ + ] + ); + if ($showSuffix) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'suffix'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'company'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'email'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'street'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'city'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'region'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'postcode'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'country_id'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'telephone'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'fax'), + 'sort_order' => $elementSort++ + ] + ); + if ($showDob) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'dob'), + 'sort_order' => $elementSort++ + ] + ); + } + if ($showTaxVat) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'taxvat'), + 'sort_order' => $elementSort++ + ] + ); + } + + /** + ***************************************************************************** + * checkout/onepage/register_guest + ***************************************************************************** + */ + + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_type'), + [ + 'code' => 'checkout_onepage_register_guest', + 'label' => 'checkout_onepage_register_guest', + 'is_system' => 1, + 'theme' => '', + 'store_id' => 0 + ] + ); + $formTypeId = $connection->lastInsertId($this->moduleDataSetup->getTable('eav_form_type')); + + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_type_entity'), + ['type_id' => $formTypeId, 'entity_type_id' => $customerEntityTypeId] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_type_entity'), + ['type_id' => $formTypeId, 'entity_type_id' => $addressEntityTypeId] + ); + + $elementSort = 0; + if ($showPrefix) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'prefix'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'firstname'), + 'sort_order' => $elementSort++ + ] + ); + if ($showMiddlename) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'middlename'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'lastname'), + 'sort_order' => $elementSort++ + ] + ); + if ($showSuffix) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'suffix'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'company'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'email'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'street'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'city'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'region'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'postcode'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'country_id'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'telephone'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'fax'), + 'sort_order' => $elementSort++ + ] + ); + if ($showDob) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'dob'), + 'sort_order' => $elementSort++ + ] + ); + } + if ($showTaxVat) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($customerEntityTypeId, 'taxvat'), + 'sort_order' => $elementSort++ + ] + ); + } + + /** + ***************************************************************************** + * checkout/onepage/billing_address + ***************************************************************************** + */ + + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_type'), + [ + 'code' => 'checkout_onepage_billing_address', + 'label' => 'checkout_onepage_billing_address', + 'is_system' => 1, + 'theme' => '', + 'store_id' => 0 + ] + ); + $formTypeId = $connection->lastInsertId($this->moduleDataSetup->getTable('eav_form_type')); + + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_type_entity'), + ['type_id' => $formTypeId, 'entity_type_id' => $addressEntityTypeId] + ); + + $elementSort = 0; + if ($showPrefix) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'prefix'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'firstname'), + 'sort_order' => $elementSort++ + ] + ); + if ($showMiddlename) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'middlename'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'lastname'), + 'sort_order' => $elementSort++ + ] + ); + if ($showSuffix) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'suffix'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'company'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'street'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'city'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'region'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'postcode'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'country_id'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'telephone'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'fax'), + 'sort_order' => $elementSort++ + ] + ); + + /** + ***************************************************************************** + * checkout/onepage/shipping_address + ***************************************************************************** + */ + + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_type'), + [ + 'code' => 'checkout_onepage_shipping_address', + 'label' => 'checkout_onepage_shipping_address', + 'is_system' => 1, + 'theme' => '', + 'store_id' => 0 + ] + ); + $formTypeId = $connection->lastInsertId($this->moduleDataSetup->getTable('eav_form_type')); + + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_type_entity'), + ['type_id' => $formTypeId, 'entity_type_id' => $addressEntityTypeId] + ); + + $elementSort = 0; + if ($showPrefix) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'prefix'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'firstname'), + 'sort_order' => $elementSort++ + ] + ); + if ($showMiddlename) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'middlename'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'lastname'), + 'sort_order' => $elementSort++ + ] + ); + if ($showSuffix) { + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'suffix'), + 'sort_order' => $elementSort++ + ] + ); + } + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'company'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'street'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'city'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'region'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'postcode'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'country_id'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'telephone'), + 'sort_order' => $elementSort++ + ] + ); + $connection->insert( + $this->moduleDataSetup->getTable('eav_form_element'), + [ + 'type_id' => $formTypeId, + 'fieldset_id' => null, + 'attribute_id' => $eavSetup->getAttributeId($addressEntityTypeId, 'fax'), + 'sort_order' => $elementSort++ + ] + ); + + $table = $this->moduleDataSetup->getTable('core_config_data'); + + $select = $connection->select()->from( + $table, + ['config_id', 'value'] + )->where( + 'path = ?', + 'checkout/options/onepage_checkout_disabled' + ); + + $data = $connection->fetchAll($select); + + if ($data) { + try { + $connection->beginTransaction(); + + foreach ($data as $value) { + $bind = ['path' => 'checkout/options/onepage_checkout_enabled', 'value' => !(bool)$value['value']]; + $where = 'config_id = ' . $value['config_id']; + $connection->update($table, $bind, $where); + } + + $connection->commit(); + } catch (\Exception $e) { + $connection->rollback(); + throw $e; + } + } + + $connection->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Checkout/Test/Unit/Block/Cart/ShippingTest.php b/app/code/Magento/Checkout/Test/Unit/Block/Cart/ShippingTest.php index e419a1535207e..302188224b97a 100644 --- a/app/code/Magento/Checkout/Test/Unit/Block/Cart/ShippingTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Block/Cart/ShippingTest.php @@ -99,9 +99,6 @@ public function testGetJsLayout() ->with($this->layout) ->willReturn($layoutProcessed); - $this->serializer->expects($this->once())->method('serialize')->will( - $this->returnValue($jsonLayoutProcessed) - ); $this->assertEquals( $jsonLayoutProcessed, $this->model->getJsLayout() @@ -121,9 +118,6 @@ public function testGetSerializedCheckoutConfig() { $checkoutConfig = ['checkout', 'config']; $this->configProvider->expects($this->once())->method('getConfig')->willReturn($checkoutConfig); - $this->serializer->expects($this->once())->method('serialize')->will( - $this->returnValue(json_encode($checkoutConfig)) - ); $this->assertEquals(json_encode($checkoutConfig), $this->model->getSerializedCheckoutConfig()); } diff --git a/app/code/Magento/Checkout/Test/Unit/Block/OnepageTest.php b/app/code/Magento/Checkout/Test/Unit/Block/OnepageTest.php index e47fac06d8057..54f77c95148ac 100644 --- a/app/code/Magento/Checkout/Test/Unit/Block/OnepageTest.php +++ b/app/code/Magento/Checkout/Test/Unit/Block/OnepageTest.php @@ -93,9 +93,6 @@ public function testGetJsLayout() $processedLayout = ['layout' => ['processed' => true]]; $jsonLayout = '{"layout":{"processed":true}}'; $this->layoutProcessorMock->expects($this->once())->method('process')->with([])->willReturn($processedLayout); - $this->serializer->expects($this->once())->method('serialize')->will( - $this->returnValue(json_encode($processedLayout)) - ); $this->assertEquals($jsonLayout, $this->model->getJsLayout()); } @@ -104,9 +101,6 @@ public function testGetSerializedCheckoutConfig() { $checkoutConfig = ['checkout', 'config']; $this->configProviderMock->expects($this->once())->method('getConfig')->willReturn($checkoutConfig); - $this->serializer->expects($this->once())->method('serialize')->will( - $this->returnValue(json_encode($checkoutConfig)) - ); $this->assertEquals(json_encode($checkoutConfig), $this->model->getSerializedCheckoutConfig()); } diff --git a/app/code/Magento/Checkout/etc/module.xml b/app/code/Magento/Checkout/etc/module.xml index 219ca87337fc9..153de5ef2a790 100644 --- a/app/code/Magento/Checkout/etc/module.xml +++ b/app/code/Magento/Checkout/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml index 02c969f849074..0567c61f0db60 100644 --- a/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml +++ b/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml @@ -90,7 +90,7 @@ $canApplyMsrp = $helper->isShowBeforeOrderConfirm($product) && $helper->isMinima
- + diff --git a/app/code/Magento/CheckoutAgreements/etc/db_schema.xml b/app/code/Magento/CheckoutAgreements/etc/db_schema.xml index 41bd8dffb4b34..31b3111df98eb 100644 --- a/app/code/Magento/CheckoutAgreements/etc/db_schema.xml +++ b/app/code/Magento/CheckoutAgreements/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/CheckoutAgreements/etc/module.xml b/app/code/Magento/CheckoutAgreements/etc/module.xml index 42a373eaad429..1ea97b556be67 100644 --- a/app/code/Magento/CheckoutAgreements/etc/module.xml +++ b/app/code/Magento/CheckoutAgreements/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Content.php b/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Content.php index f1e1b3797d8d3..44c2f3ca2f8c4 100644 --- a/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Content.php +++ b/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Content.php @@ -92,7 +92,10 @@ protected function _construct() */ public function getContentsUrl() { - return $this->getUrl('cms/*/contents', ['type' => $this->getRequest()->getParam('type')]); + return $this->getUrl('cms/*/contents', [ + 'type' => $this->getRequest()->getParam('type'), + 'use_storage_root' => (int) $this->getRequest()->getParam('use_storage_root'), + ]); } /** @@ -140,7 +143,9 @@ public function getNewfolderUrl() */ protected function getDeletefolderUrl() { - return $this->getUrl('cms/*/deleteFolder'); + return $this->getUrl('cms/*/deleteFolder', [ + 'use_storage_root' => (int) $this->getRequest()->getParam('use_storage_root'), + ]); } /** @@ -160,7 +165,9 @@ public function getDeleteFilesUrl() */ public function getOnInsertUrl() { - return $this->getUrl('cms/*/onInsert'); + return $this->getUrl('cms/*/onInsert', [ + 'use_storage_root' => (int) $this->getRequest()->getParam('use_storage_root'), + ]); } /** diff --git a/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php b/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php index 5471bbfb8b0f3..7bed7cee308f5 100644 --- a/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php +++ b/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php @@ -69,12 +69,21 @@ public function getTreeJson() ); $jsonArray = []; foreach ($collection as $item) { - $jsonArray[] = [ + $data = [ 'text' => $this->_cmsWysiwygImages->getShortFilename($item->getBasename(), 20), 'id' => $this->_cmsWysiwygImages->convertPathToId($item->getFilename()), 'path' => substr($item->getFilename(), strlen($storageRoot)), 'cls' => 'folder', ]; + + $hasNestedDirectories = count(glob($item->getFilename() . '/*', GLOB_ONLYDIR)) > 0; + + // if no nested directories inside dir, add 'leaf' state so that jstree hides dropdown arrow next to dir + if (!$hasNestedDirectories) { + $data['state'] = 'leaf'; + } + + $jsonArray[] = $data; } return $this->serializer->serialize($jsonArray); } @@ -86,7 +95,10 @@ public function getTreeJson() */ public function getTreeLoaderUrl() { - return $this->getUrl('cms/*/treeJson'); + return $this->getUrl( + 'cms/*/treeJson', + ['use_storage_root' => (int) $this->getRequest()->getParam('use_storage_root')] + ); } /** diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Block/Save.php b/app/code/Magento/Cms/Controller/Adminhtml/Block/Save.php index 3eb790c83ad69..4332e2edd7057 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Block/Save.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Block/Save.php @@ -7,10 +7,12 @@ namespace Magento\Cms\Controller\Adminhtml\Block; use Magento\Backend\App\Action\Context; +use Magento\Cms\Api\BlockRepositoryInterface; use Magento\Cms\Model\Block; +use Magento\Cms\Model\BlockFactory; use Magento\Framework\App\Request\DataPersistorInterface; use Magento\Framework\Exception\LocalizedException; -use Magento\TestFramework\Inspection\Exception; +use Magento\Framework\Registry; class Save extends \Magento\Cms\Controller\Adminhtml\Block { @@ -19,17 +21,35 @@ class Save extends \Magento\Cms\Controller\Adminhtml\Block */ protected $dataPersistor; + /** + * @var BlockFactory + */ + private $blockFactory; + + /** + * @var BlockRepositoryInterface + */ + private $blockRepository; + /** * @param Context $context - * @param \Magento\Framework\Registry $coreRegistry + * @param Registry $coreRegistry * @param DataPersistorInterface $dataPersistor + * @param BlockFactory|null $blockFactory + * @param BlockRepositoryInterface|null $blockRepository */ public function __construct( Context $context, - \Magento\Framework\Registry $coreRegistry, - DataPersistorInterface $dataPersistor + Registry $coreRegistry, + DataPersistorInterface $dataPersistor, + BlockFactory $blockFactory = null, + BlockRepositoryInterface $blockRepository = null ) { $this->dataPersistor = $dataPersistor; + $this->blockFactory = $blockFactory + ?: \Magento\Framework\App\ObjectManager::getInstance()->get(BlockFactory::class); + $this->blockRepository = $blockRepository + ?: \Magento\Framework\App\ObjectManager::getInstance()->get(BlockRepositoryInterface::class); parent::__construct($context, $coreRegistry); } @@ -45,8 +65,6 @@ public function execute() $resultRedirect = $this->resultRedirectFactory->create(); $data = $this->getRequest()->getPostValue(); if ($data) { - $id = $this->getRequest()->getParam('block_id'); - if (isset($data['is_active']) && $data['is_active'] === 'true') { $data['is_active'] = Block::STATUS_ENABLED; } @@ -55,27 +73,32 @@ public function execute() } /** @var \Magento\Cms\Model\Block $model */ - $model = $this->_objectManager->create(\Magento\Cms\Model\Block::class)->load($id); - if (!$model->getId() && $id) { - $this->messageManager->addError(__('This block no longer exists.')); - return $resultRedirect->setPath('*/*/'); + $model = $this->blockFactory->create(); + + $id = $this->getRequest()->getParam('block_id'); + if ($id) { + try { + $model = $this->blockRepository->getById($id); + } catch (LocalizedException $e) { + $this->messageManager->addErrorMessage(__('This block no longer exists.')); + return $resultRedirect->setPath('*/*/'); + } } $model->setData($data); try { - $model->save(); - $this->messageManager->addSuccess(__('You saved the block.')); + $this->blockRepository->save($model); + $this->messageManager->addSuccessMessage(__('You saved the block.')); $this->dataPersistor->clear('cms_block'); - if ($this->getRequest()->getParam('back')) { return $resultRedirect->setPath('*/*/edit', ['block_id' => $model->getId()]); } return $resultRedirect->setPath('*/*/'); } catch (LocalizedException $e) { - $this->messageManager->addError($e->getMessage()); + $this->messageManager->addErrorMessage($e->getMessage()); } catch (\Exception $e) { - $this->messageManager->addException($e, __('Something went wrong while saving the block.')); + $this->messageManager->addExceptionMessage($e, __('Something went wrong while saving the block.')); } $this->dataPersistor->set('cms_block', $data); diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Page/Save.php b/app/code/Magento/Cms/Controller/Adminhtml/Page/Save.php index 5644e25dd4c4a..1364e61816796 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Page/Save.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Page/Save.php @@ -46,7 +46,6 @@ class Save extends \Magento\Backend\App\Action * @param DataPersistorInterface $dataPersistor * @param \Magento\Cms\Model\PageFactory $pageFactory * @param \Magento\Cms\Api\PageRepositoryInterface $pageRepository - * */ public function __construct( Action\Context $context, @@ -90,11 +89,10 @@ public function execute() $id = $this->getRequest()->getParam('page_id'); if ($id) { - $model->load($id); - if (!$model->getId()) { + try { + $model = $this->pageRepository->getById($id); + } catch (LocalizedException $e) { $this->messageManager->addErrorMessage(__('This page no longer exists.')); - /** \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ - $resultRedirect = $this->resultRedirectFactory->create(); return $resultRedirect->setPath('*/*/'); } } diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php index 19dc989620b89..890c9bf5eae52 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFiles.php @@ -7,6 +7,9 @@ use Magento\Framework\App\Filesystem\DirectoryList; +/** + * Delete image files. + */ class DeleteFiles extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images { /** @@ -19,6 +22,11 @@ class DeleteFiles extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images */ protected $resultRawFactory; + /** + * @var \Magento\Framework\App\Filesystem\DirectoryResolver + */ + private $directoryResolver; + /** * Constructor * @@ -26,22 +34,28 @@ class DeleteFiles extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory * @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory + * @param \Magento\Framework\App\Filesystem\DirectoryResolver|null $directoryResolver */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, - \Magento\Framework\Controller\Result\RawFactory $resultRawFactory + \Magento\Framework\Controller\Result\RawFactory $resultRawFactory, + \Magento\Framework\App\Filesystem\DirectoryResolver $directoryResolver = null ) { + parent::__construct($context, $coreRegistry); + $this->resultRawFactory = $resultRawFactory; $this->resultJsonFactory = $resultJsonFactory; - parent::__construct($context, $coreRegistry); + $this->directoryResolver = $directoryResolver + ?: $this->_objectManager->get(\Magento\Framework\App\Filesystem\DirectoryResolver::class); } /** - * Delete file from media storage + * Delete file from media storage. * * @return \Magento\Framework\Controller\ResultInterface + * @throws \Magento\Framework\Exception\LocalizedException */ public function execute() { @@ -54,6 +68,11 @@ public function execute() /** @var $helper \Magento\Cms\Helper\Wysiwyg\Images */ $helper = $this->_objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); $path = $this->getStorage()->getSession()->getCurrentPath(); + if (!$this->directoryResolver->validatePath($path, DirectoryList::MEDIA)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Directory %1 is not under storage root path.', $path) + ); + } foreach ($files as $file) { $file = $helper->idDecode($file); /** @var \Magento\Framework\Filesystem $filesystem */ @@ -64,11 +83,13 @@ public function execute() $this->getStorage()->deleteFile($filePath); } } + return $this->resultRawFactory->create(); } catch (\Exception $e) { $result = ['error' => true, 'message' => $e->getMessage()]; /** @var \Magento\Framework\Controller\Result\Json $resultJson */ $resultJson = $this->resultJsonFactory->create(); + return $resultJson->setData($result); } } diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php index 8a89de87a6f85..a1de11c3c462e 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolder.php @@ -6,6 +6,11 @@ */ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; +use Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Delete image folder. + */ class DeleteFolder extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images { /** @@ -18,38 +23,55 @@ class DeleteFolder extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images */ protected $resultRawFactory; + /** + * @var \Magento\Framework\App\Filesystem\DirectoryResolver + */ + private $directoryResolver; + /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory * @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory + * @param \Magento\Framework\App\Filesystem\DirectoryResolver|null $directoryResolver */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, - \Magento\Framework\Controller\Result\RawFactory $resultRawFactory + \Magento\Framework\Controller\Result\RawFactory $resultRawFactory, + \Magento\Framework\App\Filesystem\DirectoryResolver $directoryResolver = null ) { + parent::__construct($context, $coreRegistry); $this->resultRawFactory = $resultRawFactory; $this->resultJsonFactory = $resultJsonFactory; - parent::__construct($context, $coreRegistry); + $this->directoryResolver = $directoryResolver + ?: $this->_objectManager->get(\Magento\Framework\App\Filesystem\DirectoryResolver::class); } /** - * Delete folder action + * Delete folder action. * * @return \Magento\Framework\Controller\ResultInterface + * @throws \Magento\Framework\Exception\LocalizedException */ public function execute() { try { $path = $this->getStorage()->getCmsWysiwygImages()->getCurrentPath(); + if (!$this->directoryResolver->validatePath($path, DirectoryList::MEDIA)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Directory %1 is not under storage root path.', $path) + ); + } $this->getStorage()->deleteDirectory($path); + return $this->resultRawFactory->create(); } catch (\Exception $e) { $result = ['error' => true, 'message' => $e->getMessage()]; /** @var \Magento\Framework\Controller\Result\Json $resultJson */ $resultJson = $this->resultJsonFactory->create(); + return $resultJson->setData($result); } } diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolder.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolder.php index 2124bdabe6009..a7f49e8a431a4 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolder.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolder.php @@ -6,6 +6,11 @@ */ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; +use Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Creates new folder. + */ class NewFolder extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images { /** @@ -13,24 +18,34 @@ class NewFolder extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images */ protected $resultJsonFactory; + /** + * @var \Magento\Framework\App\Filesystem\DirectoryResolver + */ + private $directoryResolver; + /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory + * @param \Magento\Framework\App\Filesystem\DirectoryResolver|null $directoryResolver */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, - \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory + \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, + \Magento\Framework\App\Filesystem\DirectoryResolver $directoryResolver = null ) { - $this->resultJsonFactory = $resultJsonFactory; parent::__construct($context, $coreRegistry); + $this->resultJsonFactory = $resultJsonFactory; + $this->directoryResolver = $directoryResolver + ?: $this->_objectManager->get(\Magento\Framework\App\Filesystem\DirectoryResolver::class); } /** - * New folder action + * New folder action. * * @return \Magento\Framework\Controller\ResultInterface + * @throws \Magento\Framework\Exception\LocalizedException */ public function execute() { @@ -38,12 +53,18 @@ public function execute() $this->_initAction(); $name = $this->getRequest()->getPost('name'); $path = $this->getStorage()->getSession()->getCurrentPath(); + if (!$this->directoryResolver->validatePath($path, DirectoryList::MEDIA)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Directory %1 is not under storage root path.', $path) + ); + } $result = $this->getStorage()->createDirectory($name, $path); } catch (\Exception $e) { $result = ['error' => true, 'message' => $e->getMessage()]; } /** @var \Magento\Framework\Controller\Result\Json $resultJson */ $resultJson = $this->resultJsonFactory->create(); + return $resultJson->setData($result); } } diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/OnInsert.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/OnInsert.php index 2daaf39d58d14..3244a7d14f0a3 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/OnInsert.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/OnInsert.php @@ -34,17 +34,26 @@ public function __construct( */ public function execute() { - $helper = $this->_objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); - $storeId = $this->getRequest()->getParam('store'); + $imagesHelper = $this->_objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $request = $this->getRequest(); - $filename = $this->getRequest()->getParam('filename'); - $filename = $helper->idDecode($filename); - $asIs = $this->getRequest()->getParam('as_is'); + $storeId = $request->getParam('store'); + + $filename = $request->getParam('filename'); + $filename = $imagesHelper->idDecode($filename); + + $asIs = $request->getParam('as_is'); + + $forceStaticPath = $request->getParam('force_static_path'); $this->_objectManager->get(\Magento\Catalog\Helper\Data::class)->setStoreId($storeId); - $helper->setStoreId($storeId); + $imagesHelper->setStoreId($storeId); - $image = $helper->getImageHtmlDeclaration($filename, $asIs); + if ($forceStaticPath) { + $image = parse_url($imagesHelper->getCurrentUrl() . $filename, PHP_URL_PATH); + } else { + $image = $imagesHelper->getImageHtmlDeclaration($filename, $asIs); + } /** @var \Magento\Framework\Controller\Result\Raw $resultRaw */ $resultRaw = $this->resultRawFactory->create(); diff --git a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/Upload.php b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/Upload.php index 7a94c4ab6aa12..5c9aa2243bc6d 100644 --- a/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/Upload.php +++ b/app/code/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/Upload.php @@ -6,6 +6,11 @@ */ namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; +use Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Upload image. + */ class Upload extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images { /** @@ -13,36 +18,52 @@ class Upload extends \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images */ protected $resultJsonFactory; + /** + * @var \Magento\Framework\App\Filesystem\DirectoryResolver + */ + private $directoryResolver; + /** * @param \Magento\Backend\App\Action\Context $context * @param \Magento\Framework\Registry $coreRegistry * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory + * @param \Magento\Framework\App\Filesystem\DirectoryResolver|null $directoryResolver */ public function __construct( \Magento\Backend\App\Action\Context $context, \Magento\Framework\Registry $coreRegistry, - \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory + \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, + \Magento\Framework\App\Filesystem\DirectoryResolver $directoryResolver = null ) { - $this->resultJsonFactory = $resultJsonFactory; parent::__construct($context, $coreRegistry); + $this->resultJsonFactory = $resultJsonFactory; + $this->directoryResolver = $directoryResolver + ?: $this->_objectManager->get(\Magento\Framework\App\Filesystem\DirectoryResolver::class); } /** - * Files upload processing + * Files upload processing. * * @return \Magento\Framework\Controller\ResultInterface + * @throws \Magento\Framework\Exception\LocalizedException */ public function execute() { try { $this->_initAction(); - $targetPath = $this->getStorage()->getSession()->getCurrentPath(); - $result = $this->getStorage()->uploadFile($targetPath, $this->getRequest()->getParam('type')); + $path = $this->getStorage()->getSession()->getCurrentPath(); + if (!$this->directoryResolver->validatePath($path, DirectoryList::MEDIA)) { + throw new \Magento\Framework\Exception\LocalizedException( + __('Directory %1 is not under storage root path.', $path) + ); + } + $result = $this->getStorage()->uploadFile($path, $this->getRequest()->getParam('type')); } catch (\Exception $e) { $result = ['error' => $e->getMessage(), 'errorcode' => $e->getCode()]; } /** @var \Magento\Framework\Controller\Result\Json $resultJson */ $resultJson = $this->resultJsonFactory->create(); + return $resultJson->setData($result); } } diff --git a/app/code/Magento/Cms/Helper/Wysiwyg/Images.php b/app/code/Magento/Cms/Helper/Wysiwyg/Images.php index 0fe36e0d74e9e..b055572795210 100644 --- a/app/code/Magento/Cms/Helper/Wysiwyg/Images.php +++ b/app/code/Magento/Cms/Helper/Wysiwyg/Images.php @@ -8,11 +8,19 @@ use Magento\Framework\App\Filesystem\DirectoryList; /** - * Wysiwyg Images Helper + * Wysiwyg Images Helper. + * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class Images extends \Magento\Framework\App\Helper\AbstractHelper { + /** + * Image directory subpath relative to media directory + * + * @var string + */ + private $imageDirectorySubpath; + /** * Current directory path * @var string @@ -80,7 +88,7 @@ public function __construct( $this->escaper = $escaper; $this->_directory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); - $this->_directory->create(\Magento\Cms\Model\Wysiwyg\Config::IMAGE_DIRECTORY); + $this->_directory->create($this->getStorageRoot()); } /** @@ -102,7 +110,19 @@ public function setStoreId($store) */ public function getStorageRoot() { - return $this->_directory->getAbsolutePath(\Magento\Cms\Model\Wysiwyg\Config::IMAGE_DIRECTORY); + return $this->_directory->getAbsolutePath($this->getStorageRootSubpath()); + } + + /** + * Get image storage root subpath. User is unable to traverse outside of this subpath in media gallery + * + * @return string + */ + public function getStorageRootSubpath() + { + return $this->_getRequest()->getParam('use_storage_root') + ? '' + : \Magento\Cms\Model\Wysiwyg\Config::IMAGE_DIRECTORY; } /** @@ -138,17 +158,23 @@ public function convertPathToId($path) } /** - * Decode HTML element id + * Decode HTML element id. * * @param string $id * @return string + * @throws \InvalidArgumentException When path contains restricted symbols. */ public function convertIdToPath($id) { if ($id === \Magento\Theme\Helper\Storage::NODE_ROOT) { return $this->getStorageRoot(); } else { - return $this->getStorageRoot() . $this->idDecode($id); + $path = $this->getStorageRoot() . $this->idDecode($id); + if (preg_match('/\.\.(\\\|\/)/', $path)) { + throw new \InvalidArgumentException('Path is invalid'); + } + + return $path; } } @@ -159,7 +185,7 @@ public function convertIdToPath($id) */ public function isUsingStaticUrlsAllowed() { - $checkResult = new \stdClass(); + $checkResult = (object) []; $checkResult->isAllowed = false; $this->_eventManager->dispatch( 'cms_wysiwyg_images_static_urls_allowed', @@ -189,7 +215,13 @@ public function getImageHtmlDeclaration($filename, $renderAsTag = false) $html = $fileUrl; } else { $directive = $this->urlEncoder->encode($directive); - $html = $this->_backendData->getUrl('cms/wysiwyg/directive', ['___directive' => $directive]); + $html = $this->_backendData->getUrl( + 'cms/wysiwyg/directive', + [ + '___directive' => $directive, + '_escape_params' => false, + ] + ); } } return $html; @@ -205,7 +237,7 @@ public function getImageHtmlDeclaration($filename, $renderAsTag = false) public function getCurrentPath() { if (!$this->_currentPath) { - $currentPath = $this->_directory->getAbsolutePath() . \Magento\Cms\Model\Wysiwyg\Config::IMAGE_DIRECTORY; + $currentPath = $this->getStorageRoot(); $path = $this->_getRequest()->getParam($this->getTreeNodeName()); if ($path) { $path = $this->convertIdToPath($path); @@ -241,7 +273,7 @@ public function getCurrentUrl() )->getBaseUrl( \Magento\Framework\UrlInterface::URL_TYPE_MEDIA ); - $this->_currentUrl = $mediaUrl . $this->_directory->getRelativePath($path) . '/'; + $this->_currentUrl = rtrim($mediaUrl . $this->_directory->getRelativePath($path), '/') . '/'; } return $this->_currentUrl; } @@ -283,4 +315,15 @@ public function getShortFilename($filename, $maxLength = 20) } return substr($filename, 0, $maxLength) . '...'; } + + /** + * Set user-traversable image directory subpath relative to media directory and relative to nested storage root + * + * @var string $subpath + * @return void + */ + public function setImageDirectorySubpath($subpath) + { + $this->imageDirectorySubpath = $subpath; + } } diff --git a/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php b/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php index 0688534dc4ad9..0c8ff7d0b2b78 100644 --- a/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php +++ b/app/code/Magento/Cms/Model/Wysiwyg/Images/Storage.php @@ -241,10 +241,12 @@ protected function getConditionsForExcludeDirs() protected function removeItemFromCollection($collection, $conditions) { $regExp = $conditions['reg_exp'] ? '~' . implode('|', array_keys($conditions['reg_exp'])) . '~i' : null; - $storageRootLength = strlen($this->_cmsWysiwygImages->getStorageRoot()); + $storageRoot = $this->_cmsWysiwygImages->getStorageRoot(); + $storageRootLength = strlen($storageRoot); foreach ($collection as $key => $value) { - $rootChildParts = explode('/', substr($value->getFilename(), $storageRootLength)); + $mediaSubPathname = substr($value->getFilename(), $storageRootLength); + $rootChildParts = explode('/', '/' . ltrim($mediaSubPathname, '/')); if (array_key_exists($rootChildParts[1], $conditions['plain']) || ($regExp && preg_match($regExp, $value->getFilename()))) { @@ -318,6 +320,8 @@ public function getFilesCollection($path, $type = null) $item->setName($item->getBasename()); $item->setShortName($this->_cmsWysiwygImages->getShortFilename($item->getBasename())); $item->setUrl($this->_cmsWysiwygImages->getCurrentUrl() . $item->getBasename()); + $item->setSize(filesize($item->getFilename())); + $item->setMimeType(\mime_content_type($item->getFilename())); if ($this->isImage($item->getBasename())) { $thumbUrl = $this->getThumbnailUrl($item->getFilename(), true); diff --git a/app/code/Magento/Cms/Setup/InstallData.php b/app/code/Magento/Cms/Setup/InstallData.php deleted file mode 100644 index 57e9aadd691d4..0000000000000 --- a/app/code/Magento/Cms/Setup/InstallData.php +++ /dev/null @@ -1,391 +0,0 @@ -pageFactory = $pageFactory; - } - - /** - * {@inheritdoc} - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $cmsPages = [ - [ - 'title' => '404 Not Found', - 'page_layout' => '2columns-right', - 'meta_keywords' => 'Page keywords', - 'meta_description' => 'Page description', - 'identifier' => 'no-route', - 'content_heading' => 'Whoops, our bad...', - 'content' => "
\r\n
The page you requested was not found, and we have a fine guess why.
\r\n" - . "
\r\n
    \r\n
  • If you typed the URL directly, please make sure the spelling" - . " is correct.
  • \r\n
  • If you clicked on a link to get here, the link is outdated.
  • \r\n" - . "
\r\n
\r\n
\r\n
What can you do?
\r\n
Have no fear, help is near!" - . " There are many ways you can get back on track with Magento Store.
\r\n
\r\n" - . "
    \r\n
  • Go back " - . "to the previous page.
  • \r\n
  • Use the search bar at the top of the page to search for your" - . " products.
  • \r\n
  • Follow these links to get you back on track!
    " - . "Store Home | " - . "My Account
\r\n", - 'is_active' => 1, - 'stores' => [0], - 'sort_order' => 0 - ], - [ - 'title' => 'Home page', - 'page_layout' => '1column', - 'identifier' => 'home', - 'content_heading' => 'Home Page', - 'content' => "

CMS homepage content goes here.

\r\n", - 'is_active' => 1, - 'stores' => [0], - 'sort_order' => 0 - ], - [ - 'title' => 'Enable Cookies', - 'page_layout' => '1column', - 'identifier' => 'enable-cookies', - 'content_heading' => 'What are Cookies?', - 'content' => "
\r\n

\"Cookies\" are little pieces of data" - . " we send when you visit our store. Cookies help us get to know you better and personalize your" - . " experience. Plus they help protect you and other shoppers from fraud.

\r\n" - . "

Set your browser to accept cookies so you can buy items, " - . "save items, and receive customized recommendations. Here’s how:

\r\n\r\n
", - 'is_active' => 1, - 'stores' => [0] - ] - ]; - - /** - * Insert default and system pages - */ - foreach ($cmsPages as $data) { - $this->createPage()->setData($data)->save(); - } - - $pageContent = << -
- - Please replace this text with your Privacy Policy. - Please add any additional cookies your website uses below (e.g. Google Analytics). - -
-

- This privacy policy sets out how this website (hereafter "the Store") uses and protects any information that - you give the Store while using this website. The Store is committed to ensuring that your privacy is protected. - Should we ask you to provide certain information by which you can be identified when using this website, then - you can be assured that it will only be used in accordance with this privacy statement. The Store may change - this policy from time to time by updating this page. You should check this page from time to time to ensure - that you are happy with any changes. -

-

What we collect

-

We may collect the following information:

-
    -
  • name
  • -
  • contact information including email address
  • -
  • demographic information such as postcode, preferences and interests
  • -
  • other information relevant to customer surveys and/or offers
  • -
-

- For the exhaustive list of cookies we collect see the List of cookies we collect section. -

-

What we do with the information we gather

-

- We require this information to understand your needs and provide you with a better service, - and in particular for the following reasons: -

-
    -
  • Internal record keeping.
  • -
  • We may use the information to improve our products and services.
  • -
  • - We may periodically send promotional emails about new products, special offers or other information which we - think you may find interesting using the email address which you have provided. -
  • -
  • - From time to time, we may also use your information to contact you for market research purposes. - We may contact you by email, phone, fax or mail. We may use the information to customise the website - according to your interests. -
  • -
-

Security

-

- We are committed to ensuring that your information is secure. In order to prevent unauthorised access or - disclosure, we have put in place suitable physical, electronic and managerial procedures to safeguard and - secure the information we collect online. -

-

How we use cookies

-

- A cookie is a small file which asks permission to be placed on your computer's hard drive. - Once you agree, the file is added and the cookie helps analyse web traffic or lets you know when you visit - a particular site. Cookies allow web applications to respond to you as an individual. The web application - can tailor its operations to your needs, likes and dislikes by gathering and remembering information about - your preferences. -

-

- We use traffic log cookies to identify which pages are being used. This helps us analyse data about web page - traffic and improve our website in order to tailor it to customer needs. We only use this information for - statistical analysis purposes and then the data is removed from the system. -

-

- Overall, cookies help us provide you with a better website, by enabling us to monitor which pages you find - useful and which you do not. A cookie in no way gives us access to your computer or any information about you, - other than the data you choose to share with us. You can choose to accept or decline cookies. - Most web browsers automatically accept cookies, but you can usually modify your browser setting - to decline cookies if you prefer. This may prevent you from taking full advantage of the website. -

-

Links to other websites

-

- Our website may contain links to other websites of interest. However, once you have used these links - to leave our site, you should note that we do not have any control over that other website. - Therefore, we cannot be responsible for the protection and privacy of any information which you provide whilst - visiting such sites and such sites are not governed by this privacy statement. - You should exercise caution and look at the privacy statement applicable to the website in question. -

-

Controlling your personal information

-

You may choose to restrict the collection or use of your personal information in the following ways:

-
    -
  • - whenever you are asked to fill in a form on the website, look for the box that you can click to indicate - that you do not want the information to be used by anybody for direct marketing purposes -
  • -
  • - if you have previously agreed to us using your personal information for direct marketing purposes, - you may change your mind at any time by letting us know using our Contact Us information -
  • -
-

- We will not sell, distribute or lease your personal information to third parties unless we have your permission - or are required by law to do so. We may use your personal information to send you promotional information - about third parties which we think you may find interesting if you tell us that you wish this to happen. -

-

- You may request details of personal information which we hold about you under the Data Protection Act 1998. - A small fee will be payable. If you would like a copy of the information held on you please email us this - request using our Contact Us information. -

-

- If you believe that any information we are holding on you is incorrect or incomplete, - please write to or email us as soon as possible, at the above address. - We will promptly correct any information found to be incorrect. -

-

List of cookies we collect

-

The table below lists the cookies we collect and what information they store.

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
COOKIE nameCOOKIE Description
CARTThe association with your shopping cart.
CATEGORY_INFOStores the category info on the page, that allows to display pages more quickly.
COMPAREThe items that you have in the Compare Products list.
CUSTOMERAn encrypted version of your customer id with the store.
CUSTOMER_AUTHAn indicator if you are currently logged into the store.
CUSTOMER_INFOAn encrypted version of the customer group you belong to.
CUSTOMER_SEGMENT_IDSStores the Customer Segment ID
EXTERNAL_NO_CACHEA flag, which indicates whether caching is disabled or not.
FORM_KEYStores form key used by page cache functionality.
FRONTENDYour session ID on the server.
GUEST-VIEWAllows guests to edit their orders.
LAST_CATEGORYThe last category you visited.
LAST_PRODUCTThe most recent product you have viewed.
NEWMESSAGEIndicates whether a new message has been received.
NO_CACHEIndicates whether it is allowed to use cache.
PERSISTENT_SHOPPING_CARTA link to information about your cart and viewing history if you have asked the site.
RECENTLYCOMPAREDThe items that you have recently compared.
STFInformation on products you have emailed to friends.
STOREThe store view or language you have selected.
USER_ALLOWED_SAVE_COOKIEIndicates whether a customer allowed to use cookies.
VIEWED_PRODUCT_IDSThe products that you have recently viewed.
WISHLISTAn encrypted list of products added to your Wish List.
WISHLIST_CNTThe number of items in your Wish List.
- -EOD; - - $privacyPageData = [ - 'title' => 'Privacy and Cookie Policy', - 'content_heading' => 'Privacy and Cookie Policy', - 'page_layout' => '1column', - 'identifier' => 'privacy-policy-cookie-restriction-mode', - 'content' => $pageContent, - 'is_active' => 1, - 'stores' => [0], - 'sort_order' => 0, - ]; - - $this->createPage()->setData($privacyPageData)->save(); - - $footerLinksBlock = $this->createPage()->load('footer_links', 'identifier'); - - if ($footerLinksBlock->getId()) { - $content = $footerLinksBlock->getContent(); - if (preg_match('/"; - $content = preg_replace('/<\\/ul>/ims', $replacment, $content); - $footerLinksBlock->setContent($content)->save(); - } - } - - $installer = $setup->createMigrationSetup(); - $setup->startSetup(); - - $installer->appendClassAliasReplace( - 'cms_block', - 'content', - Migration::ENTITY_TYPE_BLOCK, - Migration::FIELD_CONTENT_TYPE_WIKI, - ['block_id'] - ); - $installer->appendClassAliasReplace( - 'cms_page', - 'content', - Migration::ENTITY_TYPE_BLOCK, - Migration::FIELD_CONTENT_TYPE_WIKI, - ['page_id'] - ); - $installer->appendClassAliasReplace( - 'cms_page', - 'layout_update_xml', - Migration::ENTITY_TYPE_BLOCK, - Migration::FIELD_CONTENT_TYPE_XML, - ['page_id'] - ); - $installer->appendClassAliasReplace( - 'cms_page', - 'custom_layout_update_xml', - Migration::ENTITY_TYPE_BLOCK, - Migration::FIELD_CONTENT_TYPE_XML, - ['page_id'] - ); - - $installer->doUpdateClassAliases(); - - $setup->endSetup(); - } - - /** - * Create page - * - * @return Page - */ - public function createPage() - { - return $this->pageFactory->create(); - } -} diff --git a/app/code/Magento/Cms/Setup/Patch/Data/ConvertWidgetConditionsToJson.php b/app/code/Magento/Cms/Setup/Patch/Data/ConvertWidgetConditionsToJson.php new file mode 100644 index 0000000000000..61f26c9bd0710 --- /dev/null +++ b/app/code/Magento/Cms/Setup/Patch/Data/ConvertWidgetConditionsToJson.php @@ -0,0 +1,158 @@ +moduleDataSetup = $moduleDataSetup; + $this->queryModifierFactory = $queryModifierFactory; + $this->metadataPool = $metadataPool; + $this->aggregatedFieldDataConverter = $aggregatedFieldDataConverter; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $queryModifier = $this->queryModifierFactory->create( + 'like', + [ + 'values' => [ + 'content' => '%conditions_encoded%' + ] + ] + ); + $layoutUpdateXmlFieldQueryModifier = $this->queryModifierFactory->create( + 'like', + [ + 'values' => [ + 'layout_update_xml' => '%conditions_encoded%' + ] + ] + ); + $customLayoutUpdateXmlFieldQueryModifier = $this->queryModifierFactory->create( + 'like', + [ + 'values' => [ + 'custom_layout_update_xml' => '%conditions_encoded%' + ] + ] + ); + $blockMetadata = $this->metadataPool->getMetadata(BlockInterface::class); + $pageMetadata = $this->metadataPool->getMetadata(PageInterface::class); + $this->aggregatedFieldDataConverter->convert( + [ + new FieldToConvert( + ContentConverter::class, + $this->moduleDataSetup->getTable('cms_block'), + $blockMetadata->getIdentifierField(), + 'content', + $queryModifier + ), + new FieldToConvert( + ContentConverter::class, + $this->moduleDataSetup->getTable('cms_page'), + $pageMetadata->getIdentifierField(), + 'content', + $queryModifier + ), + new FieldToConvert( + LayoutUpdateConverter::class, + $this->moduleDataSetup->getTable('cms_page'), + $pageMetadata->getIdentifierField(), + 'layout_update_xml', + $layoutUpdateXmlFieldQueryModifier + ), + new FieldToConvert( + LayoutUpdateConverter::class, + $this->moduleDataSetup->getTable('cms_page'), + $pageMetadata->getIdentifierField(), + 'custom_layout_update_xml', + $customLayoutUpdateXmlFieldQueryModifier + ), + ], + $this->moduleDataSetup->getConnection() + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdatePrivacyPolicyPage::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.2'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Cms/Setup/Patch/Data/CreateDefaultPages.php b/app/code/Magento/Cms/Setup/Patch/Data/CreateDefaultPages.php new file mode 100644 index 0000000000000..615cdb144fd1f --- /dev/null +++ b/app/code/Magento/Cms/Setup/Patch/Data/CreateDefaultPages.php @@ -0,0 +1,411 @@ +pageFactory = $pageFactory; + $this->moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function apply() + { + $cmsPages = [ + [ + 'title' => '404 Not Found', + 'page_layout' => '2columns-right', + 'meta_keywords' => 'Page keywords', + 'meta_description' => 'Page description', + 'identifier' => 'no-route', + 'content_heading' => 'Whoops, our bad...', + 'content' => "
\r\n
The page you requested was not found, and we have a fine guess why.
\r\n" + . "
\r\n
    \r\n
  • If you typed the URL directly, please make sure the spelling" + . " is correct.
  • \r\n
  • If you clicked on a link to get here, the link is outdated.
  • \r\n" + . "
\r\n
\r\n
\r\n
What can you do?
\r\n
Have no fear, help is near!" + . " There are many ways you can get back on track with Magento Store.
\r\n
\r\n" + . "
    \r\n
  • Go back " + . "to the previous page.
  • \r\n
  • Use the search bar at the top of the page to search for your" + . " products.
  • \r\n
  • Follow these links to get you back on track!
    " + . "Store Home | " + . "My Account
\r\n", + 'is_active' => 1, + 'stores' => [0], + 'sort_order' => 0 + ], + [ + 'title' => 'Home page', + 'page_layout' => '1column', + 'identifier' => 'home', + 'content_heading' => 'Home Page', + 'content' => "

CMS homepage content goes here.

\r\n", + 'is_active' => 1, + 'stores' => [0], + 'sort_order' => 0 + ], + [ + 'title' => 'Enable Cookies', + 'page_layout' => '1column', + 'identifier' => 'enable-cookies', + 'content_heading' => 'What are Cookies?', + 'content' => "
\r\n

\"Cookies\" are little pieces of data" + . " we send when you visit our store. Cookies help us get to know you better and personalize your" + . " experience. Plus they help protect you and other shoppers from fraud.

\r\n" + . "

Set your browser to accept cookies so you can buy items, " + . "save items, and receive customized recommendations. Here’s how:

\r\n\r\n
", + 'is_active' => 1, + 'stores' => [0] + ] + ]; + + /** + * Insert default and system pages + */ + foreach ($cmsPages as $data) { + $this->createPage()->setData($data)->save(); + } + $pageContent = << +
+ + Please replace this text with your Privacy Policy. + Please add any additional cookies your website uses below (e.g. Google Analytics). + +
+

+ This privacy policy sets out how this website (hereafter "the Store") uses and protects any information that + you give the Store while using this website. The Store is committed to ensuring that your privacy is protected. + Should we ask you to provide certain information by which you can be identified when using this website, then + you can be assured that it will only be used in accordance with this privacy statement. The Store may change + this policy from time to time by updating this page. You should check this page from time to time to ensure + that you are happy with any changes. +

+

What we collect

+

We may collect the following information:

+
    +
  • name
  • +
  • contact information including email address
  • +
  • demographic information such as postcode, preferences and interests
  • +
  • other information relevant to customer surveys and/or offers
  • +
+

+ For the exhaustive list of cookies we collect see the List of cookies we collect section. +

+

What we do with the information we gather

+

+ We require this information to understand your needs and provide you with a better service, + and in particular for the following reasons: +

+
    +
  • Internal record keeping.
  • +
  • We may use the information to improve our products and services.
  • +
  • + We may periodically send promotional emails about new products, special offers or other information which we + think you may find interesting using the email address which you have provided. +
  • +
  • + From time to time, we may also use your information to contact you for market research purposes. + We may contact you by email, phone, fax or mail. We may use the information to customise the website + according to your interests. +
  • +
+

Security

+

+ We are committed to ensuring that your information is secure. In order to prevent unauthorised access or + disclosure, we have put in place suitable physical, electronic and managerial procedures to safeguard and + secure the information we collect online. +

+

How we use cookies

+

+ A cookie is a small file which asks permission to be placed on your computer's hard drive. + Once you agree, the file is added and the cookie helps analyse web traffic or lets you know when you visit + a particular site. Cookies allow web applications to respond to you as an individual. The web application + can tailor its operations to your needs, likes and dislikes by gathering and remembering information about + your preferences. +

+

+ We use traffic log cookies to identify which pages are being used. This helps us analyse data about web page + traffic and improve our website in order to tailor it to customer needs. We only use this information for + statistical analysis purposes and then the data is removed from the system. +

+

+ Overall, cookies help us provide you with a better website, by enabling us to monitor which pages you find + useful and which you do not. A cookie in no way gives us access to your computer or any information about you, + other than the data you choose to share with us. You can choose to accept or decline cookies. + Most web browsers automatically accept cookies, but you can usually modify your browser setting + to decline cookies if you prefer. This may prevent you from taking full advantage of the website. +

+

Links to other websites

+

+ Our website may contain links to other websites of interest. However, once you have used these links + to leave our site, you should note that we do not have any control over that other website. + Therefore, we cannot be responsible for the protection and privacy of any information which you provide whilst + visiting such sites and such sites are not governed by this privacy statement. + You should exercise caution and look at the privacy statement applicable to the website in question. +

+

Controlling your personal information

+

You may choose to restrict the collection or use of your personal information in the following ways:

+
    +
  • + whenever you are asked to fill in a form on the website, look for the box that you can click to indicate + that you do not want the information to be used by anybody for direct marketing purposes +
  • +
  • + if you have previously agreed to us using your personal information for direct marketing purposes, + you may change your mind at any time by letting us know using our Contact Us information +
  • +
+

+ We will not sell, distribute or lease your personal information to third parties unless we have your permission + or are required by law to do so. We may use your personal information to send you promotional information + about third parties which we think you may find interesting if you tell us that you wish this to happen. +

+

+ You may request details of personal information which we hold about you under the Data Protection Act 1998. + A small fee will be payable. If you would like a copy of the information held on you please email us this + request using our Contact Us information. +

+

+ If you believe that any information we are holding on you is incorrect or incomplete, + please write to or email us as soon as possible, at the above address. + We will promptly correct any information found to be incorrect. +

+

List of cookies we collect

+

The table below lists the cookies we collect and what information they store.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
COOKIE nameCOOKIE Description
CARTThe association with your shopping cart.
CATEGORY_INFOStores the category info on the page, that allows to display pages more quickly.
COMPAREThe items that you have in the Compare Products list.
CUSTOMERAn encrypted version of your customer id with the store.
CUSTOMER_AUTHAn indicator if you are currently logged into the store.
CUSTOMER_INFOAn encrypted version of the customer group you belong to.
CUSTOMER_SEGMENT_IDSStores the Customer Segment ID
EXTERNAL_NO_CACHEA flag, which indicates whether caching is disabled or not.
FORM_KEYStores form key used by page cache functionality.
FRONTENDYour session ID on the server.
GUEST-VIEWAllows guests to edit their orders.
LAST_CATEGORYThe last category you visited.
LAST_PRODUCTThe most recent product you have viewed.
NEWMESSAGEIndicates whether a new message has been received.
NO_CACHEIndicates whether it is allowed to use cache.
PERSISTENT_SHOPPING_CARTA link to information about your cart and viewing history if you have asked the site.
RECENTLYCOMPAREDThe items that you have recently compared.
STFInformation on products you have emailed to friends.
STOREThe store view or language you have selected.
USER_ALLOWED_SAVE_COOKIEIndicates whether a customer allowed to use cookies.
VIEWED_PRODUCT_IDSThe products that you have recently viewed.
WISHLISTAn encrypted list of products added to your Wish List.
WISHLIST_CNTThe number of items in your Wish List.
+ +EOD; + $privacyPageData = [ + 'title' => 'Privacy and Cookie Policy', + 'content_heading' => 'Privacy and Cookie Policy', + 'page_layout' => '1column', + 'identifier' => 'privacy-policy-cookie-restriction-mode', + 'content' => $pageContent, + 'is_active' => 1, + 'stores' => [0], + 'sort_order' => 0, + ]; + $this->createPage()->setData($privacyPageData)->save(); + $footerLinksBlock = $this->createPage()->load('footer_links', 'identifier'); + if ($footerLinksBlock->getId()) { + $content = $footerLinksBlock->getContent(); + if (preg_match('/"; + $content = preg_replace('/<\\/ul>/ims', $replacment, $content); + $footerLinksBlock->setContent($content)->save(); + } + } + $installer = $this->moduleDataSetup->createMigrationSetup(); + $this->moduleDataSetup->startSetup(); + $installer->appendClassAliasReplace( + 'cms_block', + 'content', + Migration::ENTITY_TYPE_BLOCK, + Migration::FIELD_CONTENT_TYPE_WIKI, + ['block_id'] + ); + $installer->appendClassAliasReplace( + 'cms_page', + 'content', + Migration::ENTITY_TYPE_BLOCK, + Migration::FIELD_CONTENT_TYPE_WIKI, + ['page_id'] + ); + $installer->appendClassAliasReplace( + 'cms_page', + 'layout_update_xml', + Migration::ENTITY_TYPE_BLOCK, + Migration::FIELD_CONTENT_TYPE_XML, + ['page_id'] + ); + $installer->appendClassAliasReplace( + 'cms_page', + 'custom_layout_update_xml', + Migration::ENTITY_TYPE_BLOCK, + Migration::FIELD_CONTENT_TYPE_XML, + ['page_id'] + ); + $installer->doUpdateClassAliases(); + $this->moduleDataSetup->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Create page model instance + * + * @return \Magento\Cms\Model\Page + */ + private function createPage() + { + return $this->pageFactory->create(); + } +} diff --git a/app/code/Magento/Cms/Setup/Patch/Data/UpdatePrivacyPolicyPage.php b/app/code/Magento/Cms/Setup/Patch/Data/UpdatePrivacyPolicyPage.php new file mode 100644 index 0000000000000..dff931bfd6359 --- /dev/null +++ b/app/code/Magento/Cms/Setup/Patch/Data/UpdatePrivacyPolicyPage.php @@ -0,0 +1,270 @@ +pageFactory = $pageFactory; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function apply() + { + $newPageContent = << +
+ + Please replace this text with you Privacy Policy. + Please add any additional cookies your website uses below (e.g. Google Analytics). + +
+

+ This privacy policy sets out how this website (hereafter "the Store") uses and protects any information that + you give the Store while using this website. The Store is committed to ensuring that your privacy is protected. + Should we ask you to provide certain information by which you can be identified when using this website, then + you can be assured that it will only be used in accordance with this privacy statement. The Store may change + this policy from time to time by updating this page. You should check this page from time to time to ensure + that you are happy with any changes. +

+

What we collect

+

We may collect the following information:

+
    +
  • name
  • +
  • contact information including email address
  • +
  • demographic information such as postcode, preferences and interests
  • +
  • other information relevant to customer surveys and/or offers
  • +
+

+ For the exhaustive list of cookies we collect see the List of cookies we collect section. +

+

What we do with the information we gather

+

+ We require this information to understand your needs and provide you with a better service, + and in particular for the following reasons: +

+
    +
  • Internal record keeping.
  • +
  • We may use the information to improve our products and services.
  • +
  • + We may periodically send promotional emails about new products, special offers or other information which we + think you may find interesting using the email address which you have provided. +
  • +
  • + From time to time, we may also use your information to contact you for market research purposes. + We may contact you by email, phone, fax or mail. We may use the information to customise the website + according to your interests. +
  • +
+

Security

+

+ We are committed to ensuring that your information is secure. In order to prevent unauthorised access or + disclosure, we have put in place suitable physical, electronic and managerial procedures to safeguard and + secure the information we collect online. +

+

How we use cookies

+

+ A cookie is a small file which asks permission to be placed on your computer's hard drive. + Once you agree, the file is added and the cookie helps analyse web traffic or lets you know when you visit + a particular site. Cookies allow web applications to respond to you as an individual. The web application + can tailor its operations to your needs, likes and dislikes by gathering and remembering information about + your preferences. +

+

+ We use traffic log cookies to identify which pages are being used. This helps us analyse data about web page + traffic and improve our website in order to tailor it to customer needs. We only use this information for + statistical analysis purposes and then the data is removed from the system. +

+

+ Overall, cookies help us provide you with a better website, by enabling us to monitor which pages you find + useful and which you do not. A cookie in no way gives us access to your computer or any information about you, + other than the data you choose to share with us. You can choose to accept or decline cookies. + Most web browsers automatically accept cookies, but you can usually modify your browser setting + to decline cookies if you prefer. This may prevent you from taking full advantage of the website. +

+

Links to other websites

+

+ Our website may contain links to other websites of interest. However, once you have used these links + to leave our site, you should note that we do not have any control over that other website. + Therefore, we cannot be responsible for the protection and privacy of any information which you provide whilst + visiting such sites and such sites are not governed by this privacy statement. + You should exercise caution and look at the privacy statement applicable to the website in question. +

+

Controlling your personal information

+

You may choose to restrict the collection or use of your personal information in the following ways:

+
    +
  • + whenever you are asked to fill in a form on the website, look for the box that you can click to indicate + that you do not want the information to be used by anybody for direct marketing purposes +
  • +
  • + if you have previously agreed to us using your personal information for direct marketing purposes, + you may change your mind at any time by letting us know using our Contact Us information +
  • +
+

+ We will not sell, distribute or lease your personal information to third parties unless we have your permission + or are required by law to do so. We may use your personal information to send you promotional information + about third parties which we think you may find interesting if you tell us that you wish this to happen. +

+

+ You may request details of personal information which we hold about you under the Data Protection Act 1998. + A small fee will be payable. If you would like a copy of the information held on you please email us this + request using our Contact Us information. +

+

+ If you believe that any information we are holding on you is incorrect or incomplete, + please write to or email us as soon as possible, at the above address. + We will promptly correct any information found to be incorrect. +

+

List of cookies we collect

+

The table below lists the cookies we collect and what information they store.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Cookie NameCookie Description
FORM_KEYStores randomly generated key used to prevent forged requests.
PHPSESSIDYour session ID on the server.
GUEST-VIEWAllows guests to view and edit their orders.
PERSISTENT_SHOPPING_CARTA link to information about your cart and viewing history, if you have asked for this.
STFInformation on products you have emailed to friends.
STOREThe store view or language you have selected.
USER_ALLOWED_SAVE_COOKIEIndicates whether a customer allowed to use cookies.
MAGE-CACHE-SESSIDFacilitates caching of content on the browser to make pages load faster.
MAGE-CACHE-STORAGEFacilitates caching of content on the browser to make pages load faster.
MAGE-CACHE-STORAGE-SECTION-INVALIDATIONFacilitates caching of content on the browser to make pages load faster.
MAGE-CACHE-TIMEOUTFacilitates caching of content on the browser to make pages load faster.
SECTION-DATA-IDSFacilitates caching of content on the browser to make pages load faster.
PRIVATE_CONTENT_VERSIONFacilitates caching of content on the browser to make pages load faster.
X-MAGENTO-VARYFacilitates caching of content on the server to make pages load faster.
MAGE-TRANSLATION-FILE-VERSIONFacilitates translation of content to other languages.
MAGE-TRANSLATION-STORAGEFacilitates translation of content to other languages.
+ +EOD; + $privacyAndCookiePolicyPage = $this->createPage()->load( + 'privacy-policy-cookie-restriction-mode', + 'identifier' + ); + $privacyAndCookiePolicyPageId = $privacyAndCookiePolicyPage->getId(); + if ($privacyAndCookiePolicyPageId) { + $privacyAndCookiePolicyPage->setContent($newPageContent); + $privacyAndCookiePolicyPage->save(); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + CreateDefaultPages::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Create page instance. + * + * @return \Magento\Cms\Model\Page + */ + private function createPage() + { + return $this->pageFactory->create(); + } +} diff --git a/app/code/Magento/Cms/Setup/UpgradeData.php b/app/code/Magento/Cms/Setup/UpgradeData.php deleted file mode 100644 index 91bda43d2e0e7..0000000000000 --- a/app/code/Magento/Cms/Setup/UpgradeData.php +++ /dev/null @@ -1,365 +0,0 @@ -pageFactory = $pageFactory; - $this->aggregatedFieldConverter = $aggregatedFieldConverter; - $this->queryModifierFactory = $queryModifierFactory; - $this->metadataPool = $metadataPool; - } - - /** - * Upgrades data for a module - * - * @param ModuleDataSetupInterface $setup - * @param ModuleContextInterface $context - * @return void - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $this->upgradeVersionTwoZeroOne(); - } - if (version_compare($context->getVersion(), '2.0.2', '<')) { - $this->convertWidgetConditionsToJson($setup); - } - } - - /** - * Upgrade data to version 2.0.2 - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function convertWidgetConditionsToJson(ModuleDataSetupInterface $setup) - { - $queryModifier = $this->queryModifierFactory->create( - 'like', - [ - 'values' => [ - 'content' => '%conditions_encoded%' - ] - ] - ); - $layoutUpdateXmlFieldQueryModifier = $this->queryModifierFactory->create( - 'like', - [ - 'values' => [ - 'layout_update_xml' => '%conditions_encoded%' - ] - ] - ); - $customLayoutUpdateXmlFieldQueryModifier = $this->queryModifierFactory->create( - 'like', - [ - 'values' => [ - 'custom_layout_update_xml' => '%conditions_encoded%' - ] - ] - ); - $blockMetadata = $this->metadataPool->getMetadata(BlockInterface::class); - $pageMetadata = $this->metadataPool->getMetadata(PageInterface::class); - $this->aggregatedFieldConverter->convert( - [ - new FieldToConvert( - ContentConverter::class, - $setup->getTable('cms_block'), - $blockMetadata->getIdentifierField(), - 'content', - $queryModifier - ), - new FieldToConvert( - ContentConverter::class, - $setup->getTable('cms_page'), - $pageMetadata->getIdentifierField(), - 'content', - $queryModifier - ), - new FieldToConvert( - LayoutUpdateConverter::class, - $setup->getTable('cms_page'), - $pageMetadata->getIdentifierField(), - 'layout_update_xml', - $layoutUpdateXmlFieldQueryModifier - ), - new FieldToConvert( - LayoutUpdateConverter::class, - $setup->getTable('cms_page'), - $pageMetadata->getIdentifierField(), - 'custom_layout_update_xml', - $customLayoutUpdateXmlFieldQueryModifier - ), - ], - $setup->getConnection() - ); - } - - /** - * Create page - * - * @return Page - */ - private function createPage() - { - return $this->pageFactory->create(); - } - - /** - * Upgrade data to version 2.0.1, - * - * @return void - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - private function upgradeVersionTwoZeroOne() - { - $newPageContent = << -
- - Please replace this text with you Privacy Policy. - Please add any additional cookies your website uses below (e.g. Google Analytics). - -
-

- This privacy policy sets out how this website (hereafter "the Store") uses and protects any information that - you give the Store while using this website. The Store is committed to ensuring that your privacy is protected. - Should we ask you to provide certain information by which you can be identified when using this website, then - you can be assured that it will only be used in accordance with this privacy statement. The Store may change - this policy from time to time by updating this page. You should check this page from time to time to ensure - that you are happy with any changes. -

-

What we collect

-

We may collect the following information:

-
    -
  • name
  • -
  • contact information including email address
  • -
  • demographic information such as postcode, preferences and interests
  • -
  • other information relevant to customer surveys and/or offers
  • -
-

- For the exhaustive list of cookies we collect see the List of cookies we collect section. -

-

What we do with the information we gather

-

- We require this information to understand your needs and provide you with a better service, - and in particular for the following reasons: -

-
    -
  • Internal record keeping.
  • -
  • We may use the information to improve our products and services.
  • -
  • - We may periodically send promotional emails about new products, special offers or other information which we - think you may find interesting using the email address which you have provided. -
  • -
  • - From time to time, we may also use your information to contact you for market research purposes. - We may contact you by email, phone, fax or mail. We may use the information to customise the website - according to your interests. -
  • -
-

Security

-

- We are committed to ensuring that your information is secure. In order to prevent unauthorised access or - disclosure, we have put in place suitable physical, electronic and managerial procedures to safeguard and - secure the information we collect online. -

-

How we use cookies

-

- A cookie is a small file which asks permission to be placed on your computer's hard drive. - Once you agree, the file is added and the cookie helps analyse web traffic or lets you know when you visit - a particular site. Cookies allow web applications to respond to you as an individual. The web application - can tailor its operations to your needs, likes and dislikes by gathering and remembering information about - your preferences. -

-

- We use traffic log cookies to identify which pages are being used. This helps us analyse data about web page - traffic and improve our website in order to tailor it to customer needs. We only use this information for - statistical analysis purposes and then the data is removed from the system. -

-

- Overall, cookies help us provide you with a better website, by enabling us to monitor which pages you find - useful and which you do not. A cookie in no way gives us access to your computer or any information about you, - other than the data you choose to share with us. You can choose to accept or decline cookies. - Most web browsers automatically accept cookies, but you can usually modify your browser setting - to decline cookies if you prefer. This may prevent you from taking full advantage of the website. -

-

Links to other websites

-

- Our website may contain links to other websites of interest. However, once you have used these links - to leave our site, you should note that we do not have any control over that other website. - Therefore, we cannot be responsible for the protection and privacy of any information which you provide whilst - visiting such sites and such sites are not governed by this privacy statement. - You should exercise caution and look at the privacy statement applicable to the website in question. -

-

Controlling your personal information

-

You may choose to restrict the collection or use of your personal information in the following ways:

-
    -
  • - whenever you are asked to fill in a form on the website, look for the box that you can click to indicate - that you do not want the information to be used by anybody for direct marketing purposes -
  • -
  • - if you have previously agreed to us using your personal information for direct marketing purposes, - you may change your mind at any time by letting us know using our Contact Us information -
  • -
-

- We will not sell, distribute or lease your personal information to third parties unless we have your permission - or are required by law to do so. We may use your personal information to send you promotional information - about third parties which we think you may find interesting if you tell us that you wish this to happen. -

-

- You may request details of personal information which we hold about you under the Data Protection Act 1998. - A small fee will be payable. If you would like a copy of the information held on you please email us this - request using our Contact Us information. -

-

- If you believe that any information we are holding on you is incorrect or incomplete, - please write to or email us as soon as possible, at the above address. - We will promptly correct any information found to be incorrect. -

-

List of cookies we collect

-

The table below lists the cookies we collect and what information they store.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cookie NameCookie Description
FORM_KEYStores randomly generated key used to prevent forged requests.
PHPSESSIDYour session ID on the server.
GUEST-VIEWAllows guests to view and edit their orders.
PERSISTENT_SHOPPING_CARTA link to information about your cart and viewing history, if you have asked for this.
STFInformation on products you have emailed to friends.
STOREThe store view or language you have selected.
USER_ALLOWED_SAVE_COOKIEIndicates whether a customer allowed to use cookies.
MAGE-CACHE-SESSIDFacilitates caching of content on the browser to make pages load faster.
MAGE-CACHE-STORAGEFacilitates caching of content on the browser to make pages load faster.
MAGE-CACHE-STORAGE-SECTION-INVALIDATIONFacilitates caching of content on the browser to make pages load faster.
MAGE-CACHE-TIMEOUTFacilitates caching of content on the browser to make pages load faster.
SECTION-DATA-IDSFacilitates caching of content on the browser to make pages load faster.
PRIVATE_CONTENT_VERSIONFacilitates caching of content on the browser to make pages load faster.
X-MAGENTO-VARYFacilitates caching of content on the server to make pages load faster.
MAGE-TRANSLATION-FILE-VERSIONFacilitates translation of content to other languages.
MAGE-TRANSLATION-STORAGEFacilitates translation of content to other languages.
- -EOD; - $privacyAndCookiePolicyPage = $this->createPage()->load( - 'privacy-policy-cookie-restriction-mode', - 'identifier' - ); - $privacyAndCookiePolicyPageId = $privacyAndCookiePolicyPage->getId(); - if ($privacyAndCookiePolicyPageId) { - $privacyAndCookiePolicyPage->setContent($newPageContent); - $privacyAndCookiePolicyPage->save(); - } - } -} diff --git a/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Block/SaveTest.php b/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Block/SaveTest.php index f6b709a5c96c9..40ed379e9d7e2 100644 --- a/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Block/SaveTest.php +++ b/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Block/SaveTest.php @@ -65,6 +65,16 @@ class SaveTest extends \PHPUnit\Framework\TestCase */ protected $saveController; + /** + * @var \Magento\Cms\Model\BlockFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $blockFactory; + + /** + * @var \Magento\Cms\Api\BlockRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $blockRepository; + /** * @var int */ @@ -129,11 +139,22 @@ protected function setUp() ->method('getResultRedirectFactory') ->willReturn($this->resultRedirectFactory); + $this->blockFactory = $this->getMockBuilder(\Magento\Cms\Model\BlockFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $this->blockRepository = $this->getMockBuilder(\Magento\Cms\Api\BlockRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->saveController = $this->objectManager->getObject( \Magento\Cms\Controller\Adminhtml\Block\Save::class, [ 'context' => $this->contextMock, 'dataPersistor' => $this->dataPersistorMock, + 'blockFactory' => $this->blockFactory, + 'blockRepository' => $this->blockRepository, ] ); } @@ -158,26 +179,24 @@ public function testSaveAction() ] ); - $this->objectManagerMock->expects($this->atLeastOnce()) + $this->blockFactory->expects($this->atLeastOnce()) ->method('create') - ->with($this->equalTo(\Magento\Cms\Model\Block::class)) ->willReturn($this->blockMock); - $this->blockMock->expects($this->any()) - ->method('load') - ->willReturnSelf(); - $this->blockMock->expects($this->any()) - ->method('getId') - ->willReturn(true); + $this->blockRepository->expects($this->once()) + ->method('getById') + ->with($this->blockId) + ->willReturn($this->blockMock); + $this->blockMock->expects($this->once())->method('setData'); - $this->blockMock->expects($this->once())->method('save'); + $this->blockRepository->expects($this->once())->method('save')->with($this->blockMock); $this->dataPersistorMock->expects($this->any()) ->method('clear') ->with('cms_block'); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with(__('You saved the block.')); $this->resultRedirect->expects($this->atLeastOnce())->method('setPath')->with('*/*/') ->willReturnSelf(); @@ -204,20 +223,17 @@ public function testSaveActionNoId() ] ); - $this->objectManagerMock->expects($this->atLeastOnce()) + $this->blockFactory->expects($this->atLeastOnce()) ->method('create') - ->with($this->equalTo(\Magento\Cms\Model\Block::class)) ->willReturn($this->blockMock); - $this->blockMock->expects($this->any()) - ->method('load') - ->willReturnSelf(); - $this->blockMock->expects($this->any()) - ->method('getId') - ->willReturn(false); + $this->blockRepository->expects($this->once()) + ->method('getById') + ->with($this->blockId) + ->willThrowException(new \Magento\Framework\Exception\NoSuchEntityException(__('Error message'))); $this->messageManagerMock->expects($this->once()) - ->method('addError') + ->method('addErrorMessage') ->with(__('This block no longer exists.')); $this->resultRedirect->expects($this->atLeastOnce())->method('setPath')->with('*/*/') ->willReturnSelf(); @@ -237,22 +253,20 @@ public function testSaveAndContinue() ] ); - $this->objectManagerMock->expects($this->atLeastOnce()) + $this->blockFactory->expects($this->atLeastOnce()) ->method('create') - ->with($this->equalTo(\Magento\Cms\Model\Block::class)) ->willReturn($this->blockMock); - $this->blockMock->expects($this->any()) - ->method('load') - ->willReturnSelf(); - $this->blockMock->expects($this->any()) - ->method('getId') - ->willReturn(true); + $this->blockRepository->expects($this->once()) + ->method('getById') + ->with($this->blockId) + ->willReturn($this->blockMock); + $this->blockMock->expects($this->once())->method('setData'); - $this->blockMock->expects($this->once())->method('save'); + $this->blockRepository->expects($this->once())->method('save')->with($this->blockMock); $this->messageManagerMock->expects($this->once()) - ->method('addSuccess') + ->method('addSuccessMessage') ->with(__('You saved the block.')); $this->dataPersistorMock->expects($this->any()) @@ -279,24 +293,24 @@ public function testSaveActionThrowsException() ] ); - $this->objectManagerMock->expects($this->atLeastOnce()) + $this->blockFactory->expects($this->atLeastOnce()) ->method('create') - ->with($this->equalTo(\Magento\Cms\Model\Block::class)) ->willReturn($this->blockMock); - $this->blockMock->expects($this->any()) - ->method('load') - ->willReturnSelf(); - $this->blockMock->expects($this->any()) - ->method('getId') - ->willReturn(true); + $this->blockRepository->expects($this->once()) + ->method('getById') + ->with($this->blockId) + ->willReturn($this->blockMock); + $this->blockMock->expects($this->once())->method('setData'); - $this->blockMock->expects($this->once())->method('save')->willThrowException(new \Exception('Error message.')); + $this->blockRepository->expects($this->once())->method('save') + ->with($this->blockMock) + ->willThrowException(new \Exception('Error message.')); $this->messageManagerMock->expects($this->never()) - ->method('addSuccess'); + ->method('addSuccessMessage'); $this->messageManagerMock->expects($this->once()) - ->method('addException'); + ->method('addExceptionMessage'); $this->dataPersistorMock->expects($this->any()) ->method('set') diff --git a/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/SaveTest.php b/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/SaveTest.php index 03a8fc0969064..a98dd392f6263 100644 --- a/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/SaveTest.php +++ b/app/code/Magento/Cms/Test/Unit/Controller/Adminhtml/Page/SaveTest.php @@ -153,12 +153,7 @@ public function testSaveAction() ->method('create') ->willReturn($page); - $page->expects($this->any()) - ->method('load') - ->willReturnSelf(); - $page->expects($this->any()) - ->method('getId') - ->willReturn(true); + $this->pageRepository->expects($this->once())->method('getById')->with($this->pageId)->willReturn($page); $page->expects($this->once())->method('setData'); $this->pageRepository->expects($this->once())->method('save')->with($page); @@ -182,6 +177,36 @@ public function testSaveActionWithoutData() $this->assertSame($this->resultRedirect, $this->saveController->execute()); } + public function testSaveActionNoId() + { + $this->requestMock->expects($this->any())->method('getPostValue')->willReturn(['page_id' => 1]); + $this->requestMock->expects($this->atLeastOnce()) + ->method('getParam') + ->willReturnMap( + [ + ['page_id', null, 1], + ['back', null, false], + ] + ); + + $page = $this->getMockBuilder(\Magento\Cms\Model\Page::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->pageFactory->expects($this->atLeastOnce()) + ->method('create') + ->willReturn($page); + $this->pageRepository->expects($this->once()) + ->method('getById') + ->with($this->pageId) + ->willThrowException(new \Magento\Framework\Exception\NoSuchEntityException(__('Error message'))); + $this->messageManagerMock->expects($this->once()) + ->method('addErrorMessage') + ->with(__('This page no longer exists.')); + $this->resultRedirect->expects($this->atLeastOnce())->method('setPath')->with('*/*/') ->willReturnSelf(); + $this->assertSame($this->resultRedirect, $this->saveController->execute()); + } + public function testSaveAndContinue() { $this->requestMock->expects($this->any())->method('getPostValue')->willReturn(['page_id' => $this->pageId]); @@ -204,12 +229,7 @@ public function testSaveAndContinue() ->method('create') ->willReturn($page); - $page->expects($this->any()) - ->method('load') - ->willReturnSelf(); - $page->expects($this->any()) - ->method('getId') - ->willReturn(true); + $this->pageRepository->expects($this->once())->method('getById')->with($this->pageId)->willReturn($page); $page->expects($this->once())->method('setData'); $this->pageRepository->expects($this->once())->method('save')->with($page); @@ -251,12 +271,7 @@ public function testSaveActionThrowsException() ->method('create') ->willReturn($page); - $page->expects($this->any()) - ->method('load') - ->willReturnSelf(); - $page->expects($this->any()) - ->method('getId') - ->willReturn(true); + $this->pageRepository->expects($this->once())->method('getById')->with($this->pageId)->willReturn($page); $page->expects($this->once())->method('setData'); $this->pageRepository->expects($this->once())->method('save')->with($page) ->willThrowException(new \Exception('Error message.')); diff --git a/app/code/Magento/Cms/Test/Unit/Helper/Wysiwyg/ImagesTest.php b/app/code/Magento/Cms/Test/Unit/Helper/Wysiwyg/ImagesTest.php index 82b913e0194c9..c434808d0b03f 100644 --- a/app/code/Magento/Cms/Test/Unit/Helper/Wysiwyg/ImagesTest.php +++ b/app/code/Magento/Cms/Test/Unit/Helper/Wysiwyg/ImagesTest.php @@ -110,7 +110,7 @@ protected function setUp() ->willReturnMap( [ [WysiwygConfig::IMAGE_DIRECTORY, null, $this->getAbsolutePath(WysiwygConfig::IMAGE_DIRECTORY)], - [null, null, $this->getAbsolutePath(null)] + [null, null, $this->getAbsolutePath(null)], ] ); @@ -124,7 +124,7 @@ protected function setUp() [ 'clearWebsiteCache', 'getDefaultStoreView', 'getGroup', 'getGroups', 'getStore', 'getStores', 'getWebsite', 'getWebsites', 'hasSingleStore', - 'isSingleStoreMode', 'reinitStores', 'setCurrentStore', 'setIsSingleStoreModeAllowed' + 'isSingleStoreMode', 'reinitStores', 'setCurrentStore', 'setIsSingleStoreModeAllowed', ] ) ->disableOriginalConstructor() @@ -229,7 +229,7 @@ public function providerConvertIdToPath() { return [ ['', ''], - ['/test_path', 'L3Rlc3RfcGF0aA--'] + ['/test_path', 'L3Rlc3RfcGF0aA--'], ]; } @@ -239,6 +239,15 @@ public function testConvertIdToPathNodeRoot() $this->assertEquals($this->imagesHelper->getStorageRoot(), $this->imagesHelper->convertIdToPath($pathId)); } + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Path is invalid + */ + public function testConvertIdToPathInvalid() + { + $this->imagesHelper->convertIdToPath('Ly4uLy4uLy4uLy4uLy4uL3dvcms-'); + } + /** * @param string $fileName * @param int $maxLength @@ -258,7 +267,7 @@ public function providerShortFilename() return [ ['test', 3, 'tes...'], ['test', 4, 'test'], - ['test', 20, 'test'] + ['test', 20, 'test'], ]; } @@ -280,7 +289,7 @@ public function providerShortFilenameDefaultMaxLength() return [ ['Mini text', 'Mini text'], ['20 symbols are here', '20 symbols are here'], - ['Some text for this unit test', 'Some text for this u...'] + ['Some text for this unit test', 'Some text for this u...'], ]; } @@ -319,7 +328,7 @@ public function providerIsUsingStaticUrlsAllowed() { return [ [true], - [false] + [false], ]; } @@ -331,9 +340,14 @@ public function providerIsUsingStaticUrlsAllowed() */ public function testGetCurrentPath($pathId, $expectedPath, $isExist) { - $this->requestMock->expects($this->once()) + $this->requestMock->expects($this->any()) ->method('getParam') - ->willReturn($pathId); + ->willReturnMap( + [ + ['node', null, $pathId], + ['use_storage_root', null, false], + ] + ); $this->directoryWriteMock->expects($this->any()) ->method('isDirectory') @@ -341,7 +355,7 @@ public function testGetCurrentPath($pathId, $expectedPath, $isExist) [ ['/../wysiwyg/test_path', true], ['/../wysiwyg/my.jpg', false], - ['/../wysiwyg', true] + ['/../wysiwyg', true], ] ); $this->directoryWriteMock->expects($this->any()) @@ -392,7 +406,7 @@ public function providerGetCurrentPath() [null, 'PATH/wysiwyg', true], ['L3Rlc3RfcGF0aA--', 'PATH/wysiwyg/test_path', false], ['L215LmpwZw--', 'PATH/wysiwyg', false], - [null, 'PATH/wysiwyg', false] + [null, 'PATH/wysiwyg', false], ]; } @@ -445,15 +459,15 @@ public function providerGetImageHtmlDeclarationRenderingAsTag() 'test.png', true, null, - '' + '', ], [ 'http://localhost', 'test.png', false, '{{media url="/test.png"}}', - '' - ] + '', + ], ]; } @@ -477,7 +491,7 @@ public function testGetImageHtmlDeclaration($baseUrl, $fileName, $isUsingStaticU $this->backendDataMock->expects($this->any()) ->method('getUrl') - ->with('cms/wysiwyg/directive', ['___directive' => $directive]) + ->with('cms/wysiwyg/directive', ['___directive' => $directive, '_escape_params' => false]) ->willReturn($directive); $this->assertEquals($expectedHtml, $this->imagesHelper->getImageHtmlDeclaration($fileName)); @@ -487,7 +501,7 @@ public function providerGetImageHtmlDeclaration() { return [ ['http://localhost', 'test.png', true, 'http://localhost/test.png'], - ['http://localhost', 'test.png', false, '{{media url="/test.png"}}'] + ['http://localhost', 'test.png', false, '{{media url="/test.png"}}'], ]; } diff --git a/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php b/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php index a2178489e1298..805f6d042f94a 100644 --- a/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php +++ b/app/code/Magento/Cms/Test/Unit/Model/Wysiwyg/Images/StorageTest.php @@ -127,7 +127,7 @@ protected function setUp() $this->directoryMock = $this->createPartialMock( \Magento\Framework\Filesystem\Directory\Write::class, - ['delete', 'getDriver', 'create'] + ['delete', 'getDriver', 'create', 'getRelativePath', 'isExist'] ); $this->directoryMock->expects( $this->any() @@ -151,7 +151,7 @@ protected function setUp() $this->adapterFactoryMock = $this->createMock(\Magento\Framework\Image\AdapterFactory::class); $this->imageHelperMock = $this->createPartialMock( \Magento\Cms\Helper\Wysiwyg\Images::class, - ['getStorageRoot'] + ['getStorageRoot', 'getCurrentPath'] ); $this->imageHelperMock->expects( $this->any() @@ -182,7 +182,10 @@ protected function setUp() $this->uploaderFactoryMock = $this->getMockBuilder(\Magento\MediaStorage\Model\File\UploaderFactory::class) ->disableOriginalConstructor() ->getMock(); - $this->sessionMock = $this->createMock(\Magento\Backend\Model\Session::class); + $this->sessionMock = $this->getMockBuilder(\Magento\Backend\Model\Session::class) + ->setMethods(['getCurrentPath']) + ->disableOriginalConstructor() + ->getMock(); $this->backendUrlMock = $this->createMock(\Magento\Backend\Model\Url::class); $this->coreFileStorageMock = $this->getMockBuilder(\Magento\MediaStorage\Helper\File\Storage\Database::class) diff --git a/app/code/Magento/Cms/etc/db_schema.xml b/app/code/Magento/Cms/etc/db_schema.xml index b108dc1b63c32..2b825544f56f1 100644 --- a/app/code/Magento/Cms/etc/db_schema.xml +++ b/app/code/Magento/Cms/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> diff --git a/app/code/Magento/Cms/etc/di.xml b/app/code/Magento/Cms/etc/di.xml index a795cb3cb1889..5b0f5e1413461 100644 --- a/app/code/Magento/Cms/etc/di.xml +++ b/app/code/Magento/Cms/etc/di.xml @@ -55,8 +55,41 @@ - - + + + true + pub[/\\]+media[/\\]+captcha[/\\]*$ + + + true + pub[/\\]+media[/\\]+catalog[/\\]+product[/\\]*$ + + + true + pub[/\\]+media[/\\]+customer[/\\]*$ + + + true + pub[/\\]+media[/\\]+downloadable[/\\]*$ + + + true + pub[/\\]+media[/\\]+import[/\\]*$ + + + true + pub[/\\]+media[/\\]+theme[/\\]*$ + + + true + pub[/\\]+media[/\\]+theme_customization[/\\]*$ + + + true + pub[/\\]+media[/\\]+tmp[/\\]*$ + + + diff --git a/app/code/Magento/Cms/etc/module.xml b/app/code/Magento/Cms/etc/module.xml index 18bd90fddfb90..d3fc2846217d9 100644 --- a/app/code/Magento/Cms/etc/module.xml +++ b/app/code/Magento/Cms/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/files.phtml b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/files.phtml index a4c570f9d65a1..da89991869929 100644 --- a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/files.phtml +++ b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/files.phtml @@ -14,7 +14,13 @@ $_height = $block->getImagesHeight(); ?> getFilesCount() > 0): ?> getFiles() as $file): ?> -
+

getFileThumbUrl($file)):?> <?= $block->escapeHtmlAttr($block->getFileName($file)) ?> diff --git a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml index 8693195449f71..097235bc9fb71 100644 --- a/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml +++ b/app/code/Magento/Cms/view/adminhtml/templates/browser/content/uploader.phtml @@ -7,6 +7,16 @@ // @codingStandardsIgnoreFile /** @var $block \Magento\Cms\Block\Adminhtml\Wysiwyg\Images\Content\Uploader */ + +$filters = $block->getConfig()->getFilters() ?? []; +$allowedExtensions = []; + +foreach ($filters as $media_type) { + $allowedExtensions = array_merge($allowedExtensions, array_map(function ($fileExt) { + return ltrim($fileExt, '.*'); + }, $media_type['files'])); +} + ?>

@@ -28,10 +38,15 @@ require([ 'jquery', 'mage/template', + 'Magento_Ui/js/lib/validation/validator', + 'Magento_Ui/js/modal/alert', 'jquery/file-uploader', 'domReady!', 'mage/translate' -], function ($, mageTemplate) { +], function ($, mageTemplate, validator, uiAlert) { + var maxFileSize = escapeJs($block->getFileSizeService()->getMaxFileSize()) ?>, + allowedExtensions = 'escapeHtml(implode(' ', $allowedExtensions)) ?>'; + $('#getHtmlId() ?> .fileupload').fileupload({ dataType: 'json', formData: { @@ -40,17 +55,44 @@ require([ }, sequentialUploads: true, acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, - maxFileSize: escapeJs($block->getFileSizeService()->getMaxFileSize()) ?>, + allowedExtensions: allowedExtensions, + maxFileSize: maxFileSize, + dropZone: $('#getHtmlId() ?>').closest('[role="dialog"]'), add: function (e, data) { var progressTmpl = mageTemplate('#getHtmlId() ?>-template'), fileSize, - tmpl; + tmpl, + validationResult; - $.each(data.files, function (index, file) { + data.files = data.files.filter(function (file) { fileSize = typeof file.size == "undefined" ? $.mage.__('We could not detect a size.') : byteConvert(file.size); + if (maxFileSize) { + validationResult = validator('validate-max-size', file.size, maxFileSize); + + if (!validationResult.passed) { + uiAlert({ + content: validationResult.message + }); + + return false; + } + } + + if (allowedExtensions) { + validationResult = validator('validate-file-type', file.name, allowedExtensions); + + if (!validationResult.passed) { + uiAlert({ + content: validationResult.message + }); + + return false; + } + } + data.fileId = Math.random().toString(36).substr(2, 9); tmpl = progressTmpl({ @@ -62,11 +104,15 @@ require([ }); $(tmpl).data('image', data).appendTo('#getHtmlId() ?>'); - }); - $(this).fileupload('process', data).done(function () { - data.submit(); + return true; }); + + if (data.files.length) { + $(this).fileupload('process', data).done(function () { + data.submit(); + }); + } }, done: function (e, data) { var progressSelector = '#' + data.fileId + ' .progressbar-container .progressbar'; diff --git a/app/code/Magento/Cms/view/adminhtml/web/js/folder-tree.js b/app/code/Magento/Cms/view/adminhtml/web/js/folder-tree.js index 22540ef9d0c77..6dd0b39f692c2 100644 --- a/app/code/Magento/Cms/view/adminhtml/web/js/folder-tree.js +++ b/app/code/Magento/Cms/view/adminhtml/web/js/folder-tree.js @@ -114,7 +114,7 @@ define([ metadata: { node: codeCopy }, - state: 'closed' + state: node.state || 'closed' }; }); } diff --git a/app/code/Magento/CmsUrlRewrite/etc/module.xml b/app/code/Magento/CmsUrlRewrite/etc/module.xml index bce3dce2a40e0..1e12b5b74971d 100644 --- a/app/code/Magento/CmsUrlRewrite/etc/module.xml +++ b/app/code/Magento/CmsUrlRewrite/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/CmsUrlRewriteGraphQl/etc/module.xml b/app/code/Magento/CmsUrlRewriteGraphQl/etc/module.xml index 9cdc305f2f913..d3c65b440aab7 100644 --- a/app/code/Magento/CmsUrlRewriteGraphQl/etc/module.xml +++ b/app/code/Magento/CmsUrlRewriteGraphQl/etc/module.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/app/code/Magento/Config/App/Config/Type/System.php b/app/code/Magento/Config/App/Config/Type/System.php index ed645bb63febc..4f6d9c14346f0 100644 --- a/app/code/Magento/Config/App/Config/Type/System.php +++ b/app/code/Magento/Config/App/Config/Type/System.php @@ -141,7 +141,7 @@ public function get($path = '') $pathParts = explode('/', $path); if (count($pathParts) === 1 && $pathParts[0] !== 'default') { if (!isset($this->data[$pathParts[0]])) { - $data = $this->reader->read(); + $data = $this->readData(); $this->data = array_replace_recursive($data, $this->data); } return $this->data[$pathParts[0]]; @@ -171,7 +171,7 @@ private function loadAllData() { $cachedData = $this->cache->load($this->configType); if ($cachedData === false) { - $data = $this->reader->read(); + $data = $this->readData(); } else { $data = $this->serializer->unserialize($cachedData); } @@ -188,7 +188,7 @@ private function loadDefaultScopeData($scopeType) { $cachedData = $this->cache->load($this->configType . '_' . $scopeType); if ($cachedData === false) { - $data = $this->reader->read(); + $data = $this->readData(); $this->cacheData($data); } else { $data = [$scopeType => $this->serializer->unserialize($cachedData)]; @@ -216,7 +216,7 @@ private function loadScopeData($scopeType, $scopeId) if (is_array($this->availableDataScopes) && !isset($this->availableDataScopes[$scopeType][$scopeId])) { return [$scopeType => [$scopeId => []]]; } - $data = $this->reader->read(); + $data = $this->readData(); $this->cacheData($data); } else { $data = [$scopeType => [$scopeId => $this->serializer->unserialize($cachedData)]]; @@ -282,6 +282,21 @@ private function getDataByPathParts($data, $pathParts) return $data; } + /** + * The freshly read data. + * + * @return array + */ + private function readData(): array + { + $this->data = $this->reader->read(); + $this->data = $this->postProcessor->process( + $this->data + ); + + return $this->data; + } + /** * Clean cache and global variables cache * diff --git a/app/code/Magento/Config/App/Config/Type/System/Reader.php b/app/code/Magento/Config/App/Config/Type/System/Reader.php index d5a0f09cdd631..9916b795a53b2 100644 --- a/app/code/Magento/Config/App/Config/Type/System/Reader.php +++ b/app/code/Magento/Config/App/Config/Type/System/Reader.php @@ -27,17 +27,13 @@ class Reader */ private $preProcessor; - /** - * @var \Magento\Framework\App\Config\Spi\PostProcessorInterface - */ - private $postProcessor; - /** * Reader constructor. * @param \Magento\Framework\App\Config\ConfigSourceInterface $source * @param \Magento\Store\Model\Config\Processor\Fallback $fallback * @param \Magento\Framework\App\Config\Spi\PreProcessorInterface $preProcessor * @param \Magento\Framework\App\Config\Spi\PostProcessorInterface $postProcessor + * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ public function __construct( \Magento\Framework\App\Config\ConfigSourceInterface $source, @@ -48,7 +44,6 @@ public function __construct( $this->source = $source; $this->fallback = $fallback; $this->preProcessor = $preProcessor; - $this->postProcessor = $postProcessor; } /** @@ -60,11 +55,9 @@ public function __construct( */ public function read() { - return $this->postProcessor->process( - $this->fallback->process( - $this->preProcessor->process( - $this->source->get() - ) + return $this->fallback->process( + $this->preProcessor->process( + $this->source->get() ) ); } diff --git a/app/code/Magento/Config/Block/System/Config/Form.php b/app/code/Magento/Config/Block/System/Config/Form.php index c60dbffbdc5e0..c17df229cf549 100644 --- a/app/code/Magento/Config/Block/System/Config/Form.php +++ b/app/code/Magento/Config/Block/System/Config/Form.php @@ -8,6 +8,7 @@ use Magento\Config\App\Config\Type\System; use Magento\Config\Model\Config\Reader\Source\Deployed\SettingChecker; use Magento\Config\Model\Config\Structure\ElementVisibilityInterface; +use Magento\Framework\App\Config\Data\ProcessorInterface; use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\ObjectManager; @@ -425,23 +426,21 @@ private function getFieldData(\Magento\Config\Model\Config\Structure\Element\Fie if ($placeholderValue) { $data = $placeholderValue; } - if ($data === null) { - if (array_key_exists($path, $this->_configData)) { - $data = $this->_configData[$path]; - } elseif ($field->getConfigPath() !== null) { - $data = $this->getConfigValue($field->getConfigPath()); - } else { - $data = $this->getConfigValue($path); - } + if ($data === null) { + $path = $field->getConfigPath() !== null ? $field->getConfigPath() : $path; + $data = $this->getConfigValue($path); if ($field->hasBackendModel()) { $backendModel = $field->getBackendModel(); - $backendModel->setPath($path) - ->setValue($data) - ->setWebsite($this->getWebsiteCode()) - ->setStore($this->getStoreCode()) - ->afterLoad(); - $data = $backendModel->getValue(); + // Backend models which implement ProcessorInterface are processed by ScopeConfigInterface + if (!$backendModel instanceof ProcessorInterface) { + $backendModel->setPath($path) + ->setValue($data) + ->setWebsite($this->getWebsiteCode()) + ->setStore($this->getStoreCode()) + ->afterLoad(); + $data = $backendModel->getValue(); + } } } diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php b/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php index b884fc2d91f3b..1b287573a9285 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/ConfigSetProcessorFactory.php @@ -28,7 +28,14 @@ class ConfigSetProcessorFactory * lock - save and lock configuration */ const TYPE_DEFAULT = 'default'; + + /** + * @deprecated + * @see TYPE_LOCK_ENV or TYPE_LOCK_CONFIG + */ const TYPE_LOCK = 'lock'; + const TYPE_LOCK_ENV = 'lock-env'; + const TYPE_LOCK_CONFIG = 'lock-config'; /**#@-*/ /**#@-*/ diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/DefaultProcessor.php b/app/code/Magento/Config/Console/Command/ConfigSet/DefaultProcessor.php index 2f5c10037ef06..d7d513bfad423 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/DefaultProcessor.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/DefaultProcessor.php @@ -72,7 +72,7 @@ public function process($path, $value, $scope, $scopeCode) throw new CouldNotSaveException( __( 'The value you set has already been locked. To change the value, use the --%1 option.', - ConfigSetCommand::OPTION_LOCK + ConfigSetCommand::OPTION_LOCK_ENV ) ); } diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php b/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php index 0bd28f0f78d96..6fe2adde3c41e 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/LockProcessor.php @@ -16,7 +16,8 @@ /** * Processes file lock flow of config:set command. - * This processor saves the value of configuration and lock it for editing in Admin interface. + * This processor saves the value of configuration into app/etc/env.php + * and locks it for editing in Admin interface. * * {@inheritdoc} */ @@ -49,23 +50,30 @@ class LockProcessor implements ConfigSetProcessorInterface * @var ConfigPathResolver */ private $configPathResolver; + /** + * @var string + */ + private $target; /** * @param PreparedValueFactory $preparedValueFactory The factory for prepared value * @param DeploymentConfig\Writer $writer The deployment configuration writer * @param ArrayManager $arrayManager An array manager for different manipulations with arrays * @param ConfigPathResolver $configPathResolver The resolver for configuration paths according to source type + * @param string $target */ public function __construct( PreparedValueFactory $preparedValueFactory, DeploymentConfig\Writer $writer, ArrayManager $arrayManager, - ConfigPathResolver $configPathResolver + ConfigPathResolver $configPathResolver, + $target = ConfigFilePool::APP_ENV ) { $this->preparedValueFactory = $preparedValueFactory; $this->deploymentConfigWriter = $writer; $this->arrayManager = $arrayManager; $this->configPathResolver = $configPathResolver; + $this->target = $target; } /** @@ -97,7 +105,7 @@ public function process($path, $value, $scope, $scopeCode) * we'll write value just after all validations are triggered. */ $this->deploymentConfigWriter->saveConfig( - [ConfigFilePool::APP_ENV => $this->arrayManager->set($configPath, [], $value)], + [$this->target => $this->arrayManager->set($configPath, [], $value)], false ); } diff --git a/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php b/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php index 06a01c6686bfd..fcd7c0d5335b1 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php +++ b/app/code/Magento/Config/Console/Command/ConfigSet/ProcessorFacade.php @@ -9,6 +9,7 @@ use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Scope\ValidatorInterface; use Magento\Config\Model\Config\PathValidator; +use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\ConfigurationMismatchException; use Magento\Framework\Exception\CouldNotSaveException; @@ -98,12 +99,35 @@ public function __construct( * @param boolean $lock The lock flag * @return string Processor response message * @throws ValidatorException If some validation is wrong - * @throws CouldNotSaveException If cannot save config value - * @throws ConfigurationMismatchException If processor can not be instantiated * @since 100.2.0 + * @deprecated + * @see processWithLockTarget() */ public function process($path, $value, $scope, $scopeCode, $lock) { + return $this->processWithLockTarget($path, $value, $scope, $scopeCode, $lock); + } + + /** + * Processes config:set command with the option to set a target file. + * + * @param string $path The configuration path in format section/group/field_name + * @param string $value The configuration value + * @param string $scope The configuration scope (default, website, or store) + * @param string $scopeCode The scope code + * @param boolean $lock The lock flag + * @param string $lockTarget + * @return string Processor response message + * @throws ValidatorException If some validation is wrong + */ + public function processWithLockTarget( + $path, + $value, + $scope, + $scopeCode, + $lock, + $lockTarget = ConfigFilePool::APP_ENV + ) { try { $this->scopeValidator->isValid($scope, $scopeCode); $this->pathValidator->validate($path); @@ -111,14 +135,24 @@ public function process($path, $value, $scope, $scopeCode, $lock) throw new ValidatorException(__($exception->getMessage()), $exception); } - $processor = $lock - ? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK) - : $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_DEFAULT); - $message = $lock - ? 'Value was saved and locked.' - : 'Value was saved.'; + $processor = + $lock + ? ( $lockTarget == ConfigFilePool::APP_ENV + ? $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK_ENV) + : $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_LOCK_CONFIG) + ) + : $this->configSetProcessorFactory->create(ConfigSetProcessorFactory::TYPE_DEFAULT) + ; + + $message = + $lock + ? ( $lockTarget == ConfigFilePool::APP_ENV + ? 'Value was saved in app/etc/env.php and locked.' + : 'Value was saved in app/etc/config.php and locked.' + ) + : 'Value was saved.'; - // The processing flow depends on --lock option. + // The processing flow depends on --lock and --share options. $processor->process($path, $value, $scope, $scopeCode); $this->hash->regenerate(System::CONFIG_TYPE); diff --git a/app/code/Magento/Config/Console/Command/ConfigSetCommand.php b/app/code/Magento/Config/Console/Command/ConfigSetCommand.php index 1df1b3c4bed14..cb79daddbf5f9 100644 --- a/app/code/Magento/Config/Console/Command/ConfigSetCommand.php +++ b/app/code/Magento/Config/Console/Command/ConfigSetCommand.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Config\Console\Command; use Magento\Config\App\Config\Type\System; @@ -10,6 +11,7 @@ use Magento\Deploy\Model\DeploymentConfig\ChangeDetector; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Console\Cli; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputArgument; @@ -34,6 +36,8 @@ class ConfigSetCommand extends Command const OPTION_SCOPE = 'scope'; const OPTION_SCOPE_CODE = 'scope-code'; const OPTION_LOCK = 'lock'; + const OPTION_LOCK_ENV = 'lock-env'; + const OPTION_LOCK_CONFIG = 'lock-config'; /**#@-*/ /**#@-*/ @@ -108,11 +112,24 @@ protected function configure() InputArgument::OPTIONAL, 'Scope code (required only if scope is not \'default\')' ), + new InputOption( + static::OPTION_LOCK_ENV, + 'le', + InputOption::VALUE_NONE, + 'Lock value which prevents modification in the Admin (will be saved in app/etc/env.php)' + ), + new InputOption( + static::OPTION_LOCK_CONFIG, + 'lc', + InputOption::VALUE_NONE, + 'Lock and share value with other installations, prevents modification in the Admin ' + . '(will be saved in app/etc/config.php)' + ), new InputOption( static::OPTION_LOCK, 'l', InputOption::VALUE_NONE, - 'Lock value which prevents modification in the Admin' + 'Deprecated, use the --' . static::OPTION_LOCK_ENV . ' option instead.' ), ]); @@ -146,12 +163,23 @@ protected function execute(InputInterface $input, OutputInterface $output) try { $message = $this->emulatedAreaProcessor->process(function () use ($input) { - return $this->processorFacadeFactory->create()->process( + + $lock = $input->getOption(static::OPTION_LOCK_ENV) + || $input->getOption(static::OPTION_LOCK_CONFIG) + || $input->getOption(static::OPTION_LOCK); + + $lockTargetPath = ConfigFilePool::APP_ENV; + if ($input->getOption(static::OPTION_LOCK_CONFIG)) { + $lockTargetPath = ConfigFilePool::APP_CONFIG; + } + + return $this->processorFacadeFactory->create()->processWithLockTarget( $input->getArgument(static::ARG_PATH), $input->getArgument(static::ARG_VALUE), $input->getOption(static::OPTION_SCOPE), $input->getOption(static::OPTION_SCOPE_CODE), - $input->getOption(static::OPTION_LOCK) + $lock, + $lockTargetPath ); }); diff --git a/app/code/Magento/Config/Setup/InstallData.php b/app/code/Magento/Config/Setup/InstallData.php deleted file mode 100644 index 37b8c72851712..0000000000000 --- a/app/code/Magento/Config/Setup/InstallData.php +++ /dev/null @@ -1,38 +0,0 @@ -createMigrationSetup(); - $setup->startSetup(); - - $installer->appendClassAliasReplace( - 'core_config_data', - 'value', - Migration::ENTITY_TYPE_MODEL, - Migration::FIELD_CONTENT_TYPE_PLAIN, - ['config_id'] - ); - $installer->doUpdateClassAliases(); - - $setup->endSetup(); - } -} diff --git a/app/code/Magento/Config/Setup/Patch/Data/UpdateClassAliases.php b/app/code/Magento/Config/Setup/Patch/Data/UpdateClassAliases.php new file mode 100644 index 0000000000000..8986f624c1606 --- /dev/null +++ b/app/code/Magento/Config/Setup/Patch/Data/UpdateClassAliases.php @@ -0,0 +1,76 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $installer = $this->moduleDataSetup->createMigrationSetup(); + $this->moduleDataSetup->startSetup(); + + $installer->appendClassAliasReplace( + 'core_config_data', + 'value', + Migration::ENTITY_TYPE_MODEL, + Migration::FIELD_CONTENT_TYPE_PLAIN, + ['config_id'] + ); + $installer->doUpdateClassAliases(); + $this->moduleDataSetup->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Type/System/ReaderTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Type/System/ReaderTest.php index 7fb126a00ff84..9ec2d9bb9a1f4 100644 --- a/app/code/Magento/Config/Test/Unit/App/Config/Type/System/ReaderTest.php +++ b/app/code/Magento/Config/Test/Unit/App/Config/Type/System/ReaderTest.php @@ -84,10 +84,6 @@ public function testGetCachedWithLoadDefaultScopeData() ->method('process') ->with($data) ->willReturn($data); - $this->postProcessor->expects($this->once()) - ->method('process') - ->with($data) - ->willReturn($data); $this->assertEquals($data, $this->model->read()); } } diff --git a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php index 74315af448226..40aa110382ede 100644 --- a/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php +++ b/app/code/Magento/Config/Test/Unit/App/Config/Type/SystemTest.php @@ -170,7 +170,12 @@ public function testGetNotCached() $this->reader->expects($this->once()) ->method('read') ->willReturn($data); + $this->postProcessor->expects($this->once()) + ->method('process') + ->with($data) + ->willReturn($data); $this->assertEquals($url, $this->configType->get($path)); + $this->assertEquals($url, $this->configType->get($path)); } } diff --git a/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php b/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php index 8385f75a0820a..804965e41b148 100644 --- a/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php +++ b/app/code/Magento/Config/Test/Unit/Block/System/Config/FormTest.php @@ -546,8 +546,8 @@ public function initFieldsDataProvider() return [ [ ['section1/group1/field1' => 'some_value'], - false, - null, + 'some_value', + 'section1/group1/field1', false, 'some_value', null, diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ConfigSetProcessorFactoryTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ConfigSetProcessorFactoryTest.php index decb7d52a5e0c..12b97eb254ded 100644 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ConfigSetProcessorFactoryTest.php +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ConfigSetProcessorFactoryTest.php @@ -41,7 +41,7 @@ protected function setUp() $this->model = new ConfigSetProcessorFactory( $this->objectManagerMock, [ - ConfigSetProcessorFactory::TYPE_LOCK => LockProcessor::class, + ConfigSetProcessorFactory::TYPE_LOCK_ENV => LockProcessor::class, ConfigSetProcessorFactory::TYPE_DEFAULT => DefaultProcessor::class, 'wrongType' => \stdClass::class, ] @@ -59,7 +59,7 @@ public function testCreate() $this->assertInstanceOf( ConfigSetProcessorInterface::class, - $this->model->create(ConfigSetProcessorFactory::TYPE_LOCK) + $this->model->create(ConfigSetProcessorFactory::TYPE_LOCK_ENV) ); } diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/DefaultProcessorTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/DefaultProcessorTest.php index 066b0fbe84b50..984e0fe842687 100644 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/DefaultProcessorTest.php +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/DefaultProcessorTest.php @@ -166,7 +166,9 @@ private function configMockForProcessTest($path, $scope, $scopeCode) /** * @expectedException \Magento\Framework\Exception\LocalizedException - * @expectedExceptionMessage The value you set has already been locked. To change the value, use the --lock option. + * @codingStandardsIgnoreStart + * @expectedExceptionMessage The value you set has already been locked. To change the value, use the --lock-env option. + * @codingStandardsIgnoreEnd */ public function testProcessLockedValue() { diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockConfigProcessorTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockConfigProcessorTest.php new file mode 100644 index 0000000000000..c727184efb4fc --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockConfigProcessorTest.php @@ -0,0 +1,220 @@ +preparedValueFactory = $this->getMockBuilder(PreparedValueFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->deploymentConfigWriterMock = $this->getMockBuilder(DeploymentConfig\Writer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configPathResolver = $this->getMockBuilder(ConfigPathResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->valueMock = $this->getMockBuilder(Value::class) + ->setMethods(['validateBeforeSave', 'beforeSave', 'setValue', 'getValue', 'afterSave']) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new LockProcessor( + $this->preparedValueFactory, + $this->deploymentConfigWriterMock, + $this->arrayManagerMock, + $this->configPathResolver, + ConfigFilePool::APP_CONFIG + ); + } + + /** + * Tests process of share flow. + * + * @param string $path + * @param string $value + * @param string $scope + * @param string|null $scopeCode + * @dataProvider processDataProvider + */ + public function testProcess($path, $value, $scope, $scopeCode) + { + $this->preparedValueFactory->expects($this->once()) + ->method('create') + ->with($path, $value, $scope, $scopeCode) + ->willReturn($this->valueMock); + $this->configPathResolver->expects($this->once()) + ->method('resolve') + ->willReturn('system/default/test/test/test'); + $this->arrayManagerMock->expects($this->once()) + ->method('set') + ->with('system/default/test/test/test', [], $value) + ->willReturn([ + 'system' => [ + 'default' => [ + 'test' => [ + 'test' => [ + 'test' => $value + ] + ] + ] + ] + ]); + $this->valueMock->expects($this->once()) + ->method('getValue') + ->willReturn($value); + $this->deploymentConfigWriterMock->expects($this->once()) + ->method('saveConfig') + ->with( + [ + ConfigFilePool::APP_CONFIG => [ + 'system' => [ + 'default' => [ + 'test' => [ + 'test' => [ + 'test' => $value + ] + ] + ] + ] + ] + ], + false + ); + $this->valueMock->expects($this->once()) + ->method('validateBeforeSave'); + $this->valueMock->expects($this->once()) + ->method('beforeSave'); + $this->valueMock->expects($this->once()) + ->method('afterSave'); + + $this->model->process($path, $value, $scope, $scopeCode); + } + + /** + * @return array + */ + public function processDataProvider() + { + return [ + ['test/test/test', 'value', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null], + ['test/test/test', 'value', ScopeInterface::SCOPE_WEBSITE, 'base'], + ['test/test/test', 'value', ScopeInterface::SCOPE_STORE, 'test'], + ]; + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Filesystem is not writable. + */ + public function testProcessNotReadableFs() + { + $path = 'test/test/test'; + $value = 'value'; + + $this->preparedValueFactory->expects($this->once()) + ->method('create') + ->willReturn($this->valueMock); + $this->valueMock->expects($this->once()) + ->method('getValue') + ->willReturn($value); + $this->configPathResolver->expects($this->once()) + ->method('resolve') + ->willReturn('system/default/test/test/test'); + $this->arrayManagerMock->expects($this->once()) + ->method('set') + ->with('system/default/test/test/test', [], $value) + ->willReturn(null); + $this->deploymentConfigWriterMock->expects($this->once()) + ->method('saveConfig') + ->willThrowException(new FileSystemException(__('Filesystem is not writable.'))); + + $this->model->process($path, $value, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Invalid values + */ + public function testCustomException() + { + $path = 'test/test/test'; + $value = 'value'; + + $this->configPathResolver->expects($this->once()) + ->method('resolve') + ->willReturn('system/default/test/test/test'); + $this->preparedValueFactory->expects($this->once()) + ->method('create') + ->willReturn($this->valueMock); + $this->arrayManagerMock->expects($this->never()) + ->method('set'); + $this->valueMock->expects($this->once()) + ->method('getValue'); + $this->valueMock->expects($this->once()) + ->method('afterSave') + ->willThrowException(new \Exception('Invalid values')); + $this->deploymentConfigWriterMock->expects($this->never()) + ->method('saveConfig'); + + $this->model->process($path, $value, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); + } +} diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockEnvProcessorTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockEnvProcessorTest.php new file mode 100644 index 0000000000000..4e0248f886028 --- /dev/null +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockEnvProcessorTest.php @@ -0,0 +1,220 @@ +preparedValueFactory = $this->getMockBuilder(PreparedValueFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->deploymentConfigWriterMock = $this->getMockBuilder(DeploymentConfig\Writer::class) + ->disableOriginalConstructor() + ->getMock(); + $this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configPathResolver = $this->getMockBuilder(ConfigPathResolver::class) + ->disableOriginalConstructor() + ->getMock(); + $this->valueMock = $this->getMockBuilder(Value::class) + ->setMethods(['validateBeforeSave', 'beforeSave', 'setValue', 'getValue', 'afterSave']) + ->disableOriginalConstructor() + ->getMock(); + + $this->model = new LockProcessor( + $this->preparedValueFactory, + $this->deploymentConfigWriterMock, + $this->arrayManagerMock, + $this->configPathResolver, + ConfigFilePool::APP_ENV + ); + } + + /** + * Tests process of lock flow. + * + * @param string $path + * @param string $value + * @param string $scope + * @param string|null $scopeCode + * @dataProvider processDataProvider + */ + public function testProcess($path, $value, $scope, $scopeCode) + { + $this->preparedValueFactory->expects($this->once()) + ->method('create') + ->with($path, $value, $scope, $scopeCode) + ->willReturn($this->valueMock); + $this->configPathResolver->expects($this->once()) + ->method('resolve') + ->willReturn('system/default/test/test/test'); + $this->arrayManagerMock->expects($this->once()) + ->method('set') + ->with('system/default/test/test/test', [], $value) + ->willReturn([ + 'system' => [ + 'default' => [ + 'test' => [ + 'test' => [ + 'test' => $value + ] + ] + ] + ] + ]); + $this->valueMock->expects($this->once()) + ->method('getValue') + ->willReturn($value); + $this->deploymentConfigWriterMock->expects($this->once()) + ->method('saveConfig') + ->with( + [ + ConfigFilePool::APP_ENV => [ + 'system' => [ + 'default' => [ + 'test' => [ + 'test' => [ + 'test' => $value + ] + ] + ] + ] + ] + ], + false + ); + $this->valueMock->expects($this->once()) + ->method('validateBeforeSave'); + $this->valueMock->expects($this->once()) + ->method('beforeSave'); + $this->valueMock->expects($this->once()) + ->method('afterSave'); + + $this->model->process($path, $value, $scope, $scopeCode); + } + + /** + * @return array + */ + public function processDataProvider() + { + return [ + ['test/test/test', 'value', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null], + ['test/test/test', 'value', ScopeInterface::SCOPE_WEBSITE, 'base'], + ['test/test/test', 'value', ScopeInterface::SCOPE_STORE, 'test'], + ]; + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Filesystem is not writable. + */ + public function testProcessNotReadableFs() + { + $path = 'test/test/test'; + $value = 'value'; + + $this->preparedValueFactory->expects($this->once()) + ->method('create') + ->willReturn($this->valueMock); + $this->valueMock->expects($this->once()) + ->method('getValue') + ->willReturn($value); + $this->configPathResolver->expects($this->once()) + ->method('resolve') + ->willReturn('system/default/test/test/test'); + $this->arrayManagerMock->expects($this->once()) + ->method('set') + ->with('system/default/test/test/test', [], $value) + ->willReturn(null); + $this->deploymentConfigWriterMock->expects($this->once()) + ->method('saveConfig') + ->willThrowException(new FileSystemException(__('Filesystem is not writable.'))); + + $this->model->process($path, $value, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Invalid values + */ + public function testCustomException() + { + $path = 'test/test/test'; + $value = 'value'; + + $this->configPathResolver->expects($this->once()) + ->method('resolve') + ->willReturn('system/default/test/test/test'); + $this->preparedValueFactory->expects($this->once()) + ->method('create') + ->willReturn($this->valueMock); + $this->arrayManagerMock->expects($this->never()) + ->method('set'); + $this->valueMock->expects($this->once()) + ->method('getValue'); + $this->valueMock->expects($this->once()) + ->method('afterSave') + ->willThrowException(new \Exception('Invalid values')); + $this->deploymentConfigWriterMock->expects($this->never()) + ->method('saveConfig'); + + $this->model->process($path, $value, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); + } +} diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockProcessorTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockProcessorTest.php deleted file mode 100644 index 4535e9ad888c2..0000000000000 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/LockProcessorTest.php +++ /dev/null @@ -1,219 +0,0 @@ -preparedValueFactory = $this->getMockBuilder(PreparedValueFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->deploymentConfigWriterMock = $this->getMockBuilder(DeploymentConfig\Writer::class) - ->disableOriginalConstructor() - ->getMock(); - $this->arrayManagerMock = $this->getMockBuilder(ArrayManager::class) - ->disableOriginalConstructor() - ->getMock(); - $this->configPathResolver = $this->getMockBuilder(ConfigPathResolver::class) - ->disableOriginalConstructor() - ->getMock(); - $this->valueMock = $this->getMockBuilder(Value::class) - ->setMethods(['validateBeforeSave', 'beforeSave', 'setValue', 'getValue', 'afterSave']) - ->disableOriginalConstructor() - ->getMock(); - - $this->model = new LockProcessor( - $this->preparedValueFactory, - $this->deploymentConfigWriterMock, - $this->arrayManagerMock, - $this->configPathResolver - ); - } - - /** - * Tests process of lock flow. - * - * @param string $path - * @param string $value - * @param string $scope - * @param string|null $scopeCode - * @dataProvider processDataProvider - */ - public function testProcess($path, $value, $scope, $scopeCode) - { - $this->preparedValueFactory->expects($this->once()) - ->method('create') - ->with($path, $value, $scope, $scopeCode) - ->willReturn($this->valueMock); - $this->configPathResolver->expects($this->once()) - ->method('resolve') - ->willReturn('system/default/test/test/test'); - $this->arrayManagerMock->expects($this->once()) - ->method('set') - ->with('system/default/test/test/test', [], $value) - ->willReturn([ - 'system' => [ - 'default' => [ - 'test' => [ - 'test' => [ - 'test' => $value - ] - ] - ] - ] - ]); - $this->valueMock->expects($this->once()) - ->method('getValue') - ->willReturn($value); - $this->deploymentConfigWriterMock->expects($this->once()) - ->method('saveConfig') - ->with( - [ - ConfigFilePool::APP_ENV => [ - 'system' => [ - 'default' => [ - 'test' => [ - 'test' => [ - 'test' => $value - ] - ] - ] - ] - ] - ], - false - ); - $this->valueMock->expects($this->once()) - ->method('validateBeforeSave'); - $this->valueMock->expects($this->once()) - ->method('beforeSave'); - $this->valueMock->expects($this->once()) - ->method('afterSave'); - - $this->model->process($path, $value, $scope, $scopeCode); - } - - /** - * @return array - */ - public function processDataProvider() - { - return [ - ['test/test/test', 'value', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null], - ['test/test/test', 'value', ScopeInterface::SCOPE_WEBSITE, 'base'], - ['test/test/test', 'value', ScopeInterface::SCOPE_STORE, 'test'], - ]; - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - * @expectedExceptionMessage Filesystem is not writable. - */ - public function testProcessNotReadableFs() - { - $path = 'test/test/test'; - $value = 'value'; - - $this->preparedValueFactory->expects($this->once()) - ->method('create') - ->willReturn($this->valueMock); - $this->valueMock->expects($this->once()) - ->method('getValue') - ->willReturn($value); - $this->configPathResolver->expects($this->once()) - ->method('resolve') - ->willReturn('system/default/test/test/test'); - $this->arrayManagerMock->expects($this->once()) - ->method('set') - ->with('system/default/test/test/test', [], $value) - ->willReturn(null); - $this->deploymentConfigWriterMock->expects($this->once()) - ->method('saveConfig') - ->willThrowException(new FileSystemException(__('Filesystem is not writable.'))); - - $this->model->process($path, $value, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); - } - - /** - * @expectedException \Exception - * @expectedExceptionMessage Invalid values - */ - public function testCustomException() - { - $path = 'test/test/test'; - $value = 'value'; - - $this->configPathResolver->expects($this->once()) - ->method('resolve') - ->willReturn('system/default/test/test/test'); - $this->preparedValueFactory->expects($this->once()) - ->method('create') - ->willReturn($this->valueMock); - $this->arrayManagerMock->expects($this->never()) - ->method('set'); - $this->valueMock->expects($this->once()) - ->method('getValue'); - $this->valueMock->expects($this->once()) - ->method('afterSave') - ->willThrowException(new \Exception('Invalid values')); - $this->deploymentConfigWriterMock->expects($this->never()) - ->method('saveConfig'); - - $this->model->process($path, $value, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); - } -} diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php index 4e65ab3f4cc21..ac4dda2a98517 100644 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSet/ProcessorFacadeTest.php @@ -11,6 +11,7 @@ use Magento\Framework\App\Config\ScopeConfigInterface; use Magento\Framework\App\Scope\ValidatorInterface; use Magento\Config\Model\Config\PathValidator; +use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Exception\ValidatorException; use Magento\Framework\Exception\CouldNotSaveException; @@ -122,7 +123,13 @@ public function testProcess() $this->assertSame( 'Value was saved.', - $this->model->process('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, false) + $this->model->processWithLockTarget( + 'test/test/test', + 'test', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + null, + false + ) ); } @@ -132,12 +139,19 @@ public function testProcess() */ public function testProcessWithValidatorException(LocalizedException $exception) { - $this->expectException(ValidatorException::class, 'Some error'); + $this->expectException(ValidatorException::class); + $this->expectExceptionMessage('Some error'); $this->scopeValidatorMock->expects($this->once()) ->method('isValid') ->willThrowException($exception); - $this->model->process('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, false); + $this->model->processWithLockTarget( + 'test/test/test', + 'test', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + null, + false + ); } /** @@ -172,7 +186,13 @@ public function testProcessWithConfigurationMismatchException() $this->configMock->expects($this->never()) ->method('clean'); - $this->model->process('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, false); + $this->model->processWithLockTarget( + 'test/test/test', + 'test', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + null, + false + ); } /** @@ -198,17 +218,50 @@ public function testProcessWithCouldNotSaveException() $this->configMock->expects($this->never()) ->method('clean'); - $this->model->process('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, false); + $this->model->processWithLockTarget( + 'test/test/test', + 'test', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + null, + false + ); + } + + public function testExecuteLockEnv() + { + $this->scopeValidatorMock->expects($this->once()) + ->method('isValid') + ->willReturn(true); + $this->configSetProcessorFactoryMock->expects($this->once()) + ->method('create') + ->with(ConfigSetProcessorFactory::TYPE_LOCK_ENV) + ->willReturn($this->processorMock); + $this->processorMock->expects($this->once()) + ->method('process') + ->with('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null); + $this->configMock->expects($this->once()) + ->method('clean'); + + $this->assertSame( + 'Value was saved in app/etc/env.php and locked.', + $this->model->processWithLockTarget( + 'test/test/test', + 'test', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + null, + true + ) + ); } - public function testExecuteLock() + public function testExecuteLockConfig() { $this->scopeValidatorMock->expects($this->once()) ->method('isValid') ->willReturn(true); $this->configSetProcessorFactoryMock->expects($this->once()) ->method('create') - ->with(ConfigSetProcessorFactory::TYPE_LOCK) + ->with(ConfigSetProcessorFactory::TYPE_LOCK_CONFIG) ->willReturn($this->processorMock); $this->processorMock->expects($this->once()) ->method('process') @@ -217,8 +270,15 @@ public function testExecuteLock() ->method('clean'); $this->assertSame( - 'Value was saved and locked.', - $this->model->process('test/test/test', 'test', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null, true) + 'Value was saved in app/etc/config.php and locked.', + $this->model->processWithLockTarget( + 'test/test/test', + 'test', + ScopeConfigInterface::SCOPE_TYPE_DEFAULT, + null, + true, + ConfigFilePool::APP_CONFIG + ) ); } } diff --git a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSetCommandTest.php b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSetCommandTest.php index 0271de0da81f4..cb3a401e6f1d1 100644 --- a/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSetCommandTest.php +++ b/app/code/Magento/Config/Test/Unit/Console/Command/ConfigSetCommandTest.php @@ -95,7 +95,7 @@ public function testExecute() ->method('create') ->willReturn($this->processorFacadeMock); $this->processorFacadeMock->expects($this->once()) - ->method('process') + ->method('processWithLockTarget') ->willReturn('Some message'); $this->emulatedAreProcessorMock->expects($this->once()) ->method('process') @@ -171,9 +171,7 @@ public function testExecuteWithException() ->willReturn(false); $this->emulatedAreProcessorMock->expects($this->once()) ->method('process') - ->willThrowException( - new ValidatorException(__('The "test/test/test" path doesn\'t exist. Verify and try again.')) - ); + ->willThrowException(new ValidatorException(__('The "test/test/test" path does not exists'))); $tester = new CommandTester($this->command); $tester->execute([ @@ -182,7 +180,7 @@ public function testExecuteWithException() ]); $this->assertContains( - __('The "test/test/test" path doesn\'t exist. Verify and try again.')->render(), + __('The "test/test/test" path does not exists')->render(), $tester->getDisplay() ); $this->assertSame(Cli::RETURN_FAILURE, $tester->getStatusCode()); diff --git a/app/code/Magento/Config/etc/db_schema.xml b/app/code/Magento/Config/etc/db_schema.xml index e7be05d4a8cc2..3f55d582776ce 100644 --- a/app/code/Magento/Config/etc/db_schema.xml +++ b/app/code/Magento/Config/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Config/etc/di.xml b/app/code/Magento/Config/etc/di.xml index bcddd8ceaf27a..a5dd18097fb47 100644 --- a/app/code/Magento/Config/etc/di.xml +++ b/app/code/Magento/Config/etc/di.xml @@ -296,10 +296,21 @@ Magento\Config\Console\Command\ConfigSet\DefaultProcessor - Magento\Config\Console\Command\ConfigSet\LockProcessor + Magento\Config\Console\Command\ConfigSet\VirtualLockEnvProcessor + Magento\Config\Console\Command\ConfigSet\VirtualLockConfigProcessor + + + app_env + + + + + app_config + + diff --git a/app/code/Magento/Config/etc/module.xml b/app/code/Magento/Config/etc/module.xml index b64cbe2b72623..2fd4255a2bc0c 100644 --- a/app/code/Magento/Config/etc/module.xml +++ b/app/code/Magento/Config/etc/module.xml @@ -6,5 +6,9 @@ */ --> - + + + + + diff --git a/app/code/Magento/ConfigurableImportExport/etc/module.xml b/app/code/Magento/ConfigurableImportExport/etc/module.xml index 83a4fc4e1a793..7ff81f8d63443 100644 --- a/app/code/Magento/ConfigurableImportExport/etc/module.xml +++ b/app/code/Magento/ConfigurableImportExport/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/ConfigurableProduct/CustomerData/ConfigurableItem.php b/app/code/Magento/ConfigurableProduct/CustomerData/ConfigurableItem.php index 0a4fc20578ed9..3a9ed653305c5 100644 --- a/app/code/Magento/ConfigurableProduct/CustomerData/ConfigurableItem.php +++ b/app/code/Magento/ConfigurableProduct/CustomerData/ConfigurableItem.php @@ -26,6 +26,7 @@ class ConfigurableItem extends DefaultItem * @param \Magento\Catalog\Helper\Product\ConfigurationPool $configurationPool * @param \Magento\Checkout\Helper\Data $checkoutHelper * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig + * @param \Magento\Framework\Escaper|null $escaper */ public function __construct( \Magento\Catalog\Helper\Image $imageHelper, @@ -33,14 +34,16 @@ public function __construct( \Magento\Framework\UrlInterface $urlBuilder, \Magento\Catalog\Helper\Product\ConfigurationPool $configurationPool, \Magento\Checkout\Helper\Data $checkoutHelper, - \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig + \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, + \Magento\Framework\Escaper $escaper = null ) { parent::__construct( $imageHelper, $msrpHelper, $urlBuilder, $configurationPool, - $checkoutHelper + $checkoutHelper, + $escaper ); $this->_scopeConfig = $scopeConfig; } diff --git a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php index 487ab19de2063..a30ec81528dd3 100644 --- a/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Model/ResourceModel/Product/Indexer/Price/Configurable.php @@ -133,6 +133,10 @@ protected function _applyConfigurableOption() ['le' => $this->getTable('catalog_product_entity')], 'le.' . $linkField . ' = l.parent_id', ['parent_id' => 'entity_id'] + )->join( + ['i' => $this->_getDefaultFinalPriceTable()], + 'le.entity_id = i.entity_id', + [] ); $select = $connection->select(); diff --git a/app/code/Magento/ConfigurableProduct/Setup/InstallData.php b/app/code/Magento/ConfigurableProduct/Setup/InstallData.php deleted file mode 100644 index 7bc56569dea44..0000000000000 --- a/app/code/Magento/ConfigurableProduct/Setup/InstallData.php +++ /dev/null @@ -1,74 +0,0 @@ -eavSetupFactory = $eavSetupFactory; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - $attributes = [ - 'country_of_manufacture', - 'minimal_price', - 'msrp', - 'msrp_display_actual_price_type', - 'price', - 'special_price', - 'special_from_date', - 'special_to_date', - 'tier_price', - 'weight', - 'color' - ]; - foreach ($attributes as $attributeCode) { - $relatedProductTypes = explode( - ',', - $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode, 'apply_to') - ); - if (!in_array(Configurable::TYPE_CODE, $relatedProductTypes)) { - $relatedProductTypes[] = Configurable::TYPE_CODE; - $eavSetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - $attributeCode, - 'apply_to', - implode(',', $relatedProductTypes) - ); - } - } - } -} diff --git a/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/InstallInitialConfigurableAttributes.php b/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/InstallInitialConfigurableAttributes.php new file mode 100644 index 0000000000000..c9fea3e74d3d2 --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/InstallInitialConfigurableAttributes.php @@ -0,0 +1,105 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + $attributes = [ + 'country_of_manufacture', + 'minimal_price', + 'msrp', + 'msrp_display_actual_price_type', + 'price', + 'special_price', + 'special_from_date', + 'special_to_date', + 'tier_price', + 'weight', + 'color' + ]; + foreach ($attributes as $attributeCode) { + $relatedProductTypes = explode( + ',', + $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode, 'apply_to') + ); + if (!in_array(Configurable::TYPE_CODE, $relatedProductTypes)) { + $relatedProductTypes[] = Configurable::TYPE_CODE; + $eavSetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + $attributeCode, + 'apply_to', + implode(',', $relatedProductTypes) + ); + } + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/UpdateTierPriceAttribute.php b/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/UpdateTierPriceAttribute.php new file mode 100644 index 0000000000000..325fb447d225f --- /dev/null +++ b/app/code/Magento/ConfigurableProduct/Setup/Patch/Data/UpdateTierPriceAttribute.php @@ -0,0 +1,94 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + $relatedProductTypes = explode( + ',', + $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'tier_price', 'apply_to') + ); + $key = array_search(Configurable::TYPE_CODE, $relatedProductTypes); + if ($key !== false) { + unset($relatedProductTypes[$key]); + $eavSetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'tier_price', + 'apply_to', + implode(',', $relatedProductTypes) + ); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + InstallInitialConfigurableAttributes::class, + ]; + } + + /** + * {@inheritdoc}\ + */ + public static function getVersion() + { + return '2.2.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/ConfigurableProduct/Setup/UpgradeData.php b/app/code/Magento/ConfigurableProduct/Setup/UpgradeData.php deleted file mode 100644 index 326af02fe39bb..0000000000000 --- a/app/code/Magento/ConfigurableProduct/Setup/UpgradeData.php +++ /dev/null @@ -1,65 +0,0 @@ -eavSetupFactory = $eavSetupFactory; - } - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - if (version_compare($context->getVersion(), '2.2.0') < 0) { - /** @var EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - $relatedProductTypes = explode( - ',', - $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, 'tier_price', 'apply_to') - ); - $key = array_search(Configurable::TYPE_CODE, $relatedProductTypes); - if ($key !== false) { - unset($relatedProductTypes[$key]); - $eavSetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'tier_price', - 'apply_to', - implode(',', $relatedProductTypes) - ); - } - } - - $setup->endSetup(); - } -} diff --git a/app/code/Magento/ConfigurableProduct/etc/db_schema.xml b/app/code/Magento/ConfigurableProduct/etc/db_schema.xml index d45c06bea1c3e..7c6661a5f399a 100644 --- a/app/code/Magento/ConfigurableProduct/etc/db_schema.xml +++ b/app/code/Magento/ConfigurableProduct/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
- + diff --git a/app/code/Magento/ConfigurableProductGraphQl/etc/module.xml b/app/code/Magento/ConfigurableProductGraphQl/etc/module.xml index e86b1bdf604c6..98e7957d0af8e 100644 --- a/app/code/Magento/ConfigurableProductGraphQl/etc/module.xml +++ b/app/code/Magento/ConfigurableProductGraphQl/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/ConfigurableProductSales/etc/module.xml b/app/code/Magento/ConfigurableProductSales/etc/module.xml index 4da83c9c0269b..bf5bc4472c8b2 100644 --- a/app/code/Magento/ConfigurableProductSales/etc/module.xml +++ b/app/code/Magento/ConfigurableProductSales/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Contact/etc/module.xml b/app/code/Magento/Contact/etc/module.xml index ec91859ee2c8d..64ba1c1fb0f0d 100644 --- a/app/code/Magento/Contact/etc/module.xml +++ b/app/code/Magento/Contact/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Cookie/etc/module.xml b/app/code/Magento/Cookie/etc/module.xml index 35c5a52f42ec7..df64e8b3ebfe8 100644 --- a/app/code/Magento/Cookie/etc/module.xml +++ b/app/code/Magento/Cookie/etc/module.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/app/code/Magento/Cron/etc/db_schema.xml b/app/code/Magento/Cron/etc/db_schema.xml index 9f019d108b257..deff05d3eec96 100644 --- a/app/code/Magento/Cron/etc/db_schema.xml +++ b/app/code/Magento/Cron/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Cron/etc/module.xml b/app/code/Magento/Cron/etc/module.xml index ce31b046500f7..8112b9e8c46db 100644 --- a/app/code/Magento/Cron/etc/module.xml +++ b/app/code/Magento/Cron/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/CurrencySymbol/Setup/Patch/Data/ConvertSerializedCustomCurrencySymbolToJson.php b/app/code/Magento/CurrencySymbol/Setup/Patch/Data/ConvertSerializedCustomCurrencySymbolToJson.php new file mode 100644 index 0000000000000..be2f2c5147124 --- /dev/null +++ b/app/code/Magento/CurrencySymbol/Setup/Patch/Data/ConvertSerializedCustomCurrencySymbolToJson.php @@ -0,0 +1,100 @@ +fieldDataConverterFactory = $fieldDataConverterFactory; + $this->queryModifierFactory = $queryModifierFactory; + $this->moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $queryModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'path' => [Currencysymbol::XML_PATH_CUSTOM_CURRENCY_SYMBOL] + ] + ] + ); + $fieldDataConverter->convert( + $this->moduleDataSetup->getConnection(), + $this->moduleDataSetup->getTable('core_config_data'), + 'config_id', + 'value', + $queryModifier + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/CurrencySymbol/Setup/UpgradeData.php b/app/code/Magento/CurrencySymbol/Setup/UpgradeData.php deleted file mode 100644 index 474efde78ea5b..0000000000000 --- a/app/code/Magento/CurrencySymbol/Setup/UpgradeData.php +++ /dev/null @@ -1,82 +0,0 @@ -fieldDataConverterFactory = $fieldDataConverterFactory; - $this->queryModifierFactory = $queryModifierFactory; - } - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $this->convertSerializedCustomCurrencySymbolToJson($setup); - } - } - - /** - * Converts custom currency symbol configuration in core_config_data table from serialized to JSON format - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function convertSerializedCustomCurrencySymbolToJson(ModuleDataSetupInterface $setup) - { - $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); - $queryModifier = $this->queryModifierFactory->create( - 'in', - [ - 'values' => [ - 'path' => [Currencysymbol::XML_PATH_CUSTOM_CURRENCY_SYMBOL] - ] - ] - ); - $fieldDataConverter->convert( - $setup->getConnection(), - $setup->getTable('core_config_data'), - 'config_id', - 'value', - $queryModifier - ); - } -} diff --git a/app/code/Magento/CurrencySymbol/etc/module.xml b/app/code/Magento/CurrencySymbol/etc/module.xml index f638479031f4f..2af87335518d1 100644 --- a/app/code/Magento/CurrencySymbol/etc/module.xml +++ b/app/code/Magento/CurrencySymbol/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Customer/Block/Address/Edit.php b/app/code/Magento/Customer/Block/Address/Edit.php index 6362f28a4f96d..6a42e9670ccc6 100644 --- a/app/code/Magento/Customer/Block/Address/Edit.php +++ b/app/code/Magento/Customer/Block/Address/Edit.php @@ -129,7 +129,7 @@ protected function _prepareLayout() if ($postedData = $this->_customerSession->getAddressFormData(true)) { $postedData['region'] = [ - 'region_id' => $postedData['region_id'], + 'region_id' => isset($postedData['region_id']) ? $postedData['region_id'] : null, 'region' => $postedData['region'], ]; $this->dataObjectHelper->populateWithArray( diff --git a/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php b/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php index 711fab9e608bf..20d330354bce4 100644 --- a/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php +++ b/app/code/Magento/Customer/Controller/Adminhtml/Index/Viewfile.php @@ -132,30 +132,15 @@ public function __construct( */ public function execute() { - $file = null; - $plain = false; - if ($this->getRequest()->getParam('file')) { - // download file - $file = $this->urlDecoder->decode( - $this->getRequest()->getParam('file') - ); - } elseif ($this->getRequest()->getParam('image')) { - // show plain image - $file = $this->urlDecoder->decode( - $this->getRequest()->getParam('image') - ); - $plain = true; - } else { - throw new NotFoundException(__('Page not found.')); - } + list($file, $plain) = $this->getFileParams(); /** @var \Magento\Framework\Filesystem $filesystem */ $filesystem = $this->_objectManager->get(\Magento\Framework\Filesystem::class); $directory = $filesystem->getDirectoryRead(DirectoryList::MEDIA); $fileName = CustomerMetadataInterface::ENTITY_TYPE_CUSTOMER . '/' . ltrim($file, '/'); $path = $directory->getAbsolutePath($fileName); - if (!$directory->isFile($fileName) - && !$this->_objectManager->get(\Magento\MediaStorage\Helper\File\Storage::class)->processStorageFile($path) + if (mb_strpos($path, '..') !== false || (!$directory->isFile($fileName) + && !$this->_objectManager->get(\Magento\MediaStorage\Helper\File\Storage::class)->processStorageFile($path)) ) { throw new NotFoundException(__('Page not found.')); } @@ -198,4 +183,32 @@ public function execute() ); } } + + /** + * Get parameters from request. + * + * @return array + * @throws NotFoundException + */ + private function getFileParams() + { + $file = null; + $plain = false; + if ($this->getRequest()->getParam('file')) { + // download file + $file = $this->urlDecoder->decode( + $this->getRequest()->getParam('file') + ); + } elseif ($this->getRequest()->getParam('image')) { + // show plain image + $file = $this->urlDecoder->decode( + $this->getRequest()->getParam('image') + ); + $plain = true; + } else { + throw new NotFoundException(__('Page not found.')); + } + + return [$file, $plain]; + } } diff --git a/app/code/Magento/Customer/Model/Account/Redirect.php b/app/code/Magento/Customer/Model/Account/Redirect.php index 2e8d596474e96..2ccaaea45680c 100644 --- a/app/code/Magento/Customer/Model/Account/Redirect.php +++ b/app/code/Magento/Customer/Model/Account/Redirect.php @@ -74,6 +74,11 @@ class Redirect */ private $hostChecker; + /** + * @var Session + */ + private $session; + /** * @param RequestInterface $request * @param Session $customerSession @@ -206,6 +211,10 @@ protected function processLoggedCustomer() $referer = $this->request->getParam(CustomerUrl::REFERER_QUERY_PARAM_NAME); if ($referer) { $referer = $this->urlDecoder->decode($referer); + preg_match('/logoutSuccess\//', $referer, $matches, PREG_OFFSET_CAPTURE); + if (!empty($matches)) { + $referer = str_replace('logoutSuccess/', '', $referer); + } if ($this->hostChecker->isOwnOrigin($referer)) { $this->applyRedirect($referer); } diff --git a/app/code/Magento/Customer/Model/AccountManagement.php b/app/code/Magento/Customer/Model/AccountManagement.php index cd5fef7316999..7d0b271b9b137 100644 --- a/app/code/Magento/Customer/Model/AccountManagement.php +++ b/app/code/Magento/Customer/Model/AccountManagement.php @@ -48,6 +48,9 @@ use Magento\Store\Model\ScopeInterface; use Magento\Store\Model\StoreManagerInterface; use Psr\Log\LoggerInterface as PsrLogger; +use Magento\Framework\Session\SessionManagerInterface; +use Magento\Framework\Session\SaveHandlerInterface; +use Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory; /** * Handle various customer account actions @@ -243,6 +246,21 @@ class AccountManagement implements AccountManagementInterface */ private $transportBuilder; + /** + * @var SessionManagerInterface + */ + private $sessionManager; + + /** + * @var SaveHandlerInterface + */ + private $saveHandler; + + /** + * @var CollectionFactory + */ + private $visitorCollectionFactory; + /** * @var DataObjectProcessor */ @@ -335,6 +353,9 @@ class AccountManagement implements AccountManagementInterface * @param CredentialsValidator|null $credentialsValidator * @param DateTimeFactory|null $dateTimeFactory * @param AccountConfirmation|null $accountConfirmation + * @param SessionManagerInterface|null $sessionManager + * @param SaveHandlerInterface|null $saveHandler + * @param CollectionFactory|null $visitorCollectionFactory * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -363,7 +384,10 @@ public function __construct( ExtensibleDataObjectConverter $extensibleDataObjectConverter, CredentialsValidator $credentialsValidator = null, DateTimeFactory $dateTimeFactory = null, - AccountConfirmation $accountConfirmation = null + AccountConfirmation $accountConfirmation = null, + SessionManagerInterface $sessionManager = null, + SaveHandlerInterface $saveHandler = null, + CollectionFactory $visitorCollectionFactory = null ) { $this->customerFactory = $customerFactory; $this->eventManager = $eventManager; @@ -393,6 +417,12 @@ public function __construct( $this->dateTimeFactory = $dateTimeFactory ?: ObjectManager::getInstance()->get(DateTimeFactory::class); $this->accountConfirmation = $accountConfirmation ?: ObjectManager::getInstance() ->get(AccountConfirmation::class); + $this->sessionManager = $sessionManager + ?: ObjectManager::getInstance()->get(SessionManagerInterface::class); + $this->saveHandler = $saveHandler + ?: ObjectManager::getInstance()->get(SaveHandlerInterface::class); + $this->visitorCollectionFactory = $visitorCollectionFactory + ?: ObjectManager::getInstance()->get(CollectionFactory::class); } /** @@ -594,7 +624,10 @@ public function resetPassword($email, $resetToken, $newPassword) $customerSecure->setRpToken(null); $customerSecure->setRpTokenCreatedAt(null); $customerSecure->setPasswordHash($this->createPasswordHash($newPassword)); + $this->sessionManager->destroy(); + $this->destroyCustomerSessions($customer->getId()); $this->customerRepository->save($customer); + return true; } @@ -896,7 +929,9 @@ private function changePasswordForCustomer($customer, $currentPassword, $newPass $customerSecure->setRpTokenCreatedAt(null); $this->checkPasswordStrength($newPassword); $customerSecure->setPasswordHash($this->createPasswordHash($newPassword)); + $this->destroyCustomerSessions($customer->getId()); $this->customerRepository->save($customer); + return true; } @@ -1399,4 +1434,35 @@ private function getEmailNotification() return $this->emailNotification; } } + + /** + * Destroy all active customer sessions by customer id (current session will not be destroyed). + * Customer sessions which should be deleted are collecting from the "customer_visitor" table considering + * configured session lifetime. + * + * @param string|int $customerId + * @return void + */ + private function destroyCustomerSessions($customerId) + { + $sessionLifetime = $this->scopeConfig->getValue( + \Magento\Framework\Session\Config::XML_PATH_COOKIE_LIFETIME, + \Magento\Store\Model\ScopeInterface::SCOPE_STORE + ); + $dateTime = $this->dateTimeFactory->create(); + $activeSessionsTime = $dateTime->setTimestamp($dateTime->getTimestamp() - $sessionLifetime) + ->format(DateTime::DATETIME_PHP_FORMAT); + /** @var \Magento\Customer\Model\ResourceModel\Visitor\Collection $visitorCollection */ + $visitorCollection = $this->visitorCollectionFactory->create(); + $visitorCollection->addFieldToFilter('customer_id', $customerId); + $visitorCollection->addFieldToFilter('last_visit_at', ['from' => $activeSessionsTime]); + $visitorCollection->addFieldToFilter('session_id', ['neq' => $this->sessionManager->getSessionId()]); + /** @var \Magento\Customer\Model\Visitor $visitor */ + foreach ($visitorCollection->getItems() as $visitor) { + $sessionId = $visitor->getSessionId(); + $this->sessionManager->start(); + $this->saveHandler->destroy($sessionId); + $this->sessionManager->writeClose(); + } + } } diff --git a/app/code/Magento/Customer/Model/Address/AbstractAddress.php b/app/code/Magento/Customer/Model/Address/AbstractAddress.php index aab9a811168f9..6408276630c3f 100644 --- a/app/code/Magento/Customer/Model/Address/AbstractAddress.php +++ b/app/code/Magento/Customer/Model/Address/AbstractAddress.php @@ -12,6 +12,7 @@ use Magento\Customer\Api\Data\RegionInterface; use Magento\Customer\Api\Data\RegionInterfaceFactory; use Magento\Customer\Model\Data\Address as AddressData; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Model\AbstractExtensibleModel; /** @@ -118,6 +119,9 @@ class AbstractAddress extends AbstractExtensibleModel implements AddressModelInt */ protected $dataObjectHelper; + /** @var CompositeValidator */ + private $compositeValidator; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -135,6 +139,8 @@ class AbstractAddress extends AbstractExtensibleModel implements AddressModelInt * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection * @param array $data + * @param CompositeValidator $compositeValidator + * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -153,7 +159,8 @@ public function __construct( \Magento\Framework\Api\DataObjectHelper $dataObjectHelper, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - array $data = [] + array $data = [], + CompositeValidator $compositeValidator = null ) { $this->_directoryData = $directoryData; $data = $this->_implodeArrayField($data); @@ -165,6 +172,8 @@ public function __construct( $this->addressDataFactory = $addressDataFactory; $this->regionDataFactory = $regionDataFactory; $this->dataObjectHelper = $dataObjectHelper; + $this->compositeValidator = $compositeValidator ?: ObjectManager::getInstance() + ->get(CompositeValidator::class); parent::__construct( $context, $registry, @@ -562,84 +571,22 @@ public function getDataModel($defaultBillingAddressId = null, $defaultShippingAd } /** - * Validate address attribute values - * - * + * Validate address attribute values. * - * @return bool|array - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) + * @return array|bool */ public function validate() { if ($this->getShouldIgnoreValidation()) { return true; } - - $errors = []; - if (!\Zend_Validate::is($this->getFirstname(), 'NotEmpty')) { - $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'firstname']); - } - - if (!\Zend_Validate::is($this->getLastname(), 'NotEmpty')) { - $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'lastname']); - } - - if (!\Zend_Validate::is($this->getStreetLine(1), 'NotEmpty')) { - $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'street']); - } - if (!\Zend_Validate::is($this->getCity(), 'NotEmpty')) { - $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'city']); - } - - if ($this->isTelephoneRequired()) { - if (!\Zend_Validate::is($this->getTelephone(), 'NotEmpty')) { - $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'telephone']); - } - } - - if ($this->isFaxRequired()) { - if (!\Zend_Validate::is($this->getFax(), 'NotEmpty')) { - $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'fax']); - } - } - - if ($this->isCompanyRequired()) { - if (!\Zend_Validate::is($this->getCompany(), 'NotEmpty')) { - $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'company']); - } - } - - $_havingOptionalZip = $this->_directoryData->getCountriesWithOptionalZip(); - if (!in_array( - $this->getCountryId(), - $_havingOptionalZip - ) && !\Zend_Validate::is( - $this->getPostcode(), - 'NotEmpty' - ) - ) { - $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'postcode']); - } - - if (!\Zend_Validate::is($this->getCountryId(), 'NotEmpty')) { - $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'countryId']); - } - - if ($this->getCountryModel()->getRegionCollection()->getSize() && !\Zend_Validate::is( - $this->getRegionId(), - 'NotEmpty' - ) && $this->_directoryData->isRegionRequired( - $this->getCountryId() - ) - ) { - $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'regionId']); - } + $errors = $this->compositeValidator->validate($this); if (empty($errors)) { return true; } + return $errors; } diff --git a/app/code/Magento/Customer/Model/Address/CompositeValidator.php b/app/code/Magento/Customer/Model/Address/CompositeValidator.php new file mode 100644 index 0000000000000..1d16a929532f5 --- /dev/null +++ b/app/code/Magento/Customer/Model/Address/CompositeValidator.php @@ -0,0 +1,40 @@ +validators = $validators; + } + + /** + * @inheritdoc + */ + public function validate(AbstractAddress $address) + { + $errors = []; + foreach ($this->validators as $validator) { + $errors = array_merge($errors, $validator->validate($address)); + } + + return $errors; + } +} diff --git a/app/code/Magento/Customer/Model/Address/Validator/Country.php b/app/code/Magento/Customer/Model/Address/Validator/Country.php new file mode 100644 index 0000000000000..0ba8a21ff8cd9 --- /dev/null +++ b/app/code/Magento/Customer/Model/Address/Validator/Country.php @@ -0,0 +1,100 @@ +directoryData = $directoryData; + } + + /** + * @inheritdoc + */ + public function validate(AbstractAddress $address) + { + $errors = $this->validateCountry($address); + if (empty($errors)) { + $errors = $this->validateRegion($address); + } + + return $errors; + } + + /** + * Validate country existence. + * + * @param AbstractAddress $address + * @return array + */ + private function validateCountry(AbstractAddress $address) + { + $countryId = $address->getCountryId(); + $errors = []; + if (!\Zend_Validate::is($countryId, 'NotEmpty')) { + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'countryId']); + } elseif (!in_array($countryId, $this->directoryData->getCountryCollection()->getAllIds(), true)) { + //Checking if such country exists. + $errors[] = __( + 'Invalid value of "%value" provided for the %fieldName field.', + ['fieldName' => 'countryId', 'value' => htmlspecialchars($countryId)] + ); + } + + return $errors; + } + + /** + * Validate region existence. + * + * @param AbstractAddress $address + * @return array + */ + private function validateRegion(AbstractAddress $address) + { + $errors = []; + $countryId = $address->getCountryId(); + $countryModel = $address->getCountryModel(); + $regionCollection = $countryModel->getRegionCollection(); + $region = $address->getRegion(); + $regionId = (string)$address->getRegionId(); + $allowedRegions = $regionCollection->getAllIds(); + $isRegionRequired = $this->directoryData->isRegionRequired($countryId); + if ($isRegionRequired && empty($allowedRegions) && !\Zend_Validate::is($region, 'NotEmpty')) { + //If region is required for country and country doesn't provide regions list + //region must be provided. + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'region']); + } elseif ($allowedRegions && !\Zend_Validate::is($regionId, 'NotEmpty') && $isRegionRequired) { + //If country actually has regions and requires you to + //select one then it must be selected. + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'regionId']); + } elseif ($regionId && !in_array($regionId, $allowedRegions, true)) { + //If a region is selected then checking if it exists. + $errors[] = __( + 'Invalid value of "%value" provided for the %fieldName field.', + ['fieldName' => 'regionId', 'value' => htmlspecialchars($regionId)] + ); + } + + return $errors; + } +} diff --git a/app/code/Magento/Customer/Model/Address/Validator/General.php b/app/code/Magento/Customer/Model/Address/Validator/General.php new file mode 100644 index 0000000000000..679f288712b4b --- /dev/null +++ b/app/code/Magento/Customer/Model/Address/Validator/General.php @@ -0,0 +1,151 @@ +eavConfig = $eavConfig; + $this->directoryData = $directoryData; + } + + /** + * @inheritdoc + */ + public function validate(AbstractAddress $address) + { + $errors = array_merge( + $this->checkRequredFields($address), + $this->checkOptionalFields($address) + ); + + return $errors; + } + + /** + * Check fields that are generally required. + * + * @param AbstractAddress $address + * @return array + * @throws \Zend_Validate_Exception + */ + private function checkRequredFields(AbstractAddress $address) + { + $errors = []; + if (!\Zend_Validate::is($address->getFirstname(), 'NotEmpty')) { + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'firstname']); + } + + if (!\Zend_Validate::is($address->getLastname(), 'NotEmpty')) { + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'lastname']); + } + + if (!\Zend_Validate::is($address->getStreetLine(1), 'NotEmpty')) { + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'street']); + } + + if (!\Zend_Validate::is($address->getCity(), 'NotEmpty')) { + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'city']); + } + + return $errors; + } + + /** + * Check fields that are conditionally required. + * + * @param AbstractAddress $address + * @return array + * @throws \Magento\Framework\Exception\LocalizedException + * @throws \Zend_Validate_Exception + */ + private function checkOptionalFields(AbstractAddress $address) + { + $errors = []; + if ($this->isTelephoneRequired() + && !\Zend_Validate::is($address->getTelephone(), 'NotEmpty') + ) { + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'telephone']); + } + + if ($this->isFaxRequired() + && !\Zend_Validate::is($address->getFax(), 'NotEmpty') + ) { + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'fax']); + } + + if ($this->isCompanyRequired() + && !\Zend_Validate::is($address->getCompany(), 'NotEmpty') + ) { + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'company']); + } + + $havingOptionalZip = $this->directoryData->getCountriesWithOptionalZip(); + if (!in_array($address->getCountryId(), $havingOptionalZip) + && !\Zend_Validate::is($address->getPostcode(), 'NotEmpty') + ) { + $errors[] = __('"%fieldName" is required. Enter and try again.', ['fieldName' => 'postcode']); + } + + return $errors; + } + + /** + * Check if company field required in configuration. + * + * @return bool + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function isCompanyRequired() + { + return $this->eavConfig->getAttribute('customer_address', 'company')->getIsRequired(); + } + + /** + * Check if telephone field required in configuration. + * + * @return bool + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function isTelephoneRequired() + { + return $this->eavConfig->getAttribute('customer_address', 'telephone')->getIsRequired(); + } + + /** + * Check if fax field required in configuration. + * + * @return bool + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function isFaxRequired() + { + return $this->eavConfig->getAttribute('customer_address', 'fax')->getIsRequired(); + } +} diff --git a/app/code/Magento/Customer/Model/Address/ValidatorInterface.php b/app/code/Magento/Customer/Model/Address/ValidatorInterface.php new file mode 100644 index 0000000000000..8468f28e70e70 --- /dev/null +++ b/app/code/Magento/Customer/Model/Address/ValidatorInterface.php @@ -0,0 +1,24 @@ +session = $session; $this->notificationStorage = $notificationStorage; $this->state = $state; $this->customerRepository = $customerRepository; + $this->logger = $logger; } /** @@ -63,17 +73,23 @@ public function __construct( */ public function beforeDispatch(AbstractAction $subject, RequestInterface $request) { + $customerId = $this->session->getCustomerId(); + if ($this->state->getAreaCode() == Area::AREA_FRONTEND && $request->isPost() && $this->notificationStorage->isExists( NotificationStorage::UPDATE_CUSTOMER_SESSION, - $this->session->getCustomerId() + $customerId ) ) { - $customer = $this->customerRepository->getById($this->session->getCustomerId()); - $this->session->setCustomerData($customer); - $this->session->setCustomerGroupId($customer->getGroupId()); - $this->session->regenerateId(); - $this->notificationStorage->remove(NotificationStorage::UPDATE_CUSTOMER_SESSION, $customer->getId()); + try { + $customer = $this->customerRepository->getById($customerId); + $this->session->setCustomerData($customer); + $this->session->setCustomerGroupId($customer->getGroupId()); + $this->session->regenerateId(); + $this->notificationStorage->remove(NotificationStorage::UPDATE_CUSTOMER_SESSION, $customer->getId()); + } catch (NoSuchEntityException $e) { + $this->logger->error($e); + } } } } diff --git a/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php b/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php index 2c7b778f5f485..7f69ab3c02bcf 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/AddressRepository.php @@ -92,7 +92,7 @@ public function __construct( $this->addressFactory = $addressFactory; $this->addressRegistry = $addressRegistry; $this->customerRegistry = $customerRegistry; - $this->addressResource = $addressResourceModel; + $this->addressResourceModel = $addressResourceModel; $this->directoryData = $directoryData; $this->addressSearchResultsFactory = $addressSearchResultsFactory; $this->addressCollectionFactory = $addressCollectionFactory; @@ -236,7 +236,7 @@ public function delete(\Magento\Customer\Api\Data\AddressInterface $address) $address = $this->addressRegistry->retrieve($addressId); $customerModel = $this->customerRegistry->retrieve($address->getCustomerId()); $customerModel->getAddressesCollection()->clear(); - $this->addressResource->delete($address); + $this->addressResourceModel->delete($address); $this->addressRegistry->remove($addressId); return true; } @@ -254,7 +254,7 @@ public function deleteById($addressId) $address = $this->addressRegistry->retrieve($addressId); $customerModel = $this->customerRegistry->retrieve($address->getCustomerId()); $customerModel->getAddressesCollection()->removeItemByKey($addressId); - $this->addressResource->delete($address); + $this->addressResourceModel->delete($address); $this->addressRegistry->remove($addressId); return true; } diff --git a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php index 1a15b55a1e7e3..91a593c347806 100644 --- a/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php +++ b/app/code/Magento/Customer/Model/ResourceModel/CustomerRepository.php @@ -7,10 +7,12 @@ namespace Magento\Customer\Model\ResourceModel; use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Customer\Model\Customer\NotificationStorage; use Magento\Framework\Api\DataObjectHelper; use Magento\Framework\Api\ImageProcessorInterface; use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; use Magento\Framework\Api\SearchCriteriaInterface; +use Magento\Framework\App\ObjectManager; /** * Customer repository. @@ -88,6 +90,11 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte */ private $collectionProcessor; + /** + * @var NotificationStorage + */ + private $notificationStorage; + /** * @param \Magento\Customer\Model\CustomerFactory $customerFactory * @param \Magento\Customer\Model\Data\CustomerSecureFactory $customerSecureFactory @@ -103,6 +110,7 @@ class CustomerRepository implements \Magento\Customer\Api\CustomerRepositoryInte * @param ImageProcessorInterface $imageProcessor * @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor * @param CollectionProcessorInterface $collectionProcessor + * @param NotificationStorage $notificationStorage * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -119,7 +127,8 @@ public function __construct( DataObjectHelper $dataObjectHelper, ImageProcessorInterface $imageProcessor, \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor, - CollectionProcessorInterface $collectionProcessor = null + CollectionProcessorInterface $collectionProcessor, + NotificationStorage $notificationStorage ) { $this->customerFactory = $customerFactory; $this->customerSecureFactory = $customerSecureFactory; @@ -134,7 +143,8 @@ public function __construct( $this->dataObjectHelper = $dataObjectHelper; $this->imageProcessor = $imageProcessor; $this->extensionAttributesJoinProcessor = $extensionAttributesJoinProcessor; - $this->collectionProcessor = $collectionProcessor ?: $this->getCollectionProcessor(); + $this->collectionProcessor = $collectionProcessor; + $this->notificationStorage = $notificationStorage; } /** @@ -345,6 +355,8 @@ public function deleteById($customerId) $customerModel = $this->customerRegistry->retrieve($customerId); $customerModel->delete(); $this->customerRegistry->remove($customerId); + $this->notificationStorage->remove(NotificationStorage::UPDATE_CUSTOMER_SESSION, $customerId); + return true; } @@ -370,20 +382,4 @@ protected function addFilterGroupToCollection( $collection->addFieldToFilter($fields); } } - - /** - * Retrieve collection processor - * - * @deprecated 100.2.0 - * @return CollectionProcessorInterface - */ - private function getCollectionProcessor() - { - if (!$this->collectionProcessor) { - $this->collectionProcessor = \Magento\Framework\App\ObjectManager::getInstance()->get( - 'Magento\Eav\Model\Api\SearchCriteria\CollectionProcessor' - ); - } - return $this->collectionProcessor; - } } diff --git a/app/code/Magento/Customer/Model/Visitor.php b/app/code/Magento/Customer/Model/Visitor.php index b4bad240bc825..4624dd8b6bcf5 100644 --- a/app/code/Magento/Customer/Model/Visitor.php +++ b/app/code/Magento/Customer/Model/Visitor.php @@ -151,6 +151,9 @@ public function initByRequest($observer) if ($this->session->getVisitorData()) { $this->setData($this->session->getVisitorData()); + if ($this->getSessionId() != $this->session->getSessionId()) { + $this->setSessionId($this->session->getSessionId()); + } } $this->setLastVisitAt((new \DateTime())->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT)); diff --git a/app/code/Magento/Customer/Setup/CustomerSetup.php b/app/code/Magento/Customer/Setup/CustomerSetup.php index b1f07e4872fd8..c074285765e59 100644 --- a/app/code/Magento/Customer/Setup/CustomerSetup.php +++ b/app/code/Magento/Customer/Setup/CustomerSetup.php @@ -489,4 +489,23 @@ public function getEavConfig() { return $this->eavConfig; } + + /** + * Update attributes for customer. + * + * @param array $entityAttributes + * @return void + */ + public function upgradeAttributes(array $entityAttributes) + { + foreach ($entityAttributes as $entityType => $attributes) { + foreach ($attributes as $attributeCode => $attributeData) { + $attribute = $this->getEavConfig()->getAttribute($entityType, $attributeCode); + foreach ($attributeData as $key => $value) { + $attribute->setData($key, $value); + } + $attribute->save(); + } + } + } } diff --git a/app/code/Magento/Customer/Setup/InstallData.php b/app/code/Magento/Customer/Setup/InstallData.php deleted file mode 100644 index 0bc4b19db9d1c..0000000000000 --- a/app/code/Magento/Customer/Setup/InstallData.php +++ /dev/null @@ -1,144 +0,0 @@ -customerSetupFactory = $customerSetupFactory; - } - - /** - * {@inheritdoc} - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var CustomerSetup $customerSetup */ - $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]); - - $setup->startSetup(); - - // insert default customer groups - $setup->getConnection()->insertForce( - $setup->getTable('customer_group'), - ['customer_group_id' => 0, 'customer_group_code' => 'NOT LOGGED IN', 'tax_class_id' => 3] - ); - $setup->getConnection()->insertForce( - $setup->getTable('customer_group'), - ['customer_group_id' => 1, 'customer_group_code' => 'General', 'tax_class_id' => 3] - ); - $setup->getConnection()->insertForce( - $setup->getTable('customer_group'), - ['customer_group_id' => 2, 'customer_group_code' => 'Wholesale', 'tax_class_id' => 3] - ); - $setup->getConnection()->insertForce( - $setup->getTable('customer_group'), - ['customer_group_id' => 3, 'customer_group_code' => 'Retailer', 'tax_class_id' => 3] - ); - - $customerSetup->installEntities(); - - $customerSetup->installCustomerForms(); - - $disableAGCAttribute = $customerSetup->getEavConfig()->getAttribute('customer', 'disable_auto_group_change'); - $disableAGCAttribute->setData('used_in_forms', ['adminhtml_customer']); - $disableAGCAttribute->save(); - - $attributesInfo = [ - 'vat_id' => [ - 'label' => 'VAT number', - 'type' => 'static', - 'input' => 'text', - 'position' => 140, - 'visible' => true, - 'required' => false, - ], - 'vat_is_valid' => [ - 'label' => 'VAT number validity', - 'visible' => false, - 'required' => false, - 'type' => 'static', - ], - 'vat_request_id' => [ - 'label' => 'VAT number validation request ID', - 'type' => 'static', - 'visible' => false, - 'required' => false, - ], - 'vat_request_date' => [ - 'label' => 'VAT number validation request date', - 'type' => 'static', - 'visible' => false, - 'required' => false, - ], - 'vat_request_success' => [ - 'label' => 'VAT number validation request success', - 'visible' => false, - 'required' => false, - 'type' => 'static', - ], - ]; - - foreach ($attributesInfo as $attributeCode => $attributeParams) { - $customerSetup->addAttribute('customer_address', $attributeCode, $attributeParams); - } - - $vatIdAttribute = $customerSetup->getEavConfig()->getAttribute('customer_address', 'vat_id'); - $vatIdAttribute->setData( - 'used_in_forms', - ['adminhtml_customer_address', 'customer_address_edit', 'customer_register_address'] - ); - $vatIdAttribute->save(); - - $entities = $customerSetup->getDefaultEntities(); - foreach ($entities as $entityName => $entity) { - $customerSetup->addEntityType($entityName, $entity); - } - - $customerSetup->updateAttribute( - 'customer_address', - 'street', - 'backend_model', - \Magento\Eav\Model\Entity\Attribute\Backend\DefaultBackend::class - ); - - $migrationSetup = $setup->createMigrationSetup(); - - $migrationSetup->appendClassAliasReplace( - 'customer_eav_attribute', - 'data_model', - Migration::ENTITY_TYPE_MODEL, - Migration::FIELD_CONTENT_TYPE_PLAIN, - ['attribute_id'] - ); - $migrationSetup->doUpdateClassAliases(); - - $setup->endSetup(); - } -} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/AddCustomerUpdatedAtAttribute.php b/app/code/Magento/Customer/Setup/Patch/Data/AddCustomerUpdatedAtAttribute.php new file mode 100644 index 0000000000000..bad5735bc3e3a --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/AddCustomerUpdatedAtAttribute.php @@ -0,0 +1,91 @@ +moduleDataSetup = $moduleDataSetup; + $this->customerSetupFactory = $customerSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]); + $customerSetup->addAttribute( + Customer::ENTITY, + 'updated_at', + [ + 'type' => 'static', + 'label' => 'Updated At', + 'input' => 'date', + 'required' => false, + 'sort_order' => 87, + 'visible' => false, + 'system' => false, + ] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateIdentifierCustomerAttributesVisibility::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.4'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/AddNonSpecifiedGenderAttributeOption.php b/app/code/Magento/Customer/Setup/Patch/Data/AddNonSpecifiedGenderAttributeOption.php new file mode 100644 index 0000000000000..ba50f6e17dd87 --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/AddNonSpecifiedGenderAttributeOption.php @@ -0,0 +1,94 @@ +moduleDataSetup = $moduleDataSetup; + $this->customerSetupFactory = $customerSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]); + $entityTypeId = $customerSetup->getEntityTypeId(Customer::ENTITY); + $attributeId = $customerSetup->getAttributeId($entityTypeId, 'gender'); + + $option = ['attribute_id' => $attributeId, 'values' => [3 => 'Not Specified']]; + $customerSetup->addAttributeOption($option); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateCustomerAttributesMetadata::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.2'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/AddSecurityTrackingAttributes.php b/app/code/Magento/Customer/Setup/Patch/Data/AddSecurityTrackingAttributes.php new file mode 100644 index 0000000000000..b066d14a3c63e --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/AddSecurityTrackingAttributes.php @@ -0,0 +1,126 @@ +moduleDataSetup = $moduleDataSetup; + $this->customerSetupFactory = $customerSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]); + $customerSetup->addAttribute( + Customer::ENTITY, + 'failures_num', + [ + 'type' => 'static', + 'label' => 'Failures Number', + 'input' => 'hidden', + 'required' => false, + 'sort_order' => 100, + 'visible' => false, + 'system' => true, + ] + ); + + $customerSetup->addAttribute( + Customer::ENTITY, + 'first_failure', + [ + 'type' => 'static', + 'label' => 'First Failure Date', + 'input' => 'date', + 'required' => false, + 'sort_order' => 110, + 'visible' => false, + 'system' => true, + ] + ); + + $customerSetup->addAttribute( + Customer::ENTITY, + 'lock_expires', + [ + 'type' => 'static', + 'label' => 'Failures Number', + 'input' => 'date', + 'required' => false, + 'sort_order' => 120, + 'visible' => false, + 'system' => true, + ] + ); + $configTable = $this->moduleDataSetup->getTable('core_config_data'); + + $this->moduleDataSetup->getConnection()->update( + $configTable, + ['value' => new \Zend_Db_Expr('value*24')], + ['path = ?' => \Magento\Customer\Model\Customer::XML_PATH_CUSTOMER_RESET_PASSWORD_LINK_EXPIRATION_PERIOD] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + RemoveCheckoutRegisterAndUpdateAttributes::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.7'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/ConvertValidationRulesFromSerializedToJson.php b/app/code/Magento/Customer/Setup/Patch/Data/ConvertValidationRulesFromSerializedToJson.php new file mode 100644 index 0000000000000..83c5fe7ae6d1e --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/ConvertValidationRulesFromSerializedToJson.php @@ -0,0 +1,84 @@ +moduleDataSetup = $moduleDataSetup; + $this->fieldDataConverterFactory = $fieldDataConverterFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $fieldDataConverter->convert( + $this->moduleDataSetup->getConnection(), + $this->moduleDataSetup->getTable('customer_eav_attribute'), + 'attribute_id', + 'validate_rules' + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + MigrateStoresAllowedCountriesToWebsite::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.11'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/DefaultCustomerGroupsAndAttributes.php b/app/code/Magento/Customer/Setup/Patch/Data/DefaultCustomerGroupsAndAttributes.php new file mode 100644 index 0000000000000..6e61b66f3c9db --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/DefaultCustomerGroupsAndAttributes.php @@ -0,0 +1,174 @@ +customerSetupFactory = $customerSetupFactory; + $this->moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function apply() + { + /** @var CustomerSetup $customerSetup */ + $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]); + + // insert default customer groups + $this->moduleDataSetup->getConnection()->insertForce( + $this->moduleDataSetup->getTable('customer_group'), + ['customer_group_id' => 0, 'customer_group_code' => 'NOT LOGGED IN', 'tax_class_id' => 3] + ); + $this->moduleDataSetup->getConnection()->insertForce( + $this->moduleDataSetup->getTable('customer_group'), + ['customer_group_id' => 1, 'customer_group_code' => 'General', 'tax_class_id' => 3] + ); + $this->moduleDataSetup->getConnection()->insertForce( + $this->moduleDataSetup->getTable('customer_group'), + ['customer_group_id' => 2, 'customer_group_code' => 'Wholesale', 'tax_class_id' => 3] + ); + $this->moduleDataSetup->getConnection()->insertForce( + $this->moduleDataSetup->getTable('customer_group'), + ['customer_group_id' => 3, 'customer_group_code' => 'Retailer', 'tax_class_id' => 3] + ); + + $customerSetup->installEntities(); + + $customerSetup->installCustomerForms(); + + $disableAGCAttribute = $customerSetup->getEavConfig()->getAttribute('customer', 'disable_auto_group_change'); + $disableAGCAttribute->setData('used_in_forms', ['adminhtml_customer']); + $disableAGCAttribute->save(); + + $attributesInfo = [ + 'vat_id' => [ + 'label' => 'VAT number', + 'type' => 'static', + 'input' => 'text', + 'position' => 140, + 'visible' => true, + 'required' => false, + ], + 'vat_is_valid' => [ + 'label' => 'VAT number validity', + 'visible' => false, + 'required' => false, + 'type' => 'static', + ], + 'vat_request_id' => [ + 'label' => 'VAT number validation request ID', + 'type' => 'static', + 'visible' => false, + 'required' => false, + ], + 'vat_request_date' => [ + 'label' => 'VAT number validation request date', + 'type' => 'static', + 'visible' => false, + 'required' => false, + ], + 'vat_request_success' => [ + 'label' => 'VAT number validation request success', + 'visible' => false, + 'required' => false, + 'type' => 'static', + ], + ]; + + foreach ($attributesInfo as $attributeCode => $attributeParams) { + $customerSetup->addAttribute('customer_address', $attributeCode, $attributeParams); + } + + $vatIdAttribute = $customerSetup->getEavConfig()->getAttribute('customer_address', 'vat_id'); + $vatIdAttribute->setData( + 'used_in_forms', + ['adminhtml_customer_address', 'customer_address_edit', 'customer_register_address'] + ); + $vatIdAttribute->save(); + + $entities = $customerSetup->getDefaultEntities(); + foreach ($entities as $entityName => $entity) { + $customerSetup->addEntityType($entityName, $entity); + } + + $customerSetup->updateAttribute( + 'customer_address', + 'street', + 'backend_model', + \Magento\Eav\Model\Entity\Attribute\Backend\DefaultBackend::class + ); + + $migrationSetup = $this->moduleDataSetup->createMigrationSetup(); + + $migrationSetup->appendClassAliasReplace( + 'customer_eav_attribute', + 'data_model', + Migration::ENTITY_TYPE_MODEL, + Migration::FIELD_CONTENT_TYPE_PLAIN, + ['attribute_id'] + ); + $migrationSetup->doUpdateClassAliases(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/MigrateStoresAllowedCountriesToWebsite.php b/app/code/Magento/Customer/Setup/Patch/Data/MigrateStoresAllowedCountriesToWebsite.php new file mode 100644 index 0000000000000..7488f3fd4a920 --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/MigrateStoresAllowedCountriesToWebsite.php @@ -0,0 +1,176 @@ +moduleDataSetup = $moduleDataSetup; + $this->storeManager = $storeManager; + $this->allowedCountries = $allowedCountries; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->beginTransaction(); + + try { + $this->migrateStoresAllowedCountriesToWebsite(); + $this->moduleDataSetup->getConnection()->commit(); + } catch (\Exception $e) { + $this->moduleDataSetup->getConnection()->rollBack(); + throw $e; + } + } + + /** + * Merge allowed countries from stores to websites + * + * @return void + */ + private function migrateStoresAllowedCountriesToWebsite() + { + $allowedCountries = []; + //Process Websites + foreach ($this->storeManager->getStores() as $store) { + $allowedCountries = $this->mergeAllowedCountries( + $allowedCountries, + $this->getAllowedCountries(ScopeInterface::SCOPE_STORE, $store->getId()), + $store->getWebsiteId() + ); + } + //Process stores + foreach ($this->storeManager->getWebsites() as $website) { + $allowedCountries = $this->mergeAllowedCountries( + $allowedCountries, + $this->getAllowedCountries(ScopeInterface::SCOPE_WEBSITE, $website->getId()), + $website->getId() + ); + } + + $connection = $this->moduleDataSetup->getConnection(); + + //Remove everything from stores scope + $connection->delete( + $this->moduleDataSetup->getTable('core_config_data'), + [ + 'path = ?' => AllowedCountries::ALLOWED_COUNTRIES_PATH, + 'scope = ?' => ScopeInterface::SCOPE_STORES + ] + ); + + //Update websites + foreach ($allowedCountries as $scopeId => $countries) { + $connection->update( + $this->moduleDataSetup->getTable('core_config_data'), + [ + 'value' => implode(',', $countries) + ], + [ + 'path = ?' => AllowedCountries::ALLOWED_COUNTRIES_PATH, + 'scope_id = ?' => $scopeId, + 'scope = ?' => ScopeInterface::SCOPE_WEBSITES + ] + ); + } + } + + /** + * Retrieve countries not depending on global scope + * + * @param string $scope + * @param int $scopeCode + * @return array + */ + private function getAllowedCountries($scope, $scopeCode) + { + return $this->allowedCountries->makeCountriesUnique( + $this->allowedCountries->getCountriesFromConfig($scope, $scopeCode) + ); + } + + /** + * Merge allowed countries between different scopes + * + * @param array $countries + * @param array $newCountries + * @param string $identifier + * @return array + */ + private function mergeAllowedCountries(array $countries, array $newCountries, $identifier) + { + if (!isset($countries[$identifier])) { + $countries[$identifier] = $newCountries; + } else { + $countries[$identifier] = array_replace($countries[$identifier], $newCountries); + } + + return $countries; + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateAutocompleteOnStorefrontConfigPath::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.9'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/RemoveCheckoutRegisterAndUpdateAttributes.php b/app/code/Magento/Customer/Setup/Patch/Data/RemoveCheckoutRegisterAndUpdateAttributes.php new file mode 100644 index 0000000000000..51f54dc4a432c --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/RemoveCheckoutRegisterAndUpdateAttributes.php @@ -0,0 +1,136 @@ +moduleDataSetup = $moduleDataSetup; + $this->customerSetupFactory = $customerSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->delete( + $this->moduleDataSetup->getTable('customer_form_attribute'), + ['form_code = ?' => 'checkout_register'] + ); + $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]); + $customerSetup->updateEntityType( + \Magento\Customer\Model\Customer::ENTITY, + 'entity_model', + \Magento\Customer\Model\ResourceModel\Customer::class + ); + $customerSetup->updateEntityType( + \Magento\Customer\Model\Customer::ENTITY, + 'increment_model', + \Magento\Eav\Model\Entity\Increment\NumericValue::class + ); + $customerSetup->updateEntityType( + \Magento\Customer\Model\Customer::ENTITY, + 'entity_attribute_collection', + \Magento\Customer\Model\ResourceModel\Attribute\Collection::class + ); + $customerSetup->updateEntityType( + 'customer_address', + 'entity_model', + \Magento\Customer\Model\ResourceModel\Address::class + ); + $customerSetup->updateEntityType( + 'customer_address', + 'entity_attribute_collection', + \Magento\Customer\Model\ResourceModel\Address\Attribute\Collection::class + ); + $customerSetup->updateAttribute( + 'customer_address', + 'country_id', + 'source_model', + \Magento\Customer\Model\ResourceModel\Address\Attribute\Source\Country::class + ); + $customerSetup->updateAttribute( + 'customer_address', + 'region', + 'backend_model', + \Magento\Customer\Model\ResourceModel\Address\Attribute\Backend\Region::class + ); + $customerSetup->updateAttribute( + 'customer_address', + 'region_id', + 'source_model', + \Magento\Customer\Model\ResourceModel\Address\Attribute\Source\Region::class + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpgradePasswordHashAndAddress::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.6'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/UpdateAutocompleteOnStorefrontConfigPath.php b/app/code/Magento/Customer/Setup/Patch/Data/UpdateAutocompleteOnStorefrontConfigPath.php new file mode 100644 index 0000000000000..30435ace54d46 --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/UpdateAutocompleteOnStorefrontConfigPath.php @@ -0,0 +1,72 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->update( + $this->moduleDataSetup->getTable('core_config_data'), + ['path' => \Magento\Customer\Model\Form::XML_PATH_ENABLE_AUTOCOMPLETE], + ['path = ?' => 'general/restriction/autocomplete_on_storefront'] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + AddSecurityTrackingAttributes::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.8'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/UpdateCustomerAttributeInputFilters.php b/app/code/Magento/Customer/Setup/Patch/Data/UpdateCustomerAttributeInputFilters.php new file mode 100644 index 0000000000000..938cd3cd52e73 --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/UpdateCustomerAttributeInputFilters.php @@ -0,0 +1,102 @@ +moduleDataSetup = $moduleDataSetup; + $this->customerSetupFactory = $customerSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]); + $entityAttributes = [ + 'customer_address' => [ + 'firstname' => [ + 'input_filter' => 'trim' + ], + 'lastname' => [ + 'input_filter' => 'trim' + ], + 'middlename' => [ + 'input_filter' => 'trim' + ], + ], + 'customer' => [ + 'firstname' => [ + 'input_filter' => 'trim' + ], + 'lastname' => [ + 'input_filter' => 'trim' + ], + 'middlename' => [ + 'input_filter' => 'trim' + ], + ], + ]; + $customerSetup->upgradeAttributes($entityAttributes); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateVATNumber::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.13'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/UpdateCustomerAttributesMetadata.php b/app/code/Magento/Customer/Setup/Patch/Data/UpdateCustomerAttributesMetadata.php new file mode 100644 index 0000000000000..5f4d9952590ba --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/UpdateCustomerAttributesMetadata.php @@ -0,0 +1,203 @@ +moduleDataSetup = $moduleDataSetup; + $this->customerSetupFactory = $customerSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var CustomerSetup $customerSetup */ + $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]); + $this->updateCustomerAttributesMetadata($customerSetup); + } + + /** + * @param CustomerSetup $customerSetup + * @return void + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + private function updateCustomerAttributesMetadata($customerSetup) + { + $entityAttributes = [ + 'customer' => [ + 'website_id' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => false, + ], + 'created_in' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => false, + 'is_searchable_in_grid' => true, + ], + 'email' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => true, + ], + 'group_id' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => false, + ], + 'dob' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => false, + ], + 'taxvat' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => false, + 'is_searchable_in_grid' => true, + ], + 'confirmation' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => false, + ], + 'created_at' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => false, + ], + 'gender' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => false, + ], + ], + 'customer_address' => [ + 'company' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => false, + 'is_searchable_in_grid' => true, + ], + 'street' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => false, + 'is_searchable_in_grid' => true, + ], + 'city' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => false, + 'is_searchable_in_grid' => true, + ], + 'country_id' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => false, + ], + 'region' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => false, + 'is_searchable_in_grid' => true, + ], + 'region_id' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => false, + ], + 'postcode' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => true, + ], + 'telephone' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => true, + 'is_filterable_in_grid' => true, + 'is_searchable_in_grid' => true, + ], + 'fax' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => false, + 'is_searchable_in_grid' => true, + ], + ], + ]; + $customerSetup->upgradeAttributes($entityAttributes); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + DefaultCustomerGroupsAndAttributes::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/UpdateIdentifierCustomerAttributesVisibility.php b/app/code/Magento/Customer/Setup/Patch/Data/UpdateIdentifierCustomerAttributesVisibility.php new file mode 100644 index 0000000000000..7d0cad768d6b0 --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/UpdateIdentifierCustomerAttributesVisibility.php @@ -0,0 +1,100 @@ +moduleDataSetup = $moduleDataSetup; + $this->customerSetupFactory = $customerSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]); + $entityAttributes = [ + 'customer_address' => [ + 'region_id' => [ + 'is_used_in_grid' => false, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => false, + 'is_searchable_in_grid' => false, + ], + 'firstname' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => false, + 'is_searchable_in_grid' => true, + ], + 'lastname' => [ + 'is_used_in_grid' => true, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => false, + 'is_searchable_in_grid' => true, + ], + ], + ]; + $customerSetup->upgradeAttributes($entityAttributes); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + AddNonSpecifiedGenderAttributeOption::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.3'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/UpdateVATNumber.php b/app/code/Magento/Customer/Setup/Patch/Data/UpdateVATNumber.php new file mode 100644 index 0000000000000..d31301eedf4b1 --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/UpdateVATNumber.php @@ -0,0 +1,86 @@ +moduleDataSetup = $moduleDataSetup; + $this->customerSetupFactory = $customerSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $customerSetup = $this->customerSetupFactory->create(['resourceConnection' => $this->moduleDataSetup]); + $customerSetup->updateAttribute('customer_address', 'vat_id', 'frontend_label', 'VAT Number'); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + ConvertValidationRulesFromSerializedToJson::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.12'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/Patch/Data/UpgradePasswordHashAndAddress.php b/app/code/Magento/Customer/Setup/Patch/Data/UpgradePasswordHashAndAddress.php new file mode 100644 index 0000000000000..3b8f96a037343 --- /dev/null +++ b/app/code/Magento/Customer/Setup/Patch/Data/UpgradePasswordHashAndAddress.php @@ -0,0 +1,120 @@ +moduleDataSetup = $moduleDataSetup; + $this->customerSetupFactory = $customerSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->upgradeHash(); + $entityAttributes = [ + 'customer_address' => [ + 'fax' => [ + 'is_visible' => false, + 'is_system' => false, + ], + ], + ]; + $customerSetup = $this->customerSetupFactory->create(['setup' => $this->moduleDataSetup]); + $customerSetup->upgradeAttributes($entityAttributes); + } + + /** + * @return void + */ + private function upgradeHash() + { + $customerEntityTable = $this->moduleDataSetup->getTable('customer_entity'); + + $select = $this->moduleDataSetup->getConnection()->select()->from( + $customerEntityTable, + ['entity_id', 'password_hash'] + ); + + $customers = $this->moduleDataSetup->getConnection()->fetchAll($select); + foreach ($customers as $customer) { + if ($customer['password_hash'] === null) { + continue; + } + list($hash, $salt) = explode(Encryptor::DELIMITER, $customer['password_hash']); + + $newHash = $customer['password_hash']; + if (strlen($hash) === 32) { + $newHash = implode(Encryptor::DELIMITER, [$hash, $salt, Encryptor::HASH_VERSION_MD5]); + } elseif (strlen($hash) === 64) { + $newHash = implode(Encryptor::DELIMITER, [$hash, $salt, Encryptor::HASH_VERSION_SHA256]); + } + + $bind = ['password_hash' => $newHash]; + $where = ['entity_id = ?' => (int)$customer['entity_id']]; + $this->moduleDataSetup->getConnection()->update($customerEntityTable, $bind, $where); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + AddCustomerUpdatedAtAttribute::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.5'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Customer/Setup/UpgradeData.php b/app/code/Magento/Customer/Setup/UpgradeData.php deleted file mode 100644 index 5e08759958853..0000000000000 --- a/app/code/Magento/Customer/Setup/UpgradeData.php +++ /dev/null @@ -1,700 +0,0 @@ -customerSetupFactory = $customerSetupFactory; - $this->indexerRegistry = $indexerRegistry; - $this->eavConfig = $eavConfig; - - $this->fieldDataConverterFactory = $fieldDataConverterFactory ?: ObjectManager::getInstance()->get( - FieldDataConverterFactory::class - ); - } - - /** - * {@inheritdoc} - * @SuppressWarnings(PHPMD.NPathComplexity) - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - /** @var CustomerSetup $customerSetup */ - $customerSetup = $this->customerSetupFactory->create(['setup' => $setup]); - - if (version_compare($context->getVersion(), '2.0.6', '<')) { - $this->upgradeVersionTwoZeroSix($customerSetup); - } - - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $this->upgradeVersionTwoZeroOne($customerSetup); - } - - if (version_compare($context->getVersion(), '2.0.2') < 0) { - $this->upgradeVersionTwoZeroTwo($customerSetup); - } - - if (version_compare($context->getVersion(), '2.0.3', '<')) { - $this->upgradeVersionTwoZeroThree($customerSetup); - } - - if (version_compare($context->getVersion(), '2.0.4', '<')) { - $this->upgradeVersionTwoZeroFour($customerSetup); - } - - if (version_compare($context->getVersion(), '2.0.5', '<')) { - $this->upgradeVersionTwoZeroFive($customerSetup, $setup); - } - - if (version_compare($context->getVersion(), '2.0.6', '<')) { - $setup->getConnection()->delete( - $setup->getTable('customer_form_attribute'), - ['form_code = ?' => 'checkout_register'] - ); - } - - if (version_compare($context->getVersion(), '2.0.8', '<')) { - $setup->getConnection()->update( - $setup->getTable('core_config_data'), - ['path' => \Magento\Customer\Model\Form::XML_PATH_ENABLE_AUTOCOMPLETE], - ['path = ?' => 'general/restriction/autocomplete_on_storefront'] - ); - } - - if (version_compare($context->getVersion(), '2.0.7', '<')) { - $this->upgradeVersionTwoZeroSeven($customerSetup); - $this->upgradeCustomerPasswordResetlinkExpirationPeriodConfig($setup); - } - - if (version_compare($context->getVersion(), '2.0.9', '<')) { - $setup->getConnection()->beginTransaction(); - - try { - $this->migrateStoresAllowedCountriesToWebsite($setup); - $setup->getConnection()->commit(); - } catch (\Exception $e) { - $setup->getConnection()->rollBack(); - throw $e; - } - } - if (version_compare($context->getVersion(), '2.0.11', '<')) { - $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); - $fieldDataConverter->convert( - $setup->getConnection(), - $setup->getTable('customer_eav_attribute'), - 'attribute_id', - 'validate_rules' - ); - } - - if (version_compare($context->getVersion(), '2.0.12', '<')) { - $this->upgradeVersionTwoZeroTwelve($customerSetup); - } - - if (version_compare($context->getVersion(), '2.0.13', '<')) { - $this->upgradeVersionTwoZeroThirteen($customerSetup); - } - - $this->eavConfig->clear(); - $setup->endSetup(); - } - - /** - * Retrieve Store Manager - * - * @deprecated 100.1.3 - * @return StoreManagerInterface - */ - private function getStoreManager() - { - if (!$this->storeManager) { - $this->storeManager = ObjectManager::getInstance()->get(StoreManagerInterface::class); - } - - return $this->storeManager; - } - - /** - * Retrieve Allowed Countries Reader - * - * @deprecated 100.1.3 - * @return AllowedCountries - */ - private function getAllowedCountriesReader() - { - if (!$this->allowedCountriesReader) { - $this->allowedCountriesReader = ObjectManager::getInstance()->get(AllowedCountries::class); - } - - return $this->allowedCountriesReader; - } - - /** - * Merge allowed countries between different scopes - * - * @param array $countries - * @param array $newCountries - * @param string $identifier - * @return array - */ - private function mergeAllowedCountries(array $countries, array $newCountries, $identifier) - { - if (!isset($countries[$identifier])) { - $countries[$identifier] = $newCountries; - } else { - $countries[$identifier] = - array_replace($countries[$identifier], $newCountries); - } - - return $countries; - } - - /** - * Retrieve countries not depending on global scope - * - * @param string $scope - * @param int $scopeCode - * @return array - */ - private function getAllowedCountries($scope, $scopeCode) - { - $reader = $this->getAllowedCountriesReader(); - return $reader->makeCountriesUnique($reader->getCountriesFromConfig($scope, $scopeCode)); - } - - /** - * Merge allowed countries from stores to websites - * - * @param SetupInterface $setup - * @return void - */ - private function migrateStoresAllowedCountriesToWebsite(SetupInterface $setup) - { - $allowedCountries = []; - //Process Websites - foreach ($this->getStoreManager()->getStores() as $store) { - $allowedCountries = $this->mergeAllowedCountries( - $allowedCountries, - $this->getAllowedCountries(ScopeInterface::SCOPE_STORE, $store->getId()), - $store->getWebsiteId() - ); - } - //Process stores - foreach ($this->getStoreManager()->getWebsites() as $website) { - $allowedCountries = $this->mergeAllowedCountries( - $allowedCountries, - $this->getAllowedCountries(ScopeInterface::SCOPE_WEBSITE, $website->getId()), - $website->getId() - ); - } - - $connection = $setup->getConnection(); - - //Remove everything from stores scope - $connection->delete( - $setup->getTable('core_config_data'), - [ - 'path = ?' => AllowedCountries::ALLOWED_COUNTRIES_PATH, - 'scope = ?' => ScopeInterface::SCOPE_STORES - ] - ); - - //Update websites - foreach ($allowedCountries as $scopeId => $countries) { - $connection->update( - $setup->getTable('core_config_data'), - [ - 'value' => implode(',', $countries) - ], - [ - 'path = ?' => AllowedCountries::ALLOWED_COUNTRIES_PATH, - 'scope_id = ?' => $scopeId, - 'scope = ?' => ScopeInterface::SCOPE_WEBSITES - ] - ); - } - } - - /** - * @param array $entityAttributes - * @param CustomerSetup $customerSetup - * @return void - */ - protected function upgradeAttributes(array $entityAttributes, CustomerSetup $customerSetup) - { - foreach ($entityAttributes as $entityType => $attributes) { - foreach ($attributes as $attributeCode => $attributeData) { - $attribute = $customerSetup->getEavConfig()->getAttribute($entityType, $attributeCode); - foreach ($attributeData as $key => $value) { - $attribute->setData($key, $value); - } - $attribute->save(); - } - } - } - - /** - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function upgradeHash($setup) - { - $customerEntityTable = $setup->getTable('customer_entity'); - - $select = $setup->getConnection()->select()->from( - $customerEntityTable, - ['entity_id', 'password_hash'] - ); - - $customers = $setup->getConnection()->fetchAll($select); - foreach ($customers as $customer) { - if ($customer['password_hash'] === null) { - continue; - } - list($hash, $salt) = explode(Encryptor::DELIMITER, $customer['password_hash']); - - $newHash = $customer['password_hash']; - if (strlen($hash) === 32) { - $newHash = implode(Encryptor::DELIMITER, [$hash, $salt, Encryptor::HASH_VERSION_MD5]); - } elseif (strlen($hash) === 64) { - $newHash = implode(Encryptor::DELIMITER, [$hash, $salt, Encryptor::HASH_VERSION_SHA256]); - } - - $bind = ['password_hash' => $newHash]; - $where = ['entity_id = ?' => (int)$customer['entity_id']]; - $setup->getConnection()->update($customerEntityTable, $bind, $where); - } - } - - /** - * @param CustomerSetup $customerSetup - * @return void - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - private function upgradeVersionTwoZeroOne($customerSetup) - { - $entityAttributes = [ - 'customer' => [ - 'website_id' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => false, - ], - 'created_in' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => false, - 'is_searchable_in_grid' => true, - ], - 'email' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => true, - ], - 'group_id' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => false, - ], - 'dob' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => false, - ], - 'taxvat' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => false, - 'is_searchable_in_grid' => true, - ], - 'confirmation' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => false, - ], - 'created_at' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => false, - ], - 'gender' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => false, - ], - ], - 'customer_address' => [ - 'company' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => false, - 'is_searchable_in_grid' => true, - ], - 'street' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => false, - 'is_searchable_in_grid' => true, - ], - 'city' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => false, - 'is_searchable_in_grid' => true, - ], - 'country_id' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => false, - ], - 'region' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => false, - 'is_searchable_in_grid' => true, - ], - 'region_id' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => false, - ], - 'postcode' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => true, - ], - 'telephone' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => true, - 'is_filterable_in_grid' => true, - 'is_searchable_in_grid' => true, - ], - 'fax' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => false, - 'is_searchable_in_grid' => true, - ], - ], - ]; - $this->upgradeAttributes($entityAttributes, $customerSetup); - } - - /** - * @param CustomerSetup $customerSetup - * @return void - */ - private function upgradeVersionTwoZeroTwo($customerSetup) - { - $entityTypeId = $customerSetup->getEntityTypeId(Customer::ENTITY); - $attributeId = $customerSetup->getAttributeId($entityTypeId, 'gender'); - - $option = ['attribute_id' => $attributeId, 'values' => [3 => 'Not Specified']]; - $customerSetup->addAttributeOption($option); - } - - /** - * @param CustomerSetup $customerSetup - * @return void - */ - private function upgradeVersionTwoZeroThree($customerSetup) - { - $entityAttributes = [ - 'customer_address' => [ - 'region_id' => [ - 'is_used_in_grid' => false, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => false, - 'is_searchable_in_grid' => false, - ], - 'firstname' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => false, - 'is_searchable_in_grid' => true, - ], - 'lastname' => [ - 'is_used_in_grid' => true, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => false, - 'is_searchable_in_grid' => true, - ], - ], - ]; - $this->upgradeAttributes($entityAttributes, $customerSetup); - } - - /** - * @param CustomerSetup $customerSetup - * @return void - */ - private function upgradeVersionTwoZeroFour($customerSetup) - { - $customerSetup->addAttribute( - Customer::ENTITY, - 'updated_at', - [ - 'type' => 'static', - 'label' => 'Updated At', - 'input' => 'date', - 'required' => false, - 'sort_order' => 87, - 'visible' => false, - 'system' => false, - ] - ); - } - - /** - * @param CustomerSetup $customerSetup - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function upgradeVersionTwoZeroFive($customerSetup, $setup) - { - $this->upgradeHash($setup); - $entityAttributes = [ - 'customer_address' => [ - 'fax' => [ - 'is_visible' => false, - 'is_system' => false, - ], - ], - ]; - $this->upgradeAttributes($entityAttributes, $customerSetup); - } - - /** - * @param CustomerSetup $customerSetup - * @return void - */ - private function upgradeVersionTwoZeroSix($customerSetup) - { - $customerSetup->updateEntityType( - \Magento\Customer\Model\Customer::ENTITY, - 'entity_model', - \Magento\Customer\Model\ResourceModel\Customer::class - ); - $customerSetup->updateEntityType( - \Magento\Customer\Model\Customer::ENTITY, - 'increment_model', - \Magento\Eav\Model\Entity\Increment\NumericValue::class - ); - $customerSetup->updateEntityType( - \Magento\Customer\Model\Customer::ENTITY, - 'entity_attribute_collection', - \Magento\Customer\Model\ResourceModel\Attribute\Collection::class - ); - $customerSetup->updateEntityType( - 'customer_address', - 'entity_model', - \Magento\Customer\Model\ResourceModel\Address::class - ); - $customerSetup->updateEntityType( - 'customer_address', - 'entity_attribute_collection', - \Magento\Customer\Model\ResourceModel\Address\Attribute\Collection::class - ); - $customerSetup->updateAttribute( - 'customer_address', - 'country_id', - 'source_model', - \Magento\Customer\Model\ResourceModel\Address\Attribute\Source\Country::class - ); - $customerSetup->updateAttribute( - 'customer_address', - 'region', - 'backend_model', - \Magento\Customer\Model\ResourceModel\Address\Attribute\Backend\Region::class - ); - $customerSetup->updateAttribute( - 'customer_address', - 'region_id', - 'source_model', - \Magento\Customer\Model\ResourceModel\Address\Attribute\Source\Region::class - ); - } - - /** - * @param CustomerSetup $customerSetup - * @return void - */ - private function upgradeVersionTwoZeroSeven($customerSetup) - { - $customerSetup->addAttribute( - Customer::ENTITY, - 'failures_num', - [ - 'type' => 'static', - 'label' => 'Failures Number', - 'input' => 'hidden', - 'required' => false, - 'sort_order' => 100, - 'visible' => false, - 'system' => true, - ] - ); - - $customerSetup->addAttribute( - Customer::ENTITY, - 'first_failure', - [ - 'type' => 'static', - 'label' => 'First Failure Date', - 'input' => 'date', - 'required' => false, - 'sort_order' => 110, - 'visible' => false, - 'system' => true, - ] - ); - - $customerSetup->addAttribute( - Customer::ENTITY, - 'lock_expires', - [ - 'type' => 'static', - 'label' => 'Failures Number', - 'input' => 'date', - 'required' => false, - 'sort_order' => 120, - 'visible' => false, - 'system' => true, - ] - ); - } - - /** - * @param CustomerSetup $customerSetup - * @return void - */ - private function upgradeVersionTwoZeroTwelve(CustomerSetup $customerSetup) - { - $customerSetup->updateAttribute('customer_address', 'vat_id', 'frontend_label', 'VAT Number'); - } - - /** - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function upgradeCustomerPasswordResetlinkExpirationPeriodConfig($setup) - { - $configTable = $setup->getTable('core_config_data'); - - $setup->getConnection()->update( - $configTable, - ['value' => new \Zend_Db_Expr('value*24')], - ['path = ?' => \Magento\Customer\Model\Customer::XML_PATH_CUSTOMER_RESET_PASSWORD_LINK_EXPIRATION_PERIOD] - ); - } - - /** - * @param CustomerSetup $customerSetup - */ - private function upgradeVersionTwoZeroThirteen(CustomerSetup $customerSetup) - { - $entityAttributes = [ - 'customer_address' => [ - 'firstname' => [ - 'input_filter' => 'trim' - ], - 'lastname' => [ - 'input_filter' => 'trim' - ], - 'middlename' => [ - 'input_filter' => 'trim' - ], - ], - 'customer' => [ - 'firstname' => [ - 'input_filter' => 'trim' - ], - 'lastname' => [ - 'input_filter' => 'trim' - ], - 'middlename' => [ - 'input_filter' => 'trim' - ], - ], - ]; - $this->upgradeAttributes($entityAttributes, $customerSetup); - } -} diff --git a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php index 59c940bb85297..8e1aeaa87a10e 100644 --- a/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php +++ b/app/code/Magento/Customer/Test/Unit/Controller/Adminhtml/Index/ViewfileTest.php @@ -206,4 +206,53 @@ public function testExecuteGetParamImage() ); $this->assertSame($this->resultRawMock, $controller->execute()); } + + /** + * @expectedException \Magento\Framework\Exception\NotFoundException + * @expectedExceptionMessage Page not found. + */ + public function testExecuteInvalidFile() + { + $file = '../../../app/etc/env.php'; + $decodedFile = base64_encode($file); + $fileName = 'customer/' . $file; + $path = 'path'; + + $this->requestMock->expects($this->atLeastOnce())->method('getParam')->with('file')->willReturn($decodedFile); + + $this->directoryMock->expects($this->once())->method('getAbsolutePath')->with($fileName)->willReturn($path); + + $this->fileSystemMock->expects($this->once())->method('getDirectoryRead') + ->with(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA) + ->willReturn($this->directoryMock); + + $this->storage->expects($this->once())->method('processStorageFile')->with($path)->willReturn(false); + + $this->objectManagerMock->expects($this->any())->method('get') + ->willReturnMap( + [ + [\Magento\Framework\Filesystem::class, $this->fileSystemMock], + [\Magento\MediaStorage\Helper\File\Storage::class, $this->storage], + ] + ); + + $this->urlDecoderMock->expects($this->once())->method('decode')->with($decodedFile)->willReturn($file); + $fileFactoryMock = $this->createMock( + \Magento\Framework\App\Response\Http\FileFactory::class, + [], + [], + '', + false + ); + + $controller = $this->objectManager->getObject( + \Magento\Customer\Controller\Adminhtml\Index\Viewfile::class, + [ + 'context' => $this->contextMock, + 'urlDecoder' => $this->urlDecoderMock, + 'fileFactory' => $fileFactoryMock, + ] + ); + $controller->execute(); + } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php index e63ce964c15b0..0138c6c709b7c 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Account/RedirectTest.php @@ -11,9 +11,9 @@ use Magento\Customer\Model\Account\Redirect; use Magento\Customer\Model\Url as CustomerUrl; use Magento\Framework\Controller\ResultFactory; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Framework\Url\HostChecker; use Magento\Store\Model\ScopeInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -147,15 +147,15 @@ protected function setUp() $this->model = $objectManager->getObject( \Magento\Customer\Model\Account\Redirect::class, [ - 'request' => $this->request, - 'customerSession' => $this->customerSession, - 'scopeConfig' => $this->scopeConfig, - 'storeManager' => $this->storeManager, - 'url' => $this->url, - 'urlDecoder' => $this->urlDecoder, - 'customerUrl' => $this->customerUrl, - 'resultFactory' => $this->resultFactory, - 'hostChecker' => $this->hostChecker + 'request' => $this->request, + 'customerSession' => $this->customerSession, + 'scopeConfig' => $this->scopeConfig, + 'storeManager' => $this->storeManager, + 'url' => $this->url, + 'urlDecoder' => $this->urlDecoder, + 'customerUrl' => $this->customerUrl, + 'resultFactory' => $this->resultFactory, + 'hostChecker' => $this->hostChecker, ] ); } @@ -191,57 +191,31 @@ public function testGetRedirect( $redirectToDashboard ) { // Preparations for method updateLastCustomerId() - $this->customerSession->expects($this->once()) - ->method('getLastCustomerId') - ->willReturn($customerId); - $this->customerSession->expects($this->any()) - ->method('isLoggedIn') - ->willReturn($customerLoggedIn); - $this->customerSession->expects($this->any()) - ->method('getId') - ->willReturn($lastCustomerId); - $this->customerSession->expects($this->any()) - ->method('unsBeforeAuthUrl') - ->willReturnSelf(); + $this->customerSession->expects($this->once())->method('getLastCustomerId')->willReturn($customerId); + $this->customerSession->expects($this->any())->method('isLoggedIn')->willReturn($customerLoggedIn); + $this->customerSession->expects($this->any())->method('getId')->willReturn($lastCustomerId); + $this->customerSession->expects($this->any())->method('unsBeforeAuthUrl')->willReturnSelf(); $this->customerSession->expects($this->any()) ->method('setLastCustomerId') ->with($lastCustomerId) ->willReturnSelf(); // Preparations for method prepareRedirectUrl() - $this->store->expects($this->once()) - ->method('getBaseUrl') - ->willReturn($baseUrl); + $this->store->expects($this->once())->method('getBaseUrl')->willReturn($baseUrl); - $this->customerSession->expects($this->any()) - ->method('getBeforeAuthUrl') - ->willReturn($beforeAuthUrl); - $this->customerSession->expects($this->any()) - ->method('setBeforeAuthUrl') - ->willReturnSelf(); - $this->customerSession->expects($this->any()) - ->method('getAfterAuthUrl') - ->willReturn($afterAuthUrl); + $this->customerSession->expects($this->any())->method('getBeforeAuthUrl')->willReturn($beforeAuthUrl); + $this->customerSession->expects($this->any())->method('setBeforeAuthUrl')->willReturnSelf(); + $this->customerSession->expects($this->any())->method('getAfterAuthUrl')->willReturn($afterAuthUrl); $this->customerSession->expects($this->any()) ->method('setAfterAuthUrl') ->with($beforeAuthUrl) ->willReturnSelf(); - $this->customerSession->expects($this->any()) - ->method('getBeforeRequestParams') - ->willReturn(false); - - $this->customerUrl->expects($this->any()) - ->method('getAccountUrl') - ->willReturn($accountUrl); - $this->customerUrl->expects($this->any()) - ->method('getLoginUrl') - ->willReturn($loginUrl); - $this->customerUrl->expects($this->any()) - ->method('getLogoutUrl') - ->willReturn($logoutUrl); - $this->customerUrl->expects($this->any()) - ->method('getDashboardUrl') - ->willReturn($dashboardUrl); + $this->customerSession->expects($this->any())->method('getBeforeRequestParams')->willReturn(false); + + $this->customerUrl->expects($this->any())->method('getAccountUrl')->willReturn($accountUrl); + $this->customerUrl->expects($this->any())->method('getLoginUrl')->willReturn($loginUrl); + $this->customerUrl->expects($this->any())->method('getLogoutUrl')->willReturn($logoutUrl); + $this->customerUrl->expects($this->any())->method('getDashboardUrl')->willReturn($dashboardUrl); $this->scopeConfig->expects($this->any()) ->method('isSetFlag') @@ -253,25 +227,19 @@ public function testGetRedirect( ->with(CustomerUrl::REFERER_QUERY_PARAM_NAME) ->willReturn($referer); - $this->urlDecoder->expects($this->any()) - ->method('decode') - ->with($referer) - ->willReturn($referer); + $this->urlDecoder->expects($this->any())->method('decode')->with($referer)->willReturn($referer); - $this->url->expects($this->any()) - ->method('isOwnOriginUrl') - ->willReturn(true); + $this->url->expects($this->any())->method('isOwnOriginUrl')->willReturn(true); - $this->resultRedirect->expects($this->once()) - ->method('setUrl') - ->with($beforeAuthUrl) - ->willReturnSelf(); + $this->resultRedirect->expects($this->once())->method('setUrl')->with($beforeAuthUrl)->willReturnSelf(); $this->resultFactory->expects($this->once()) ->method('create') ->with(ResultFactory::TYPE_REDIRECT) ->willReturn($this->resultRedirect); + $this->hostChecker->expects($this->any())->method('isOwnOrigin')->willReturn(true); + $this->model->getRedirect(); } @@ -306,6 +274,21 @@ public function getRedirectDataProvider() [1, 2, 'referer', 'base', 'logout', '', 'account', 'login', 'logout', 'dashboard', false, true], // Default redirect [1, 2, 'referer', 'base', 'defined', '', 'account', 'login', 'logout', 'dashboard', true, true], + // Logout, Without Redirect to Dashboard + [ + 'customer_id' => 1, + 'last_customer_id' => 2, + 'referer' => 'http://base.com/customer/account/logoutSuccess/', + 'base_url' => 'http://base.com/', + 'before_auth_url' => 'http://base.com/', + 'after_auth_url' => 'http://base.com/customer/account/', + 'account_url' => 'account', + 'login_url' => 'login', + 'logout_url' => 'logout', + 'dashboard_url' => 'dashboard', + 'is_customer_logged_id_flag' => true, + 'redirect_to_dashboard_flag' => false, + ], ]; } diff --git a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php index 0ca79833e8a13..cf55928a6d30f 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/AccountManagementTest.php @@ -127,6 +127,21 @@ class AccountManagementTest extends \PHPUnit\Framework\TestCase */ private $accountConfirmation; + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Session\SessionManagerInterface + */ + private $sessionManager; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory + */ + private $visitorCollectionFactory; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Session\SaveHandlerInterface + */ + private $saveHandler; + /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ @@ -179,6 +194,19 @@ protected function setUp() $this->dateTimeFactory = $this->createMock(DateTimeFactory::class); $this->accountConfirmation = $this->createMock(AccountConfirmation::class); + $this->visitorCollectionFactory = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class + ) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->sessionManager = $this->getMockBuilder(\Magento\Framework\Session\SessionManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->saveHandler = $this->getMockBuilder(\Magento\Framework\Session\SaveHandlerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManagerHelper = new ObjectManagerHelper($this); $this->accountManagement = $this->objectManagerHelper->getObject( \Magento\Customer\Model\AccountManagement::class, @@ -207,16 +235,22 @@ protected function setUp() 'objectFactory' => $this->objectFactory, 'extensibleDataObjectConverter' => $this->extensibleDataObjectConverter, 'dateTimeFactory' => $this->dateTimeFactory, - 'accountConfirmation' => $this->accountConfirmation + 'accountConfirmation' => $this->accountConfirmation, + 'sessionManager' => $this->sessionManager, + 'saveHandler' => $this->saveHandler, + 'visitorCollectionFactory' => $this->visitorCollectionFactory, ] ); - $reflection = new \ReflectionClass(get_class($this->accountManagement)); - $reflectionProperty = $reflection->getProperty('authentication'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->accountManagement, $this->authenticationMock); - $reflectionProperty = $reflection->getProperty('emailNotification'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->accountManagement, $this->emailNotificationMock); + $this->objectManagerHelper->setBackwardCompatibleProperty( + $this->accountManagement, + 'authentication', + $this->authenticationMock + ); + $this->objectManagerHelper->setBackwardCompatibleProperty( + $this->accountManagement, + 'emailNotification', + $this->emailNotificationMock + ); } /** @@ -672,14 +706,14 @@ public function dataProviderCheckPasswordStrength() 'testNumber' => 1, 'password' => 'qwer', 'minPasswordLength' => 5, - 'minCharacterSetsNum' => 1 + 'minCharacterSetsNum' => 1, ], [ 'testNumber' => 2, 'password' => 'wrfewqedf1', 'minPasswordLength' => 5, - 'minCharacterSetsNum' => 3 - ] + 'minCharacterSetsNum' => 3, + ], ]; } @@ -711,7 +745,8 @@ public function testCreateAccountWithPasswordInputException( AccountManagement::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER, 'default', null, - $minCharacterSetsNum], + $minCharacterSetsNum, + ], ] ) ); @@ -795,7 +830,8 @@ public function testCreateAccountWithPassword() AccountManagement::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER, 'default', null, - $minCharacterSetsNum], + $minCharacterSetsNum, + ], [ AccountManagement::XML_PATH_REGISTER_EMAIL_TEMPLATE, ScopeInterface::SCOPE_STORE, @@ -806,8 +842,8 @@ public function testCreateAccountWithPassword() AccountManagement::XML_PATH_REGISTER_EMAIL_IDENTITY, ScopeInterface::SCOPE_STORE, 1, - $sender - ] + $sender, + ], ] ); $this->string->expects($this->any()) @@ -1276,27 +1312,67 @@ private function reInitModel() { $this->customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) ->disableOriginalConstructor() - ->setMethods(['getRpToken', 'getRpTokenCreatedAt']) + ->setMethods( + [ + 'getRpToken', + 'getRpTokenCreatedAt', + 'getPasswordHash', + 'setPasswordHash', + 'setRpToken', + 'setRpTokenCreatedAt', + ] + ) ->getMock(); - - $this->customerSecure - ->expects($this->any()) + $this->customerSecure->expects($this->any()) ->method('getRpToken') ->willReturn('newStringToken'); - $pastDateTime = '2016-10-25 00:00:00'; - - $this->customerSecure - ->expects($this->any()) + $this->customerSecure->expects($this->any()) ->method('getRpTokenCreatedAt') ->willReturn($pastDateTime); - $this->customer = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) ->disableOriginalConstructor() ->setMethods(['getResetPasswordLinkExpirationPeriod']) ->getMock(); $this->prepareDateTimeFactory(); + $this->sessionManager = $this->getMockBuilder(\Magento\Framework\Session\SessionManagerInterface::class) + ->disableOriginalConstructor() + ->setMethods(['destroy', 'start', 'writeClose']) + ->getMockForAbstractClass(); + $this->visitorCollectionFactory = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class + ) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->saveHandler = $this->getMockBuilder(\Magento\Framework\Session\SaveHandlerInterface::class) + ->disableOriginalConstructor() + ->setMethods(['destroy']) + ->getMockForAbstractClass(); + + $dateTime = '2017-10-25 18:57:08'; + $timestamp = '1508983028'; + $dateTimeMock = $this->getMockBuilder(\DateTime::class) + ->disableOriginalConstructor() + ->setMethods(['format', 'getTimestamp', 'setTimestamp']) + ->getMock(); + + $dateTimeMock->expects($this->any()) + ->method('format') + ->with(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT) + ->willReturn($dateTime); + $dateTimeMock->expects($this->any()) + ->method('getTimestamp') + ->willReturn($timestamp); + $dateTimeMock->expects($this->any()) + ->method('setTimestamp') + ->willReturnSelf(); + $dateTimeFactory = $this->getMockBuilder(DateTimeFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $dateTimeFactory->expects($this->any())->method('create')->willReturn($dateTimeMock); $this->objectManagerHelper = new ObjectManagerHelper($this); $this->accountManagement = $this->objectManagerHelper->getObject( @@ -1306,13 +1382,23 @@ private function reInitModel() 'customerRegistry' => $this->customerRegistry, 'customerRepository' => $this->customerRepository, 'customerModel' => $this->customer, - 'dateTimeFactory' => $this->dateTimeFactory, + 'dateTimeFactory' => $dateTimeFactory, + 'stringHelper' => $this->string, + 'scopeConfig' => $this->scopeConfig, + 'sessionManager' => $this->sessionManager, + 'visitorCollectionFactory' => $this->visitorCollectionFactory, + 'saveHandler' => $this->saveHandler, + 'encryptor' => $this->encryptor, + 'dataProcessor' => $this->dataObjectProcessor, + 'storeManager' => $this->storeManager, + 'transportBuilder' => $this->transportBuilder, ] ); - $reflection = new \ReflectionClass(get_class($this->accountManagement)); - $reflectionProperty = $reflection->getProperty('authentication'); - $reflectionProperty->setAccessible(true); - $reflectionProperty->setValue($this->accountManagement, $this->authenticationMock); + $this->objectManagerHelper->setBackwardCompatibleProperty( + $this->accountManagement, + 'authentication', + $this->authenticationMock + ); } /** @@ -1326,6 +1412,7 @@ public function testChangePassword() $newPassword = 'abcdefg'; $passwordHash = '1a2b3f4c'; + $this->reInitModel(); $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) ->getMock(); $customer->expects($this->any()) @@ -1341,24 +1428,20 @@ public function testChangePassword() $this->authenticationMock->expects($this->once()) ->method('authenticate'); - $customerSecure = $this->getMockBuilder(\Magento\Customer\Model\Data\CustomerSecure::class) - ->setMethods(['setRpToken', 'setRpTokenCreatedAt', 'getPasswordHash']) - ->disableOriginalConstructor() - ->getMock(); - $customerSecure->expects($this->once()) + $this->customerSecure->expects($this->once()) ->method('setRpToken') ->with(null); - $customerSecure->expects($this->once()) + $this->customerSecure->expects($this->once()) ->method('setRpTokenCreatedAt') ->willReturnSelf(); - $customerSecure->expects($this->any()) + $this->customerSecure->expects($this->any()) ->method('getPasswordHash') ->willReturn($passwordHash); $this->customerRegistry->expects($this->any()) ->method('retrieveSecureData') ->with($customerId) - ->willReturn($customerSecure); + ->willReturn($this->customerSecure); $this->scopeConfig->expects($this->any()) ->method('getValue') @@ -1374,7 +1457,7 @@ public function testChangePassword() AccountManagement::XML_PATH_REQUIRED_CHARACTER_CLASSES_NUMBER, 'default', null, - 1 + 1, ], ] ); @@ -1388,9 +1471,85 @@ public function testChangePassword() ->method('save') ->with($customer); + $this->sessionManager->expects($this->atLeastOnce())->method('start'); + $this->sessionManager->expects($this->atLeastOnce())->method('writeClose'); + $this->sessionManager->expects($this->atLeastOnce())->method('getSessionId'); + + $visitor = $this->getMockBuilder(\Magento\Customer\Model\Visitor::class) + ->disableOriginalConstructor() + ->setMethods(['getSessionId']) + ->getMock(); + $visitor->expects($this->atLeastOnce())->method('getSessionId') + ->willReturnOnConsecutiveCalls('session_id_1', 'session_id_2'); + $visitorCollection = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class + ) + ->disableOriginalConstructor()->setMethods(['addFieldToFilter', 'getItems'])->getMock(); + $visitorCollection->expects($this->atLeastOnce())->method('addFieldToFilter')->willReturnSelf(); + $visitorCollection->expects($this->atLeastOnce())->method('getItems')->willReturn([$visitor, $visitor]); + $this->visitorCollectionFactory->expects($this->atLeastOnce())->method('create') + ->willReturn($visitorCollection); + $this->saveHandler->expects($this->atLeastOnce())->method('destroy') + ->withConsecutive( + ['session_id_1'], + ['session_id_2'] + ); + $this->assertTrue($this->accountManagement->changePassword($email, $currentPassword, $newPassword)); } + public function testResetPassword() + { + $customerEmail = 'customer@example.com'; + $customerId = '1'; + $resetToken = 'newStringToken'; + $newPassword = 'new_password'; + + $this->reInitModel(); + $customer = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class)->getMock(); + $customer->expects($this->any())->method('getId')->willReturn($customerId); + $this->customerRepository->expects($this->atLeastOnce())->method('get')->with($customerEmail) + ->willReturn($customer); + $this->customer->expects($this->atLeastOnce())->method('getResetPasswordLinkExpirationPeriod') + ->willReturn(100000); + $this->string->expects($this->any())->method('strlen')->willReturnCallback( + function ($string) { + return strlen($string); + } + ); + $this->customerRegistry->expects($this->atLeastOnce())->method('retrieveSecureData') + ->willReturn($this->customerSecure); + + $this->customerSecure->expects($this->once())->method('setRpToken')->with(null); + $this->customerSecure->expects($this->once())->method('setRpTokenCreatedAt')->with(null); + $this->customerSecure->expects($this->any())->method('setPasswordHash')->willReturn(null); + + $this->sessionManager->expects($this->atLeastOnce())->method('destroy'); + $this->sessionManager->expects($this->atLeastOnce())->method('start'); + $this->sessionManager->expects($this->atLeastOnce())->method('writeClose'); + $this->sessionManager->expects($this->atLeastOnce())->method('getSessionId'); + $visitor = $this->getMockBuilder(\Magento\Customer\Model\Visitor::class) + ->disableOriginalConstructor() + ->setMethods(['getSessionId']) + ->getMock(); + $visitor->expects($this->atLeastOnce())->method('getSessionId') + ->willReturnOnConsecutiveCalls('session_id_1', 'session_id_2'); + $visitorCollection = $this->getMockBuilder( + \Magento\Customer\Model\ResourceModel\Visitor\CollectionFactory::class + ) + ->disableOriginalConstructor()->setMethods(['addFieldToFilter', 'getItems'])->getMock(); + $visitorCollection->expects($this->atLeastOnce())->method('addFieldToFilter')->willReturnSelf(); + $visitorCollection->expects($this->atLeastOnce())->method('getItems')->willReturn([$visitor, $visitor]); + $this->visitorCollectionFactory->expects($this->atLeastOnce())->method('create') + ->willReturn($visitorCollection); + $this->saveHandler->expects($this->atLeastOnce())->method('destroy') + ->withConsecutive( + ['session_id_1'], + ['session_id_2'] + ); + $this->assertTrue($this->accountManagement->resetPassword($customerEmail, $resetToken, $newPassword)); + } + /** * @return void */ @@ -1466,10 +1625,10 @@ public function testAuthenticate() ->withConsecutive( [ 'customer_customer_authenticated', - ['model' => $customerModel, 'password' => $password] + ['model' => $customerModel, 'password' => $password], ], [ - 'customer_data_object_login', ['customer' => $customerData] + 'customer_data_object_login', ['customer' => $customerData], ] ); diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php index a94b7e39bc0eb..0fc3d01673c47 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/AbstractAddressTest.php @@ -6,6 +6,8 @@ namespace Magento\Customer\Test\Unit\Model\Address; +use Magento\Customer\Model\Address\CompositeValidator; + /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ @@ -41,6 +43,12 @@ class AbstractAddressTest extends \PHPUnit\Framework\TestCase /** @var \Magento\Customer\Model\Address\AbstractAddress */ protected $model; + /** @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager */ + private $objectManager; + + /** @var \Magento\Customer\Model\Address\CompositeValidator|\PHPUnit_Framework_MockObject_MockObject */ + private $compositeValidatorMock; + protected function setUp() { $this->contextMock = $this->createMock(\Magento\Framework\Model\Context::class); @@ -69,8 +77,9 @@ protected function setUp() $this->resourceCollectionMock = $this->getMockBuilder(\Magento\Framework\Data\Collection\AbstractDb::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->model = $objectManager->getObject( + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->compositeValidatorMock = $this->createMock(CompositeValidator::class); + $this->model = $this->objectManager->getObject( \Magento\Customer\Model\Address\AbstractAddress::class, [ 'context' => $this->contextMock, @@ -81,7 +90,8 @@ protected function setUp() 'regionFactory' => $this->regionFactoryMock, 'countryFactory' => $this->countryFactoryMock, 'resource' => $this->resourceMock, - 'resourceCollection' => $this->resourceCollectionMock + 'resourceCollection' => $this->resourceCollectionMock, + 'compositeValidator' => $this->compositeValidatorMock, ] ); } @@ -275,28 +285,15 @@ public function testSetDataWithObject() } /** - * @param $data - * @param $expected + * @param array $data + * @param array|bool $expected + * @return void * * @dataProvider validateDataProvider */ - public function testValidate($data, $expected) + public function testValidate(array $data, $expected) { - $attributeMock = $this->createMock(\Magento\Eav\Model\Entity\Attribute::class); - $attributeMock->expects($this->any()) - ->method('getIsRequired') - ->willReturn(true); - - $this->eavConfigMock->expects($this->any()) - ->method('getAttribute') - ->will($this->returnValue($attributeMock)); - - $this->directoryDataMock->expects($this->once()) - ->method('getCountriesWithOptionalZip') - ->will($this->returnValue([])); - - $this->directoryDataMock->expects($this->never()) - ->method('isRegionRequired'); + $this->compositeValidatorMock->method('validate')->with($this->model)->willReturn($expected); foreach ($data as $key => $value) { $this->model->setData($key, $value); @@ -349,6 +346,10 @@ public function validateDataProvider() array_merge(array_diff_key($data, ['postcode' => '']), ['country_id' => $countryId++]), ['"postcode" is required. Enter and try again.'], ], + 'region_id' => [ + array_merge($data, ['country_id' => $countryId++, 'region_id' => 2]), + ['Invalid value of "2" provided for the regionId field.'], + ], 'country_id' => [ array_diff_key($data, ['country_id' => '']), ['"countryId" is required. Enter and try again.'], @@ -388,4 +389,13 @@ public function getStreetFullDataProvider() ['single line', 'single line'], ]; } + + protected function tearDown() + { + $this->objectManager->setBackwardCompatibleProperty( + $this->model, + '_countryModels', + [] + ); + } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/Validator/CountryTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/Validator/CountryTest.php new file mode 100644 index 0000000000000..e70f93edab12c --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/Validator/CountryTest.php @@ -0,0 +1,160 @@ +directoryDataMock = $this->createMock(\Magento\Directory\Helper\Data::class); + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $this->objectManager->getObject( + \Magento\Customer\Model\Address\Validator\Country::class, + [ + 'directoryData' => $this->directoryDataMock, + ] + ); + } + + /** + * @param array $data + * @param array $countryIds + * @param array $allowedRegions + * @param array $expected + * @return void + * + * @dataProvider validateDataProvider + */ + public function testValidate(array $data, array $countryIds, array $allowedRegions, array $expected) + { + $addressMock = $this + ->getMockBuilder(\Magento\Customer\Model\Address\AbstractAddress::class) + ->disableOriginalConstructor() + ->setMethods( + [ + 'getCountryId', + 'getRegion', + 'getRegionId', + 'getCountryModel', + ] + )->getMock(); + + $this->directoryDataMock->expects($this->any()) + ->method('isRegionRequired') + ->willReturn($data['regionRequired']); + + $countryCollectionMock = $this->getMockBuilder(\Magento\Directory\Model\ResourceModel\Country\Collection::class) + ->disableOriginalConstructor() + ->setMethods(['getAllIds']) + ->getMock(); + + $this->directoryDataMock->expects($this->any()) + ->method('getCountryCollection') + ->willReturn($countryCollectionMock); + + $countryCollectionMock->expects($this->any())->method('getAllIds')->willReturn($countryIds); + + $addressMock->method('getCountryId')->willReturn($data['country_id']); + + $countryModelMock = $this->getMockBuilder(\Magento\Directory\Model\Country::class) + ->disableOriginalConstructor() + ->setMethods(['getRegionCollection']) + ->getMock(); + + $addressMock->method('getCountryModel')->willReturn($countryModelMock); + + $regionCollectionMock = $this->getMockBuilder(\Magento\Directory\Model\ResourceModel\Region\Collection::class) + ->disableOriginalConstructor() + ->setMethods(['getAllIds']) + ->getMock(); + $countryModelMock + ->expects($this->any()) + ->method('getRegionCollection') + ->willReturn($regionCollectionMock); + $regionCollectionMock->expects($this->any())->method('getAllIds')->willReturn($allowedRegions); + + $addressMock->method('getRegionId')->willReturn($data['region_id']); + $addressMock->method('getRegion')->willReturn(null); + + $actual = $this->model->validate($addressMock); + $this->assertEquals($expected, $actual); + } + + /** + * @return array + */ + public function validateDataProvider() + { + $countryId = 1; + $data = [ + 'firstname' => 'First Name', + 'lastname' => 'Last Name', + 'street' => "Street 1\nStreet 2", + 'city' => 'Odessa', + 'telephone' => '555-55-55', + 'country_id' => $countryId, + 'postcode' => 07201, + 'region_id' => 1, + 'region' => '', + 'regionRequired' => false, + 'company' => 'Magento', + 'fax' => '222-22-22', + ]; + $result = [ + 'country_id1' => [ + array_merge($data, ['country_id' => null]), + [], + [1], + ['"countryId" is required. Enter and try again.'], + ], + 'country_id2' => [ + $data, + [], + [1], + ['Invalid value of "' . $countryId . '" provided for the countryId field.'], + ], + 'region' => [ + array_merge($data, ['country_id' => $countryId, 'regionRequired' => true]), + [$countryId++], + [], + ['"region" is required. Enter and try again.'], + ], + 'region_id1' => [ + array_merge($data, ['country_id' => $countryId, 'regionRequired' => true, 'region_id' => '']), + [$countryId++], + [1], + ['"regionId" is required. Enter and try again.'], + ], + 'region_id2' => [ + array_merge($data, ['country_id' => $countryId, 'region_id' => 2]), + [$countryId++], + [1], + ['Invalid value of "2" provided for the regionId field.'], + ], + 'validated' => [ + array_merge($data, ['country_id' => $countryId]), + [$countryId], + ['1'], + [], + ], + ]; + + return $result; + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/Address/Validator/GeneralTest.php b/app/code/Magento/Customer/Test/Unit/Model/Address/Validator/GeneralTest.php new file mode 100644 index 0000000000000..058a69e86b43a --- /dev/null +++ b/app/code/Magento/Customer/Test/Unit/Model/Address/Validator/GeneralTest.php @@ -0,0 +1,140 @@ +directoryDataMock = $this->createMock(\Magento\Directory\Helper\Data::class); + $this->eavConfigMock = $this->createMock(\Magento\Eav\Model\Config::class); + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->model = $this->objectManager->getObject( + \Magento\Customer\Model\Address\Validator\General::class, + [ + 'eavConfig' => $this->eavConfigMock, + 'directoryData' => $this->directoryDataMock, + ] + ); + } + + /** + * @param array $data + * @param array $expected + * @return void + * + * @dataProvider validateDataProvider + */ + public function testValidate(array $data, array $expected) + { + $addressMock = $this + ->getMockBuilder(\Magento\Customer\Model\Address\AbstractAddress::class) + ->disableOriginalConstructor() + ->setMethods( + [ + 'getFirstname', + 'getLastname', + 'getStreetLine', + 'getCity', + 'getTelephone', + 'getFax', + 'getCompany', + 'getPostcode', + 'getCountryId', + ] + )->getMock(); + + $attributeMock = $this->createMock(\Magento\Eav\Model\Entity\Attribute::class); + $attributeMock->expects($this->any()) + ->method('getIsRequired') + ->willReturn(true); + + $this->eavConfigMock->expects($this->any()) + ->method('getAttribute') + ->will($this->returnValue($attributeMock)); + + $this->directoryDataMock->expects($this->once()) + ->method('getCountriesWithOptionalZip') + ->will($this->returnValue([])); + + $addressMock->method('getFirstName')->willReturn($data['firstname']); + $addressMock->method('getLastname')->willReturn($data['lastname']); + $addressMock->method('getStreetLine')->with(1)->willReturn($data['street']); + $addressMock->method('getCity')->willReturn($data['city']); + $addressMock->method('getTelephone')->willReturn($data['telephone']); + $addressMock->method('getFax')->willReturn($data['fax']); + $addressMock->method('getCompany')->willReturn($data['company']); + $addressMock->method('getPostcode')->willReturn($data['postcode']); + $addressMock->method('getCountryId')->willReturn($data['country_id']); + + $actual = $this->model->validate($addressMock); + $this->assertEquals($expected, $actual); + } + + /** + * @return array + */ + public function validateDataProvider() + { + $countryId = 1; + $data = [ + 'firstname' => 'First Name', + 'lastname' => 'Last Name', + 'street' => "Street 1\nStreet 2", + 'city' => 'Odessa', + 'telephone' => '555-55-55', + 'country_id' => $countryId, + 'postcode' => 07201, + 'company' => 'Magento', + 'fax' => '222-22-22', + ]; + $result = [ + 'firstname' => [ + array_merge(array_merge($data, ['firstname' => '']), ['country_id' => $countryId++]), + ['"firstname" is required. Enter and try again.'], + ], + 'lastname' => [ + array_merge(array_merge($data, ['lastname' => '']), ['country_id' => $countryId++]), + ['"lastname" is required. Enter and try again.'], + ], + 'street' => [ + array_merge(array_merge($data, ['street' => '']), ['country_id' => $countryId++]), + ['"street" is required. Enter and try again.'], + ], + 'city' => [ + array_merge(array_merge($data, ['city' => '']), ['country_id' => $countryId++]), + ['"city" is required. Enter and try again.'], + ], + 'telephone' => [ + array_merge(array_merge($data, ['telephone' => '']), ['country_id' => $countryId++]), + ['"telephone" is required. Enter and try again.'], + ], + 'postcode' => [ + array_merge(array_merge($data, ['postcode' => '']), ['country_id' => $countryId++]), + ['"postcode" is required. Enter and try again.'], + ], + 'validated' => [array_merge($data, ['country_id' => $countryId++]), []], + ]; + + return $result; + } +} diff --git a/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerNotificationTest.php b/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerNotificationTest.php index 14a95dda76f61..c3c853bca1469 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerNotificationTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Plugin/CustomerNotificationTest.php @@ -5,82 +5,119 @@ */ namespace Magento\Customer\Test\Unit\Model\Plugin; +use Magento\Backend\App\AbstractAction; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Customer\Api\Data\CustomerInterface; use Magento\Customer\Model\Customer\NotificationStorage; use Magento\Customer\Model\Plugin\CustomerNotification; +use Magento\Customer\Model\Session; +use Magento\Framework\App\Area; +use Magento\Framework\App\RequestInterface; +use Magento\Framework\App\State; +use Magento\Framework\Exception\NoSuchEntityException; +use Psr\Log\LoggerInterface; class CustomerNotificationTest extends \PHPUnit\Framework\TestCase { - /** @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject */ - protected $session; + /** @var Session|\PHPUnit_Framework_MockObject_MockObject */ + private $sessionMock; - /** @var \Magento\Customer\Model\Customer\NotificationStorage|\PHPUnit_Framework_MockObject_MockObject */ - protected $notificationStorage; + /** @var NotificationStorage|\PHPUnit_Framework_MockObject_MockObject */ + private $notificationStorageMock; - /** @var \Magento\Customer\Api\CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerRepository; + /** @var CustomerRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $customerRepositoryMock; - /** @var \Magento\Framework\App\State|\PHPUnit_Framework_MockObject_MockObject */ - protected $appState; + /** @var State|\PHPUnit_Framework_MockObject_MockObject */ + private $appStateMock; - /** @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $request; + /** @var RequestInterface|\PHPUnit_Framework_MockObject_MockObject */ + private $requestMock; - /** @var \Magento\Backend\App\AbstractAction|\PHPUnit_Framework_MockObject_MockObject */ - protected $abstractAction; + /** @var AbstractAction|\PHPUnit_Framework_MockObject_MockObject */ + private $abstractActionMock; + + /** @var LoggerInterface */ + private $loggerMock; /** @var CustomerNotification */ - protected $plugin; + private $plugin; + + /** @var int */ + private static $customerId = 1; protected function setUp() { - $this->session = $this->getMockBuilder(\Magento\Customer\Model\Session::class) + $this->sessionMock = $this->getMockBuilder(Session::class) ->disableOriginalConstructor() + ->setMethods(['getCustomerId', 'setCustomerData', 'setCustomerGroupId', 'regenerateId']) ->getMock(); - $this->notificationStorage = $this->getMockBuilder(\Magento\Customer\Model\Customer\NotificationStorage::class) + $this->notificationStorageMock = $this->getMockBuilder(NotificationStorage::class) ->disableOriginalConstructor() + ->setMethods(['isExists', 'remove']) ->getMock(); - $this->customerRepository = $this->getMockBuilder(\Magento\Customer\Api\CustomerRepositoryInterface::class) + $this->customerRepositoryMock = $this->getMockBuilder(CustomerRepositoryInterface::class) ->getMockForAbstractClass(); - $this->abstractAction = $this->getMockBuilder(\Magento\Backend\App\AbstractAction::class) + $this->abstractActionMock = $this->getMockBuilder(AbstractAction::class) ->disableOriginalConstructor() ->getMockForAbstractClass(); - $this->request = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class) + $this->requestMock = $this->getMockBuilder(RequestInterface::class) ->setMethods(['isPost']) ->getMockForAbstractClass(); - $this->appState = $this->getMockBuilder(\Magento\Framework\App\State::class) - ->disableOriginalConstructor()->getMock(); + $this->appStateMock = $this->getMockBuilder(State::class) + ->disableOriginalConstructor() + ->setMethods(['getAreaCode']) + ->getMock(); + + $this->loggerMock = $this->getMockForAbstractClass(LoggerInterface::class); + $this->appStateMock->method('getAreaCode')->willReturn(Area::AREA_FRONTEND); + $this->requestMock->method('isPost')->willReturn(true); + $this->sessionMock->method('getCustomerId')->willReturn(self::$customerId); + $this->notificationStorageMock->expects($this->any()) + ->method('isExists') + ->with(NotificationStorage::UPDATE_CUSTOMER_SESSION, self::$customerId) + ->willReturn(true); + $this->plugin = new CustomerNotification( - $this->session, - $this->notificationStorage, - $this->appState, - $this->customerRepository + $this->sessionMock, + $this->notificationStorageMock, + $this->appStateMock, + $this->customerRepositoryMock, + $this->loggerMock ); } public function testBeforeDispatch() { - $customerId = 1; $customerGroupId =1; - $this->appState->expects($this->any()) - ->method('getAreaCode') - ->willReturn(\Magento\Framework\App\Area::AREA_FRONTEND); - $this->request->expects($this->any())->method('isPost')->willReturn(true); - $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) - ->getMockForAbstractClass(); - $customerMock->expects($this->any())->method('getGroupId')->willReturn($customerGroupId); - $this->customerRepository->expects($this->any()) + + $customerMock = $this->getMockForAbstractClass(CustomerInterface::class); + $customerMock->method('getGroupId')->willReturn($customerGroupId); + $customerMock->method('getId')->willReturn(self::$customerId); + + $this->customerRepositoryMock->expects($this->once()) ->method('getById') - ->with($customerId) + ->with(self::$customerId) ->willReturn($customerMock); - $this->session->expects($this->any())->method('getCustomerId')->willReturn($customerId); - $this->session->expects($this->any())->method('setCustomerData')->with($customerMock); - $this->session->expects($this->any())->method('setCustomerGroupId')->with($customerGroupId); - $this->session->expects($this->once())->method('regenerateId'); - $this->notificationStorage->expects($this->any()) - ->method('isExists') - ->with(NotificationStorage::UPDATE_CUSTOMER_SESSION, $customerId) - ->willReturn(true); + $this->notificationStorageMock->expects($this->once()) + ->method('remove') + ->with(NotificationStorage::UPDATE_CUSTOMER_SESSION, self::$customerId); + + $this->sessionMock->expects($this->once())->method('setCustomerData')->with($customerMock); + $this->sessionMock->expects($this->once())->method('setCustomerGroupId')->with($customerGroupId); + $this->sessionMock->expects($this->once())->method('regenerateId'); + + $this->plugin->beforeDispatch($this->abstractActionMock, $this->requestMock); + } + + public function testBeforeDispatchWithNoCustomerFound() + { + $this->customerRepositoryMock->method('getById') + ->with(self::$customerId) + ->willThrowException(new NoSuchEntityException()); + $this->loggerMock->expects($this->once()) + ->method('error'); - $this->plugin->beforeDispatch($this->abstractAction, $this->request); + $this->plugin->beforeDispatch($this->abstractActionMock, $this->requestMock); } } diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php index a05e9e23ef94f..06133dd89d754 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/CustomerRepositoryTest.php @@ -7,6 +7,7 @@ namespace Magento\Customer\Test\Unit\Model\ResourceModel; use Magento\Customer\Api\CustomerMetadataInterface; +use Magento\Customer\Model\Customer\NotificationStorage; use Magento\Framework\Api\SearchCriteria\CollectionProcessorInterface; /** @@ -18,82 +19,87 @@ class CustomerRepositoryTest extends \PHPUnit\Framework\TestCase /** * @var \Magento\Customer\Model\CustomerFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerFactory; + private $customerFactory; /** * @var \Magento\Customer\Model\Data\CustomerSecureFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerSecureFactory; + private $customerSecureFactory; /** * @var \Magento\Customer\Model\CustomerRegistry|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerRegistry; + private $customerRegistry; /** * @var \Magento\Customer\Model\ResourceModel\AddressRepository|\PHPUnit_Framework_MockObject_MockObject */ - protected $addressRepository; + private $addressRepository; /** * @var \Magento\Customer\Model\ResourceModel\Customer|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerResourceModel; + private $customerResourceModel; /** * @var \Magento\Customer\Api\CustomerMetadataInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerMetadata; + private $customerMetadata; /** * @var \Magento\Customer\Api\Data\CustomerSearchResultsInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $searchResultsFactory; + private $searchResultsFactory; /** * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $eventManager; + private $eventManager; /** * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $storeManager; + private $storeManager; /** * @var \Magento\Framework\Api\ExtensibleDataObjectConverter|\PHPUnit_Framework_MockObject_MockObject */ - protected $extensibleDataObjectConverter; + private $extensibleDataObjectConverter; /** * @var \Magento\Framework\Api\DataObjectHelper|\PHPUnit_Framework_MockObject_MockObject */ - protected $dataObjectHelper; + private $dataObjectHelper; /** * @var \Magento\Framework\Api\ImageProcessorInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $imageProcessor; + private $imageProcessor; /** * @var \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $extensionAttributesJoinProcessor; + private $extensionAttributesJoinProcessor; /** * @var \Magento\Customer\Api\Data\CustomerInterface|\PHPUnit_Framework_MockObject_MockObject */ - protected $customer; + private $customer; /** * @var CollectionProcessorInterface|\PHPUnit_Framework_MockObject_MockObject */ private $collectionProcessorMock; + /** + * @var NotificationStorage|\PHPUnit_Framework_MockObject_MockObject + */ + private $notificationStorage; + /** * @var \Magento\Customer\Model\ResourceModel\CustomerRepository */ - protected $model; + private $model; protected function setUp() { @@ -158,6 +164,10 @@ protected function setUp() ); $this->collectionProcessorMock = $this->getMockBuilder(CollectionProcessorInterface::class) ->getMock(); + $this->notificationStorage = $this->getMockBuilder(NotificationStorage::class) + ->disableOriginalConstructor() + ->getMock(); + $this->model = new \Magento\Customer\Model\ResourceModel\CustomerRepository( $this->customerFactory, $this->customerSecureFactory, @@ -172,7 +182,8 @@ protected function setUp() $this->dataObjectHelper, $this->imageProcessor, $this->extensionAttributesJoinProcessor, - $this->collectionProcessorMock + $this->collectionProcessorMock, + $this->notificationStorage ); } @@ -793,6 +804,9 @@ public function testDelete() $this->customerRegistry->expects($this->atLeastOnce()) ->method('remove') ->with($customerId); + $this->notificationStorage->expects($this->atLeastOnce()) + ->method('remove') + ->with(NotificationStorage::UPDATE_CUSTOMER_SESSION, $customerId); $this->assertTrue($this->model->delete($this->customer)); } diff --git a/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php b/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php index ca6b8708f695c..ec787b9d3c873 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/VisitorTest.php @@ -60,15 +60,15 @@ protected function setUp() 'commit', 'clean', ])->disableOriginalConstructor()->getMock(); - $this->resource->expects($this->any())->method('getIdFieldName')->will($this->returnValue('visitor_id')); - $this->resource->expects($this->any())->method('addCommitCallback')->will($this->returnSelf()); + $this->resource->expects($this->any())->method('getIdFieldName')->willReturn('visitor_id'); + $this->resource->expects($this->any())->method('addCommitCallback')->willReturnSelf(); $arguments = $this->objectManagerHelper->getConstructArguments( \Magento\Customer\Model\Visitor::class, [ 'registry' => $this->registry, 'session' => $this->session, - 'resource' => $this->resource + 'resource' => $this->resource, ] ); @@ -77,14 +77,13 @@ protected function setUp() public function testInitByRequest() { - $this->session->expects($this->once())->method('getSessionId') - ->will($this->returnValue('asdfhasdfjhkj2198sadf8sdf897')); - $this->visitor->initByRequest(null); - $this->assertEquals('asdfhasdfjhkj2198sadf8sdf897', $this->visitor->getSessionId()); - - $this->visitor->setData(['visitor_id' => 1]); + $oldSessionId = 'asdfhasdfjhkj2198sadf8sdf897'; + $newSessionId = 'bsdfhasdfjhkj2198sadf8sdf897'; + $this->session->expects($this->any())->method('getSessionId')->willReturn($newSessionId); + $this->session->expects($this->atLeastOnce())->method('getVisitorData') + ->willReturn(['session_id' => $oldSessionId]); $this->visitor->initByRequest(null); - $this->assertNull($this->visitor->getSessionId()); + $this->assertEquals($newSessionId, $this->visitor->getSessionId()); } public function testSaveByRequest() @@ -101,7 +100,7 @@ public function testIsModuleIgnored() 'registry' => $this->registry, 'session' => $this->session, 'resource' => $this->resource, - 'ignores' => ['test_route_name' => true] + 'ignores' => ['test_route_name' => true], ] ); $request = new \Magento\Framework\DataObject(['route_name' => 'test_route_name']); @@ -164,7 +163,7 @@ public function testBindQuoteDestroy() public function testClean() { - $this->resource->expects($this->once())->method('clean')->with($this->visitor)->will($this->returnSelf()); + $this->resource->expects($this->once())->method('clean')->with($this->visitor)->willReturnSelf(); $this->visitor->clean(); } } diff --git a/app/code/Magento/Customer/etc/db_schema.xml b/app/code/Magento/Customer/etc/db_schema.xml index 490211e4307ab..368ca417432fd 100644 --- a/app/code/Magento/Customer/etc/db_schema.xml +++ b/app/code/Magento/Customer/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml index 6df04c7f89656..43c2b9cf7bb80 100644 --- a/app/code/Magento/Customer/etc/di.xml +++ b/app/code/Magento/Customer/etc/di.xml @@ -420,4 +420,17 @@ + + + Magento\Framework\Session\SessionManagerInterface\Proxy + + + + + + Magento\Customer\Model\Address\Validator\General + Magento\Customer\Model\Address\Validator\Country + + + diff --git a/app/code/Magento/Customer/etc/events.xml b/app/code/Magento/Customer/etc/events.xml index 66c9a3813892c..d841d8faa9c38 100644 --- a/app/code/Magento/Customer/etc/events.xml +++ b/app/code/Magento/Customer/etc/events.xml @@ -10,7 +10,7 @@ - + diff --git a/app/code/Magento/Customer/etc/module.xml b/app/code/Magento/Customer/etc/module.xml index 2dfe561d0da8f..853157fed1f5d 100644 --- a/app/code/Magento/Customer/etc/module.xml +++ b/app/code/Magento/Customer/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js index 71ca63f6750bb..be2e0aedfe4bb 100644 --- a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js +++ b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js @@ -31,6 +31,8 @@ define([ this.options.cache.label = $(this.options.passwordStrengthMeterLabelSelector, this.element); // We need to look outside the module for backward compatibility, since someone can already use the module. + // @todo Narrow this selector in 2.3 so it doesn't accidentally finds the the email field from the + // newsletter email field or any other "email" field. this.options.cache.email = $(this.options.formSelector).find(this.options.emailSelector); this._bind(); }, @@ -74,7 +76,9 @@ define([ 'password-not-equal-to-user-name': this.options.cache.email.val() }); - if (password.toLowerCase() === this.options.cache.email.val().toLowerCase()) { + // We should only perform this check in case there is an email field on screen + if (this.options.cache.email.length && + password.toLowerCase() === this.options.cache.email.val().toLowerCase()) { displayScore = 1; } else { isValid = $.validator.validateSingleElement(this.options.cache.input); diff --git a/app/code/Magento/CustomerAnalytics/etc/module.xml b/app/code/Magento/CustomerAnalytics/etc/module.xml index adc4f8dd849c2..a6a3380b3462e 100644 --- a/app/code/Magento/CustomerAnalytics/etc/module.xml +++ b/app/code/Magento/CustomerAnalytics/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/CustomerGraphQl/etc/module.xml b/app/code/Magento/CustomerGraphQl/etc/module.xml index 88f08623c717d..c3149965b0fe0 100644 --- a/app/code/Magento/CustomerGraphQl/etc/module.xml +++ b/app/code/Magento/CustomerGraphQl/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/CustomerImportExport/etc/module.xml b/app/code/Magento/CustomerImportExport/etc/module.xml index 865b2e991418d..2b351d06a5ffd 100644 --- a/app/code/Magento/CustomerImportExport/etc/module.xml +++ b/app/code/Magento/CustomerImportExport/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/Deploy/Console/ConsoleLogger.php b/app/code/Magento/Deploy/Console/ConsoleLogger.php index a7d3b48fde130..0ca34439c7d4f 100644 --- a/app/code/Magento/Deploy/Console/ConsoleLogger.php +++ b/app/code/Magento/Deploy/Console/ConsoleLogger.php @@ -82,8 +82,8 @@ class ConsoleLogger extends AbstractLogger LogLevel::CRITICAL => OutputInterface::VERBOSITY_NORMAL, LogLevel::ERROR => OutputInterface::VERBOSITY_NORMAL, LogLevel::WARNING => OutputInterface::VERBOSITY_NORMAL, - LogLevel::NOTICE => OutputInterface::VERBOSITY_VERBOSE, - LogLevel::INFO => OutputInterface::VERBOSITY_VERY_VERBOSE, + LogLevel::NOTICE => OutputInterface::VERBOSITY_NORMAL, + LogLevel::INFO => OutputInterface::VERBOSITY_VERBOSE, LogLevel::DEBUG => OutputInterface::VERBOSITY_DEBUG ]; diff --git a/app/code/Magento/Deploy/Model/Filesystem.php b/app/code/Magento/Deploy/Model/Filesystem.php index 3dd28f4d3e820..59880d2d669b4 100644 --- a/app/code/Magento/Deploy/Model/Filesystem.php +++ b/app/code/Magento/Deploy/Model/Filesystem.php @@ -10,6 +10,7 @@ use Magento\Framework\App\DeploymentConfig\Writer; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Validator\Locale; use Magento\User\Model\ResourceModel\User\Collection as UserCollection; /** @@ -100,6 +101,11 @@ class Filesystem */ private $userCollection; + /** + * @var Locale + */ + private $locale; + /** * @param \Magento\Framework\App\DeploymentConfig\Writer $writer * @param \Magento\Framework\App\DeploymentConfig\Reader $reader @@ -109,6 +115,9 @@ class Filesystem * @param \Magento\Framework\Filesystem\Driver\File $driverFile * @param \Magento\Store\Model\Config\StoreView $storeView * @param \Magento\Framework\ShellInterface $shell + * @param UserCollection|null $userCollection + * @param Locale|null $locale + * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( \Magento\Framework\App\DeploymentConfig\Writer $writer, @@ -118,7 +127,9 @@ public function __construct( \Magento\Framework\App\Filesystem\DirectoryList $directoryList, \Magento\Framework\Filesystem\Driver\File $driverFile, \Magento\Store\Model\Config\StoreView $storeView, - \Magento\Framework\ShellInterface $shell + \Magento\Framework\ShellInterface $shell, + UserCollection $userCollection = null, + Locale $locale = null ) { $this->writer = $writer; $this->reader = $reader; @@ -128,6 +139,8 @@ public function __construct( $this->driverFile = $driverFile; $this->storeView = $storeView; $this->shell = $shell; + $this->userCollection = $userCollection ?: $this->objectManager->get(UserCollection::class); + $this->locale = $locale ?: $this->objectManager->get(Locale::class); $this->functionCallPath = PHP_BINARY . ' -f ' . BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento '; } @@ -193,16 +206,17 @@ protected function deployStaticContent( private function getAdminUserInterfaceLocales() { $locales = []; - foreach ($this->getUserCollection() as $user) { + foreach ($this->userCollection as $user) { $locales[] = $user->getInterfaceLocale(); } return $locales; } /** - * Get used store and admin user locales + * Get used store and admin user locales. * * @return array + * @throws \InvalidArgumentException if unknown locale is provided by the store configuration */ private function getUsedLocales() { @@ -210,25 +224,19 @@ private function getUsedLocales() $this->storeView->retrieveLocales(), $this->getAdminUserInterfaceLocales() ); - return array_unique($usedLocales); - } - /** - * Get user collection - * - * @return UserCollection - * @deprecated 100.1.0 Added to not break backward compatibility of the constructor signature - * by injecting the new dependency directly. - * The method can be removed in a future major release, when constructor signature can be changed. - */ - private function getUserCollection() - { - if (!($this->userCollection instanceof UserCollection)) { - return \Magento\Framework\App\ObjectManager::getInstance()->get( - UserCollection::class - ); - } - return $this->userCollection; + return array_map( + function ($locale) { + if (!$this->locale->isValid($locale)) { + throw new \InvalidArgumentException( + $locale . ' argument has invalid value, run info:language:list for list of available locales' + ); + } + + return $locale; + }, + array_unique($usedLocales) + ); } /** diff --git a/app/code/Magento/Deploy/Model/Mode.php b/app/code/Magento/Deploy/Model/Mode.php index c7ee9b6849665..d4ae72d63bce7 100644 --- a/app/code/Magento/Deploy/Model/Mode.php +++ b/app/code/Magento/Deploy/Model/Mode.php @@ -236,7 +236,7 @@ private function saveAppConfigs($mode) $configs = $this->configProvider->getConfigs($this->getMode(), $mode); foreach ($configs as $path => $item) { $this->emulatedAreaProcessor->process(function () use ($path, $item) { - $this->processorFacadeFactory->create()->process( + $this->processorFacadeFactory->create()->processWithLockTarget( $path, $item['value'], ScopeConfigInterface::SCOPE_TYPE_DEFAULT, diff --git a/app/code/Magento/Deploy/Process/Queue.php b/app/code/Magento/Deploy/Process/Queue.php index e5e10c8f54a19..75b21b2b7fb84 100644 --- a/app/code/Magento/Deploy/Process/Queue.php +++ b/app/code/Magento/Deploy/Process/Queue.php @@ -161,7 +161,7 @@ public function process() foreach ($packages as $name => $packageJob) { $this->assertAndExecute($name, $packages, $packageJob); } - $this->logger->notice('.'); + $this->logger->info('.'); sleep(3); foreach ($this->inProgress as $name => $package) { if ($this->isDeployed($package)) { @@ -214,7 +214,7 @@ private function awaitForAllProcesses() unset($this->inProgress[$name]); } } - $this->logger->notice('.'); + $this->logger->info('.'); sleep(5); } if ($this->isCanBeParalleled()) { diff --git a/app/code/Magento/Deploy/Service/DeployPackage.php b/app/code/Magento/Deploy/Service/DeployPackage.php index 2e7b10a159c3a..7a5eb09912471 100644 --- a/app/code/Magento/Deploy/Service/DeployPackage.php +++ b/app/code/Magento/Deploy/Service/DeployPackage.php @@ -267,7 +267,7 @@ private function register(Package $package, PackageFile $file = null, $skipLoggi $this->deployStaticFile->writeTmpFile('info.json', $package->getPath(), json_encode($info)); if (!$skipLogging) { - $this->logger->notice($logMessage); + $this->logger->info($logMessage); } } } diff --git a/app/code/Magento/Deploy/Test/Unit/Model/FilesystemTest.php b/app/code/Magento/Deploy/Test/Unit/Model/FilesystemTest.php index 673f31c04ffd3..00f70c6527a0d 100644 --- a/app/code/Magento/Deploy/Test/Unit/Model/FilesystemTest.php +++ b/app/code/Magento/Deploy/Test/Unit/Model/FilesystemTest.php @@ -5,47 +5,64 @@ */ namespace Magento\Deploy\Test\Unit\Model; +use Magento\Deploy\Model\Filesystem as DeployFilesystem; +use Magento\Framework\Filesystem; +use Magento\Framework\Filesystem\Directory\WriteInterface; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\ShellInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Store\Model\Config\StoreView; +use Magento\User\Model\ResourceModel\User\Collection; +use Magento\User\Model\User; +use PHPUnit_Framework_MockObject_MockObject as MockObject; +use Symfony\Component\Console\Output\OutputInterface; +use Magento\Framework\Validator\Locale; +use Magento\Framework\Setup\Lists; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class FilesystemTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Store\Model\Config\StoreView + * @var StoreView|MockObject */ - private $storeViewMock; + private $storeView; /** - * @var \Magento\Framework\ShellInterface + * @var ShellInterface|MockObject */ - private $shellMock; + private $shell; /** - * @var \Magento\User\Model\ResourceModel\User\Collection + * @var OutputInterface|MockObject */ - private $userCollectionMock; + private $output; /** - * @var \Symfony\Component\Console\Output\OutputInterface + * @var Filesystem|MockObject */ - private $outputMock; + private $filesystem; /** - * @var \Magento\Framework\Filesystem + * @var WriteInterface|MockObject */ - private $filesystemMock; + private $directoryWrite; /** - * @var \Magento\Framework\Filesystem\Directory\WriteInterface + * @var Collection|MockObject */ - private $directoryWriteMock; + private $userCollection; /** - * @var \Magento\Framework\ObjectManagerInterface + * @var ObjectManagerInterface|MockObject */ - private $objectManagerMock; + private $objectManager; /** - * @var \Magento\Deploy\Model\Filesystem + * @var DeployFilesystem */ - private $filesystem; + private $deployFilesystem; /** * @var string @@ -54,75 +71,146 @@ class FilesystemTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - - $this->storeViewMock = $this->createMock(\Magento\Store\Model\Config\StoreView::class); - $this->shellMock = $this->createMock(\Magento\Framework\ShellInterface::class); - $this->userCollectionMock = $this->createMock(\Magento\User\Model\ResourceModel\User\Collection::class); - $this->outputMock = $this->createMock(\Symfony\Component\Console\Output\OutputInterface::class); - $this->objectManagerMock = $this->createMock(\Magento\Framework\ObjectManagerInterface::class); - $this->filesystemMock = $this->createMock(\Magento\Framework\Filesystem::class); - $this->directoryWriteMock = $this->createMock(\Magento\Framework\Filesystem\Directory\WriteInterface::class); - $this->filesystemMock->expects($this->any()) - ->method('getDirectoryWrite') - ->willReturn($this->directoryWriteMock); - $this->filesystem = $objectManager->getObject( - \Magento\Deploy\Model\Filesystem::class, + $objectManager = new ObjectManager($this); + + $this->storeView = $this->getMockBuilder(StoreView::class) + ->disableOriginalConstructor() + ->getMock(); + $this->shell = $this->getMockBuilder(ShellInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->output = $this->getMockBuilder(OutputInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManager = $this->getMockBuilder(ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->filesystem = $this->getMockBuilder(Filesystem::class) + ->disableOriginalConstructor() + ->getMock(); + $this->directoryWrite = $this->getMockBuilder(WriteInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->filesystem->method('getDirectoryWrite') + ->willReturn($this->directoryWrite); + + $this->userCollection = $this->getMockBuilder(Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $lists = $this->getMockBuilder(Lists::class) + ->disableOriginalConstructor() + ->getMock(); + + $lists->method('getLocaleList') + ->willReturn([ + 'fr_FR' => 'France', + 'de_DE' => 'Germany', + 'nl_NL' => 'Netherlands', + 'en_US' => 'USA', + ]); + $locale = $objectManager->getObject(Locale::class, ['lists' => $lists]); + + $this->deployFilesystem = $objectManager->getObject( + DeployFilesystem::class, [ - 'storeView' => $this->storeViewMock, - 'shell' => $this->shellMock, - 'filesystem' => $this->filesystemMock + 'storeView' => $this->storeView, + 'shell' => $this->shell, + 'filesystem' => $this->filesystem, + 'userCollection' => $this->userCollection, + 'locale' => $locale, ] ); - $userCollection = new \ReflectionProperty(\Magento\Deploy\Model\Filesystem::class, 'userCollection'); - $userCollection->setAccessible(true); - $userCollection->setValue($this->filesystem, $this->userCollectionMock); - $this->cmdPrefix = PHP_BINARY . ' -f ' . BP . DIRECTORY_SEPARATOR . 'bin' . DIRECTORY_SEPARATOR . 'magento '; } public function testRegenerateStatic() { $storeLocales = ['fr_FR', 'de_DE', 'nl_NL']; - $adminUserInterfaceLocales = ['de_DE', 'en_US']; - $this->storeViewMock->expects($this->once()) - ->method('retrieveLocales') + $this->storeView->method('retrieveLocales') ->willReturn($storeLocales); - $userMock = $this->createMock(\Magento\User\Model\User::class); - $userMock->expects($this->once()) - ->method('getInterfaceLocale') - ->willReturn('en_US'); - $this->userCollectionMock->expects($this->once()) - ->method('getIterator') - ->willReturn(new \ArrayIterator([$userMock])); - - $usedLocales = array_unique( - array_merge($storeLocales, $adminUserInterfaceLocales) - ); - $staticContentDeployCmd = $this->cmdPrefix . 'setup:static-content:deploy -f ' - . implode(' ', $usedLocales); + $setupDiCompileCmd = $this->cmdPrefix . 'setup:di:compile'; - $this->shellMock->expects($this->at(0)) + $this->shell->expects(self::at(0)) ->method('execute') ->with($setupDiCompileCmd); - $this->shellMock->expects($this->at(1)) + + $this->initAdminLocaleMock('en_US'); + + $usedLocales = ['fr_FR', 'de_DE', 'nl_NL', 'en_US']; + $staticContentDeployCmd = $this->cmdPrefix . 'setup:static-content:deploy -f ' + . implode(' ', $usedLocales); + $this->shell->expects(self::at(1)) ->method('execute') ->with($staticContentDeployCmd); - $this->outputMock->expects($this->at(0)) + $this->output->expects(self::at(0)) ->method('writeln') ->with('Starting compilation'); - $this->outputMock->expects($this->at(2)) + $this->output->expects(self::at(2)) ->method('writeln') ->with('Compilation complete'); - $this->outputMock->expects($this->at(3)) + $this->output->expects(self::at(3)) ->method('writeln') ->with('Starting deployment of static content'); - $this->outputMock->expects($this->at(5)) + $this->output->expects(self::at(5)) ->method('writeln') ->with('Deployment of static content complete'); - $this->filesystem->regenerateStatic($this->outputMock); + $this->deployFilesystem->regenerateStatic($this->output); + } + + /** + * Checks a case when configuration contains incorrect locale code. + * + * @return void + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage ;echo argument has invalid value, run info:language:list for list of available locales + */ + public function testGenerateStaticForNotAllowedStoreViewLocale() + { + $storeLocales = ['fr_FR', 'de_DE', ';echo']; + $this->storeView->method('retrieveLocales') + ->willReturn($storeLocales); + + $this->initAdminLocaleMock('en_US'); + + $this->deployFilesystem->regenerateStatic($this->output); + } + + /** + * Checks as case when admin locale is incorrect. + * + * @return void + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage ;echo argument has invalid value, run info:language:list for list of available locales + */ + public function testGenerateStaticForNotAllowedAdminLocale() + { + $storeLocales = ['fr_FR', 'de_DE', 'en_US']; + $this->storeView->method('retrieveLocales') + ->willReturn($storeLocales); + + $this->initAdminLocaleMock(';echo'); + + $this->deployFilesystem->regenerateStatic($this->output); + } + + /** + * Initializes admin user locale. + * + * @param string $locale + * @return void + */ + private function initAdminLocaleMock($locale) + { + /** @var User|MockObject $user */ + $user = $this->getMockBuilder(User::class) + ->disableOriginalConstructor() + ->getMock(); + $user->method('getInterfaceLocale') + ->willReturn($locale); + $this->userCollection->method('getIterator') + ->willReturn(new \ArrayIterator([$user])); } } diff --git a/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php b/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php index 25625eaa5e267..50725a3382073 100644 --- a/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php +++ b/app/code/Magento/Deploy/Test/Unit/Model/ModeTest.php @@ -241,7 +241,7 @@ public function testEnableProductionModeMinimal() ->willReturn($this->processorFacade); $this->processorFacade ->expects($this->once()) - ->method('process') + ->method('processWithLockTarget') ->with( 'dev/debug/debug_logging', 0, diff --git a/app/code/Magento/Deploy/etc/module.xml b/app/code/Magento/Deploy/etc/module.xml index a61f9e1546e05..d4785cd7a3112 100644 --- a/app/code/Magento/Deploy/etc/module.xml +++ b/app/code/Magento/Deploy/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Developer/Console/Command/GeneratePatchCommand.php b/app/code/Magento/Developer/Console/Command/GeneratePatchCommand.php new file mode 100644 index 0000000000000..7a7deba98ea4e --- /dev/null +++ b/app/code/Magento/Developer/Console/Command/GeneratePatchCommand.php @@ -0,0 +1,124 @@ +componentRegistrar = $componentRegistrar; + parent::__construct(); + } + + /** + * {@inheritdoc} + * @throws InvalidArgumentException + */ + protected function configure() + { + $this->setName(self::COMMAND_NAME) + ->setDescription('Generate patch and put it in specific folder.') + ->setDefinition([ + new InputArgument( + self::MODULE_NAME, + InputArgument::REQUIRED, + 'Module name' + ), + new InputArgument( + self::INPUT_KEY_PATCH_NAME, + InputArgument::REQUIRED, + 'Patch name' + ), + new InputOption( + self::INPUT_KEY_IS_REVERTABLE, + null, + InputOption::VALUE_OPTIONAL, + 'Check whether patch is revertable or not.', + false + ), + new InputOption( + self::INPUT_KEY_PATCH_TYPE, + null, + InputOption::VALUE_OPTIONAL, + 'Find out what type of patch should be generated.', + 'data' + ), + ]); + + parent::configure(); + } + + /** + * Patch template + * + * @return string + */ + private function getPatchTemplate() + { + return file_get_contents(__DIR__ . '/patch_template.php.dist'); + } + + /** + * {@inheritdoc} + * @throws \InvalidArgumentException + */ + protected function execute(InputInterface $input, OutputInterface $output) + { + $moduleName = $input->getArgument(self::MODULE_NAME); + $patchName = $input->getArgument(self::INPUT_KEY_PATCH_NAME); + $type = $input->getOption(self::INPUT_KEY_PATCH_TYPE); + $modulePath = $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, $moduleName); + $preparedModuleName = str_replace('_', '\\', $moduleName); + $preparedType = ucfirst($type); + $patchInterface = sprintf('%sPatchInterface', $preparedType); + $patchTemplateData = $this->getPatchTemplate(); + $patchTemplateData = str_replace('%moduleName%', $preparedModuleName, $patchTemplateData); + $patchTemplateData = str_replace('%patchType%', $preparedType, $patchTemplateData); + $patchTemplateData = str_replace('%patchInterface%', $patchInterface, $patchTemplateData); + $patchTemplateData = str_replace('%class%', $patchName, $patchTemplateData); + $patchDir = $patchToFile = $modulePath . '/Setup/Patch/' . $preparedType; + + if (!is_dir($patchDir)) { + mkdir($patchDir, 0777, true); + } + $patchToFile = $patchDir . '/' . $patchName . '.php'; + file_put_contents($patchToFile, $patchTemplateData); + return Cli::RETURN_SUCCESS; + } +} diff --git a/app/code/Magento/Developer/Console/Command/TablesWhitelistGenerateCommand.php b/app/code/Magento/Developer/Console/Command/TablesWhitelistGenerateCommand.php index 3313b7ef68a68..6715ecd681efe 100644 --- a/app/code/Magento/Developer/Console/Command/TablesWhitelistGenerateCommand.php +++ b/app/code/Magento/Developer/Console/Command/TablesWhitelistGenerateCommand.php @@ -8,8 +8,9 @@ use Magento\Framework\Component\ComponentRegistrar; use Magento\Framework\Config\FileResolverByModule; use Magento\Framework\Module\Dir; +use Magento\Framework\Setup\Declaration\Schema\Diff\Diff; use Magento\Framework\Setup\JsonPersistor; -use Magento\Setup\Model\Declaration\Schema\Declaration\ReaderComposite; +use Magento\Framework\Setup\Declaration\Schema\Declaration\ReaderComposite; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -103,7 +104,7 @@ private function persistModule($moduleName) . DIRECTORY_SEPARATOR . Dir::MODULE_ETC_DIR . DIRECTORY_SEPARATOR - . self::GENERATED_FILE_NAME; + . Diff::GENERATED_WHITELIST_FILE_NAME; //We need to load whitelist file and update it with new revision of code. if (file_exists($whiteListFileName)) { $content = json_decode(file_get_contents($whiteListFileName), true); diff --git a/app/code/Magento/Developer/Console/Command/patch_template.php.dist b/app/code/Magento/Developer/Console/Command/patch_template.php.dist new file mode 100644 index 0000000000000..c1b07246e644f --- /dev/null +++ b/app/code/Magento/Developer/Console/Command/patch_template.php.dist @@ -0,0 +1,59 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * Do Upgrade + * + * @return void + */ + public function apply() + { + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + + ]; + } +} diff --git a/app/code/Magento/Developer/Test/Unit/Console/Command/TablesWhitelistGenerateCommandTest.php b/app/code/Magento/Developer/Test/Unit/Console/Command/TablesWhitelistGenerateCommandTest.php index 49235e19cc07d..66fd7e3eec638 100644 --- a/app/code/Magento/Developer/Test/Unit/Console/Command/TablesWhitelistGenerateCommandTest.php +++ b/app/code/Magento/Developer/Test/Unit/Console/Command/TablesWhitelistGenerateCommandTest.php @@ -10,7 +10,7 @@ use Magento\Framework\Component\ComponentRegistrar; use Magento\Framework\Setup\JsonPersistor; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use Magento\Setup\Model\Declaration\Schema\Declaration\ReaderComposite; +use Magento\Framework\Setup\Declaration\Schema\Declaration\ReaderComposite; use Symfony\Component\Console\Tester\CommandTester; /** diff --git a/app/code/Magento/Developer/Test/Unit/Console/Command/_files/test.xml b/app/code/Magento/Developer/Test/Unit/Console/Command/_files/test.xml index ce31b046500f7..8112b9e8c46db 100644 --- a/app/code/Magento/Developer/Test/Unit/Console/Command/_files/test.xml +++ b/app/code/Magento/Developer/Test/Unit/Console/Command/_files/test.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Developer/etc/di.xml b/app/code/Magento/Developer/etc/di.xml index f68d01b8339d0..2254c94a8a913 100644 --- a/app/code/Magento/Developer/etc/di.xml +++ b/app/code/Magento/Developer/etc/di.xml @@ -105,6 +105,7 @@ Magento\Developer\Console\Command\TemplateHintsEnableCommand Magento\Developer\Console\Command\ProfilerDisableCommand Magento\Developer\Console\Command\ProfilerEnableCommand + Magento\Developer\Console\Command\GeneratePatchCommand diff --git a/app/code/Magento/Developer/etc/module.xml b/app/code/Magento/Developer/etc/module.xml index 96a8828b00c4b..e3cf8132e3e92 100644 --- a/app/code/Magento/Developer/etc/module.xml +++ b/app/code/Magento/Developer/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Dhl/Setup/InstallData.php b/app/code/Magento/Dhl/Setup/InstallData.php deleted file mode 100644 index 48f359aa63659..0000000000000 --- a/app/code/Magento/Dhl/Setup/InstallData.php +++ /dev/null @@ -1,68 +0,0 @@ -localeResolver = $localeResolver; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $days = (new DataBundle())->get( - $this->localeResolver->getLocale() - )['calendar']['gregorian']['dayNames']['format']['abbreviated']; - - $select = $setup->getConnection()->select()->from( - $setup->getTable('core_config_data'), - ['config_id', 'value'] - )->where( - 'path = ?', - 'carriers/dhl/shipment_days' - ); - - foreach ($setup->getConnection()->fetchAll($select) as $configRow) { - $row = [ - 'value' => implode( - ',', - array_intersect_key(iterator_to_array($days), array_flip(explode(',', $configRow['value']))) - ) - ]; - $setup->getConnection()->update( - $setup->getTable('core_config_data'), - $row, - ['config_id = ?' => $configRow['config_id']] - ); - } - } -} diff --git a/app/code/Magento/Dhl/Setup/Patch/Data/PrepareShipmentDays.php b/app/code/Magento/Dhl/Setup/Patch/Data/PrepareShipmentDays.php new file mode 100644 index 0000000000000..8b91b842c36e6 --- /dev/null +++ b/app/code/Magento/Dhl/Setup/Patch/Data/PrepareShipmentDays.php @@ -0,0 +1,99 @@ +moduleDataSetup = $moduleDataSetup; + $this->localeResolver = $localeResolver; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $days = (new DataBundle())->get( + $this->localeResolver->getLocale() + )['calendar']['gregorian']['dayNames']['format']['abbreviated']; + + $select = $this->moduleDataSetup->getConnection()->select()->from( + $this->moduleDataSetup->getTable('core_config_data'), + ['config_id', 'value'] + )->where( + 'path = ?', + 'carriers/dhl/shipment_days' + ); + foreach ($this->moduleDataSetup->getConnection()->fetchAll($select) as $configRow) { + $row = [ + 'value' => implode( + ',', + array_intersect_key(iterator_to_array($days), array_flip(explode(',', $configRow['value']))) + ) + ]; + $this->moduleDataSetup->getConnection()->update( + $this->moduleDataSetup->getTable('core_config_data'), + $row, + ['config_id = ?' => $configRow['config_id']] + ); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Dhl/etc/module.xml b/app/code/Magento/Dhl/etc/module.xml index 4723b14763a12..b1af1baf97fc2 100644 --- a/app/code/Magento/Dhl/etc/module.xml +++ b/app/code/Magento/Dhl/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/Directory/Model/ResourceModel/Country.php b/app/code/Magento/Directory/Model/ResourceModel/Country.php index c4c0a6b95dfb4..59fb2de85c8a3 100644 --- a/app/code/Magento/Directory/Model/ResourceModel/Country.php +++ b/app/code/Magento/Directory/Model/ResourceModel/Country.php @@ -44,7 +44,7 @@ public function loadByCode(\Magento\Directory\Model\Country $country, $code) default: throw new \Magento\Framework\Exception\LocalizedException( - __('Please correct the country code: %1.', $code) + __('Please correct the country code: %1.', htmlspecialchars($code)) ); } diff --git a/app/code/Magento/Directory/Setup/DataInstaller.php b/app/code/Magento/Directory/Setup/DataInstaller.php new file mode 100644 index 0000000000000..9fccc16e1d49b --- /dev/null +++ b/app/code/Magento/Directory/Setup/DataInstaller.php @@ -0,0 +1,76 @@ +data = $data; + $this->resourceConnection = $resourceConnection; + } + + /** + * Add country-region data. + * + * @param AdapterInterface $adapter + * @param array $data + */ + public function addCountryRegions(AdapterInterface $adapter, array $data) + { + /** + * Fill table directory/country_region + * Fill table directory/country_region_name for en_US locale + */ + foreach ($data as $row) { + $bind = ['country_id' => $row[0], 'code' => $row[1], 'default_name' => $row[2]]; + $adapter->insert($this->resourceConnection->getTableName('directory_country_region'), $bind); + $regionId = $adapter->lastInsertId($this->resourceConnection->getTableName('directory_country_region')); + $bind = ['locale' => 'en_US', 'region_id' => $regionId, 'name' => $row[2]]; + $adapter->insert($this->resourceConnection->getTableName('directory_country_region_name'), $bind); + } + /** + * Upgrade core_config_data general/region/state_required field. + */ + $countries = $this->data->getCountryCollection()->getCountriesWithRequiredStates(); + $adapter->update( + $this->resourceConnection->getTableName('core_config_data'), + [ + 'value' => implode(',', array_keys($countries)) + ], + [ + 'scope="default"', + 'scope_id=0', + 'path=?' => \Magento\Directory\Helper\Data::XML_PATH_STATES_REQUIRED + ] + ); + } +} diff --git a/app/code/Magento/Directory/Setup/InstallData.php b/app/code/Magento/Directory/Setup/InstallData.php deleted file mode 100644 index 33c3ae4558e16..0000000000000 --- a/app/code/Magento/Directory/Setup/InstallData.php +++ /dev/null @@ -1,857 +0,0 @@ -directoryData = $directoryData; - } - - /** - * {@inheritdoc} - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** - * Fill table directory/country - */ - $data = [ - ['AD', 'AD', 'AND'], - ['AE', 'AE', 'ARE'], - ['AF', 'AF', 'AFG'], - ['AG', 'AG', 'ATG'], - ['AI', 'AI', 'AIA'], - ['AL', 'AL', 'ALB'], - ['AM', 'AM', 'ARM'], - ['AN', 'AN', 'ANT'], - ['AO', 'AO', 'AGO'], - ['AQ', 'AQ', 'ATA'], - ['AR', 'AR', 'ARG'], - ['AS', 'AS', 'ASM'], - ['AT', 'AT', 'AUT'], - ['AU', 'AU', 'AUS'], - ['AW', 'AW', 'ABW'], - ['AX', 'AX', 'ALA'], - ['AZ', 'AZ', 'AZE'], - ['BA', 'BA', 'BIH'], - ['BB', 'BB', 'BRB'], - ['BD', 'BD', 'BGD'], - ['BE', 'BE', 'BEL'], - ['BF', 'BF', 'BFA'], - ['BG', 'BG', 'BGR'], - ['BH', 'BH', 'BHR'], - ['BI', 'BI', 'BDI'], - ['BJ', 'BJ', 'BEN'], - ['BL', 'BL', 'BLM'], - ['BM', 'BM', 'BMU'], - ['BN', 'BN', 'BRN'], - ['BO', 'BO', 'BOL'], - ['BR', 'BR', 'BRA'], - ['BS', 'BS', 'BHS'], - ['BT', 'BT', 'BTN'], - ['BV', 'BV', 'BVT'], - ['BW', 'BW', 'BWA'], - ['BY', 'BY', 'BLR'], - ['BZ', 'BZ', 'BLZ'], - ['CA', 'CA', 'CAN'], - ['CC', 'CC', 'CCK'], - ['CD', 'CD', 'COD'], - ['CF', 'CF', 'CAF'], - ['CG', 'CG', 'COG'], - ['CH', 'CH', 'CHE'], - ['CI', 'CI', 'CIV'], - ['CK', 'CK', 'COK'], - ['CL', 'CL', 'CHL'], - ['CM', 'CM', 'CMR'], - ['CN', 'CN', 'CHN'], - ['CO', 'CO', 'COL'], - ['CR', 'CR', 'CRI'], - ['CU', 'CU', 'CUB'], - ['CV', 'CV', 'CPV'], - ['CX', 'CX', 'CXR'], - ['CY', 'CY', 'CYP'], - ['CZ', 'CZ', 'CZE'], - ['DE', 'DE', 'DEU'], - ['DJ', 'DJ', 'DJI'], - ['DK', 'DK', 'DNK'], - ['DM', 'DM', 'DMA'], - ['DO', 'DO', 'DOM'], - ['DZ', 'DZ', 'DZA'], - ['EC', 'EC', 'ECU'], - ['EE', 'EE', 'EST'], - ['EG', 'EG', 'EGY'], - ['EH', 'EH', 'ESH'], - ['ER', 'ER', 'ERI'], - ['ES', 'ES', 'ESP'], - ['ET', 'ET', 'ETH'], - ['FI', 'FI', 'FIN'], - ['FJ', 'FJ', 'FJI'], - ['FK', 'FK', 'FLK'], - ['FM', 'FM', 'FSM'], - ['FO', 'FO', 'FRO'], - ['FR', 'FR', 'FRA'], - ['GA', 'GA', 'GAB'], - ['GB', 'GB', 'GBR'], - ['GD', 'GD', 'GRD'], - ['GE', 'GE', 'GEO'], - ['GF', 'GF', 'GUF'], - ['GG', 'GG', 'GGY'], - ['GH', 'GH', 'GHA'], - ['GI', 'GI', 'GIB'], - ['GL', 'GL', 'GRL'], - ['GM', 'GM', 'GMB'], - ['GN', 'GN', 'GIN'], - ['GP', 'GP', 'GLP'], - ['GQ', 'GQ', 'GNQ'], - ['GR', 'GR', 'GRC'], - ['GS', 'GS', 'SGS'], - ['GT', 'GT', 'GTM'], - ['GU', 'GU', 'GUM'], - ['GW', 'GW', 'GNB'], - ['GY', 'GY', 'GUY'], - ['HK', 'HK', 'HKG'], - ['HM', 'HM', 'HMD'], - ['HN', 'HN', 'HND'], - ['HR', 'HR', 'HRV'], - ['HT', 'HT', 'HTI'], - ['HU', 'HU', 'HUN'], - ['ID', 'ID', 'IDN'], - ['IE', 'IE', 'IRL'], - ['IL', 'IL', 'ISR'], - ['IM', 'IM', 'IMN'], - ['IN', 'IN', 'IND'], - ['IO', 'IO', 'IOT'], - ['IQ', 'IQ', 'IRQ'], - ['IR', 'IR', 'IRN'], - ['IS', 'IS', 'ISL'], - ['IT', 'IT', 'ITA'], - ['JE', 'JE', 'JEY'], - ['JM', 'JM', 'JAM'], - ['JO', 'JO', 'JOR'], - ['JP', 'JP', 'JPN'], - ['KE', 'KE', 'KEN'], - ['KG', 'KG', 'KGZ'], - ['KH', 'KH', 'KHM'], - ['KI', 'KI', 'KIR'], - ['KM', 'KM', 'COM'], - ['KN', 'KN', 'KNA'], - ['KP', 'KP', 'PRK'], - ['KR', 'KR', 'KOR'], - ['KW', 'KW', 'KWT'], - ['KY', 'KY', 'CYM'], - ['KZ', 'KZ', 'KAZ'], - ['LA', 'LA', 'LAO'], - ['LB', 'LB', 'LBN'], - ['LC', 'LC', 'LCA'], - ['LI', 'LI', 'LIE'], - ['LK', 'LK', 'LKA'], - ['LR', 'LR', 'LBR'], - ['LS', 'LS', 'LSO'], - ['LT', 'LT', 'LTU'], - ['LU', 'LU', 'LUX'], - ['LV', 'LV', 'LVA'], - ['LY', 'LY', 'LBY'], - ['MA', 'MA', 'MAR'], - ['MC', 'MC', 'MCO'], - ['MD', 'MD', 'MDA'], - ['ME', 'ME', 'MNE'], - ['MF', 'MF', 'MAF'], - ['MG', 'MG', 'MDG'], - ['MH', 'MH', 'MHL'], - ['MK', 'MK', 'MKD'], - ['ML', 'ML', 'MLI'], - ['MM', 'MM', 'MMR'], - ['MN', 'MN', 'MNG'], - ['MO', 'MO', 'MAC'], - ['MP', 'MP', 'MNP'], - ['MQ', 'MQ', 'MTQ'], - ['MR', 'MR', 'MRT'], - ['MS', 'MS', 'MSR'], - ['MT', 'MT', 'MLT'], - ['MU', 'MU', 'MUS'], - ['MV', 'MV', 'MDV'], - ['MW', 'MW', 'MWI'], - ['MX', 'MX', 'MEX'], - ['MY', 'MY', 'MYS'], - ['MZ', 'MZ', 'MOZ'], - ['NA', 'NA', 'NAM'], - ['NC', 'NC', 'NCL'], - ['NE', 'NE', 'NER'], - ['NF', 'NF', 'NFK'], - ['NG', 'NG', 'NGA'], - ['NI', 'NI', 'NIC'], - ['NL', 'NL', 'NLD'], - ['NO', 'NO', 'NOR'], - ['NP', 'NP', 'NPL'], - ['NR', 'NR', 'NRU'], - ['NU', 'NU', 'NIU'], - ['NZ', 'NZ', 'NZL'], - ['OM', 'OM', 'OMN'], - ['PA', 'PA', 'PAN'], - ['PE', 'PE', 'PER'], - ['PF', 'PF', 'PYF'], - ['PG', 'PG', 'PNG'], - ['PH', 'PH', 'PHL'], - ['PK', 'PK', 'PAK'], - ['PL', 'PL', 'POL'], - ['PM', 'PM', 'SPM'], - ['PN', 'PN', 'PCN'], - ['PS', 'PS', 'PSE'], - ['PT', 'PT', 'PRT'], - ['PW', 'PW', 'PLW'], - ['PY', 'PY', 'PRY'], - ['QA', 'QA', 'QAT'], - ['RE', 'RE', 'REU'], - ['RO', 'RO', 'ROU'], - ['RS', 'RS', 'SRB'], - ['RU', 'RU', 'RUS'], - ['RW', 'RW', 'RWA'], - ['SA', 'SA', 'SAU'], - ['SB', 'SB', 'SLB'], - ['SC', 'SC', 'SYC'], - ['SD', 'SD', 'SDN'], - ['SE', 'SE', 'SWE'], - ['SG', 'SG', 'SGP'], - ['SH', 'SH', 'SHN'], - ['SI', 'SI', 'SVN'], - ['SJ', 'SJ', 'SJM'], - ['SK', 'SK', 'SVK'], - ['SL', 'SL', 'SLE'], - ['SM', 'SM', 'SMR'], - ['SN', 'SN', 'SEN'], - ['SO', 'SO', 'SOM'], - ['SR', 'SR', 'SUR'], - ['ST', 'ST', 'STP'], - ['SV', 'SV', 'SLV'], - ['SY', 'SY', 'SYR'], - ['SZ', 'SZ', 'SWZ'], - ['TC', 'TC', 'TCA'], - ['TD', 'TD', 'TCD'], - ['TF', 'TF', 'ATF'], - ['TG', 'TG', 'TGO'], - ['TH', 'TH', 'THA'], - ['TJ', 'TJ', 'TJK'], - ['TK', 'TK', 'TKL'], - ['TL', 'TL', 'TLS'], - ['TM', 'TM', 'TKM'], - ['TN', 'TN', 'TUN'], - ['TO', 'TO', 'TON'], - ['TR', 'TR', 'TUR'], - ['TT', 'TT', 'TTO'], - ['TV', 'TV', 'TUV'], - ['TW', 'TW', 'TWN'], - ['TZ', 'TZ', 'TZA'], - ['UA', 'UA', 'UKR'], - ['UG', 'UG', 'UGA'], - ['UM', 'UM', 'UMI'], - ['US', 'US', 'USA'], - ['UY', 'UY', 'URY'], - ['UZ', 'UZ', 'UZB'], - ['VA', 'VA', 'VAT'], - ['VC', 'VC', 'VCT'], - ['VE', 'VE', 'VEN'], - ['VG', 'VG', 'VGB'], - ['VI', 'VI', 'VIR'], - ['VN', 'VN', 'VNM'], - ['VU', 'VU', 'VUT'], - ['WF', 'WF', 'WLF'], - ['WS', 'WS', 'WSM'], - ['YE', 'YE', 'YEM'], - ['YT', 'YT', 'MYT'], - ['ZA', 'ZA', 'ZAF'], - ['ZM', 'ZM', 'ZMB'], - ['ZW', 'ZW', 'ZWE'], - ]; - - $columns = ['country_id', 'iso2_code', 'iso3_code']; - $setup->getConnection()->insertArray($setup->getTable('directory_country'), $columns, $data); - - /** - * Fill table directory/country_region - * Fill table directory/country_region_name for en_US locale - */ - $data = [ - ['US', 'AL', 'Alabama'], - ['US', 'AK', 'Alaska'], - ['US', 'AS', 'American Samoa'], - ['US', 'AZ', 'Arizona'], - ['US', 'AR', 'Arkansas'], - ['US', 'AE', 'Armed Forces Africa'], - ['US', 'AA', 'Armed Forces Americas'], - ['US', 'AE', 'Armed Forces Canada'], - ['US', 'AE', 'Armed Forces Europe'], - ['US', 'AE', 'Armed Forces Middle East'], - ['US', 'AP', 'Armed Forces Pacific'], - ['US', 'CA', 'California'], - ['US', 'CO', 'Colorado'], - ['US', 'CT', 'Connecticut'], - ['US', 'DE', 'Delaware'], - ['US', 'DC', 'District of Columbia'], - ['US', 'FM', 'Federated States Of Micronesia'], - ['US', 'FL', 'Florida'], - ['US', 'GA', 'Georgia'], - ['US', 'GU', 'Guam'], - ['US', 'HI', 'Hawaii'], - ['US', 'ID', 'Idaho'], - ['US', 'IL', 'Illinois'], - ['US', 'IN', 'Indiana'], - ['US', 'IA', 'Iowa'], - ['US', 'KS', 'Kansas'], - ['US', 'KY', 'Kentucky'], - ['US', 'LA', 'Louisiana'], - ['US', 'ME', 'Maine'], - ['US', 'MH', 'Marshall Islands'], - ['US', 'MD', 'Maryland'], - ['US', 'MA', 'Massachusetts'], - ['US', 'MI', 'Michigan'], - ['US', 'MN', 'Minnesota'], - ['US', 'MS', 'Mississippi'], - ['US', 'MO', 'Missouri'], - ['US', 'MT', 'Montana'], - ['US', 'NE', 'Nebraska'], - ['US', 'NV', 'Nevada'], - ['US', 'NH', 'New Hampshire'], - ['US', 'NJ', 'New Jersey'], - ['US', 'NM', 'New Mexico'], - ['US', 'NY', 'New York'], - ['US', 'NC', 'North Carolina'], - ['US', 'ND', 'North Dakota'], - ['US', 'MP', 'Northern Mariana Islands'], - ['US', 'OH', 'Ohio'], - ['US', 'OK', 'Oklahoma'], - ['US', 'OR', 'Oregon'], - ['US', 'PW', 'Palau'], - ['US', 'PA', 'Pennsylvania'], - ['US', 'PR', 'Puerto Rico'], - ['US', 'RI', 'Rhode Island'], - ['US', 'SC', 'South Carolina'], - ['US', 'SD', 'South Dakota'], - ['US', 'TN', 'Tennessee'], - ['US', 'TX', 'Texas'], - ['US', 'UT', 'Utah'], - ['US', 'VT', 'Vermont'], - ['US', 'VI', 'Virgin Islands'], - ['US', 'VA', 'Virginia'], - ['US', 'WA', 'Washington'], - ['US', 'WV', 'West Virginia'], - ['US', 'WI', 'Wisconsin'], - ['US', 'WY', 'Wyoming'], - ['CA', 'AB', 'Alberta'], - ['CA', 'BC', 'British Columbia'], - ['CA', 'MB', 'Manitoba'], - ['CA', 'NL', 'Newfoundland and Labrador'], - ['CA', 'NB', 'New Brunswick'], - ['CA', 'NS', 'Nova Scotia'], - ['CA', 'NT', 'Northwest Territories'], - ['CA', 'NU', 'Nunavut'], - ['CA', 'ON', 'Ontario'], - ['CA', 'PE', 'Prince Edward Island'], - ['CA', 'QC', 'Quebec'], - ['CA', 'SK', 'Saskatchewan'], - ['CA', 'YT', 'Yukon Territory'], - ['DE', 'NDS', 'Niedersachsen'], - ['DE', 'BAW', 'Baden-Württemberg'], - ['DE', 'BAY', 'Bayern'], - ['DE', 'BER', 'Berlin'], - ['DE', 'BRG', 'Brandenburg'], - ['DE', 'BRE', 'Bremen'], - ['DE', 'HAM', 'Hamburg'], - ['DE', 'HES', 'Hessen'], - ['DE', 'MEC', 'Mecklenburg-Vorpommern'], - ['DE', 'NRW', 'Nordrhein-Westfalen'], - ['DE', 'RHE', 'Rheinland-Pfalz'], - ['DE', 'SAR', 'Saarland'], - ['DE', 'SAS', 'Sachsen'], - ['DE', 'SAC', 'Sachsen-Anhalt'], - ['DE', 'SCN', 'Schleswig-Holstein'], - ['DE', 'THE', 'Thüringen'], - ['AT', 'WI', 'Wien'], - ['AT', 'NO', 'Niederösterreich'], - ['AT', 'OO', 'Oberösterreich'], - ['AT', 'SB', 'Salzburg'], - ['AT', 'KN', 'Kärnten'], - ['AT', 'ST', 'Steiermark'], - ['AT', 'TI', 'Tirol'], - ['AT', 'BL', 'Burgenland'], - ['AT', 'VB', 'Vorarlberg'], - ['CH', 'AG', 'Aargau'], - ['CH', 'AI', 'Appenzell Innerrhoden'], - ['CH', 'AR', 'Appenzell Ausserrhoden'], - ['CH', 'BE', 'Bern'], - ['CH', 'BL', 'Basel-Landschaft'], - ['CH', 'BS', 'Basel-Stadt'], - ['CH', 'FR', 'Freiburg'], - ['CH', 'GE', 'Genf'], - ['CH', 'GL', 'Glarus'], - ['CH', 'GR', 'Graubünden'], - ['CH', 'JU', 'Jura'], - ['CH', 'LU', 'Luzern'], - ['CH', 'NE', 'Neuenburg'], - ['CH', 'NW', 'Nidwalden'], - ['CH', 'OW', 'Obwalden'], - ['CH', 'SG', 'St. Gallen'], - ['CH', 'SH', 'Schaffhausen'], - ['CH', 'SO', 'Solothurn'], - ['CH', 'SZ', 'Schwyz'], - ['CH', 'TG', 'Thurgau'], - ['CH', 'TI', 'Tessin'], - ['CH', 'UR', 'Uri'], - ['CH', 'VD', 'Waadt'], - ['CH', 'VS', 'Wallis'], - ['CH', 'ZG', 'Zug'], - ['CH', 'ZH', 'Zürich'], - ['ES', 'A Coruсa', 'A Coruña'], - ['ES', 'Alava', 'Alava'], - ['ES', 'Albacete', 'Albacete'], - ['ES', 'Alicante', 'Alicante'], - ['ES', 'Almeria', 'Almeria'], - ['ES', 'Asturias', 'Asturias'], - ['ES', 'Avila', 'Avila'], - ['ES', 'Badajoz', 'Badajoz'], - ['ES', 'Baleares', 'Baleares'], - ['ES', 'Barcelona', 'Barcelona'], - ['ES', 'Burgos', 'Burgos'], - ['ES', 'Caceres', 'Caceres'], - ['ES', 'Cadiz', 'Cadiz'], - ['ES', 'Cantabria', 'Cantabria'], - ['ES', 'Castellon', 'Castellon'], - ['ES', 'Ceuta', 'Ceuta'], - ['ES', 'Ciudad Real', 'Ciudad Real'], - ['ES', 'Cordoba', 'Cordoba'], - ['ES', 'Cuenca', 'Cuenca'], - ['ES', 'Girona', 'Girona'], - ['ES', 'Granada', 'Granada'], - ['ES', 'Guadalajara', 'Guadalajara'], - ['ES', 'Guipuzcoa', 'Guipuzcoa'], - ['ES', 'Huelva', 'Huelva'], - ['ES', 'Huesca', 'Huesca'], - ['ES', 'Jaen', 'Jaen'], - ['ES', 'La Rioja', 'La Rioja'], - ['ES', 'Las Palmas', 'Las Palmas'], - ['ES', 'Leon', 'Leon'], - ['ES', 'Lleida', 'Lleida'], - ['ES', 'Lugo', 'Lugo'], - ['ES', 'Madrid', 'Madrid'], - ['ES', 'Malaga', 'Malaga'], - ['ES', 'Melilla', 'Melilla'], - ['ES', 'Murcia', 'Murcia'], - ['ES', 'Navarra', 'Navarra'], - ['ES', 'Ourense', 'Ourense'], - ['ES', 'Palencia', 'Palencia'], - ['ES', 'Pontevedra', 'Pontevedra'], - ['ES', 'Salamanca', 'Salamanca'], - ['ES', 'Santa Cruz de Tenerife', 'Santa Cruz de Tenerife'], - ['ES', 'Segovia', 'Segovia'], - ['ES', 'Sevilla', 'Sevilla'], - ['ES', 'Soria', 'Soria'], - ['ES', 'Tarragona', 'Tarragona'], - ['ES', 'Teruel', 'Teruel'], - ['ES', 'Toledo', 'Toledo'], - ['ES', 'Valencia', 'Valencia'], - ['ES', 'Valladolid', 'Valladolid'], - ['ES', 'Vizcaya', 'Vizcaya'], - ['ES', 'Zamora', 'Zamora'], - ['ES', 'Zaragoza', 'Zaragoza'], - ['FR', 1, 'Ain'], - ['FR', 2, 'Aisne'], - ['FR', 3, 'Allier'], - ['FR', 4, 'Alpes-de-Haute-Provence'], - ['FR', 5, 'Hautes-Alpes'], - ['FR', 6, 'Alpes-Maritimes'], - ['FR', 7, 'Ardèche'], - ['FR', 8, 'Ardennes'], - ['FR', 9, 'Ariège'], - ['FR', 10, 'Aube'], - ['FR', 11, 'Aude'], - ['FR', 12, 'Aveyron'], - ['FR', 13, 'Bouches-du-Rhône'], - ['FR', 14, 'Calvados'], - ['FR', 15, 'Cantal'], - ['FR', 16, 'Charente'], - ['FR', 17, 'Charente-Maritime'], - ['FR', 18, 'Cher'], - ['FR', 19, 'Corrèze'], - ['FR', '2A', 'Corse-du-Sud'], - ['FR', '2B', 'Haute-Corse'], - ['FR', 21, 'Côte-d\'Or'], - ['FR', 22, 'Côtes-d\'Armor'], - ['FR', 23, 'Creuse'], - ['FR', 24, 'Dordogne'], - ['FR', 25, 'Doubs'], - ['FR', 26, 'Drôme'], - ['FR', 27, 'Eure'], - ['FR', 28, 'Eure-et-Loir'], - ['FR', 29, 'Finistère'], - ['FR', 30, 'Gard'], - ['FR', 31, 'Haute-Garonne'], - ['FR', 32, 'Gers'], - ['FR', 33, 'Gironde'], - ['FR', 34, 'Hérault'], - ['FR', 35, 'Ille-et-Vilaine'], - ['FR', 36, 'Indre'], - ['FR', 37, 'Indre-et-Loire'], - ['FR', 38, 'Isère'], - ['FR', 39, 'Jura'], - ['FR', 40, 'Landes'], - ['FR', 41, 'Loir-et-Cher'], - ['FR', 42, 'Loire'], - ['FR', 43, 'Haute-Loire'], - ['FR', 44, 'Loire-Atlantique'], - ['FR', 45, 'Loiret'], - ['FR', 46, 'Lot'], - ['FR', 47, 'Lot-et-Garonne'], - ['FR', 48, 'Lozère'], - ['FR', 49, 'Maine-et-Loire'], - ['FR', 50, 'Manche'], - ['FR', 51, 'Marne'], - ['FR', 52, 'Haute-Marne'], - ['FR', 53, 'Mayenne'], - ['FR', 54, 'Meurthe-et-Moselle'], - ['FR', 55, 'Meuse'], - ['FR', 56, 'Morbihan'], - ['FR', 57, 'Moselle'], - ['FR', 58, 'Nièvre'], - ['FR', 59, 'Nord'], - ['FR', 60, 'Oise'], - ['FR', 61, 'Orne'], - ['FR', 62, 'Pas-de-Calais'], - ['FR', 63, 'Puy-de-Dôme'], - ['FR', 64, 'Pyrénées-Atlantiques'], - ['FR', 65, 'Hautes-Pyrénées'], - ['FR', 66, 'Pyrénées-Orientales'], - ['FR', 67, 'Bas-Rhin'], - ['FR', 68, 'Haut-Rhin'], - ['FR', 69, 'Rhône'], - ['FR', 70, 'Haute-Saône'], - ['FR', 71, 'Saône-et-Loire'], - ['FR', 72, 'Sarthe'], - ['FR', 73, 'Savoie'], - ['FR', 74, 'Haute-Savoie'], - ['FR', 75, 'Paris'], - ['FR', 76, 'Seine-Maritime'], - ['FR', 77, 'Seine-et-Marne'], - ['FR', 78, 'Yvelines'], - ['FR', 79, 'Deux-Sèvres'], - ['FR', 80, 'Somme'], - ['FR', 81, 'Tarn'], - ['FR', 82, 'Tarn-et-Garonne'], - ['FR', 83, 'Var'], - ['FR', 84, 'Vaucluse'], - ['FR', 85, 'Vendée'], - ['FR', 86, 'Vienne'], - ['FR', 87, 'Haute-Vienne'], - ['FR', 88, 'Vosges'], - ['FR', 89, 'Yonne'], - ['FR', 90, 'Territoire-de-Belfort'], - ['FR', 91, 'Essonne'], - ['FR', 92, 'Hauts-de-Seine'], - ['FR', 93, 'Seine-Saint-Denis'], - ['FR', 94, 'Val-de-Marne'], - ['FR', 95, 'Val-d\'Oise'], - ['RO', 'AB', 'Alba'], - ['RO', 'AR', 'Arad'], - ['RO', 'AG', 'Argeş'], - ['RO', 'BC', 'Bacău'], - ['RO', 'BH', 'Bihor'], - ['RO', 'BN', 'Bistriţa-Năsăud'], - ['RO', 'BT', 'Botoşani'], - ['RO', 'BV', 'Braşov'], - ['RO', 'BR', 'Brăila'], - ['RO', 'B', 'Bucureşti'], - ['RO', 'BZ', 'Buzău'], - ['RO', 'CS', 'Caraş-Severin'], - ['RO', 'CL', 'Călăraşi'], - ['RO', 'CJ', 'Cluj'], - ['RO', 'CT', 'Constanţa'], - ['RO', 'CV', 'Covasna'], - ['RO', 'DB', 'Dâmboviţa'], - ['RO', 'DJ', 'Dolj'], - ['RO', 'GL', 'Galaţi'], - ['RO', 'GR', 'Giurgiu'], - ['RO', 'GJ', 'Gorj'], - ['RO', 'HR', 'Harghita'], - ['RO', 'HD', 'Hunedoara'], - ['RO', 'IL', 'Ialomiţa'], - ['RO', 'IS', 'Iaşi'], - ['RO', 'IF', 'Ilfov'], - ['RO', 'MM', 'Maramureş'], - ['RO', 'MH', 'Mehedinţi'], - ['RO', 'MS', 'Mureş'], - ['RO', 'NT', 'Neamţ'], - ['RO', 'OT', 'Olt'], - ['RO', 'PH', 'Prahova'], - ['RO', 'SM', 'Satu-Mare'], - ['RO', 'SJ', 'Sălaj'], - ['RO', 'SB', 'Sibiu'], - ['RO', 'SV', 'Suceava'], - ['RO', 'TR', 'Teleorman'], - ['RO', 'TM', 'Timiş'], - ['RO', 'TL', 'Tulcea'], - ['RO', 'VS', 'Vaslui'], - ['RO', 'VL', 'Vâlcea'], - ['RO', 'VN', 'Vrancea'], - ['FI', 'Lappi', 'Lappi'], - ['FI', 'Pohjois-Pohjanmaa', 'Pohjois-Pohjanmaa'], - ['FI', 'Kainuu', 'Kainuu'], - ['FI', 'Pohjois-Karjala', 'Pohjois-Karjala'], - ['FI', 'Pohjois-Savo', 'Pohjois-Savo'], - ['FI', 'Etelä-Savo', 'Etelä-Savo'], - ['FI', 'Etelä-Pohjanmaa', 'Etelä-Pohjanmaa'], - ['FI', 'Pohjanmaa', 'Pohjanmaa'], - ['FI', 'Pirkanmaa', 'Pirkanmaa'], - ['FI', 'Satakunta', 'Satakunta'], - ['FI', 'Keski-Pohjanmaa', 'Keski-Pohjanmaa'], - ['FI', 'Keski-Suomi', 'Keski-Suomi'], - ['FI', 'Varsinais-Suomi', 'Varsinais-Suomi'], - ['FI', 'Etelä-Karjala', 'Etelä-Karjala'], - ['FI', 'Päijät-Häme', 'Päijät-Häme'], - ['FI', 'Kanta-Häme', 'Kanta-Häme'], - ['FI', 'Uusimaa', 'Uusimaa'], - ['FI', 'Itä-Uusimaa', 'Itä-Uusimaa'], - ['FI', 'Kymenlaakso', 'Kymenlaakso'], - ['FI', 'Ahvenanmaa', 'Ahvenanmaa'], - ['EE', 'EE-37', 'Harjumaa'], - ['EE', 'EE-39', 'Hiiumaa'], - ['EE', 'EE-44', 'Ida-Virumaa'], - ['EE', 'EE-49', 'Jõgevamaa'], - ['EE', 'EE-51', 'Järvamaa'], - ['EE', 'EE-57', 'Läänemaa'], - ['EE', 'EE-59', 'Lääne-Virumaa'], - ['EE', 'EE-65', 'Põlvamaa'], - ['EE', 'EE-67', 'Pärnumaa'], - ['EE', 'EE-70', 'Raplamaa'], - ['EE', 'EE-74', 'Saaremaa'], - ['EE', 'EE-78', 'Tartumaa'], - ['EE', 'EE-82', 'Valgamaa'], - ['EE', 'EE-84', 'Viljandimaa'], - ['EE', 'EE-86', 'Võrumaa'], - ['LV', 'LV-DGV', 'Daugavpils'], - ['LV', 'LV-JEL', 'Jelgava'], - ['LV', 'Jēkabpils', 'Jēkabpils'], - ['LV', 'LV-JUR', 'Jūrmala'], - ['LV', 'LV-LPX', 'Liepāja'], - ['LV', 'LV-LE', 'Liepājas novads'], - ['LV', 'LV-REZ', 'Rēzekne'], - ['LV', 'LV-RIX', 'Rīga'], - ['LV', 'LV-RI', 'Rīgas novads'], - ['LV', 'Valmiera', 'Valmiera'], - ['LV', 'LV-VEN', 'Ventspils'], - ['LV', 'Aglonas novads', 'Aglonas novads'], - ['LV', 'LV-AI', 'Aizkraukles novads'], - ['LV', 'Aizputes novads', 'Aizputes novads'], - ['LV', 'Aknīstes novads', 'Aknīstes novads'], - ['LV', 'Alojas novads', 'Alojas novads'], - ['LV', 'Alsungas novads', 'Alsungas novads'], - ['LV', 'LV-AL', 'Alūksnes novads'], - ['LV', 'Amatas novads', 'Amatas novads'], - ['LV', 'Apes novads', 'Apes novads'], - ['LV', 'Auces novads', 'Auces novads'], - ['LV', 'Babītes novads', 'Babītes novads'], - ['LV', 'Baldones novads', 'Baldones novads'], - ['LV', 'Baltinavas novads', 'Baltinavas novads'], - ['LV', 'LV-BL', 'Balvu novads'], - ['LV', 'LV-BU', 'Bauskas novads'], - ['LV', 'Beverīnas novads', 'Beverīnas novads'], - ['LV', 'Brocēnu novads', 'Brocēnu novads'], - ['LV', 'Burtnieku novads', 'Burtnieku novads'], - ['LV', 'Carnikavas novads', 'Carnikavas novads'], - ['LV', 'Cesvaines novads', 'Cesvaines novads'], - ['LV', 'Ciblas novads', 'Ciblas novads'], - ['LV', 'LV-CE', 'Cēsu novads'], - ['LV', 'Dagdas novads', 'Dagdas novads'], - ['LV', 'LV-DA', 'Daugavpils novads'], - ['LV', 'LV-DO', 'Dobeles novads'], - ['LV', 'Dundagas novads', 'Dundagas novads'], - ['LV', 'Durbes novads', 'Durbes novads'], - ['LV', 'Engures novads', 'Engures novads'], - ['LV', 'Garkalnes novads', 'Garkalnes novads'], - ['LV', 'Grobiņas novads', 'Grobiņas novads'], - ['LV', 'LV-GU', 'Gulbenes novads'], - ['LV', 'Iecavas novads', 'Iecavas novads'], - ['LV', 'Ikšķiles novads', 'Ikšķiles novads'], - ['LV', 'Ilūkstes novads', 'Ilūkstes novads'], - ['LV', 'Inčukalna novads', 'Inčukalna novads'], - ['LV', 'Jaunjelgavas novads', 'Jaunjelgavas novads'], - ['LV', 'Jaunpiebalgas novads', 'Jaunpiebalgas novads'], - ['LV', 'Jaunpils novads', 'Jaunpils novads'], - ['LV', 'LV-JL', 'Jelgavas novads'], - ['LV', 'LV-JK', 'Jēkabpils novads'], - ['LV', 'Kandavas novads', 'Kandavas novads'], - ['LV', 'Kokneses novads', 'Kokneses novads'], - ['LV', 'Krimuldas novads', 'Krimuldas novads'], - ['LV', 'Krustpils novads', 'Krustpils novads'], - ['LV', 'LV-KR', 'Krāslavas novads'], - ['LV', 'LV-KU', 'Kuldīgas novads'], - ['LV', 'Kārsavas novads', 'Kārsavas novads'], - ['LV', 'Lielvārdes novads', 'Lielvārdes novads'], - ['LV', 'LV-LM', 'Limbažu novads'], - ['LV', 'Lubānas novads', 'Lubānas novads'], - ['LV', 'LV-LU', 'Ludzas novads'], - ['LV', 'Līgatnes novads', 'Līgatnes novads'], - ['LV', 'Līvānu novads', 'Līvānu novads'], - ['LV', 'LV-MA', 'Madonas novads'], - ['LV', 'Mazsalacas novads', 'Mazsalacas novads'], - ['LV', 'Mālpils novads', 'Mālpils novads'], - ['LV', 'Mārupes novads', 'Mārupes novads'], - ['LV', 'Naukšēnu novads', 'Naukšēnu novads'], - ['LV', 'Neretas novads', 'Neretas novads'], - ['LV', 'Nīcas novads', 'Nīcas novads'], - ['LV', 'LV-OG', 'Ogres novads'], - ['LV', 'Olaines novads', 'Olaines novads'], - ['LV', 'Ozolnieku novads', 'Ozolnieku novads'], - ['LV', 'LV-PR', 'Preiļu novads'], - ['LV', 'Priekules novads', 'Priekules novads'], - ['LV', 'Priekuļu novads', 'Priekuļu novads'], - ['LV', 'Pārgaujas novads', 'Pārgaujas novads'], - ['LV', 'Pāvilostas novads', 'Pāvilostas novads'], - ['LV', 'Pļaviņu novads', 'Pļaviņu novads'], - ['LV', 'Raunas novads', 'Raunas novads'], - ['LV', 'Riebiņu novads', 'Riebiņu novads'], - ['LV', 'Rojas novads', 'Rojas novads'], - ['LV', 'Ropažu novads', 'Ropažu novads'], - ['LV', 'Rucavas novads', 'Rucavas novads'], - ['LV', 'Rugāju novads', 'Rugāju novads'], - ['LV', 'Rundāles novads', 'Rundāles novads'], - ['LV', 'LV-RE', 'Rēzeknes novads'], - ['LV', 'Rūjienas novads', 'Rūjienas novads'], - ['LV', 'Salacgrīvas novads', 'Salacgrīvas novads'], - ['LV', 'Salas novads', 'Salas novads'], - ['LV', 'Salaspils novads', 'Salaspils novads'], - ['LV', 'LV-SA', 'Saldus novads'], - ['LV', 'Saulkrastu novads', 'Saulkrastu novads'], - ['LV', 'Siguldas novads', 'Siguldas novads'], - ['LV', 'Skrundas novads', 'Skrundas novads'], - ['LV', 'Skrīveru novads', 'Skrīveru novads'], - ['LV', 'Smiltenes novads', 'Smiltenes novads'], - ['LV', 'Stopiņu novads', 'Stopiņu novads'], - ['LV', 'Strenču novads', 'Strenču novads'], - ['LV', 'Sējas novads', 'Sējas novads'], - ['LV', 'LV-TA', 'Talsu novads'], - ['LV', 'LV-TU', 'Tukuma novads'], - ['LV', 'Tērvetes novads', 'Tērvetes novads'], - ['LV', 'Vaiņodes novads', 'Vaiņodes novads'], - ['LV', 'LV-VK', 'Valkas novads'], - ['LV', 'LV-VM', 'Valmieras novads'], - ['LV', 'Varakļānu novads', 'Varakļānu novads'], - ['LV', 'Vecpiebalgas novads', 'Vecpiebalgas novads'], - ['LV', 'Vecumnieku novads', 'Vecumnieku novads'], - ['LV', 'LV-VE', 'Ventspils novads'], - ['LV', 'Viesītes novads', 'Viesītes novads'], - ['LV', 'Viļakas novads', 'Viļakas novads'], - ['LV', 'Viļānu novads', 'Viļānu novads'], - ['LV', 'Vārkavas novads', 'Vārkavas novads'], - ['LV', 'Zilupes novads', 'Zilupes novads'], - ['LV', 'Ādažu novads', 'Ādažu novads'], - ['LV', 'Ērgļu novads', 'Ērgļu novads'], - ['LV', 'Ķeguma novads', 'Ķeguma novads'], - ['LV', 'Ķekavas novads', 'Ķekavas novads'], - ['LT', 'LT-AL', 'Alytaus Apskritis'], - ['LT', 'LT-KU', 'Kauno Apskritis'], - ['LT', 'LT-KL', 'Klaipėdos Apskritis'], - ['LT', 'LT-MR', 'Marijampolės Apskritis'], - ['LT', 'LT-PN', 'Panevėžio Apskritis'], - ['LT', 'LT-SA', 'Šiaulių Apskritis'], - ['LT', 'LT-TA', 'Tauragės Apskritis'], - ['LT', 'LT-TE', 'Telšių Apskritis'], - ['LT', 'LT-UT', 'Utenos Apskritis'], - ['LT', 'LT-VL', 'Vilniaus Apskritis'], - ['BR', 'AC', 'Acre'], - ['BR', 'AL', 'Alagoas'], - ['BR', 'AP', 'Amapá'], - ['BR', 'AM', 'Amazonas'], - ['BR', 'BA', 'Bahia'], - ['BR', 'CE', 'Ceará'], - ['BR', 'ES', 'Espírito Santo'], - ['BR', 'GO', 'Goiás'], - ['BR', 'MA', 'Maranhão'], - ['BR', 'MT', 'Mato Grosso'], - ['BR', 'MS', 'Mato Grosso do Sul'], - ['BR', 'MG', 'Minas Gerais'], - ['BR', 'PA', 'Pará'], - ['BR', 'PB', 'Paraíba'], - ['BR', 'PR', 'Paraná'], - ['BR', 'PE', 'Pernambuco'], - ['BR', 'PI', 'Piauí'], - ['BR', 'RJ', 'Rio de Janeiro'], - ['BR', 'RN', 'Rio Grande do Norte'], - ['BR', 'RS', 'Rio Grande do Sul'], - ['BR', 'RO', 'Rondônia'], - ['BR', 'RR', 'Roraima'], - ['BR', 'SC', 'Santa Catarina'], - ['BR', 'SP', 'São Paulo'], - ['BR', 'SE', 'Sergipe'], - ['BR', 'TO', 'Tocantins'], - ['BR', 'DF', 'Distrito Federal'], - ]; - - foreach ($data as $row) { - $bind = ['country_id' => $row[0], 'code' => $row[1], 'default_name' => $row[2]]; - $setup->getConnection()->insert($setup->getTable('directory_country_region'), $bind); - $regionId = $setup->getConnection()->lastInsertId($setup->getTable('directory_country_region')); - - $bind = ['locale' => 'en_US', 'region_id' => $regionId, 'name' => $row[2]]; - $setup->getConnection()->insert($setup->getTable('directory_country_region_name'), $bind); - } - - /** - * Fill table directory/currency_rate - */ - $data = [ - ['EUR', 'EUR', 1], - ['EUR', 'USD', 1.415000000000], - ['USD', 'EUR', 0.706700000000], - ['USD', 'USD', 1], - ]; - - $columns = ['currency_from', 'currency_to', 'rate']; - $setup->getConnection()->insertArray($setup->getTable('directory_currency_rate'), $columns, $data); - - $setup->getConnection()->insert( - $setup->getTable('core_config_data'), - [ - 'scope' => 'default', - 'scope_id' => 0, - 'path' => Data::XML_PATH_DISPLAY_ALL_STATES, - 'value' => 1 - ] - ); - - $countries = $this->directoryData->getCountryCollection()->getCountriesWithRequiredStates(); - $setup->getConnection()->insert( - $setup->getTable('core_config_data'), - [ - 'scope' => 'default', - 'scope_id' => 0, - 'path' => Data::XML_PATH_STATES_REQUIRED, - 'value' => implode(',', array_keys($countries)) - ] - ); - } -} diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForCroatia.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForCroatia.php new file mode 100644 index 0000000000000..eb9d4f4018b1a --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForCroatia.php @@ -0,0 +1,115 @@ +moduleDataSetup = $moduleDataSetup; + $this->dataInstallerFactory = $dataInstallerFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var DataInstaller $dataInstaller */ + $dataInstaller = $this->dataInstallerFactory->create(); + $dataInstaller->addCountryRegions( + $this->moduleDataSetup->getConnection(), + $this->getDataForCroatia() + ); + } + + /** + * Croatian states data. + * + * @return array + */ + private function getDataForCroatia() + { + return [ + ['HR', 'HR-01', 'Zagrebačka županija'], + ['HR', 'HR-02', 'Krapinsko-zagorska županija'], + ['HR', 'HR-03', 'Sisačko-moslavačka županija'], + ['HR', 'HR-04', 'Karlovačka županija'], + ['HR', 'HR-05', 'Varaždinska županija'], + ['HR', 'HR-06', 'Koprivničko-križevačka županija'], + ['HR', 'HR-07', 'Bjelovarsko-bilogorska županija'], + ['HR', 'HR-08', 'Primorsko-goranska županija'], + ['HR', 'HR-09', 'Ličko-senjska županija'], + ['HR', 'HR-10', 'Virovitičko-podravska županija'], + ['HR', 'HR-11', 'Požeško-slavonska županija'], + ['HR', 'HR-12', 'Brodsko-posavska županija'], + ['HR', 'HR-13', 'Zadarska županija'], + ['HR', 'HR-14', 'Osječko-baranjska županija'], + ['HR', 'HR-15', 'Šibensko-kninska županija'], + ['HR', 'HR-16', 'Vukovarsko-srijemska županija'], + ['HR', 'HR-17', 'Splitsko-dalmatinska županija'], + ['HR', 'HR-18', 'Istarska županija'], + ['HR', 'HR-19', 'Dubrovačko-neretvanska županija'], + ['HR', 'HR-20', 'Međimurska županija'], + ['HR', 'HR-21', 'Grad Zagreb'] + ]; + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + InitializeDirectoryData::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Directory/Setup/Patch/Data/AddDataForIndia.php b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForIndia.php new file mode 100644 index 0000000000000..69d500960d3f0 --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/AddDataForIndia.php @@ -0,0 +1,130 @@ +moduleDataSetup = $moduleDataSetup; + $this->dataInstallerFactory = $dataInstallerFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var DataInstaller $dataInstaller */ + $dataInstaller = $this->dataInstallerFactory->create(); + $dataInstaller->addCountryRegions( + $this->moduleDataSetup->getConnection(), + $this->getDataForIndia() + ); + } + + /** + * Indian states data. + * + * @return array + */ + private function getDataForIndia() + { + return [ + ['IN', 'AN', 'Andaman and Nicobar Islands'], + ['IN', 'AP', 'Andhra Pradesh'], + ['IN', 'AR', 'Arunachal Pradesh'], + ['IN', 'AS', 'Assam'], + ['IN', 'BR', 'Bihar'], + ['IN', 'CH', 'Chandigarh'], + ['IN', 'CT', 'Chhattisgarh'], + ['IN', 'DN', 'Dadra and Nagar Haveli'], + ['IN', 'DD', 'Daman and Diu'], + ['IN', 'DL', 'Delhi'], + ['IN', 'GA', 'Goa'], + ['IN', 'GJ', 'Gujarat'], + ['IN', 'HR', 'Haryana'], + ['IN', 'HP', 'Himachal Pradesh'], + ['IN', 'JK', 'Jammu and Kashmir'], + ['IN', 'JH', 'Jharkhand'], + ['IN', 'KA', 'Karnataka'], + ['IN', 'KL', 'Kerala'], + ['IN', 'LD', 'Lakshadweep'], + ['IN', 'MP', 'Madhya Pradesh'], + ['IN', 'MH', 'Maharashtra'], + ['IN', 'MN', 'Manipur'], + ['IN', 'ML', 'Meghalaya'], + ['IN', 'MZ', 'Mizoram'], + ['IN', 'NL', 'Nagaland'], + ['IN', 'OR', 'Odisha'], + ['IN', 'PY', 'Puducherry'], + ['IN', 'PB', 'Punjab'], + ['IN', 'RJ', 'Rajasthan'], + ['IN', 'SK', 'Sikkim'], + ['IN', 'TN', 'Tamil Nadu'], + ['IN', 'TG', 'Telangana'], + ['IN', 'TR', 'Tripura'], + ['IN', 'UP', 'Uttar Pradesh'], + ['IN', 'UT', 'Uttarakhand'], + ['IN', 'WB', 'West Bengal'] + ]; + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + InitializeDirectoryData::class, + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.2'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Directory/Setup/Patch/Data/InitializeDirectoryData.php b/app/code/Magento/Directory/Setup/Patch/Data/InitializeDirectoryData.php new file mode 100644 index 0000000000000..79ac53d3a449f --- /dev/null +++ b/app/code/Magento/Directory/Setup/Patch/Data/InitializeDirectoryData.php @@ -0,0 +1,899 @@ +moduleDataSetup = $moduleDataSetup; + $this->directoryDataFactory = $directoryDataFactory; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function apply() + { + /** + * Fill table directory/country + */ + $data = [ + ['AD', 'AD', 'AND'], + ['AE', 'AE', 'ARE'], + ['AF', 'AF', 'AFG'], + ['AG', 'AG', 'ATG'], + ['AI', 'AI', 'AIA'], + ['AL', 'AL', 'ALB'], + ['AM', 'AM', 'ARM'], + ['AN', 'AN', 'ANT'], + ['AO', 'AO', 'AGO'], + ['AQ', 'AQ', 'ATA'], + ['AR', 'AR', 'ARG'], + ['AS', 'AS', 'ASM'], + ['AT', 'AT', 'AUT'], + ['AU', 'AU', 'AUS'], + ['AW', 'AW', 'ABW'], + ['AX', 'AX', 'ALA'], + ['AZ', 'AZ', 'AZE'], + ['BA', 'BA', 'BIH'], + ['BB', 'BB', 'BRB'], + ['BD', 'BD', 'BGD'], + ['BE', 'BE', 'BEL'], + ['BF', 'BF', 'BFA'], + ['BG', 'BG', 'BGR'], + ['BH', 'BH', 'BHR'], + ['BI', 'BI', 'BDI'], + ['BJ', 'BJ', 'BEN'], + ['BL', 'BL', 'BLM'], + ['BM', 'BM', 'BMU'], + ['BN', 'BN', 'BRN'], + ['BO', 'BO', 'BOL'], + ['BR', 'BR', 'BRA'], + ['BS', 'BS', 'BHS'], + ['BT', 'BT', 'BTN'], + ['BV', 'BV', 'BVT'], + ['BW', 'BW', 'BWA'], + ['BY', 'BY', 'BLR'], + ['BZ', 'BZ', 'BLZ'], + ['CA', 'CA', 'CAN'], + ['CC', 'CC', 'CCK'], + ['CD', 'CD', 'COD'], + ['CF', 'CF', 'CAF'], + ['CG', 'CG', 'COG'], + ['CH', 'CH', 'CHE'], + ['CI', 'CI', 'CIV'], + ['CK', 'CK', 'COK'], + ['CL', 'CL', 'CHL'], + ['CM', 'CM', 'CMR'], + ['CN', 'CN', 'CHN'], + ['CO', 'CO', 'COL'], + ['CR', 'CR', 'CRI'], + ['CU', 'CU', 'CUB'], + ['CV', 'CV', 'CPV'], + ['CX', 'CX', 'CXR'], + ['CY', 'CY', 'CYP'], + ['CZ', 'CZ', 'CZE'], + ['DE', 'DE', 'DEU'], + ['DJ', 'DJ', 'DJI'], + ['DK', 'DK', 'DNK'], + ['DM', 'DM', 'DMA'], + ['DO', 'DO', 'DOM'], + ['DZ', 'DZ', 'DZA'], + ['EC', 'EC', 'ECU'], + ['EE', 'EE', 'EST'], + ['EG', 'EG', 'EGY'], + ['EH', 'EH', 'ESH'], + ['ER', 'ER', 'ERI'], + ['ES', 'ES', 'ESP'], + ['ET', 'ET', 'ETH'], + ['FI', 'FI', 'FIN'], + ['FJ', 'FJ', 'FJI'], + ['FK', 'FK', 'FLK'], + ['FM', 'FM', 'FSM'], + ['FO', 'FO', 'FRO'], + ['FR', 'FR', 'FRA'], + ['GA', 'GA', 'GAB'], + ['GB', 'GB', 'GBR'], + ['GD', 'GD', 'GRD'], + ['GE', 'GE', 'GEO'], + ['GF', 'GF', 'GUF'], + ['GG', 'GG', 'GGY'], + ['GH', 'GH', 'GHA'], + ['GI', 'GI', 'GIB'], + ['GL', 'GL', 'GRL'], + ['GM', 'GM', 'GMB'], + ['GN', 'GN', 'GIN'], + ['GP', 'GP', 'GLP'], + ['GQ', 'GQ', 'GNQ'], + ['GR', 'GR', 'GRC'], + ['GS', 'GS', 'SGS'], + ['GT', 'GT', 'GTM'], + ['GU', 'GU', 'GUM'], + ['GW', 'GW', 'GNB'], + ['GY', 'GY', 'GUY'], + ['HK', 'HK', 'HKG'], + ['HM', 'HM', 'HMD'], + ['HN', 'HN', 'HND'], + ['HR', 'HR', 'HRV'], + ['HT', 'HT', 'HTI'], + ['HU', 'HU', 'HUN'], + ['ID', 'ID', 'IDN'], + ['IE', 'IE', 'IRL'], + ['IL', 'IL', 'ISR'], + ['IM', 'IM', 'IMN'], + ['IN', 'IN', 'IND'], + ['IO', 'IO', 'IOT'], + ['IQ', 'IQ', 'IRQ'], + ['IR', 'IR', 'IRN'], + ['IS', 'IS', 'ISL'], + ['IT', 'IT', 'ITA'], + ['JE', 'JE', 'JEY'], + ['JM', 'JM', 'JAM'], + ['JO', 'JO', 'JOR'], + ['JP', 'JP', 'JPN'], + ['KE', 'KE', 'KEN'], + ['KG', 'KG', 'KGZ'], + ['KH', 'KH', 'KHM'], + ['KI', 'KI', 'KIR'], + ['KM', 'KM', 'COM'], + ['KN', 'KN', 'KNA'], + ['KP', 'KP', 'PRK'], + ['KR', 'KR', 'KOR'], + ['KW', 'KW', 'KWT'], + ['KY', 'KY', 'CYM'], + ['KZ', 'KZ', 'KAZ'], + ['LA', 'LA', 'LAO'], + ['LB', 'LB', 'LBN'], + ['LC', 'LC', 'LCA'], + ['LI', 'LI', 'LIE'], + ['LK', 'LK', 'LKA'], + ['LR', 'LR', 'LBR'], + ['LS', 'LS', 'LSO'], + ['LT', 'LT', 'LTU'], + ['LU', 'LU', 'LUX'], + ['LV', 'LV', 'LVA'], + ['LY', 'LY', 'LBY'], + ['MA', 'MA', 'MAR'], + ['MC', 'MC', 'MCO'], + ['MD', 'MD', 'MDA'], + ['ME', 'ME', 'MNE'], + ['MF', 'MF', 'MAF'], + ['MG', 'MG', 'MDG'], + ['MH', 'MH', 'MHL'], + ['MK', 'MK', 'MKD'], + ['ML', 'ML', 'MLI'], + ['MM', 'MM', 'MMR'], + ['MN', 'MN', 'MNG'], + ['MO', 'MO', 'MAC'], + ['MP', 'MP', 'MNP'], + ['MQ', 'MQ', 'MTQ'], + ['MR', 'MR', 'MRT'], + ['MS', 'MS', 'MSR'], + ['MT', 'MT', 'MLT'], + ['MU', 'MU', 'MUS'], + ['MV', 'MV', 'MDV'], + ['MW', 'MW', 'MWI'], + ['MX', 'MX', 'MEX'], + ['MY', 'MY', 'MYS'], + ['MZ', 'MZ', 'MOZ'], + ['NA', 'NA', 'NAM'], + ['NC', 'NC', 'NCL'], + ['NE', 'NE', 'NER'], + ['NF', 'NF', 'NFK'], + ['NG', 'NG', 'NGA'], + ['NI', 'NI', 'NIC'], + ['NL', 'NL', 'NLD'], + ['NO', 'NO', 'NOR'], + ['NP', 'NP', 'NPL'], + ['NR', 'NR', 'NRU'], + ['NU', 'NU', 'NIU'], + ['NZ', 'NZ', 'NZL'], + ['OM', 'OM', 'OMN'], + ['PA', 'PA', 'PAN'], + ['PE', 'PE', 'PER'], + ['PF', 'PF', 'PYF'], + ['PG', 'PG', 'PNG'], + ['PH', 'PH', 'PHL'], + ['PK', 'PK', 'PAK'], + ['PL', 'PL', 'POL'], + ['PM', 'PM', 'SPM'], + ['PN', 'PN', 'PCN'], + ['PS', 'PS', 'PSE'], + ['PT', 'PT', 'PRT'], + ['PW', 'PW', 'PLW'], + ['PY', 'PY', 'PRY'], + ['QA', 'QA', 'QAT'], + ['RE', 'RE', 'REU'], + ['RO', 'RO', 'ROU'], + ['RS', 'RS', 'SRB'], + ['RU', 'RU', 'RUS'], + ['RW', 'RW', 'RWA'], + ['SA', 'SA', 'SAU'], + ['SB', 'SB', 'SLB'], + ['SC', 'SC', 'SYC'], + ['SD', 'SD', 'SDN'], + ['SE', 'SE', 'SWE'], + ['SG', 'SG', 'SGP'], + ['SH', 'SH', 'SHN'], + ['SI', 'SI', 'SVN'], + ['SJ', 'SJ', 'SJM'], + ['SK', 'SK', 'SVK'], + ['SL', 'SL', 'SLE'], + ['SM', 'SM', 'SMR'], + ['SN', 'SN', 'SEN'], + ['SO', 'SO', 'SOM'], + ['SR', 'SR', 'SUR'], + ['ST', 'ST', 'STP'], + ['SV', 'SV', 'SLV'], + ['SY', 'SY', 'SYR'], + ['SZ', 'SZ', 'SWZ'], + ['TC', 'TC', 'TCA'], + ['TD', 'TD', 'TCD'], + ['TF', 'TF', 'ATF'], + ['TG', 'TG', 'TGO'], + ['TH', 'TH', 'THA'], + ['TJ', 'TJ', 'TJK'], + ['TK', 'TK', 'TKL'], + ['TL', 'TL', 'TLS'], + ['TM', 'TM', 'TKM'], + ['TN', 'TN', 'TUN'], + ['TO', 'TO', 'TON'], + ['TR', 'TR', 'TUR'], + ['TT', 'TT', 'TTO'], + ['TV', 'TV', 'TUV'], + ['TW', 'TW', 'TWN'], + ['TZ', 'TZ', 'TZA'], + ['UA', 'UA', 'UKR'], + ['UG', 'UG', 'UGA'], + ['UM', 'UM', 'UMI'], + ['US', 'US', 'USA'], + ['UY', 'UY', 'URY'], + ['UZ', 'UZ', 'UZB'], + ['VA', 'VA', 'VAT'], + ['VC', 'VC', 'VCT'], + ['VE', 'VE', 'VEN'], + ['VG', 'VG', 'VGB'], + ['VI', 'VI', 'VIR'], + ['VN', 'VN', 'VNM'], + ['VU', 'VU', 'VUT'], + ['WF', 'WF', 'WLF'], + ['WS', 'WS', 'WSM'], + ['YE', 'YE', 'YEM'], + ['YT', 'YT', 'MYT'], + ['ZA', 'ZA', 'ZAF'], + ['ZM', 'ZM', 'ZMB'], + ['ZW', 'ZW', 'ZWE'], + ]; + + $columns = ['country_id', 'iso2_code', 'iso3_code']; + $this->moduleDataSetup->getConnection()->insertArray( + $this->moduleDataSetup->getTable('directory_country'), + $columns, + $data + ); + /** + * Fill table directory/country_region + * Fill table directory/country_region_name for en_US locale + */ + $data = [ + ['US', 'AL', 'Alabama'], + ['US', 'AK', 'Alaska'], + ['US', 'AS', 'American Samoa'], + ['US', 'AZ', 'Arizona'], + ['US', 'AR', 'Arkansas'], + ['US', 'AE', 'Armed Forces Africa'], + ['US', 'AA', 'Armed Forces Americas'], + ['US', 'AE', 'Armed Forces Canada'], + ['US', 'AE', 'Armed Forces Europe'], + ['US', 'AE', 'Armed Forces Middle East'], + ['US', 'AP', 'Armed Forces Pacific'], + ['US', 'CA', 'California'], + ['US', 'CO', 'Colorado'], + ['US', 'CT', 'Connecticut'], + ['US', 'DE', 'Delaware'], + ['US', 'DC', 'District of Columbia'], + ['US', 'FM', 'Federated States Of Micronesia'], + ['US', 'FL', 'Florida'], + ['US', 'GA', 'Georgia'], + ['US', 'GU', 'Guam'], + ['US', 'HI', 'Hawaii'], + ['US', 'ID', 'Idaho'], + ['US', 'IL', 'Illinois'], + ['US', 'IN', 'Indiana'], + ['US', 'IA', 'Iowa'], + ['US', 'KS', 'Kansas'], + ['US', 'KY', 'Kentucky'], + ['US', 'LA', 'Louisiana'], + ['US', 'ME', 'Maine'], + ['US', 'MH', 'Marshall Islands'], + ['US', 'MD', 'Maryland'], + ['US', 'MA', 'Massachusetts'], + ['US', 'MI', 'Michigan'], + ['US', 'MN', 'Minnesota'], + ['US', 'MS', 'Mississippi'], + ['US', 'MO', 'Missouri'], + ['US', 'MT', 'Montana'], + ['US', 'NE', 'Nebraska'], + ['US', 'NV', 'Nevada'], + ['US', 'NH', 'New Hampshire'], + ['US', 'NJ', 'New Jersey'], + ['US', 'NM', 'New Mexico'], + ['US', 'NY', 'New York'], + ['US', 'NC', 'North Carolina'], + ['US', 'ND', 'North Dakota'], + ['US', 'MP', 'Northern Mariana Islands'], + ['US', 'OH', 'Ohio'], + ['US', 'OK', 'Oklahoma'], + ['US', 'OR', 'Oregon'], + ['US', 'PW', 'Palau'], + ['US', 'PA', 'Pennsylvania'], + ['US', 'PR', 'Puerto Rico'], + ['US', 'RI', 'Rhode Island'], + ['US', 'SC', 'South Carolina'], + ['US', 'SD', 'South Dakota'], + ['US', 'TN', 'Tennessee'], + ['US', 'TX', 'Texas'], + ['US', 'UT', 'Utah'], + ['US', 'VT', 'Vermont'], + ['US', 'VI', 'Virgin Islands'], + ['US', 'VA', 'Virginia'], + ['US', 'WA', 'Washington'], + ['US', 'WV', 'West Virginia'], + ['US', 'WI', 'Wisconsin'], + ['US', 'WY', 'Wyoming'], + ['CA', 'AB', 'Alberta'], + ['CA', 'BC', 'British Columbia'], + ['CA', 'MB', 'Manitoba'], + ['CA', 'NL', 'Newfoundland and Labrador'], + ['CA', 'NB', 'New Brunswick'], + ['CA', 'NS', 'Nova Scotia'], + ['CA', 'NT', 'Northwest Territories'], + ['CA', 'NU', 'Nunavut'], + ['CA', 'ON', 'Ontario'], + ['CA', 'PE', 'Prince Edward Island'], + ['CA', 'QC', 'Quebec'], + ['CA', 'SK', 'Saskatchewan'], + ['CA', 'YT', 'Yukon Territory'], + ['DE', 'NDS', 'Niedersachsen'], + ['DE', 'BAW', 'Baden-Württemberg'], + ['DE', 'BAY', 'Bayern'], + ['DE', 'BER', 'Berlin'], + ['DE', 'BRG', 'Brandenburg'], + ['DE', 'BRE', 'Bremen'], + ['DE', 'HAM', 'Hamburg'], + ['DE', 'HES', 'Hessen'], + ['DE', 'MEC', 'Mecklenburg-Vorpommern'], + ['DE', 'NRW', 'Nordrhein-Westfalen'], + ['DE', 'RHE', 'Rheinland-Pfalz'], + ['DE', 'SAR', 'Saarland'], + ['DE', 'SAS', 'Sachsen'], + ['DE', 'SAC', 'Sachsen-Anhalt'], + ['DE', 'SCN', 'Schleswig-Holstein'], + ['DE', 'THE', 'Thüringen'], + ['AT', 'WI', 'Wien'], + ['AT', 'NO', 'Niederösterreich'], + ['AT', 'OO', 'Oberösterreich'], + ['AT', 'SB', 'Salzburg'], + ['AT', 'KN', 'Kärnten'], + ['AT', 'ST', 'Steiermark'], + ['AT', 'TI', 'Tirol'], + ['AT', 'BL', 'Burgenland'], + ['AT', 'VB', 'Vorarlberg'], + ['CH', 'AG', 'Aargau'], + ['CH', 'AI', 'Appenzell Innerrhoden'], + ['CH', 'AR', 'Appenzell Ausserrhoden'], + ['CH', 'BE', 'Bern'], + ['CH', 'BL', 'Basel-Landschaft'], + ['CH', 'BS', 'Basel-Stadt'], + ['CH', 'FR', 'Freiburg'], + ['CH', 'GE', 'Genf'], + ['CH', 'GL', 'Glarus'], + ['CH', 'GR', 'Graubünden'], + ['CH', 'JU', 'Jura'], + ['CH', 'LU', 'Luzern'], + ['CH', 'NE', 'Neuenburg'], + ['CH', 'NW', 'Nidwalden'], + ['CH', 'OW', 'Obwalden'], + ['CH', 'SG', 'St. Gallen'], + ['CH', 'SH', 'Schaffhausen'], + ['CH', 'SO', 'Solothurn'], + ['CH', 'SZ', 'Schwyz'], + ['CH', 'TG', 'Thurgau'], + ['CH', 'TI', 'Tessin'], + ['CH', 'UR', 'Uri'], + ['CH', 'VD', 'Waadt'], + ['CH', 'VS', 'Wallis'], + ['CH', 'ZG', 'Zug'], + ['CH', 'ZH', 'Zürich'], + ['ES', 'A Coruсa', 'A Coruña'], + ['ES', 'Alava', 'Alava'], + ['ES', 'Albacete', 'Albacete'], + ['ES', 'Alicante', 'Alicante'], + ['ES', 'Almeria', 'Almeria'], + ['ES', 'Asturias', 'Asturias'], + ['ES', 'Avila', 'Avila'], + ['ES', 'Badajoz', 'Badajoz'], + ['ES', 'Baleares', 'Baleares'], + ['ES', 'Barcelona', 'Barcelona'], + ['ES', 'Burgos', 'Burgos'], + ['ES', 'Caceres', 'Caceres'], + ['ES', 'Cadiz', 'Cadiz'], + ['ES', 'Cantabria', 'Cantabria'], + ['ES', 'Castellon', 'Castellon'], + ['ES', 'Ceuta', 'Ceuta'], + ['ES', 'Ciudad Real', 'Ciudad Real'], + ['ES', 'Cordoba', 'Cordoba'], + ['ES', 'Cuenca', 'Cuenca'], + ['ES', 'Girona', 'Girona'], + ['ES', 'Granada', 'Granada'], + ['ES', 'Guadalajara', 'Guadalajara'], + ['ES', 'Guipuzcoa', 'Guipuzcoa'], + ['ES', 'Huelva', 'Huelva'], + ['ES', 'Huesca', 'Huesca'], + ['ES', 'Jaen', 'Jaen'], + ['ES', 'La Rioja', 'La Rioja'], + ['ES', 'Las Palmas', 'Las Palmas'], + ['ES', 'Leon', 'Leon'], + ['ES', 'Lleida', 'Lleida'], + ['ES', 'Lugo', 'Lugo'], + ['ES', 'Madrid', 'Madrid'], + ['ES', 'Malaga', 'Malaga'], + ['ES', 'Melilla', 'Melilla'], + ['ES', 'Murcia', 'Murcia'], + ['ES', 'Navarra', 'Navarra'], + ['ES', 'Ourense', 'Ourense'], + ['ES', 'Palencia', 'Palencia'], + ['ES', 'Pontevedra', 'Pontevedra'], + ['ES', 'Salamanca', 'Salamanca'], + ['ES', 'Santa Cruz de Tenerife', 'Santa Cruz de Tenerife'], + ['ES', 'Segovia', 'Segovia'], + ['ES', 'Sevilla', 'Sevilla'], + ['ES', 'Soria', 'Soria'], + ['ES', 'Tarragona', 'Tarragona'], + ['ES', 'Teruel', 'Teruel'], + ['ES', 'Toledo', 'Toledo'], + ['ES', 'Valencia', 'Valencia'], + ['ES', 'Valladolid', 'Valladolid'], + ['ES', 'Vizcaya', 'Vizcaya'], + ['ES', 'Zamora', 'Zamora'], + ['ES', 'Zaragoza', 'Zaragoza'], + ['FR', 1, 'Ain'], + ['FR', 2, 'Aisne'], + ['FR', 3, 'Allier'], + ['FR', 4, 'Alpes-de-Haute-Provence'], + ['FR', 5, 'Hautes-Alpes'], + ['FR', 6, 'Alpes-Maritimes'], + ['FR', 7, 'Ardèche'], + ['FR', 8, 'Ardennes'], + ['FR', 9, 'Ariège'], + ['FR', 10, 'Aube'], + ['FR', 11, 'Aude'], + ['FR', 12, 'Aveyron'], + ['FR', 13, 'Bouches-du-Rhône'], + ['FR', 14, 'Calvados'], + ['FR', 15, 'Cantal'], + ['FR', 16, 'Charente'], + ['FR', 17, 'Charente-Maritime'], + ['FR', 18, 'Cher'], + ['FR', 19, 'Corrèze'], + ['FR', '2A', 'Corse-du-Sud'], + ['FR', '2B', 'Haute-Corse'], + ['FR', 21, 'Côte-d\'Or'], + ['FR', 22, 'Côtes-d\'Armor'], + ['FR', 23, 'Creuse'], + ['FR', 24, 'Dordogne'], + ['FR', 25, 'Doubs'], + ['FR', 26, 'Drôme'], + ['FR', 27, 'Eure'], + ['FR', 28, 'Eure-et-Loir'], + ['FR', 29, 'Finistère'], + ['FR', 30, 'Gard'], + ['FR', 31, 'Haute-Garonne'], + ['FR', 32, 'Gers'], + ['FR', 33, 'Gironde'], + ['FR', 34, 'Hérault'], + ['FR', 35, 'Ille-et-Vilaine'], + ['FR', 36, 'Indre'], + ['FR', 37, 'Indre-et-Loire'], + ['FR', 38, 'Isère'], + ['FR', 39, 'Jura'], + ['FR', 40, 'Landes'], + ['FR', 41, 'Loir-et-Cher'], + ['FR', 42, 'Loire'], + ['FR', 43, 'Haute-Loire'], + ['FR', 44, 'Loire-Atlantique'], + ['FR', 45, 'Loiret'], + ['FR', 46, 'Lot'], + ['FR', 47, 'Lot-et-Garonne'], + ['FR', 48, 'Lozère'], + ['FR', 49, 'Maine-et-Loire'], + ['FR', 50, 'Manche'], + ['FR', 51, 'Marne'], + ['FR', 52, 'Haute-Marne'], + ['FR', 53, 'Mayenne'], + ['FR', 54, 'Meurthe-et-Moselle'], + ['FR', 55, 'Meuse'], + ['FR', 56, 'Morbihan'], + ['FR', 57, 'Moselle'], + ['FR', 58, 'Nièvre'], + ['FR', 59, 'Nord'], + ['FR', 60, 'Oise'], + ['FR', 61, 'Orne'], + ['FR', 62, 'Pas-de-Calais'], + ['FR', 63, 'Puy-de-Dôme'], + ['FR', 64, 'Pyrénées-Atlantiques'], + ['FR', 65, 'Hautes-Pyrénées'], + ['FR', 66, 'Pyrénées-Orientales'], + ['FR', 67, 'Bas-Rhin'], + ['FR', 68, 'Haut-Rhin'], + ['FR', 69, 'Rhône'], + ['FR', 70, 'Haute-Saône'], + ['FR', 71, 'Saône-et-Loire'], + ['FR', 72, 'Sarthe'], + ['FR', 73, 'Savoie'], + ['FR', 74, 'Haute-Savoie'], + ['FR', 75, 'Paris'], + ['FR', 76, 'Seine-Maritime'], + ['FR', 77, 'Seine-et-Marne'], + ['FR', 78, 'Yvelines'], + ['FR', 79, 'Deux-Sèvres'], + ['FR', 80, 'Somme'], + ['FR', 81, 'Tarn'], + ['FR', 82, 'Tarn-et-Garonne'], + ['FR', 83, 'Var'], + ['FR', 84, 'Vaucluse'], + ['FR', 85, 'Vendée'], + ['FR', 86, 'Vienne'], + ['FR', 87, 'Haute-Vienne'], + ['FR', 88, 'Vosges'], + ['FR', 89, 'Yonne'], + ['FR', 90, 'Territoire-de-Belfort'], + ['FR', 91, 'Essonne'], + ['FR', 92, 'Hauts-de-Seine'], + ['FR', 93, 'Seine-Saint-Denis'], + ['FR', 94, 'Val-de-Marne'], + ['FR', 95, 'Val-d\'Oise'], + ['RO', 'AB', 'Alba'], + ['RO', 'AR', 'Arad'], + ['RO', 'AG', 'Argeş'], + ['RO', 'BC', 'Bacău'], + ['RO', 'BH', 'Bihor'], + ['RO', 'BN', 'Bistriţa-Năsăud'], + ['RO', 'BT', 'Botoşani'], + ['RO', 'BV', 'Braşov'], + ['RO', 'BR', 'Brăila'], + ['RO', 'B', 'Bucureşti'], + ['RO', 'BZ', 'Buzău'], + ['RO', 'CS', 'Caraş-Severin'], + ['RO', 'CL', 'Călăraşi'], + ['RO', 'CJ', 'Cluj'], + ['RO', 'CT', 'Constanţa'], + ['RO', 'CV', 'Covasna'], + ['RO', 'DB', 'Dâmboviţa'], + ['RO', 'DJ', 'Dolj'], + ['RO', 'GL', 'Galaţi'], + ['RO', 'GR', 'Giurgiu'], + ['RO', 'GJ', 'Gorj'], + ['RO', 'HR', 'Harghita'], + ['RO', 'HD', 'Hunedoara'], + ['RO', 'IL', 'Ialomiţa'], + ['RO', 'IS', 'Iaşi'], + ['RO', 'IF', 'Ilfov'], + ['RO', 'MM', 'Maramureş'], + ['RO', 'MH', 'Mehedinţi'], + ['RO', 'MS', 'Mureş'], + ['RO', 'NT', 'Neamţ'], + ['RO', 'OT', 'Olt'], + ['RO', 'PH', 'Prahova'], + ['RO', 'SM', 'Satu-Mare'], + ['RO', 'SJ', 'Sălaj'], + ['RO', 'SB', 'Sibiu'], + ['RO', 'SV', 'Suceava'], + ['RO', 'TR', 'Teleorman'], + ['RO', 'TM', 'Timiş'], + ['RO', 'TL', 'Tulcea'], + ['RO', 'VS', 'Vaslui'], + ['RO', 'VL', 'Vâlcea'], + ['RO', 'VN', 'Vrancea'], + ['FI', 'Lappi', 'Lappi'], + ['FI', 'Pohjois-Pohjanmaa', 'Pohjois-Pohjanmaa'], + ['FI', 'Kainuu', 'Kainuu'], + ['FI', 'Pohjois-Karjala', 'Pohjois-Karjala'], + ['FI', 'Pohjois-Savo', 'Pohjois-Savo'], + ['FI', 'Etelä-Savo', 'Etelä-Savo'], + ['FI', 'Etelä-Pohjanmaa', 'Etelä-Pohjanmaa'], + ['FI', 'Pohjanmaa', 'Pohjanmaa'], + ['FI', 'Pirkanmaa', 'Pirkanmaa'], + ['FI', 'Satakunta', 'Satakunta'], + ['FI', 'Keski-Pohjanmaa', 'Keski-Pohjanmaa'], + ['FI', 'Keski-Suomi', 'Keski-Suomi'], + ['FI', 'Varsinais-Suomi', 'Varsinais-Suomi'], + ['FI', 'Etelä-Karjala', 'Etelä-Karjala'], + ['FI', 'Päijät-Häme', 'Päijät-Häme'], + ['FI', 'Kanta-Häme', 'Kanta-Häme'], + ['FI', 'Uusimaa', 'Uusimaa'], + ['FI', 'Itä-Uusimaa', 'Itä-Uusimaa'], + ['FI', 'Kymenlaakso', 'Kymenlaakso'], + ['FI', 'Ahvenanmaa', 'Ahvenanmaa'], + ['EE', 'EE-37', 'Harjumaa'], + ['EE', 'EE-39', 'Hiiumaa'], + ['EE', 'EE-44', 'Ida-Virumaa'], + ['EE', 'EE-49', 'Jõgevamaa'], + ['EE', 'EE-51', 'Järvamaa'], + ['EE', 'EE-57', 'Läänemaa'], + ['EE', 'EE-59', 'Lääne-Virumaa'], + ['EE', 'EE-65', 'Põlvamaa'], + ['EE', 'EE-67', 'Pärnumaa'], + ['EE', 'EE-70', 'Raplamaa'], + ['EE', 'EE-74', 'Saaremaa'], + ['EE', 'EE-78', 'Tartumaa'], + ['EE', 'EE-82', 'Valgamaa'], + ['EE', 'EE-84', 'Viljandimaa'], + ['EE', 'EE-86', 'Võrumaa'], + ['LV', 'LV-DGV', 'Daugavpils'], + ['LV', 'LV-JEL', 'Jelgava'], + ['LV', 'Jēkabpils', 'Jēkabpils'], + ['LV', 'LV-JUR', 'Jūrmala'], + ['LV', 'LV-LPX', 'Liepāja'], + ['LV', 'LV-LE', 'Liepājas novads'], + ['LV', 'LV-REZ', 'Rēzekne'], + ['LV', 'LV-RIX', 'Rīga'], + ['LV', 'LV-RI', 'Rīgas novads'], + ['LV', 'Valmiera', 'Valmiera'], + ['LV', 'LV-VEN', 'Ventspils'], + ['LV', 'Aglonas novads', 'Aglonas novads'], + ['LV', 'LV-AI', 'Aizkraukles novads'], + ['LV', 'Aizputes novads', 'Aizputes novads'], + ['LV', 'Aknīstes novads', 'Aknīstes novads'], + ['LV', 'Alojas novads', 'Alojas novads'], + ['LV', 'Alsungas novads', 'Alsungas novads'], + ['LV', 'LV-AL', 'Alūksnes novads'], + ['LV', 'Amatas novads', 'Amatas novads'], + ['LV', 'Apes novads', 'Apes novads'], + ['LV', 'Auces novads', 'Auces novads'], + ['LV', 'Babītes novads', 'Babītes novads'], + ['LV', 'Baldones novads', 'Baldones novads'], + ['LV', 'Baltinavas novads', 'Baltinavas novads'], + ['LV', 'LV-BL', 'Balvu novads'], + ['LV', 'LV-BU', 'Bauskas novads'], + ['LV', 'Beverīnas novads', 'Beverīnas novads'], + ['LV', 'Brocēnu novads', 'Brocēnu novads'], + ['LV', 'Burtnieku novads', 'Burtnieku novads'], + ['LV', 'Carnikavas novads', 'Carnikavas novads'], + ['LV', 'Cesvaines novads', 'Cesvaines novads'], + ['LV', 'Ciblas novads', 'Ciblas novads'], + ['LV', 'LV-CE', 'Cēsu novads'], + ['LV', 'Dagdas novads', 'Dagdas novads'], + ['LV', 'LV-DA', 'Daugavpils novads'], + ['LV', 'LV-DO', 'Dobeles novads'], + ['LV', 'Dundagas novads', 'Dundagas novads'], + ['LV', 'Durbes novads', 'Durbes novads'], + ['LV', 'Engures novads', 'Engures novads'], + ['LV', 'Garkalnes novads', 'Garkalnes novads'], + ['LV', 'Grobiņas novads', 'Grobiņas novads'], + ['LV', 'LV-GU', 'Gulbenes novads'], + ['LV', 'Iecavas novads', 'Iecavas novads'], + ['LV', 'Ikšķiles novads', 'Ikšķiles novads'], + ['LV', 'Ilūkstes novads', 'Ilūkstes novads'], + ['LV', 'Inčukalna novads', 'Inčukalna novads'], + ['LV', 'Jaunjelgavas novads', 'Jaunjelgavas novads'], + ['LV', 'Jaunpiebalgas novads', 'Jaunpiebalgas novads'], + ['LV', 'Jaunpils novads', 'Jaunpils novads'], + ['LV', 'LV-JL', 'Jelgavas novads'], + ['LV', 'LV-JK', 'Jēkabpils novads'], + ['LV', 'Kandavas novads', 'Kandavas novads'], + ['LV', 'Kokneses novads', 'Kokneses novads'], + ['LV', 'Krimuldas novads', 'Krimuldas novads'], + ['LV', 'Krustpils novads', 'Krustpils novads'], + ['LV', 'LV-KR', 'Krāslavas novads'], + ['LV', 'LV-KU', 'Kuldīgas novads'], + ['LV', 'Kārsavas novads', 'Kārsavas novads'], + ['LV', 'Lielvārdes novads', 'Lielvārdes novads'], + ['LV', 'LV-LM', 'Limbažu novads'], + ['LV', 'Lubānas novads', 'Lubānas novads'], + ['LV', 'LV-LU', 'Ludzas novads'], + ['LV', 'Līgatnes novads', 'Līgatnes novads'], + ['LV', 'Līvānu novads', 'Līvānu novads'], + ['LV', 'LV-MA', 'Madonas novads'], + ['LV', 'Mazsalacas novads', 'Mazsalacas novads'], + ['LV', 'Mālpils novads', 'Mālpils novads'], + ['LV', 'Mārupes novads', 'Mārupes novads'], + ['LV', 'Naukšēnu novads', 'Naukšēnu novads'], + ['LV', 'Neretas novads', 'Neretas novads'], + ['LV', 'Nīcas novads', 'Nīcas novads'], + ['LV', 'LV-OG', 'Ogres novads'], + ['LV', 'Olaines novads', 'Olaines novads'], + ['LV', 'Ozolnieku novads', 'Ozolnieku novads'], + ['LV', 'LV-PR', 'Preiļu novads'], + ['LV', 'Priekules novads', 'Priekules novads'], + ['LV', 'Priekuļu novads', 'Priekuļu novads'], + ['LV', 'Pārgaujas novads', 'Pārgaujas novads'], + ['LV', 'Pāvilostas novads', 'Pāvilostas novads'], + ['LV', 'Pļaviņu novads', 'Pļaviņu novads'], + ['LV', 'Raunas novads', 'Raunas novads'], + ['LV', 'Riebiņu novads', 'Riebiņu novads'], + ['LV', 'Rojas novads', 'Rojas novads'], + ['LV', 'Ropažu novads', 'Ropažu novads'], + ['LV', 'Rucavas novads', 'Rucavas novads'], + ['LV', 'Rugāju novads', 'Rugāju novads'], + ['LV', 'Rundāles novads', 'Rundāles novads'], + ['LV', 'LV-RE', 'Rēzeknes novads'], + ['LV', 'Rūjienas novads', 'Rūjienas novads'], + ['LV', 'Salacgrīvas novads', 'Salacgrīvas novads'], + ['LV', 'Salas novads', 'Salas novads'], + ['LV', 'Salaspils novads', 'Salaspils novads'], + ['LV', 'LV-SA', 'Saldus novads'], + ['LV', 'Saulkrastu novads', 'Saulkrastu novads'], + ['LV', 'Siguldas novads', 'Siguldas novads'], + ['LV', 'Skrundas novads', 'Skrundas novads'], + ['LV', 'Skrīveru novads', 'Skrīveru novads'], + ['LV', 'Smiltenes novads', 'Smiltenes novads'], + ['LV', 'Stopiņu novads', 'Stopiņu novads'], + ['LV', 'Strenču novads', 'Strenču novads'], + ['LV', 'Sējas novads', 'Sējas novads'], + ['LV', 'LV-TA', 'Talsu novads'], + ['LV', 'LV-TU', 'Tukuma novads'], + ['LV', 'Tērvetes novads', 'Tērvetes novads'], + ['LV', 'Vaiņodes novads', 'Vaiņodes novads'], + ['LV', 'LV-VK', 'Valkas novads'], + ['LV', 'LV-VM', 'Valmieras novads'], + ['LV', 'Varakļānu novads', 'Varakļānu novads'], + ['LV', 'Vecpiebalgas novads', 'Vecpiebalgas novads'], + ['LV', 'Vecumnieku novads', 'Vecumnieku novads'], + ['LV', 'LV-VE', 'Ventspils novads'], + ['LV', 'Viesītes novads', 'Viesītes novads'], + ['LV', 'Viļakas novads', 'Viļakas novads'], + ['LV', 'Viļānu novads', 'Viļānu novads'], + ['LV', 'Vārkavas novads', 'Vārkavas novads'], + ['LV', 'Zilupes novads', 'Zilupes novads'], + ['LV', 'Ādažu novads', 'Ādažu novads'], + ['LV', 'Ērgļu novads', 'Ērgļu novads'], + ['LV', 'Ķeguma novads', 'Ķeguma novads'], + ['LV', 'Ķekavas novads', 'Ķekavas novads'], + ['LT', 'LT-AL', 'Alytaus Apskritis'], + ['LT', 'LT-KU', 'Kauno Apskritis'], + ['LT', 'LT-KL', 'Klaipėdos Apskritis'], + ['LT', 'LT-MR', 'Marijampolės Apskritis'], + ['LT', 'LT-PN', 'Panevėžio Apskritis'], + ['LT', 'LT-SA', 'Šiaulių Apskritis'], + ['LT', 'LT-TA', 'Tauragės Apskritis'], + ['LT', 'LT-TE', 'Telšių Apskritis'], + ['LT', 'LT-UT', 'Utenos Apskritis'], + ['LT', 'LT-VL', 'Vilniaus Apskritis'], + ['BR', 'AC', 'Acre'], + ['BR', 'AL', 'Alagoas'], + ['BR', 'AP', 'Amapá'], + ['BR', 'AM', 'Amazonas'], + ['BR', 'BA', 'Bahia'], + ['BR', 'CE', 'Ceará'], + ['BR', 'ES', 'Espírito Santo'], + ['BR', 'GO', 'Goiás'], + ['BR', 'MA', 'Maranhão'], + ['BR', 'MT', 'Mato Grosso'], + ['BR', 'MS', 'Mato Grosso do Sul'], + ['BR', 'MG', 'Minas Gerais'], + ['BR', 'PA', 'Pará'], + ['BR', 'PB', 'Paraíba'], + ['BR', 'PR', 'Paraná'], + ['BR', 'PE', 'Pernambuco'], + ['BR', 'PI', 'Piauí'], + ['BR', 'RJ', 'Rio de Janeiro'], + ['BR', 'RN', 'Rio Grande do Norte'], + ['BR', 'RS', 'Rio Grande do Sul'], + ['BR', 'RO', 'Rondônia'], + ['BR', 'RR', 'Roraima'], + ['BR', 'SC', 'Santa Catarina'], + ['BR', 'SP', 'São Paulo'], + ['BR', 'SE', 'Sergipe'], + ['BR', 'TO', 'Tocantins'], + ['BR', 'DF', 'Distrito Federal'], + ]; + foreach ($data as $row) { + $bind = ['country_id' => $row[0], 'code' => $row[1], 'default_name' => $row[2]]; + $this->moduleDataSetup->getConnection()->insert( + $this->moduleDataSetup->getTable('directory_country_region'), + $bind + ); + $regionId = $this->moduleDataSetup->getConnection()->lastInsertId( + $this->moduleDataSetup->getTable('directory_country_region') + ); + $bind = ['locale' => 'en_US', 'region_id' => $regionId, 'name' => $row[2]]; + $this->moduleDataSetup->getConnection()->insert( + $this->moduleDataSetup->getTable('directory_country_region_name'), + $bind + ); + } + /** + * Fill table directory/currency_rate + */ + $data = [ + ['EUR', 'EUR', 1], + ['EUR', 'USD', 1.415000000000], + ['USD', 'EUR', 0.706700000000], + ['USD', 'USD', 1], + ]; + $columns = ['currency_from', 'currency_to', 'rate']; + $this->moduleDataSetup->getConnection()->insertArray( + $this->moduleDataSetup->getTable('directory_currency_rate'), + $columns, + $data + ); + $this->moduleDataSetup->getConnection()->insert( + $this->moduleDataSetup->getTable('core_config_data'), + [ + 'scope' => 'default', + 'scope_id' => 0, + 'path' => Data::XML_PATH_DISPLAY_ALL_STATES, + 'value' => 1 + ] + ); + /** @var \Magento\Directory\Helper\Data $helper */ + $helper = $this->directoryDataFactory->create(); + $countries = $helper->getCountryCollection()->getCountriesWithRequiredStates(); + $this->moduleDataSetup->getConnection()->insert( + $this->moduleDataSetup->getTable('core_config_data'), + [ + 'scope' => 'default', + 'scope_id' => 0, + 'path' => Data::XML_PATH_STATES_REQUIRED, + 'value' => implode(',', array_keys($countries)) + ] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Directory/Setup/UpgradeData.php b/app/code/Magento/Directory/Setup/UpgradeData.php deleted file mode 100644 index 4ee9ea33673d7..0000000000000 --- a/app/code/Magento/Directory/Setup/UpgradeData.php +++ /dev/null @@ -1,166 +0,0 @@ -directoryData = $directoryData; - } - - /** - * Upgrades data for Directry module. - * - * @param ModuleDataSetupInterface $setup - * @param ModuleContextInterface $context - * @return void - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $this->addCountryRegions($setup, $this->getDataForCroatia()); - } - if (version_compare($context->getVersion(), '2.0.2', '<')) { - $this->addCountryRegions($setup, $this->getDataForIndia()); - } - } - - /** - * Croatian states data. - * - * @return array - */ - private function getDataForCroatia() - { - return [ - ['HR', 'HR-01', 'Zagrebačka županija'], - ['HR', 'HR-02', 'Krapinsko-zagorska županija'], - ['HR', 'HR-03', 'Sisačko-moslavačka županija'], - ['HR', 'HR-04', 'Karlovačka županija'], - ['HR', 'HR-05', 'Varaždinska županija'], - ['HR', 'HR-06', 'Koprivničko-križevačka županija'], - ['HR', 'HR-07', 'Bjelovarsko-bilogorska županija'], - ['HR', 'HR-08', 'Primorsko-goranska županija'], - ['HR', 'HR-09', 'Ličko-senjska županija'], - ['HR', 'HR-10', 'Virovitičko-podravska županija'], - ['HR', 'HR-11', 'Požeško-slavonska županija'], - ['HR', 'HR-12', 'Brodsko-posavska županija'], - ['HR', 'HR-13', 'Zadarska županija'], - ['HR', 'HR-14', 'Osječko-baranjska županija'], - ['HR', 'HR-15', 'Šibensko-kninska županija'], - ['HR', 'HR-16', 'Vukovarsko-srijemska županija'], - ['HR', 'HR-17', 'Splitsko-dalmatinska županija'], - ['HR', 'HR-18', 'Istarska županija'], - ['HR', 'HR-19', 'Dubrovačko-neretvanska županija'], - ['HR', 'HR-20', 'Međimurska županija'], - ['HR', 'HR-21', 'Grad Zagreb'] - ]; - } - - /** - * Indian states data. - * - * @return array - */ - private function getDataForIndia() - { - return [ - ['IN', 'AN', 'Andaman and Nicobar Islands'], - ['IN', 'AP', 'Andhra Pradesh'], - ['IN', 'AR', 'Arunachal Pradesh'], - ['IN', 'AS', 'Assam'], - ['IN', 'BR', 'Bihar'], - ['IN', 'CH', 'Chandigarh'], - ['IN', 'CT', 'Chhattisgarh'], - ['IN', 'DN', 'Dadra and Nagar Haveli'], - ['IN', 'DD', 'Daman and Diu'], - ['IN', 'DL', 'Delhi'], - ['IN', 'GA', 'Goa'], - ['IN', 'GJ', 'Gujarat'], - ['IN', 'HR', 'Haryana'], - ['IN', 'HP', 'Himachal Pradesh'], - ['IN', 'JK', 'Jammu and Kashmir'], - ['IN', 'JH', 'Jharkhand'], - ['IN', 'KA', 'Karnataka'], - ['IN', 'KL', 'Kerala'], - ['IN', 'LD', 'Lakshadweep'], - ['IN', 'MP', 'Madhya Pradesh'], - ['IN', 'MH', 'Maharashtra'], - ['IN', 'MN', 'Manipur'], - ['IN', 'ML', 'Meghalaya'], - ['IN', 'MZ', 'Mizoram'], - ['IN', 'NL', 'Nagaland'], - ['IN', 'OR', 'Odisha'], - ['IN', 'PY', 'Puducherry'], - ['IN', 'PB', 'Punjab'], - ['IN', 'RJ', 'Rajasthan'], - ['IN', 'SK', 'Sikkim'], - ['IN', 'TN', 'Tamil Nadu'], - ['IN', 'TG', 'Telangana'], - ['IN', 'TR', 'Tripura'], - ['IN', 'UP', 'Uttar Pradesh'], - ['IN', 'UT', 'Uttarakhand'], - ['IN', 'WB', 'West Bengal'] - ]; - } - - /** - * Add country regions data to appropriate tables. - * - * @param ModuleDataSetupInterface $setup - * @param array $data - * @return void - */ - private function addCountryRegions(ModuleDataSetupInterface $setup, array $data) - { - /** - * Fill table directory/country_region - * Fill table directory/country_region_name for en_US locale - */ - foreach ($data as $row) { - $bind = ['country_id' => $row[0], 'code' => $row[1], 'default_name' => $row[2]]; - $setup->getConnection()->insert($setup->getTable('directory_country_region'), $bind); - $regionId = $setup->getConnection()->lastInsertId($setup->getTable('directory_country_region')); - $bind = ['locale' => 'en_US', 'region_id' => $regionId, 'name' => $row[2]]; - $setup->getConnection()->insert($setup->getTable('directory_country_region_name'), $bind); - } - /** - * Upgrade core_config_data general/region/state_required field. - */ - $countries = $this->directoryData->getCountryCollection()->getCountriesWithRequiredStates(); - $setup->getConnection()->update( - $setup->getTable('core_config_data'), - [ - 'value' => implode(',', array_keys($countries)) - ], - [ - 'scope="default"', - 'scope_id=0', - 'path=?' => Data::XML_PATH_STATES_REQUIRED - ] - ); - } -} diff --git a/app/code/Magento/Directory/etc/db_schema.xml b/app/code/Magento/Directory/etc/db_schema.xml index 769c253d45f11..72fd929b98a07 100644 --- a/app/code/Magento/Directory/etc/db_schema.xml +++ b/app/code/Magento/Directory/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Directory/etc/module.xml b/app/code/Magento/Directory/etc/module.xml index a3735ca6ddde1..3a750db5e7cfd 100644 --- a/app/code/Magento/Directory/etc/module.xml +++ b/app/code/Magento/Directory/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/Product/Edit/Link.php b/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/Product/Edit/Link.php index 8ee93c37a7775..8d5f64e02be47 100644 --- a/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/Product/Edit/Link.php +++ b/app/code/Magento/Downloadable/Controller/Adminhtml/Downloadable/Product/Edit/Link.php @@ -7,6 +7,7 @@ namespace Magento\Downloadable\Controller\Adminhtml\Downloadable\Product\Edit; use Magento\Downloadable\Helper\Download as DownloadHelper; +use Magento\Framework\App\Response\Http as HttpResponse; class Link extends \Magento\Catalog\Controller\Adminhtml\Product\Edit { @@ -42,7 +43,9 @@ protected function _processDownload($resource, $resourceType) $fileName = $helper->getFilename(); $contentType = $helper->getContentType(); - $this->getResponse()->setHttpResponseCode( + /** @var HttpResponse $response */ + $response = $this->getResponse(); + $response->setHttpResponseCode( 200 )->setHeader( 'Pragma', @@ -59,16 +62,22 @@ protected function _processDownload($resource, $resourceType) ); if ($fileSize = $helper->getFileSize()) { - $this->getResponse()->setHeader('Content-Length', $fileSize); + $response->setHeader('Content-Length', $fileSize); } - - if ($contentDisposition = $helper->getContentDisposition()) { - $this->getResponse() - ->setHeader('Content-Disposition', $contentDisposition . '; filename=' . $fileName); + //Setting disposition as state in the config or forcing it for HTML. + /** @var string|null $contentDisposition */ + $contentDisposition = $helper->getContentDisposition(); + if (!$contentDisposition || $contentType === 'text/html') { + $contentDisposition = 'attachment'; } - - $this->getResponse()->clearBody(); - $this->getResponse()->sendHeaders(); + $response->setHeader( + 'Content-Disposition', + $contentDisposition . '; filename=' . $fileName + ); + //Rendering + $response->clearBody(); + $response->sendHeaders(); + $helper->output(); } diff --git a/app/code/Magento/Downloadable/Controller/Download.php b/app/code/Magento/Downloadable/Controller/Download.php index b2cf89c1af980..f0bef425d4b45 100644 --- a/app/code/Magento/Downloadable/Controller/Download.php +++ b/app/code/Magento/Downloadable/Controller/Download.php @@ -6,6 +6,7 @@ namespace Magento\Downloadable\Controller; use Magento\Downloadable\Helper\Download as DownloadHelper; +use Magento\Framework\App\Response\Http as HttpResponse; /** * Download controller @@ -14,6 +15,13 @@ */ abstract class Download extends \Magento\Framework\App\Action\Action { + /** + * @var array + */ + private $disallowedContentTypes = [ + 'text/html', + ]; + /** * Prepare response to output resource contents * @@ -28,9 +36,12 @@ protected function _processDownload($path, $resourceType) $helper->setResource($path, $resourceType); $fileName = $helper->getFilename(); + $contentType = $helper->getContentType(); - $this->getResponse()->setHttpResponseCode( + /** @var HttpResponse $response */ + $response = $this->getResponse(); + $response->setHttpResponseCode( 200 )->setHeader( 'Pragma', @@ -47,15 +58,19 @@ protected function _processDownload($path, $resourceType) ); if ($fileSize = $helper->getFileSize()) { - $this->getResponse()->setHeader('Content-Length', $fileSize); + $response->setHeader('Content-Length', $fileSize); } - if ($contentDisposition = $helper->getContentDisposition()) { - $this->getResponse()->setHeader('Content-Disposition', $contentDisposition . '; filename=' . $fileName); + $contentDisposition = $helper->getContentDisposition(); + if (!$contentDisposition || in_array($contentType, $this->disallowedContentTypes)) { + // For security reasons we force browsers to download the file instead of opening it. + $contentDisposition = \Zend_Mime::DISPOSITION_ATTACHMENT; } - $this->getResponse()->clearBody(); - $this->getResponse()->sendHeaders(); + $response->setHeader('Content-Disposition', $contentDisposition . '; filename=' . $fileName); + //Rendering + $response->clearBody(); + $response->sendHeaders(); $helper->output(); } diff --git a/app/code/Magento/Downloadable/Setup/InstallData.php b/app/code/Magento/Downloadable/Setup/InstallData.php deleted file mode 100644 index e015f3a23c191..0000000000000 --- a/app/code/Magento/Downloadable/Setup/InstallData.php +++ /dev/null @@ -1,178 +0,0 @@ -eavSetupFactory = $eavSetupFactory; - } - - /** - * {@inheritdoc} - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - /** - * Add attributes to the eav/attribute table - */ - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'links_purchased_separately', - [ - 'type' => 'int', - 'backend' => '', - 'frontend' => '', - 'label' => 'Links can be purchased separately', - 'input' => '', - 'class' => '', - 'source' => '', - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, - 'visible' => false, - 'required' => true, - 'user_defined' => false, - 'default' => '', - 'searchable' => false, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'unique' => false, - 'apply_to' => 'downloadable', - 'used_in_product_listing' => true - ] - ); - - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'samples_title', - [ - 'type' => 'varchar', - 'backend' => '', - 'frontend' => '', - 'label' => 'Samples title', - 'input' => '', - 'class' => '', - 'source' => '', - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, - 'visible' => false, - 'required' => true, - 'user_defined' => false, - 'default' => '', - 'searchable' => false, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'unique' => false, - 'apply_to' => 'downloadable' - ] - ); - - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'links_title', - [ - 'type' => 'varchar', - 'backend' => '', - 'frontend' => '', - 'label' => 'Links title', - 'input' => '', - 'class' => '', - 'source' => '', - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, - 'visible' => false, - 'required' => true, - 'user_defined' => false, - 'default' => '', - 'searchable' => false, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'unique' => false, - 'apply_to' => 'downloadable' - ] - ); - - $eavSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'links_exist', - [ - 'type' => 'int', - 'backend' => '', - 'frontend' => '', - 'label' => '', - 'input' => '', - 'class' => '', - 'source' => '', - 'global' => true, - 'visible' => false, - 'required' => false, - 'user_defined' => false, - 'default' => '0', - 'searchable' => false, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'unique' => false, - 'apply_to' => 'downloadable', - 'used_in_product_listing' => 1 - ] - ); - - $fieldList = [ - 'price', - 'special_price', - 'special_from_date', - 'special_to_date', - 'minimal_price', - 'cost', - 'tier_price', - 'weight', - ]; - - // make these attributes applicable to downloadable products - foreach ($fieldList as $field) { - $applyTo = explode( - ',', - $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field, 'apply_to') - ); - if (!in_array('downloadable', $applyTo)) { - $applyTo[] = 'downloadable'; - $eavSetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - $field, - 'apply_to', - implode(',', $applyTo) - ); - } - } - } -} diff --git a/app/code/Magento/Downloadable/Setup/Patch/Data/InstallDownloadableAttributes.php b/app/code/Magento/Downloadable/Setup/Patch/Data/InstallDownloadableAttributes.php new file mode 100644 index 0000000000000..9c101425e49ae --- /dev/null +++ b/app/code/Magento/Downloadable/Setup/Patch/Data/InstallDownloadableAttributes.php @@ -0,0 +1,206 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function apply() + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + /** + * Add attributes to the eav/attribute table + */ + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'links_purchased_separately', + [ + 'type' => 'int', + 'backend' => '', + 'frontend' => '', + 'label' => 'Links can be purchased separately', + 'input' => '', + 'class' => '', + 'source' => '', + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL, + 'visible' => false, + 'required' => true, + 'user_defined' => false, + 'default' => '', + 'searchable' => false, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'unique' => false, + 'apply_to' => 'downloadable', + 'used_in_product_listing' => true + ] + ); + + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'samples_title', + [ + 'type' => 'varchar', + 'backend' => '', + 'frontend' => '', + 'label' => 'Samples title', + 'input' => '', + 'class' => '', + 'source' => '', + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'visible' => false, + 'required' => true, + 'user_defined' => false, + 'default' => '', + 'searchable' => false, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'unique' => false, + 'apply_to' => 'downloadable' + ] + ); + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'links_title', + [ + 'type' => 'varchar', + 'backend' => '', + 'frontend' => '', + 'label' => 'Links title', + 'input' => '', + 'class' => '', + 'source' => '', + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, + 'visible' => false, + 'required' => true, + 'user_defined' => false, + 'default' => '', + 'searchable' => false, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'unique' => false, + 'apply_to' => 'downloadable' + ] + ); + $eavSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'links_exist', + [ + 'type' => 'int', + 'backend' => '', + 'frontend' => '', + 'label' => '', + 'input' => '', + 'class' => '', + 'source' => '', + 'global' => true, + 'visible' => false, + 'required' => false, + 'user_defined' => false, + 'default' => '0', + 'searchable' => false, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'unique' => false, + 'apply_to' => 'downloadable', + 'used_in_product_listing' => 1 + ] + ); + $fieldList = [ + 'price', + 'special_price', + 'special_from_date', + 'special_to_date', + 'minimal_price', + 'cost', + 'tier_price', + 'weight', + ]; + // make these attributes applicable to downloadable products + foreach ($fieldList as $field) { + $applyTo = explode( + ',', + $eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $field, 'apply_to') + ); + if (!in_array('downloadable', $applyTo)) { + $applyTo[] = 'downloadable'; + $eavSetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + $field, + 'apply_to', + implode(',', $applyTo) + ); + } + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/LinkTest.php b/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/LinkTest.php index e125ddee9c5d8..aa8b774ab5511 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/LinkTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Controller/Adminhtml/Downloadable/Product/Edit/LinkTest.php @@ -22,7 +22,7 @@ class LinkTest extends \PHPUnit\Framework\TestCase protected $request; /** - * @var \Magento\Framework\App\ResponseInterface + * @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $response; @@ -109,6 +109,8 @@ protected function setUp() */ public function testExecuteFile($fileType) { + $fileSize = 58493; + $fileName = 'link.jpg'; $this->request->expects($this->at(0))->method('getParam')->with('id', 0) ->will($this->returnValue(1)); $this->request->expects($this->at(1))->method('getParam')->with('type', 0) @@ -117,7 +119,20 @@ public function testExecuteFile($fileType) ->will($this->returnSelf()); $this->response->expects($this->once())->method('clearBody') ->will($this->returnSelf()); - $this->response->expects($this->any())->method('setHeader') + $this->response + ->expects($this->any()) + ->method('setHeader') + ->withConsecutive( + ['Pragma', 'public', true], + [ + 'Cache-Control', + 'must-revalidate, post-check=0, pre-check=0', + true, + ], + ['Content-type', 'text/html'], + ['Content-Length', $fileSize], + ['Content-Disposition', 'attachment; filename=' . $fileName] + ) ->will($this->returnSelf()); $this->response->expects($this->once())->method('sendHeaders') ->will($this->returnSelf()); @@ -132,13 +147,13 @@ public function testExecuteFile($fileType) $this->downloadHelper->expects($this->once())->method('setResource') ->will($this->returnSelf()); $this->downloadHelper->expects($this->once())->method('getFilename') - ->will($this->returnValue('link.jpg')); + ->will($this->returnValue($fileName)); $this->downloadHelper->expects($this->once())->method('getContentType') - ->will($this->returnSelf('file')); + ->willReturn('text/html'); $this->downloadHelper->expects($this->once())->method('getFileSize') - ->will($this->returnValue(null)); + ->will($this->returnValue($fileSize)); $this->downloadHelper->expects($this->once())->method('getContentDisposition') - ->will($this->returnValue(null)); + ->will($this->returnValue('inline')); $this->downloadHelper->expects($this->once())->method('output') ->will($this->returnSelf()); $this->linkModel->expects($this->once())->method('load') diff --git a/app/code/Magento/Downloadable/Test/Unit/Controller/Download/LinkTest.php b/app/code/Magento/Downloadable/Test/Unit/Controller/Download/LinkTest.php index 3e1255766f1f9..f2e288d75a40a 100644 --- a/app/code/Magento/Downloadable/Test/Unit/Controller/Download/LinkTest.php +++ b/app/code/Magento/Downloadable/Test/Unit/Controller/Download/LinkTest.php @@ -273,7 +273,13 @@ public function testGetLinkForWrongCustomer() $this->assertEquals($this->response, $this->link->execute()); } - public function testExceptionInUpdateLinkStatus() + /** + * @param string $mimeType + * @param string $disposition + * @dataProvider downloadTypesDataProvider + * @return void + */ + public function testExceptionInUpdateLinkStatus($mimeType, $disposition) { $this->objectManager->expects($this->at(0)) ->method('get') @@ -303,7 +309,7 @@ public function testExceptionInUpdateLinkStatus() $this->linkPurchasedItem->expects($this->once())->method('getLinkType')->willReturn('url'); $this->linkPurchasedItem->expects($this->once())->method('getLinkUrl')->willReturn('link_url'); - $this->processDownload('link_url', 'url'); + $this->processDownload('link_url', 'url', $mimeType, $disposition); $this->linkPurchasedItem->expects($this->any())->method('setNumberOfDownloadsUsed')->willReturnSelf(); $this->linkPurchasedItem->expects($this->any())->method('setStatus')->with('expired')->willReturnSelf(); @@ -317,8 +323,18 @@ public function testExceptionInUpdateLinkStatus() $this->assertEquals($this->response, $this->link->execute()); } - private function processDownload($resource, $resourceType) + /** + * @param string $resource + * @param string $resourceType + * @param string $mimeType + * @param string $disposition + * @return void + */ + private function processDownload($resource, $resourceType, $mimeType, $disposition) { + $fileSize = 58493; + $fileName = 'link.jpg'; + $this->objectManager->expects($this->at(3)) ->method('get') ->with(\Magento\Downloadable\Helper\Download::class) @@ -327,30 +343,23 @@ private function processDownload($resource, $resourceType) ->method('setResource') ->with($resource, $resourceType) ->willReturnSelf(); - $this->downloadHelper->expects($this->once())->method('getFilename')->willReturn('file_name'); - $this->downloadHelper->expects($this->once())->method('getContentType')->willReturn('content_type'); + $this->downloadHelper->expects($this->once())->method('getFilename')->willReturn($fileName); + $this->downloadHelper->expects($this->once())->method('getContentType')->willReturn($mimeType); $this->response->expects($this->once())->method('setHttpResponseCode')->with(200)->willReturnSelf(); - $this->response->expects($this->at(1))->method('setHeader')->with('Pragma', 'public', true)->willReturnSelf(); - $this->response->expects($this->at(2)) - ->method('setHeader') - ->with('Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true) - ->willReturnSelf(); - $this->response->expects($this->at(3)) + $this->response + ->expects($this->any()) ->method('setHeader') - ->with('Content-type', 'content_type', true) - ->willReturnSelf(); - $this->downloadHelper->expects($this->once())->method('getFileSize')->willReturn('file_size'); - $this->response->expects($this->at(4)) - ->method('setHeader') - ->with('Content-Length', 'file_size') - ->willReturnSelf(); - $this->downloadHelper->expects($this->once()) - ->method('getContentDisposition') - ->willReturn('content_disposition'); - $this->response->expects($this->at(5)) - ->method('setHeader') - ->with('Content-Disposition', 'content_disposition; filename=file_name') + ->withConsecutive( + ['Pragma', 'public', true], + ['Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true], + ['Content-type', $mimeType, true], + ['Content-Length', $fileSize], + ['Content-Disposition', $disposition . '; filename=' . $fileName] + ) ->willReturnSelf(); + + $this->downloadHelper->expects($this->once())->method('getContentDisposition')->willReturn($disposition); + $this->downloadHelper->expects($this->once())->method('getFileSize')->willReturn($fileSize); $this->response->expects($this->once())->method('clearBody')->willReturnSelf(); $this->response->expects($this->once())->method('sendHeaders')->willReturnSelf(); $this->downloadHelper->expects($this->once())->method('output'); @@ -394,6 +403,76 @@ public function testLinkNotAvailable($messageType, $status, $notice) $this->assertEquals($this->response, $this->link->execute()); } + /** + * @param string $mimeType + * @param string $disposition + * @dataProvider downloadTypesDataProvider + * @return void + */ + public function testContentDisposition($mimeType, $disposition) + { + $this->objectManager->expects($this->any()) + ->method('get') + ->willReturnMap([ + [ + \Magento\Customer\Model\Session::class, + $this->session, + ], + [ + \Magento\Downloadable\Helper\Data::class, + $this->helperData, + ], + [ + \Magento\Downloadable\Helper\Download::class, + $this->downloadHelper, + ], + ]); + + $this->request->expects($this->once())->method('getParam')->with('id', 0)->willReturn('some_id'); + $this->objectManager->expects($this->at(1)) + ->method('create') + ->with(\Magento\Downloadable\Model\Link\Purchased\Item::class) + ->willReturn($this->linkPurchasedItem); + $this->linkPurchasedItem->expects($this->once()) + ->method('load') + ->with('some_id', 'link_hash') + ->willReturnSelf(); + $this->linkPurchasedItem->expects($this->once())->method('getId')->willReturn(5); + $this->helperData->expects($this->once()) + ->method('getIsShareable') + ->with($this->linkPurchasedItem) + ->willReturn(true); + $this->linkPurchasedItem->expects($this->any())->method('getNumberOfDownloadsBought')->willReturn(10); + $this->linkPurchasedItem->expects($this->any())->method('getNumberOfDownloadsUsed')->willReturn(9); + $this->linkPurchasedItem->expects($this->once())->method('getStatus')->willReturn('available'); + $this->linkPurchasedItem->expects($this->once())->method('getLinkType')->willReturn('url'); + $this->linkPurchasedItem->expects($this->once())->method('getLinkUrl')->willReturn('link_url'); + + $fileSize = 58493; + $fileName = 'link.jpg'; + + $this->downloadHelper->expects($this->once()) + ->method('setResource') + ->with('link_url', 'url') + ->willReturnSelf(); + $this->downloadHelper->expects($this->once())->method('getFilename')->willReturn($fileName); + $this->downloadHelper->expects($this->once())->method('getContentType')->willReturn($mimeType); + $this->response->expects($this->once())->method('setHttpResponseCode')->with(200)->willReturnSelf(); + $this->response + ->expects($this->any()) + ->method('setHeader') + ->withConsecutive( + ['Pragma', 'public', true], + ['Cache-Control', 'must-revalidate, post-check=0, pre-check=0', true], + ['Content-type', $mimeType, true], + ['Content-Length', $fileSize], + ['Content-Disposition', $disposition . '; filename=' . $fileName] + ) + ->willReturnSelf(); + + $this->assertEquals($this->response, $this->link->execute()); + } + /** * @return array */ @@ -406,4 +485,15 @@ public function linkNotAvailableDataProvider() ['addError', 'wrong_status', 'Something went wrong while getting the requested content.'] ]; } + + /** + * @return array + */ + public function downloadTypesDataProvider() + { + return [ + ['mimeType' => 'text/html', 'disposition' => \Zend_Mime::DISPOSITION_ATTACHMENT], + ['mimeType' => 'image/jpeg', 'disposition' => \Zend_Mime::DISPOSITION_INLINE], + ]; + } } diff --git a/app/code/Magento/Downloadable/etc/db_schema.xml b/app/code/Magento/Downloadable/etc/db_schema.xml index 675c9a5c85679..ed25628bcffd9 100644 --- a/app/code/Magento/Downloadable/etc/db_schema.xml +++ b/app/code/Magento/Downloadable/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Downloadable/etc/module.xml b/app/code/Magento/Downloadable/etc/module.xml index 4c4e165feb014..72aadff621eca 100644 --- a/app/code/Magento/Downloadable/etc/module.xml +++ b/app/code/Magento/Downloadable/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml b/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml index 2515e5e339366..3ec6010218fb6 100644 --- a/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml +++ b/app/code/Magento/Downloadable/view/adminhtml/templates/product/edit/downloadable/links.phtml @@ -21,7 +21,7 @@
isSingleStoreMode() ? ' data-config-scope="' . __('[STORE VIEW]') . '"' : '' ?>>
- getStoreId() && $block->getUsedDefault()) ? 'disabled="disabled"' : '' ?>> + getStoreId() && $block->getUsedDefault()) ? 'disabled="disabled"' : '' ?>> getStoreId()): ?>
getUsedDefault() ? 'checked="checked"' : '' ?> /> @@ -158,9 +158,9 @@ require([ ''+ '
'+ '' + - '' + + '' + '"@example.com', + 'sender_email' => '""@example.com', + ], + [ + 'sender' => '"<script>alert(document.domain)</script>"@example.com', + 'sender_email' => '"<script>alert(document.domain)</script>"@example.com', + ], + ], + ]; + } +} diff --git a/app/code/Magento/Newsletter/etc/db_schema.xml b/app/code/Magento/Newsletter/etc/db_schema.xml index 35ee306a27df5..5084b8b6d01e7 100644 --- a/app/code/Magento/Newsletter/etc/db_schema.xml +++ b/app/code/Magento/Newsletter/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Newsletter/etc/module.xml b/app/code/Magento/Newsletter/etc/module.xml index 5da16a9a3e9ba..23e9d84b203cf 100644 --- a/app/code/Magento/Newsletter/etc/module.xml +++ b/app/code/Magento/Newsletter/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/OfflinePayments/etc/module.xml b/app/code/Magento/OfflinePayments/etc/module.xml index dfea6036c2e92..7388b5631aeb9 100644 --- a/app/code/Magento/OfflinePayments/etc/module.xml +++ b/app/code/Magento/OfflinePayments/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateQuoteShippingAddresses.php b/app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateQuoteShippingAddresses.php new file mode 100644 index 0000000000000..b89942230c50c --- /dev/null +++ b/app/code/Magento/OfflineShipping/Setup/Patch/Data/UpdateQuoteShippingAddresses.php @@ -0,0 +1,97 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + // setup default + $this->moduleDataSetup->getConnection()->startSetup(); + $connection = $this->moduleDataSetup->getConnection(); + $salesConnection = $this->moduleDataSetup->getConnection('sales'); + $checkoutConnection = $this->moduleDataSetup->getConnection('checkout'); + $connection->update( + $this->moduleDataSetup->getTable('salesrule'), + ['simple_free_shipping' => 0], + [new \Zend_Db_Expr('simple_free_shipping IS NULL')] + ); + $this->moduleDataSetup->getConnection()->endSetup(); + + // setup sales + $salesConnection->startSetup(); + $salesConnection->update( + $this->moduleDataSetup->getTable('sales_order_item'), + ['free_shipping' => 0], + [new \Zend_Db_Expr('free_shipping IS NULL')] + ); + $salesConnection->endSetup(); + + // setup checkout + $checkoutConnection->startSetup(); + $checkoutConnection->update( + $this->moduleDataSetup->getTable('quote_address'), + ['free_shipping' => 0], + [new \Zend_Db_Expr('free_shipping IS NULL')] + ); + $checkoutConnection->update( + $this->moduleDataSetup->getTable('quote_item'), + ['free_shipping' => 0], + [new \Zend_Db_Expr('free_shipping IS NULL')] + ); + $checkoutConnection->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/OfflineShipping/Setup/UpgradeData.php b/app/code/Magento/OfflineShipping/Setup/UpgradeData.php deleted file mode 100644 index f0a11c66ca6de..0000000000000 --- a/app/code/Magento/OfflineShipping/Setup/UpgradeData.php +++ /dev/null @@ -1,69 +0,0 @@ -startSetup(); - if ($context->getVersion() && version_compare($context->getVersion(), '2.0.1') < 0) { - $this->updateQuoteShippingAddresses($setup); - } - $setup->endSetup(); - } - - /** - * Replace Null with '0' for 'free_shipping' and 'simple_free_shipping' accordingly to upgraded schema. - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function updateQuoteShippingAddresses(ModuleDataSetupInterface $setup) - { - $setup->getConnection()->update( - $setup->getTable('salesrule'), - ['simple_free_shipping' => 0], - [new \Zend_Db_Expr('simple_free_shipping IS NULL')] - ); - $setup->getConnection($this->salesConnectionName)->update( - $setup->getTable('sales_order_item'), - ['free_shipping' => 0], - [new \Zend_Db_Expr('free_shipping IS NULL')] - ); - $setup->getConnection($this->quoteConnectionName)->update( - $setup->getTable('quote_address'), - ['free_shipping' => 0], - [new \Zend_Db_Expr('free_shipping IS NULL')] - ); - $setup->getConnection($this->quoteConnectionName)->update( - $setup->getTable('quote_item'), - ['free_shipping' => 0], - [new \Zend_Db_Expr('free_shipping IS NULL')] - ); - } -} diff --git a/app/code/Magento/OfflineShipping/etc/db_schema.xml b/app/code/Magento/OfflineShipping/etc/db_schema.xml index 4e277cb80bd21..1a4ecd89582c6 100644 --- a/app/code/Magento/OfflineShipping/etc/db_schema.xml +++ b/app/code/Magento/OfflineShipping/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/OfflineShipping/etc/module.xml b/app/code/Magento/OfflineShipping/etc/module.xml index 7df8c8cc0db75..c65f99d59c9c5 100644 --- a/app/code/Magento/OfflineShipping/etc/module.xml +++ b/app/code/Magento/OfflineShipping/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/PageCache/etc/module.xml b/app/code/Magento/PageCache/etc/module.xml index 53420ac17d93e..17e83e7cff7d4 100644 --- a/app/code/Magento/PageCache/etc/module.xml +++ b/app/code/Magento/PageCache/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Payment/etc/module.xml b/app/code/Magento/Payment/etc/module.xml index 5593a94ca0d91..ece160e6ae3eb 100644 --- a/app/code/Magento/Payment/etc/module.xml +++ b/app/code/Magento/Payment/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Paypal/Setup/InstallData.php b/app/code/Magento/Paypal/Setup/InstallData.php deleted file mode 100644 index 688d7dabb2ceb..0000000000000 --- a/app/code/Magento/Paypal/Setup/InstallData.php +++ /dev/null @@ -1,83 +0,0 @@ -salesSetupFactory = $salesSetupFactory; - $this->quoteSetupFactory = $quoteSetupFactory; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** - * Prepare database for install - */ - $setup->startSetup(); - - $quoteInstaller = $this->quoteSetupFactory->create(['resourceName' => 'quote_setup', 'setup' => $setup]); - $salesInstaller = $this->salesSetupFactory->create(['resourceName' => 'sales_setup', 'setup' => $setup]); - /** - * Add paypal attributes to the: - * - sales/flat_quote_payment_item table - * - sales/flat_order table - */ - $quoteInstaller->addAttribute('quote_payment', 'paypal_payer_id', []); - $quoteInstaller->addAttribute('quote_payment', 'paypal_payer_status', []); - $quoteInstaller->addAttribute('quote_payment', 'paypal_correlation_id', []); - $salesInstaller->addAttribute( - 'order', - 'paypal_ipn_customer_notified', - ['type' => 'int', 'visible' => false, 'default' => 0] - ); - - $data = []; - $statuses = [ - 'pending_paypal' => __('Pending PayPal'), - 'paypal_reversed' => __('PayPal Reversed'), - 'paypal_canceled_reversal' => __('PayPal Canceled Reversal'), - ]; - foreach ($statuses as $code => $info) { - $data[] = ['status' => $code, 'label' => $info]; - } - $setup->getConnection() - ->insertArray($setup->getTable('sales_order_status'), ['status', 'label'], $data); - - /** - * Prepare database after install - */ - $setup->endSetup(); - } -} diff --git a/app/code/Magento/Paypal/Setup/Patch/Data/AddPaypalOrderStatuses.php b/app/code/Magento/Paypal/Setup/Patch/Data/AddPaypalOrderStatuses.php new file mode 100644 index 0000000000000..495b7618cce49 --- /dev/null +++ b/app/code/Magento/Paypal/Setup/Patch/Data/AddPaypalOrderStatuses.php @@ -0,0 +1,120 @@ +moduleDataSetup = $moduleDataSetup; + $this->quoteSetupFactory = $quoteSetupFactory; + $this->salesSetupFactory = $salesSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** + * Prepare database for install + */ + $this->moduleDataSetup->getConnection()->startSetup(); + + $quoteInstaller = $this->quoteSetupFactory->create(); + $salesInstaller = $this->salesSetupFactory->create(); + /** + * Add paypal attributes to the: + * - sales/flat_quote_payment_item table + * - sales/flat_order table + */ + $quoteInstaller->addAttribute('quote_payment', 'paypal_payer_id', []); + $quoteInstaller->addAttribute('quote_payment', 'paypal_payer_status', []); + $quoteInstaller->addAttribute('quote_payment', 'paypal_correlation_id', []); + $salesInstaller->addAttribute( + 'order', + 'paypal_ipn_customer_notified', + ['type' => 'int', 'visible' => false, 'default' => 0] + ); + $data = []; + $statuses = [ + 'pending_paypal' => __('Pending PayPal'), + 'paypal_reversed' => __('PayPal Reversed'), + 'paypal_canceled_reversal' => __('PayPal Canceled Reversal'), + ]; + foreach ($statuses as $code => $info) { + $data[] = ['status' => $code, 'label' => $info]; + } + $this->moduleDataSetup->getConnection()->insertArray( + $this->moduleDataSetup->getTable('sales_order_status'), + ['status', 'label'], + $data + ); + /** + * Prepare database after install + */ + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Paypal/etc/db_schema.xml b/app/code/Magento/Paypal/etc/db_schema.xml index 5d9a1faa2675e..f6f5448dbc2f0 100644 --- a/app/code/Magento/Paypal/etc/db_schema.xml +++ b/app/code/Magento/Paypal/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Paypal/etc/module.xml b/app/code/Magento/Paypal/etc/module.xml index 056fc1a80e8ac..3049d9a2891b4 100644 --- a/app/code/Magento/Paypal/etc/module.xml +++ b/app/code/Magento/Paypal/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Persistent/etc/db_schema.xml b/app/code/Magento/Persistent/etc/db_schema.xml index 5035f3332ea4c..31adf5be6f0c4 100644 --- a/app/code/Magento/Persistent/etc/db_schema.xml +++ b/app/code/Magento/Persistent/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Persistent/etc/module.xml b/app/code/Magento/Persistent/etc/module.xml index 452130810c4bb..4f6e0744ce6ef 100644 --- a/app/code/Magento/Persistent/etc/module.xml +++ b/app/code/Magento/Persistent/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/ProductAlert/etc/db_schema.xml b/app/code/Magento/ProductAlert/etc/db_schema.xml index 8aa149277c62a..ddf8be8a37e9c 100644 --- a/app/code/Magento/ProductAlert/etc/db_schema.xml +++ b/app/code/Magento/ProductAlert/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/ProductAlert/etc/module.xml b/app/code/Magento/ProductAlert/etc/module.xml index 699faf4b9133b..4d519294ae7ab 100644 --- a/app/code/Magento/ProductAlert/etc/module.xml +++ b/app/code/Magento/ProductAlert/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/ProductVideo/etc/db_schema.xml b/app/code/Magento/ProductVideo/etc/db_schema.xml index b17252ecf127d..ceaf4d7fbd85d 100644 --- a/app/code/Magento/ProductVideo/etc/db_schema.xml +++ b/app/code/Magento/ProductVideo/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
- + diff --git a/app/code/Magento/Quote/Setup/InstallData.php b/app/code/Magento/Quote/Setup/InstallData.php deleted file mode 100644 index f039c15797c27..0000000000000 --- a/app/code/Magento/Quote/Setup/InstallData.php +++ /dev/null @@ -1,59 +0,0 @@ -quoteSetupFactory = $setupFactory; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var QuoteSetup $quoteSetup */ - $quoteSetup = $this->quoteSetupFactory->create(['setup' => $setup]); - - /** - * Install eav entity types to the eav/entity_type table - */ - $attributes = [ - 'vat_id' => ['type' => Table::TYPE_TEXT], - 'vat_is_valid' => ['type' => Table::TYPE_SMALLINT], - 'vat_request_id' => ['type' => Table::TYPE_TEXT], - 'vat_request_date' => ['type' => Table::TYPE_TEXT], - 'vat_request_success' => ['type' => Table::TYPE_SMALLINT], - ]; - - foreach ($attributes as $attributeCode => $attributeParams) { - $quoteSetup->addAttribute('quote_address', $attributeCode, $attributeParams); - } - } -} diff --git a/app/code/Magento/Quote/Setup/Patch/Data/ConvertSerializedDataToJson.php b/app/code/Magento/Quote/Setup/Patch/Data/ConvertSerializedDataToJson.php new file mode 100644 index 0000000000000..f537280272227 --- /dev/null +++ b/app/code/Magento/Quote/Setup/Patch/Data/ConvertSerializedDataToJson.php @@ -0,0 +1,84 @@ +moduleDataSetup = $moduleDataSetup; + $this->quoteSetupFactory = $quoteSetupFactory; + $this->convertSerializedDataToJsonFactory = $convertSerializedDataToJsonFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $quoteSetup = $this->quoteSetupFactory->create(); + $this->convertSerializedDataToJsonFactory->create(['quoteSetup' => $quoteSetup])->convert(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + InstallEntityTypes::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.6'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Quote/Setup/Patch/Data/InstallEntityTypes.php b/app/code/Magento/Quote/Setup/Patch/Data/InstallEntityTypes.php new file mode 100644 index 0000000000000..24ff3ecad58e6 --- /dev/null +++ b/app/code/Magento/Quote/Setup/Patch/Data/InstallEntityTypes.php @@ -0,0 +1,90 @@ +moduleDataSetup = $moduleDataSetup; + $this->quoteSetupFactory = $quoteSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var QuoteSetup $quoteSetup */ + $quoteSetup = $this->quoteSetupFactory->create(['setup' => $this->moduleDataSetup]); + + /** + * Install eav entity types to the eav/entity_type table + */ + $attributes = [ + 'vat_id' => ['type' => Table::TYPE_TEXT], + 'vat_is_valid' => ['type' => Table::TYPE_SMALLINT], + 'vat_request_id' => ['type' => Table::TYPE_TEXT], + 'vat_request_date' => ['type' => Table::TYPE_TEXT], + 'vat_request_success' => ['type' => Table::TYPE_SMALLINT], + ]; + foreach ($attributes as $attributeCode => $attributeParams) { + $quoteSetup->addAttribute('quote_address', $attributeCode, $attributeParams); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Quote/Setup/UpgradeData.php b/app/code/Magento/Quote/Setup/UpgradeData.php deleted file mode 100644 index fde232c2e593b..0000000000000 --- a/app/code/Magento/Quote/Setup/UpgradeData.php +++ /dev/null @@ -1,49 +0,0 @@ -quoteSetupFactory = $quoteSetupFactory; - $this->convertSerializedDataToJsonFactory = $convertSerializedDataToJsonFactory; - } - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - if (version_compare($context->getVersion(), '2.0.6', '<')) { - $quoteSetup = $this->quoteSetupFactory->create(['setup' => $setup]); - $this->convertSerializedDataToJsonFactory->create(['quoteSetup' => $quoteSetup]) - ->convert(); - } - } -} diff --git a/app/code/Magento/Quote/etc/db_schema.xml b/app/code/Magento/Quote/etc/db_schema.xml index 3d76bee3da760..ff127b9c06f0e 100644 --- a/app/code/Magento/Quote/etc/db_schema.xml +++ b/app/code/Magento/Quote/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Quote/etc/module.xml b/app/code/Magento/Quote/etc/module.xml index 6607dea5809b1..852100221b563 100644 --- a/app/code/Magento/Quote/etc/module.xml +++ b/app/code/Magento/Quote/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/QuoteAnalytics/etc/module.xml b/app/code/Magento/QuoteAnalytics/etc/module.xml index d72e36b748748..947a792547143 100644 --- a/app/code/Magento/QuoteAnalytics/etc/module.xml +++ b/app/code/Magento/QuoteAnalytics/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/ReleaseNotification/etc/db_schema.xml b/app/code/Magento/ReleaseNotification/etc/db_schema.xml index 5574f1722b4cf..367957fc17732 100644 --- a/app/code/Magento/ReleaseNotification/etc/db_schema.xml +++ b/app/code/Magento/ReleaseNotification/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
- + diff --git a/app/code/Magento/Reports/Setup/InstallData.php b/app/code/Magento/Reports/Setup/InstallData.php deleted file mode 100644 index 2ef7f9507380d..0000000000000 --- a/app/code/Magento/Reports/Setup/InstallData.php +++ /dev/null @@ -1,96 +0,0 @@ -pageFactory = $pageFactory; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - /* - * Report Event Types default data - */ - $eventTypeData = [ - [ - 'event_type_id' => \Magento\Reports\Model\Event::EVENT_PRODUCT_VIEW, - 'event_name' => 'catalog_product_view' - ], - ['event_type_id' => \Magento\Reports\Model\Event::EVENT_PRODUCT_SEND, 'event_name' => 'sendfriend_product'], - [ - 'event_type_id' => \Magento\Reports\Model\Event::EVENT_PRODUCT_COMPARE, - 'event_name' => 'catalog_product_compare_add_product' - ], - [ - 'event_type_id' => \Magento\Reports\Model\Event::EVENT_PRODUCT_TO_CART, - 'event_name' => 'checkout_cart_add_product' - ], - [ - 'event_type_id' => \Magento\Reports\Model\Event::EVENT_PRODUCT_TO_WISHLIST, - 'event_name' => 'wishlist_add_product' - ], - ['event_type_id' => \Magento\Reports\Model\Event::EVENT_WISHLIST_SHARE, 'event_name' => 'wishlist_share'], - ]; - - foreach ($eventTypeData as $row) { - $setup->getConnection() - ->insertForce($setup->getTable('report_event_types'), $row); - } - - /** - * Prepare database after data upgrade - */ - $setup->endSetup(); - - /** - * Cms Page with 'home' identifier page modification for report pages - */ - /** @var $cms \Magento\Cms\Model\Page */ - $cms = $this->pageFactory->create(); - $cms->load('home', 'identifier'); - - // @codingStandardsIgnoreStart - $reportLayoutUpdate = ''; - // @codingStandardsIgnoreEnd - - /* - * Merge and save old layout update data with report layout data - */ - $cms->setLayoutUpdateXml($cms->getLayoutUpdateXml() . $reportLayoutUpdate) - ->save(); - } -} diff --git a/app/code/Magento/Reports/Setup/Patch/Data/InitializeReportEntityTypesAndPages.php b/app/code/Magento/Reports/Setup/Patch/Data/InitializeReportEntityTypesAndPages.php new file mode 100644 index 0000000000000..77824689b8557 --- /dev/null +++ b/app/code/Magento/Reports/Setup/Patch/Data/InitializeReportEntityTypesAndPages.php @@ -0,0 +1,123 @@ +moduleDataSetup = $moduleDataSetup; + $this->pageFactory = $pageFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + /* + * Report Event Types default data + */ + $eventTypeData = [ + [ + 'event_type_id' => \Magento\Reports\Model\Event::EVENT_PRODUCT_VIEW, + 'event_name' => 'catalog_product_view' + ], + ['event_type_id' => \Magento\Reports\Model\Event::EVENT_PRODUCT_SEND, 'event_name' => 'sendfriend_product'], + [ + 'event_type_id' => \Magento\Reports\Model\Event::EVENT_PRODUCT_COMPARE, + 'event_name' => 'catalog_product_compare_add_product' + ], + [ + 'event_type_id' => \Magento\Reports\Model\Event::EVENT_PRODUCT_TO_CART, + 'event_name' => 'checkout_cart_add_product' + ], + [ + 'event_type_id' => \Magento\Reports\Model\Event::EVENT_PRODUCT_TO_WISHLIST, + 'event_name' => 'wishlist_add_product' + ], + ['event_type_id' => \Magento\Reports\Model\Event::EVENT_WISHLIST_SHARE, 'event_name' => 'wishlist_share'], + ]; + + foreach ($eventTypeData as $row) { + $this->moduleDataSetup->getConnection() + ->insertForce($this->moduleDataSetup->getTable('report_event_types'), $row); + } + /** + * Prepare database after data upgrade + */ + $this->moduleDataSetup->getConnection()->endSetup(); + /** + * Cms Page with 'home' identifier page modification for report pages + */ + /** @var $cms \Magento\Cms\Model\Page */ + $cms = $this->pageFactory->create(); + $cms->load('home', 'identifier'); + // @codingStandardsIgnoreStart + $reportLayoutUpdate = ''; + // @codingStandardsIgnoreEnd + /* + * Merge and save old layout update data with report layout data + */ + $cms->setLayoutUpdateXml($cms->getLayoutUpdateXml() . $reportLayoutUpdate) + ->save(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Reports/etc/db_schema.xml b/app/code/Magento/Reports/etc/db_schema.xml index 7b19d0bc7266b..f6c8074411bfc 100644 --- a/app/code/Magento/Reports/etc/db_schema.xml +++ b/app/code/Magento/Reports/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
- + diff --git a/app/code/Magento/RequireJs/Model/FileManager.php b/app/code/Magento/RequireJs/Model/FileManager.php index 019c2cbedb75c..ec41c4238967f 100644 --- a/app/code/Magento/RequireJs/Model/FileManager.php +++ b/app/code/Magento/RequireJs/Model/FileManager.php @@ -183,6 +183,9 @@ public function createBundleJsPool() } foreach ($libDir->read($bundleDir) as $bundleFile) { + if (pathinfo($bundleFile, PATHINFO_EXTENSION) !== 'js') { + continue; + } $relPath = $libDir->getRelativePath($bundleFile); $bundles[] = $this->assetRepo->createArbitrary($relPath, ''); } diff --git a/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php b/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php index 6b6d709cbb608..834ee5b68485e 100644 --- a/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php +++ b/app/code/Magento/RequireJs/Test/Unit/Model/FileManagerTest.php @@ -153,7 +153,7 @@ public function testCreateBundleJsPool() ->expects($this->once()) ->method('read') ->with('path/to/bundle/dir/js/bundle') - ->willReturn(['bundle1.js', 'bundle2.js']); + ->willReturn(['bundle1.js', 'bundle2.js', 'some_file.not_js']); $dirRead ->expects($this->exactly(2)) ->method('getRelativePath') diff --git a/app/code/Magento/RequireJs/etc/module.xml b/app/code/Magento/RequireJs/etc/module.xml index 7935092e2c9b0..e2b8db50762df 100644 --- a/app/code/Magento/RequireJs/etc/module.xml +++ b/app/code/Magento/RequireJs/etc/module.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/app/code/Magento/Review/Setup/InstallData.php b/app/code/Magento/Review/Setup/InstallData.php deleted file mode 100644 index 8e9e60d3d64df..0000000000000 --- a/app/code/Magento/Review/Setup/InstallData.php +++ /dev/null @@ -1,76 +0,0 @@ -getConnection()->insert($installer->getTable('review_entity'), ['entity_code' => $entityCode]); - } - - //Fill table review/review_entity - $reviewStatuses = [ - \Magento\Review\Model\Review::STATUS_APPROVED => 'Approved', - \Magento\Review\Model\Review::STATUS_PENDING => 'Pending', - \Magento\Review\Model\Review::STATUS_NOT_APPROVED => 'Not Approved', - ]; - foreach ($reviewStatuses as $k => $v) { - $bind = ['status_id' => $k, 'status_code' => $v]; - $installer->getConnection()->insertForce($installer->getTable('review_status'), $bind); - } - - $data = [ - \Magento\Review\Model\Rating::ENTITY_PRODUCT_CODE => [ - ['rating_code' => 'Quality', 'position' => 0], - ['rating_code' => 'Value', 'position' => 0], - ['rating_code' => 'Price', 'position' => 0], - ], - \Magento\Review\Model\Rating::ENTITY_PRODUCT_REVIEW_CODE => [], - \Magento\Review\Model\Rating::ENTITY_REVIEW_CODE => [], - ]; - - foreach ($data as $entityCode => $ratings) { - //Fill table rating/rating_entity - $installer->getConnection()->insert($installer->getTable('rating_entity'), ['entity_code' => $entityCode]); - $entityId = $installer->getConnection()->lastInsertId($installer->getTable('rating_entity')); - - foreach ($ratings as $bind) { - //Fill table rating/rating - $bind['entity_id'] = $entityId; - $installer->getConnection()->insert($installer->getTable('rating'), $bind); - - //Fill table rating/rating_option - $ratingId = $installer->getConnection()->lastInsertId($installer->getTable('rating')); - $optionData = []; - for ($i = 1; $i <= 5; $i++) { - $optionData[] = ['rating_id' => $ratingId, 'code' => (string)$i, 'value' => $i, 'position' => $i]; - } - $installer->getConnection()->insertMultiple($installer->getTable('rating_option'), $optionData); - } - } - } -} diff --git a/app/code/Magento/Review/Setup/Patch/Data/InitReviewStatusesAndData.php b/app/code/Magento/Review/Setup/Patch/Data/InitReviewStatusesAndData.php new file mode 100644 index 0000000000000..0ad7042668c0e --- /dev/null +++ b/app/code/Magento/Review/Setup/Patch/Data/InitReviewStatusesAndData.php @@ -0,0 +1,124 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + //Fill table review/review_entity + $reviewEntityCodes = [ + \Magento\Review\Model\Review::ENTITY_PRODUCT_CODE, + \Magento\Review\Model\Review::ENTITY_CUSTOMER_CODE, + \Magento\Review\Model\Review::ENTITY_CATEGORY_CODE, + ]; + foreach ($reviewEntityCodes as $entityCode) { + $this->moduleDataSetup->getConnection()->insert( + $this->moduleDataSetup->getTable('review_entity'), + ['entity_code' => $entityCode] + ); + } + //Fill table review/review_entity + $reviewStatuses = [ + \Magento\Review\Model\Review::STATUS_APPROVED => 'Approved', + \Magento\Review\Model\Review::STATUS_PENDING => 'Pending', + \Magento\Review\Model\Review::STATUS_NOT_APPROVED => 'Not Approved', + ]; + foreach ($reviewStatuses as $k => $v) { + $bind = ['status_id' => $k, 'status_code' => $v]; + $this->moduleDataSetup->getConnection()->insertForce( + $this->moduleDataSetup->getTable('review_status'), + $bind + ); + } + $data = [ + \Magento\Review\Model\Rating::ENTITY_PRODUCT_CODE => [ + ['rating_code' => 'Quality', 'position' => 0], + ['rating_code' => 'Value', 'position' => 0], + ['rating_code' => 'Price', 'position' => 0], + ], + \Magento\Review\Model\Rating::ENTITY_PRODUCT_REVIEW_CODE => [], + \Magento\Review\Model\Rating::ENTITY_REVIEW_CODE => [], + ]; + foreach ($data as $entityCode => $ratings) { + //Fill table rating/rating_entity + $this->moduleDataSetup->getConnection()->insert( + $this->moduleDataSetup->getTable('rating_entity'), + ['entity_code' => $entityCode] + ); + $entityId = $this->moduleDataSetup->getConnection()->lastInsertId( + $this->moduleDataSetup->getTable('rating_entity') + ); + foreach ($ratings as $bind) { + //Fill table rating/rating + $bind['entity_id'] = $entityId; + $this->moduleDataSetup->getConnection()->insert( + $this->moduleDataSetup->getTable('rating'), + $bind + ); + //Fill table rating/rating_option + $ratingId = $this->moduleDataSetup->getConnection()->lastInsertId( + $this->moduleDataSetup->getTable('rating') + ); + $optionData = []; + for ($i = 1; $i <= 5; $i++) { + $optionData[] = ['rating_id' => $ratingId, 'code' => (string)$i, 'value' => $i, 'position' => $i]; + } + $this->moduleDataSetup->getConnection()->insertMultiple( + $this->moduleDataSetup->getTable('rating_option'), + $optionData + ); + } + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Review/etc/db_schema.xml b/app/code/Magento/Review/etc/db_schema.xml index 0db686d16ed61..1a2ff588180ce 100644 --- a/app/code/Magento/Review/etc/db_schema.xml +++ b/app/code/Magento/Review/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Review/etc/module.xml b/app/code/Magento/Review/etc/module.xml index 3f2431edd1707..9ce62a8a0c646 100644 --- a/app/code/Magento/Review/etc/module.xml +++ b/app/code/Magento/Review/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Review/view/adminhtml/web/js/rating.js b/app/code/Magento/Review/view/adminhtml/web/js/rating.js index cc72d386dc053..b8d1b1b241b8f 100644 --- a/app/code/Magento/Review/view/adminhtml/web/js/rating.js +++ b/app/code/Magento/Review/view/adminhtml/web/js/rating.js @@ -27,7 +27,7 @@ define([ _bind: function () { this._labels.on({ click: $.proxy(function (e) { - $('[id="' + $(e.currentTarget).attr('for') + '"]').prop('checked', true); + $(e.currentTarget).prev().prop('checked', true); this._updateRating(); }, this), diff --git a/app/code/Magento/ReviewAnalytics/etc/module.xml b/app/code/Magento/ReviewAnalytics/etc/module.xml index 65df87bac4af1..ce2f870f2be79 100644 --- a/app/code/Magento/ReviewAnalytics/etc/module.xml +++ b/app/code/Magento/ReviewAnalytics/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Robots/etc/module.xml b/app/code/Magento/Robots/etc/module.xml index ab04dfb7486f7..6a6b36a66c778 100644 --- a/app/code/Magento/Robots/etc/module.xml +++ b/app/code/Magento/Robots/etc/module.xml @@ -7,7 +7,7 @@ --> - + diff --git a/app/code/Magento/Rss/Model/Rss.php b/app/code/Magento/Rss/Model/Rss.php index 7461c780fb230..96f71133cb832 100644 --- a/app/code/Magento/Rss/Model/Rss.php +++ b/app/code/Magento/Rss/Model/Rss.php @@ -8,6 +8,7 @@ use Magento\Framework\App\ObjectManager; use Magento\Framework\App\Rss\DataProviderInterface; use Magento\Framework\Serialize\SerializerInterface; +use Zend\Feed\Writer\FeedFactory; /** * Provides functionality to work with RSS feeds @@ -92,7 +93,7 @@ public function setDataProvider(DataProviderInterface $dataProvider) */ public function createRssXml() { - $rssFeedFromArray = \Zend_Feed::importArray($this->getFeeds(), 'rss'); - return $rssFeedFromArray->saveXML(); + $feed = FeedFactory::factory($this->getFeeds()); + return $feed->export('rss'); } } diff --git a/app/code/Magento/Rss/Test/Unit/Controller/Adminhtml/Feed/IndexTest.php b/app/code/Magento/Rss/Test/Unit/Controller/Adminhtml/Feed/IndexTest.php index 32aab6ffb92bc..58fd541bab8cb 100644 --- a/app/code/Magento/Rss/Test/Unit/Controller/Adminhtml/Feed/IndexTest.php +++ b/app/code/Magento/Rss/Test/Unit/Controller/Adminhtml/Feed/IndexTest.php @@ -6,6 +6,7 @@ namespace Magento\Rss\Test\Unit\Controller\Adminhtml\Feed; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Zend\Feed\Writer\Exception\InvalidArgumentException; /** * Class IndexTest @@ -110,7 +111,7 @@ public function testExecuteWithException() $this->rssFactory->expects($this->once())->method('create')->will($this->returnValue($rssModel)); $this->rssManager->expects($this->once())->method('getProvider')->will($this->returnValue($dataProvider)); - $this->expectException('\Zend_Feed_Builder_Exception'); + $this->expectException(InvalidArgumentException::class); $this->controller->execute(); } } diff --git a/app/code/Magento/Rss/Test/Unit/Controller/Feed/IndexTest.php b/app/code/Magento/Rss/Test/Unit/Controller/Feed/IndexTest.php index 71802deee0a8d..e8f7a85382f27 100644 --- a/app/code/Magento/Rss/Test/Unit/Controller/Feed/IndexTest.php +++ b/app/code/Magento/Rss/Test/Unit/Controller/Feed/IndexTest.php @@ -6,6 +6,7 @@ namespace Magento\Rss\Test\Unit\Controller\Feed; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Zend\Feed\Writer\Exception\InvalidArgumentException; /** * Class IndexTest @@ -97,7 +98,7 @@ public function testExecuteWithException() $this->rssFactory->expects($this->once())->method('create')->will($this->returnValue($rssModel)); $this->rssManager->expects($this->once())->method('getProvider')->will($this->returnValue($dataProvider)); - $this->expectException('\Zend_Feed_Builder_Exception'); + $this->expectException(InvalidArgumentException::class); $this->controller->execute(); } } diff --git a/app/code/Magento/Rss/Test/Unit/Model/RssTest.php b/app/code/Magento/Rss/Test/Unit/Model/RssTest.php index 6f98b9f202e30..34f9940556a93 100644 --- a/app/code/Magento/Rss/Test/Unit/Model/RssTest.php +++ b/app/code/Magento/Rss/Test/Unit/Model/RssTest.php @@ -119,11 +119,11 @@ public function testCreateRssXml() $this->rss->setDataProvider($dataProvider); $result = $this->rss->createRssXml(); $this->assertContains('', $result); - $this->assertContains('<![CDATA[Feed Title]]>', $result); - $this->assertContains('<![CDATA[Feed 1 Title]]>', $result); + $this->assertContains('Feed Title', $result); + $this->assertContains('Feed 1 Title', $result); $this->assertContains('http://magento.com/rss/link', $result); $this->assertContains('http://magento.com/rss/link/id/1', $result); - $this->assertContains('', $result); + $this->assertContains('Feed Description', $result); $this->assertContains('', $result); } } diff --git a/app/code/Magento/Rss/etc/module.xml b/app/code/Magento/Rss/etc/module.xml index c0daf630f75e8..196d8c3ac5655 100644 --- a/app/code/Magento/Rss/etc/module.xml +++ b/app/code/Magento/Rss/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/Rule/etc/module.xml b/app/code/Magento/Rule/etc/module.xml index f5e43eaed237b..ee1bd4605c85e 100644 --- a/app/code/Magento/Rule/etc/module.xml +++ b/app/code/Magento/Rule/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/Save.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/Save.php index 74b7ad2165332..621705c7937cb 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/Save.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create/Save.php @@ -63,6 +63,8 @@ public function execute() } $resultRedirect->setPath('sales/*/'); } catch (\Magento\Framework\Exception\LocalizedException $e) { + // customer can be created before place order flow is completed and should be stored in current session + $this->_getSession()->setCustomerId($this->_getSession()->getQuote()->getCustomerId()); $message = $e->getMessage(); if (!empty($message)) { $this->messageManager->addError($message); diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index ebe0aa6a20368..679693abd5540 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -14,6 +14,7 @@ use Magento\Quote\Model\Quote\Item; use Magento\Sales\Api\Data\OrderAddressInterface; use Magento\Sales\Model\Order; +use Psr\Log\LoggerInterface; /** * Order create model @@ -1996,9 +1997,13 @@ protected function _validate() } } if (!empty($this->_errors)) { + /** @var LoggerInterface $logger */ + $logger = ObjectManager::getInstance()->get(LoggerInterface::class); foreach ($this->_errors as $error) { + $logger->error($error); $this->messageManager->addError($error); } + throw new \Magento\Framework\Exception\LocalizedException(__('Validation is failed.')); } diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender.php b/app/code/Magento/Sales/Model/Order/Email/Sender.php index 8ada6a3f321d2..6d4480c4c45e0 100644 --- a/app/code/Magento/Sales/Model/Order/Email/Sender.php +++ b/app/code/Magento/Sales/Model/Order/Email/Sender.php @@ -84,6 +84,8 @@ protected function checkAndSend(Order $order) $sender->sendCopyTo(); } catch (\Exception $e) { $this->logger->error($e->getMessage()); + + return false; } return true; diff --git a/app/code/Magento/Sales/Model/Order/Shipment.php b/app/code/Magento/Sales/Model/Order/Shipment.php index ae0c00505940a..64e20d5a69041 100644 --- a/app/code/Magento/Sales/Model/Order/Shipment.php +++ b/app/code/Magento/Sales/Model/Order/Shipment.php @@ -262,8 +262,6 @@ public function register() if (!$item->getOrderItem()->isDummy(true)) { $totalQty += $item->getQty(); } - } else { - $item->isDeleted(true); } } diff --git a/app/code/Magento/Sales/Model/Order/Shipment/OrderRegistrar.php b/app/code/Magento/Sales/Model/Order/Shipment/OrderRegistrar.php index 9001267f6bc4a..69077749902b5 100644 --- a/app/code/Magento/Sales/Model/Order/Shipment/OrderRegistrar.php +++ b/app/code/Magento/Sales/Model/Order/Shipment/OrderRegistrar.php @@ -17,12 +17,19 @@ class OrderRegistrar implements \Magento\Sales\Model\Order\Shipment\OrderRegistr */ public function register(OrderInterface $order, ShipmentInterface $shipment) { - /** @var \Magento\Sales\Api\Data\ShipmentItemInterface|\Magento\Sales\Model\Order\Shipment\Item $item */ + $totalQty = 0; + /** @var \Magento\Sales\Model\Order\Shipment\Item $item */ foreach ($shipment->getItems() as $item) { if ($item->getQty() > 0) { $item->register(); + + if (!$item->getOrderItem()->isDummy(true)) { + $totalQty += $item->getQty(); + } } } + $shipment->setTotalQty($totalQty); + return $order; } } diff --git a/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php b/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php index 3e2dabbd8dba8..c0a3f84e8846d 100644 --- a/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php +++ b/app/code/Magento/Sales/Model/Order/ShipmentDocumentFactory.php @@ -14,6 +14,7 @@ use Magento\Sales\Api\Data\OrderInterface; use Magento\Sales\Api\Data\ShipmentCommentCreationInterface; use Magento\Sales\Api\Data\ShipmentCreationArgumentsInterface; +use Magento\Sales\Api\Data\OrderItemInterface; /** * Class ShipmentDocumentFactory @@ -77,13 +78,23 @@ public function create( array $packages = [], ShipmentCreationArgumentsInterface $arguments = null ) { - $shipmentItems = $this->itemsToArray($items); + $shipmentItems = empty($items) + ? $this->getQuantitiesFromOrderItems($order->getItems()) + : $this->getQuantitiesFromShipmentItems($items); + /** @var Shipment $shipment */ $shipment = $this->shipmentFactory->create( $order, $shipmentItems ); - $this->prepareTracks($shipment, $tracks); + + foreach ($tracks as $track) { + $hydrator = $this->hydratorPool->getHydrator( + \Magento\Sales\Api\Data\ShipmentTrackCreationInterface::class + ); + $shipment->addTrack($this->trackFactory->create(['data' => $hydrator->extract($track)])); + } + if ($comment) { $shipment->addComment( $comment->getComment(), @@ -101,30 +112,29 @@ public function create( } /** - * Adds tracks to the shipment. + * Translate OrderItemInterface array to product id => product quantity array. * - * @param ShipmentInterface $shipment - * @param ShipmentTrackCreationInterface[] $tracks - * @return ShipmentInterface + * @param OrderItemInterface[] $items + * @return int[] */ - private function prepareTracks(\Magento\Sales\Api\Data\ShipmentInterface $shipment, array $tracks) + private function getQuantitiesFromOrderItems(array $items) { - foreach ($tracks as $track) { - $hydrator = $this->hydratorPool->getHydrator( - \Magento\Sales\Api\Data\ShipmentTrackCreationInterface::class - ); - $shipment->addTrack($this->trackFactory->create(['data' => $hydrator->extract($track)])); + $shipmentItems = []; + foreach ($items as $item) { + if (!$item->getIsVirtual() && (!$item->getParentItem() || $item->isShipSeparately())) { + $shipmentItems[$item->getItemId()] = $item->getQtyOrdered(); + } } - return $shipment; + return $shipmentItems; } /** - * Convert items to array + * Translate ShipmentItemCreationInterface array to product id => product quantity array. * * @param ShipmentItemCreationInterface[] $items - * @return array + * @return int[] */ - private function itemsToArray(array $items = []) + private function getQuantitiesFromShipmentItems(array $items) { $shipmentItems = []; foreach ($items as $item) { diff --git a/app/code/Magento/Sales/Model/Order/ShipmentFactory.php b/app/code/Magento/Sales/Model/Order/ShipmentFactory.php index dcb2cdf1d8ed9..642f8647ef56b 100644 --- a/app/code/Magento/Sales/Model/Order/ShipmentFactory.php +++ b/app/code/Magento/Sales/Model/Order/ShipmentFactory.php @@ -96,14 +96,17 @@ protected function prepareItems( \Magento\Sales\Model\Order $order, array $items = [] ) { - $totalQty = 0; + $shipmentItems = []; foreach ($order->getAllItems() as $orderItem) { - if (!$this->canShipItem($orderItem, $items)) { + if ($this->validateItem($orderItem, $items) === false) { continue; } /** @var \Magento\Sales\Model\Order\Shipment\Item $item */ $item = $this->converter->itemToShipmentItem($orderItem); + if ($orderItem->getIsVirtual() || ($orderItem->getParentItemId() && !$orderItem->isShipSeparately())) { + $item->isDeleted(true); + } if ($orderItem->isDummy(true)) { $qty = 0; @@ -121,8 +124,7 @@ protected function prepareItems( $qty = min($qty, $orderItem->getSimpleQtyToShip()); $item->setQty($this->castQty($orderItem, $qty)); - $shipment->addItem($item); - + $shipmentItems[] = $item; continue; } else { $qty = 1; @@ -141,10 +143,65 @@ protected function prepareItems( } } - $totalQty += $qty; - $item->setQty($this->castQty($orderItem, $qty)); - $shipment->addItem($item); + $shipmentItems[] = $item; + } + return $this->setItemsToShipment($shipment, $shipmentItems); + } + + /** + * Validate order item before shipment + * + * @param Item $orderItem + * @param array $items + * @return bool + */ + private function validateItem(\Magento\Sales\Model\Order\Item $orderItem, array $items) + { + if (!$this->canShipItem($orderItem, $items)) { + return false; + } + + // Remove from shipment items without qty or with qty=0 + if (!$orderItem->isDummy(true) + && (!isset($items[$orderItem->getId()]) || $items[$orderItem->getId()] <= 0) + ) { + return false; + } + return true; + } + + /** + * Set prepared items to shipment document + * + * @param \Magento\Sales\Api\Data\ShipmentInterface $shipment + * @param array $shipmentItems + * @return \Magento\Sales\Api\Data\ShipmentInterface + */ + private function setItemsToShipment(\Magento\Sales\Api\Data\ShipmentInterface $shipment, $shipmentItems) + { + $totalQty = 0; + + /** + * Verify that composite products shipped separately has children, if not -> remove from collection + */ + /** @var \Magento\Sales\Model\Order\Shipment\Item $shipmentItem */ + foreach ($shipmentItems as $key => $shipmentItem) { + if ($shipmentItem->getOrderItem()->getHasChildren() + && $shipmentItem->getOrderItem()->isShipSeparately() + ) { + $containerId = $shipmentItem->getOrderItem()->getId(); + $childItems = array_filter($shipmentItems, function ($item) use ($containerId) { + return $containerId == $item->getOrderItem()->getParentItemId(); + }); + + if (count($childItems) <= 0) { + unset($shipmentItems[$key]); + continue; + } + } + $totalQty += $shipmentItem->getQty(); + $shipment->addItem($shipmentItem); } return $shipment->setTotalQty($totalQty); } diff --git a/app/code/Magento/Sales/Setup/InstallData.php b/app/code/Magento/Sales/Setup/InstallData.php deleted file mode 100644 index d4fef6a690513..0000000000000 --- a/app/code/Magento/Sales/Setup/InstallData.php +++ /dev/null @@ -1,177 +0,0 @@ -salesSetupFactory = $salesSetupFactory; - $this->sequenceBuilder = $sequenceBuilder; - $this->sequenceConfig = $sequenceConfig; - } - - /** - * {@inheritdoc} - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var \Magento\Sales\Setup\SalesSetup $salesSetup */ - $salesSetup = $this->salesSetupFactory->create(['setup' => $setup]); - - /** - * Install eav entity types to the eav/entity_type table - */ - $salesSetup->installEntities(); - - /** - * Install order statuses from config - */ - $data = []; - $statuses = [ - 'pending' => __('Pending'), - 'pending_payment' => __('Pending Payment'), - 'processing' => __('Processing'), - 'holded' => __('On Hold'), - 'complete' => __('Complete'), - 'closed' => __('Closed'), - 'canceled' => __('Canceled'), - 'fraud' => __('Suspected Fraud'), - 'payment_review' => __('Payment Review'), - ]; - foreach ($statuses as $code => $info) { - $data[] = ['status' => $code, 'label' => $info]; - } - $setup->getConnection()->insertArray($setup->getTable('sales_order_status'), ['status', 'label'], $data); - - /** - * Install order states from config - */ - $data = []; - $states = [ - 'new' => [ - 'label' => __('New'), - 'statuses' => ['pending' => ['default' => '1']], - 'visible_on_front' => true, - ], - 'pending_payment' => [ - 'label' => __('Pending Payment'), - 'statuses' => ['pending_payment' => ['default' => '1']], - ], - 'processing' => [ - 'label' => __('Processing'), - 'statuses' => ['processing' => ['default' => '1'], 'fraud' => []], - 'visible_on_front' => true, - ], - 'complete' => [ - 'label' => __('Complete'), - 'statuses' => ['complete' => ['default' => '1']], - 'visible_on_front' => true, - ], - 'closed' => [ - 'label' => __('Closed'), - 'statuses' => ['closed' => ['default' => '1']], - 'visible_on_front' => true, - ], - 'canceled' => [ - 'label' => __('Canceled'), - 'statuses' => ['canceled' => ['default' => '1']], - 'visible_on_front' => true, - ], - 'holded' => [ - 'label' => __('On Hold'), - 'statuses' => ['holded' => ['default' => '1']], - 'visible_on_front' => true, - ], - 'payment_review' => [ - 'label' => __('Payment Review'), - 'statuses' => ['payment_review' => ['default' => '1'], 'fraud' => []], - 'visible_on_front' => true, - ], - ]; - - foreach ($states as $code => $info) { - if (isset($info['statuses'])) { - foreach ($info['statuses'] as $status => $statusInfo) { - $data[] = [ - 'status' => $status, - 'state' => $code, - 'is_default' => is_array($statusInfo) && isset($statusInfo['default']) ? 1 : 0, - ]; - } - } - } - $setup->getConnection()->insertArray( - $setup->getTable('sales_order_status_state'), - ['status', 'state', 'is_default'], - $data - ); - - $entitiesToAlter = ['order_address']; - - $attributes = [ - 'vat_id' => ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT], - 'vat_is_valid' => ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT], - 'vat_request_id' => ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT], - 'vat_request_date' => ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT], - 'vat_request_success' => ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT], - ]; - - foreach ($entitiesToAlter as $entityName) { - foreach ($attributes as $attributeCode => $attributeParams) { - $salesSetup->addAttribute($entityName, $attributeCode, $attributeParams); - } - } - - /** Update visibility for states */ - $states = ['new', 'processing', 'complete', 'closed', 'canceled', 'holded', 'payment_review']; - foreach ($states as $state) { - $setup->getConnection()->update( - $setup->getTable('sales_order_status_state'), - ['visible_on_front' => 1], - ['state = ?' => $state] - ); - } - } -} diff --git a/app/code/Magento/Sales/Setup/Patch/Data/ConvertSerializedDataToJson.php b/app/code/Magento/Sales/Setup/Patch/Data/ConvertSerializedDataToJson.php new file mode 100644 index 0000000000000..542476c7dd902 --- /dev/null +++ b/app/code/Magento/Sales/Setup/Patch/Data/ConvertSerializedDataToJson.php @@ -0,0 +1,154 @@ +moduleDataSetup = $moduleDataSetup; + $this->salesSetupFactory = $salesSetupFactory; + $this->eavConfig = $eavConfig; + $this->aggregatedFieldDataConverter = $aggregatedFieldDataConverter; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var SalesSetup $salesSetup */ + $salesSetup = $this->salesSetupFactory->create(); + $this->convertSerializedDataToJson($salesSetup); + $this->eavConfig->clear(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateEntityTypes::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.6'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Convert native serialization to JSON. + * + * @param SalesSetup $salesSetup + */ + private function convertSerializedDataToJson(SalesSetup $salesSetup) + { + $fieldsToUpdate = [ + new FieldToConvert( + SerializedToJson::class, + $salesSetup->getTable('sales_invoice_item'), + 'entity_id', + 'tax_ratio' + ), + new FieldToConvert( + SerializedToJson::class, + $salesSetup->getTable('sales_creditmemo_item'), + 'entity_id', + 'tax_ratio' + ), + ]; + $fieldsToUpdate[] = new FieldToConvert( + SerializedDataConverter::class, + $salesSetup->getTable('sales_order_item'), + 'item_id', + 'product_options' + ); + $fieldsToUpdate[] = new FieldToConvert( + SerializedToJson::class, + $salesSetup->getTable('sales_shipment'), + 'entity_id', + 'packages' + ); + $fieldsToUpdate[] = new FieldToConvert( + SalesOrderPaymentDataConverter::class, + $salesSetup->getTable('sales_order_payment'), + 'entity_id', + 'additional_information' + ); + $fieldsToUpdate[] = new FieldToConvert( + SerializedToJson::class, + $salesSetup->getTable('sales_payment_transaction'), + 'transaction_id', + 'additional_information' + ); + $this->aggregatedFieldDataConverter->convert($fieldsToUpdate, $salesSetup->getConnection()); + } +} diff --git a/app/code/Magento/Sales/Setup/Patch/Data/FillQuoteAddressIdInSalesOrderAddress.php b/app/code/Magento/Sales/Setup/Patch/Data/FillQuoteAddressIdInSalesOrderAddress.php new file mode 100644 index 0000000000000..0ad2245a6287e --- /dev/null +++ b/app/code/Magento/Sales/Setup/Patch/Data/FillQuoteAddressIdInSalesOrderAddress.php @@ -0,0 +1,145 @@ +moduleDataSetup = $moduleDataSetup; + $this->salesSetupFactory = $salesSetupFactory; + $this->state = $state; + $this->eavConfig = $eavConfig; + $this->addressCollectionFactory = $addressCollectionFactory; + $this->orderFactory = $orderFactory; + $this->quoteFactory = $quoteFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->state->emulateAreaCode( + \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE, + [$this, 'fillQuoteAddressIdInSalesOrderAddress'] + ); + $this->eavConfig->clear(); + } + + /** + * Fill quote_address_id in table sales_order_address if it is empty. + */ + public function fillQuoteAddressIdInSalesOrderAddress() + { + $addressCollection = $this->addressCollectionFactory->create(); + /** @var \Magento\Sales\Model\Order\Address $orderAddress */ + foreach ($addressCollection as $orderAddress) { + if (!$orderAddress->getData('quote_address_id')) { + $orderId = $orderAddress->getParentId(); + $addressType = $orderAddress->getAddressType(); + + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->orderFactory->create()->load($orderId); + $quoteId = $order->getQuoteId(); + $quote = $this->quoteFactory->create()->load($quoteId); + + if ($addressType == \Magento\Sales\Model\Order\Address::TYPE_SHIPPING) { + $quoteAddressId = $quote->getShippingAddress()->getId(); + $orderAddress->setData('quote_address_id', $quoteAddressId); + } elseif ($addressType == \Magento\Sales\Model\Order\Address::TYPE_BILLING) { + $quoteAddressId = $quote->getBillingAddress()->getId(); + $orderAddress->setData('quote_address_id', $quoteAddressId); + } + + $orderAddress->save(); + } + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + ConvertSerializedDataToJson::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.8'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Sales/Setup/Patch/Data/InstallOrderStatusesAndInitialSalesConfig.php b/app/code/Magento/Sales/Setup/Patch/Data/InstallOrderStatusesAndInitialSalesConfig.php new file mode 100644 index 0000000000000..ba0535875d96b --- /dev/null +++ b/app/code/Magento/Sales/Setup/Patch/Data/InstallOrderStatusesAndInitialSalesConfig.php @@ -0,0 +1,188 @@ +moduleDataSetup = $moduleDataSetup; + $this->salesSetupFactory = $salesSetupFactory; + } + + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function apply() + { + /** @var \Magento\Sales\Setup\SalesSetup $salesSetup */ + $salesSetup = $this->salesSetupFactory->create(['setup' => $this->moduleDataSetup]); + + /** + * Install eav entity types to the eav/entity_type table + */ + $salesSetup->installEntities(); + /** + * Install order statuses from config + */ + $data = []; + $statuses = [ + 'pending' => __('Pending'), + 'pending_payment' => __('Pending Payment'), + 'processing' => __('Processing'), + 'holded' => __('On Hold'), + 'complete' => __('Complete'), + 'closed' => __('Closed'), + 'canceled' => __('Canceled'), + 'fraud' => __('Suspected Fraud'), + 'payment_review' => __('Payment Review'), + ]; + foreach ($statuses as $code => $info) { + $data[] = ['status' => $code, 'label' => $info]; + } + $this->moduleDataSetup->getConnection()->insertArray( + $this->moduleDataSetup->getTable('sales_order_status'), + ['status', 'label'], + $data + ); + /** + * Install order states from config + */ + $data = []; + $states = [ + 'new' => [ + 'label' => __('New'), + 'statuses' => ['pending' => ['default' => '1']], + 'visible_on_front' => true, + ], + 'pending_payment' => [ + 'label' => __('Pending Payment'), + 'statuses' => ['pending_payment' => ['default' => '1']], + ], + 'processing' => [ + 'label' => __('Processing'), + 'statuses' => ['processing' => ['default' => '1'], 'fraud' => []], + 'visible_on_front' => true, + ], + 'complete' => [ + 'label' => __('Complete'), + 'statuses' => ['complete' => ['default' => '1']], + 'visible_on_front' => true, + ], + 'closed' => [ + 'label' => __('Closed'), + 'statuses' => ['closed' => ['default' => '1']], + 'visible_on_front' => true, + ], + 'canceled' => [ + 'label' => __('Canceled'), + 'statuses' => ['canceled' => ['default' => '1']], + 'visible_on_front' => true, + ], + 'holded' => [ + 'label' => __('On Hold'), + 'statuses' => ['holded' => ['default' => '1']], + 'visible_on_front' => true, + ], + 'payment_review' => [ + 'label' => __('Payment Review'), + 'statuses' => ['payment_review' => ['default' => '1'], 'fraud' => []], + 'visible_on_front' => true, + ], + ]; + foreach ($states as $code => $info) { + if (isset($info['statuses'])) { + foreach ($info['statuses'] as $status => $statusInfo) { + $data[] = [ + 'status' => $status, + 'state' => $code, + 'is_default' => is_array($statusInfo) && isset($statusInfo['default']) ? 1 : 0, + ]; + } + } + } + $this->moduleDataSetup->getConnection()->insertArray( + $this->moduleDataSetup->getTable('sales_order_status_state'), + ['status', 'state', 'is_default'], + $data + ); + $entitiesToAlter = ['order_address']; + $attributes = [ + 'vat_id' => ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT], + 'vat_is_valid' => ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT], + 'vat_request_id' => ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT], + 'vat_request_date' => ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT], + 'vat_request_success' => ['type' => \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT], + ]; + foreach ($entitiesToAlter as $entityName) { + foreach ($attributes as $attributeCode => $attributeParams) { + $salesSetup->addAttribute($entityName, $attributeCode, $attributeParams); + } + } + /** Update visibility for states */ + $states = ['new', 'processing', 'complete', 'closed', 'canceled', 'holded', 'payment_review']; + foreach ($states as $state) { + $this->moduleDataSetup->getConnection()->update( + $this->moduleDataSetup->getTable('sales_order_status_state'), + ['visible_on_front' => 1], + ['state = ?' => $state] + ); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Sales/Setup/Patch/Data/UpdateEntityTypeModelForInvoice.php b/app/code/Magento/Sales/Setup/Patch/Data/UpdateEntityTypeModelForInvoice.php new file mode 100644 index 0000000000000..99e15df8420ef --- /dev/null +++ b/app/code/Magento/Sales/Setup/Patch/Data/UpdateEntityTypeModelForInvoice.php @@ -0,0 +1,86 @@ +moduleDataSetup = $moduleDataSetup; + $this->salesSetupFactory = $salesSetupFactory; + $this->eavConfig = $eavConfig; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $salesSetup = $this->salesSetupFactory->create(); + //Correct wrong source model for "invoice" entity type, introduced by mistake in 2.0.1 upgrade. + $salesSetup->updateEntityType( + 'invoice', + 'entity_model', + \Magento\Sales\Model\ResourceModel\Order\Invoice::class + ); + $this->eavConfig->clear(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + FillQuoteAddressIdInSalesOrderAddress::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.9'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Sales/Setup/Patch/Data/UpdateEntityTypes.php b/app/code/Magento/Sales/Setup/Patch/Data/UpdateEntityTypes.php new file mode 100644 index 0000000000000..9e39976203631 --- /dev/null +++ b/app/code/Magento/Sales/Setup/Patch/Data/UpdateEntityTypes.php @@ -0,0 +1,81 @@ +moduleDataSetup = $moduleDataSetup; + $this->salesSetupFactory = $salesSetupFactory; + $this->eavConfig = $eavConfig; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $salesSetup = $this->salesSetupFactory->create(); + $salesSetup->updateEntityTypes(); + $this->eavConfig->clear(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + InstallOrderStatusesAndInitialSalesConfig::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Sales/Setup/SalesSetup.php b/app/code/Magento/Sales/Setup/SalesSetup.php index cfaa9106d1c7c..bfc05c549ddb3 100644 --- a/app/code/Magento/Sales/Setup/SalesSetup.php +++ b/app/code/Magento/Sales/Setup/SalesSetup.php @@ -10,6 +10,7 @@ use Magento\Eav\Setup\EavSetup; use Magento\Framework\App\CacheInterface; use Magento\Framework\App\Config\ScopeConfigInterface; +use Magento\Framework\App\ResourceConnection; use Magento\Framework\Encryption\EncryptorInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; diff --git a/app/code/Magento/Sales/Setup/UpgradeData.php b/app/code/Magento/Sales/Setup/UpgradeData.php deleted file mode 100644 index 16455d616d853..0000000000000 --- a/app/code/Magento/Sales/Setup/UpgradeData.php +++ /dev/null @@ -1,203 +0,0 @@ -salesSetupFactory = $salesSetupFactory; - $this->eavConfig = $eavConfig; - $this->aggregatedFieldConverter = $aggregatedFieldConverter; - $this->addressCollectionFactory = $addressCollFactory; - $this->orderFactory = $orderFactory; - $this->quoteFactory = $quoteFactory; - $this->state = $state; - } - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $salesSetup = $this->salesSetupFactory->create(['setup' => $setup]); - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $salesSetup->updateEntityTypes(); - } - if (version_compare($context->getVersion(), '2.0.6', '<')) { - $this->convertSerializedDataToJson($context->getVersion(), $salesSetup); - } - if (version_compare($context->getVersion(), '2.0.8', '<')) { - $this->state->emulateAreaCode( - \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE, - [$this, 'fillQuoteAddressIdInSalesOrderAddress'], - [$setup] - ); - } - if (version_compare($context->getVersion(), '2.0.9', '<')) { - //Correct wrong source model for "invoice" entity type, introduced by mistake in 2.0.1 upgrade. - $salesSetup->updateEntityType( - 'invoice', - 'entity_model', - \Magento\Sales\Model\ResourceModel\Order\Invoice::class - ); - } - $this->eavConfig->clear(); - } - - /** - * Convert data from serialized to JSON encoded - * - * @param string $setupVersion - * @param SalesSetup $salesSetup - * @return void - */ - private function convertSerializedDataToJson($setupVersion, SalesSetup $salesSetup) - { - $fieldsToUpdate = [ - new FieldToConvert( - SerializedToJson::class, - $salesSetup->getTable('sales_invoice_item'), - 'entity_id', - 'tax_ratio' - ), - new FieldToConvert( - SerializedToJson::class, - $salesSetup->getTable('sales_creditmemo_item'), - 'entity_id', - 'tax_ratio' - ), - ]; - if (version_compare($setupVersion, '2.0.5', '<')) { - $fieldsToUpdate[] = new FieldToConvert( - SerializedDataConverter::class, - $salesSetup->getTable('sales_order_item'), - 'item_id', - 'product_options' - ); - $fieldsToUpdate[] = new FieldToConvert( - SerializedToJson::class, - $salesSetup->getTable('sales_shipment'), - 'entity_id', - 'packages' - ); - $fieldsToUpdate[] = new FieldToConvert( - SalesOrderPaymentDataConverter::class, - $salesSetup->getTable('sales_order_payment'), - 'entity_id', - 'additional_information' - ); - $fieldsToUpdate[] = new FieldToConvert( - SerializedToJson::class, - $salesSetup->getTable('sales_payment_transaction'), - 'transaction_id', - 'additional_information' - ); - } - $this->aggregatedFieldConverter->convert($fieldsToUpdate, $salesSetup->getConnection()); - } - - /** - * Fill quote_address_id in table sales_order_address if it is empty. - */ - public function fillQuoteAddressIdInSalesOrderAddress() - { - $addressCollection = $this->addressCollectionFactory->create(); - /** @var \Magento\Sales\Model\Order\Address $orderAddress */ - foreach ($addressCollection as $orderAddress) { - if (!$orderAddress->getData('quote_address_id')) { - $orderId = $orderAddress->getParentId(); - $addressType = $orderAddress->getAddressType(); - - /** @var \Magento\Sales\Model\Order $order */ - $order = $this->orderFactory->create()->load($orderId); - $quoteId = $order->getQuoteId(); - $quote = $this->quoteFactory->create()->load($quoteId); - - if ($addressType == \Magento\Sales\Model\Order\Address::TYPE_SHIPPING) { - $quoteAddressId = $quote->getShippingAddress()->getId(); - $orderAddress->setData('quote_address_id', $quoteAddressId); - } elseif ($addressType == \Magento\Sales\Model\Order\Address::TYPE_BILLING) { - $quoteAddressId = $quote->getBillingAddress()->getId(); - $orderAddress->setData('quote_address_id', $quoteAddressId); - } - - $orderAddress->save(); - } - } - } -} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderSenderTest.php index 411dd9e1433d7..46c44c03b1514 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderSenderTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderSenderTest.php @@ -53,10 +53,11 @@ protected function setUp() * @param int $configValue * @param bool|null $forceSyncMode * @param bool|null $emailSendingResult - * @dataProvider sendDataProvider + * @param $senderSendException * @return void + * @dataProvider sendDataProvider */ - public function testSend($configValue, $forceSyncMode, $emailSendingResult) + public function testSend($configValue, $forceSyncMode, $emailSendingResult, $senderSendException) { $address = 'address_test'; $configPath = 'sales_email/general/async_sending'; @@ -110,19 +111,23 @@ public function testSend($configValue, $forceSyncMode, $emailSendingResult) $this->senderMock->expects($this->once())->method('send'); - $this->senderMock->expects($this->once())->method('sendCopyTo'); + if ($senderSendException) { + $this->checkSenderSendExceptionCase(); + } else { + $this->senderMock->expects($this->once())->method('sendCopyTo'); - $this->orderMock->expects($this->once()) - ->method('setEmailSent') - ->with(true); + $this->orderMock->expects($this->once()) + ->method('setEmailSent') + ->with(true); - $this->orderResourceMock->expects($this->once()) - ->method('saveAttribute') - ->with($this->orderMock, ['send_email', 'email_sent']); + $this->orderResourceMock->expects($this->once()) + ->method('saveAttribute') + ->with($this->orderMock, ['send_email', 'email_sent']); - $this->assertTrue( - $this->sender->send($this->orderMock) - ); + $this->assertTrue( + $this->sender->send($this->orderMock) + ); + } } else { $this->orderResourceMock->expects($this->once()) ->method('saveAttribute') @@ -146,19 +151,42 @@ public function testSend($configValue, $forceSyncMode, $emailSendingResult) } } + /** + * Methods check case when method "send" in "senderMock" throw exception. + * + * @return void + */ + protected function checkSenderSendExceptionCase() + { + $this->senderMock->expects($this->once()) + ->method('send') + ->willThrowException(new \Exception('exception')); + + $this->orderResourceMock->expects($this->once()) + ->method('saveAttribute') + ->with($this->orderMock, 'send_email'); + + $this->assertFalse( + $this->sender->send($this->orderMock) + ); + } + /** * @return array */ public function sendDataProvider() { return [ - [0, 0, true], - [0, 0, true], - [0, 0, false], - [0, 0, false], - [0, 1, true], - [0, 1, true], - [1, null, null, null] + [0, 0, true, false], + [0, 0, true, false], + [0, 0, true, true], + [0, 0, false, false], + [0, 0, false, false], + [0, 0, false, true], + [0, 1, true, false], + [0, 1, true, false], + [0, 1, true, false], + [1, null, null, false] ]; } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/OrderRegistrarTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/OrderRegistrarTest.php index ecc37a2cd427d..9eb6be5f6d66e 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/OrderRegistrarTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Shipment/OrderRegistrarTest.php @@ -37,23 +37,20 @@ protected function setUp() public function testRegister() { $item1 = $this->getShipmentItemMock(); - $item1->expects($this->once()) - ->method('getQty') - ->willReturn(0); - $item1->expects($this->never()) - ->method('register'); + $item1->expects($this->once())->method('getQty')->willReturn(0); + $item1->expects($this->never())->method('register'); + $item1->expects($this->never())->method('getOrderItem'); $item2 = $this->getShipmentItemMock(); - $item2->expects($this->once()) - ->method('getQty') - ->willReturn(0.5); - $item2->expects($this->once()) - ->method('register'); + $item2->expects($this->atLeastOnce())->method('getQty')->willReturn(0.5); + $item2->expects($this->once())->method('register'); + + $orderItemMock = $this->createMock(\Magento\Sales\Model\Order\Item::class); + $orderItemMock->expects($this->once())->method('isDummy')->with(true)->willReturn(false); + $item2->expects($this->once())->method('getOrderItem')->willReturn($orderItemMock); $items = [$item1, $item2]; - $this->shipmentMock->expects($this->once()) - ->method('getItems') - ->willReturn($items); + $this->shipmentMock->expects($this->once())->method('getItems')->willReturn($items); $this->assertEquals( $this->orderMock, $this->model->register($this->orderMock, $this->shipmentMock) @@ -67,7 +64,7 @@ private function getShipmentItemMock() { return $this->getMockBuilder(\Magento\Sales\Api\Data\ShipmentItemInterface::class) ->disableOriginalConstructor() - ->setMethods(['register']) + ->setMethods(['register', 'getOrderItem']) ->getMockForAbstractClass(); } } diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php index e51d912d3f420..bf9b3a67f9640 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentDocumentFactoryTest.php @@ -19,6 +19,7 @@ /** * Class ShipmentDocumentFactoryTest + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ShipmentDocumentFactoryTest extends \PHPUnit\Framework\TestCase { @@ -128,6 +129,8 @@ public function testCreate() $packages = []; $items = [1 => 10]; + $this->itemMock->expects($this->once())->method('getOrderItemId')->willReturn(1); + $this->itemMock->expects($this->once())->method('getQty')->willReturn(10); $this->itemMock->expects($this->once()) ->method('getOrderItemId') ->willReturn(1); diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php index b4fb645c02f8b..e65b1b8330b93 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/ShipmentFactoryTest.php @@ -71,18 +71,31 @@ protected function setUp() */ public function testCreate($tracks) { - $orderItem = $this->createPartialMock(\Magento\Sales\Model\Order\Item::class, ['getId', 'getQtyOrdered']); + $orderItem = $this->createPartialMock( + \Magento\Sales\Model\Order\Item::class, + ['getId', 'getQtyOrdered', 'getParentItemId', 'getIsVirtual'] + ); $orderItem->expects($this->any()) ->method('getId') ->willReturn(1); $orderItem->expects($this->any()) ->method('getQtyOrdered') ->willReturn(5); + $orderItem->expects($this->any())->method('getParentItemId')->willReturn(false); + $orderItem->expects($this->any())->method('getIsVirtual')->willReturn(false); - $shipmentItem = $this->createPartialMock(\Magento\Sales\Model\Order\Shipment\Item::class, ['setQty']); + $shipmentItem = $this->createPartialMock( + \Magento\Sales\Model\Order\Shipment\Item::class, + ['setQty', 'getOrderItem', 'getQty'] + ); $shipmentItem->expects($this->once()) ->method('setQty') ->with(5); + $shipmentItem->expects($this->once()) + ->method('getQty') + ->willReturn(5); + + $shipmentItem->expects($this->atLeastOnce())->method('getOrderItem')->willReturn($orderItem); $order = $this->createPartialMock(\Magento\Sales\Model\Order::class, ['getAllItems']); $order->expects($this->any()) diff --git a/app/code/Magento/Sales/etc/db_schema.xml b/app/code/Magento/Sales/etc/db_schema.xml index c084a5b87b109..8c91a8b5fbc13 100644 --- a/app/code/Magento/Sales/etc/db_schema.xml +++ b/app/code/Magento/Sales/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Sales/etc/module.xml b/app/code/Magento/Sales/etc/module.xml index b234cdad876cc..11eebaa3d5a3d 100644 --- a/app/code/Magento/Sales/etc/module.xml +++ b/app/code/Magento/Sales/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/SalesAnalytics/etc/module.xml b/app/code/Magento/SalesAnalytics/etc/module.xml index 7a15075a4bc21..54f67fa13aa36 100644 --- a/app/code/Magento/SalesAnalytics/etc/module.xml +++ b/app/code/Magento/SalesAnalytics/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/SalesInventory/etc/module.xml b/app/code/Magento/SalesInventory/etc/module.xml index f40a587f66fed..7d71924d3591f 100644 --- a/app/code/Magento/SalesInventory/etc/module.xml +++ b/app/code/Magento/SalesInventory/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/SalesRule/Setup/InstallData.php b/app/code/Magento/SalesRule/Setup/InstallData.php deleted file mode 100644 index 6d234aa803ddc..0000000000000 --- a/app/code/Magento/SalesRule/Setup/InstallData.php +++ /dev/null @@ -1,45 +0,0 @@ -createMigrationSetup(); - $setup->startSetup(); - - $installer->appendClassAliasReplace( - 'salesrule', - 'conditions_serialized', - \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_MODEL, - \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_SERIALIZED, - ['rule_id'] - ); - $installer->appendClassAliasReplace( - 'salesrule', - 'actions_serialized', - \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_MODEL, - \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_SERIALIZED, - ['rule_id'] - ); - - $installer->doUpdateClassAliases(); - - $setup->endSetup(); - } -} diff --git a/app/code/Magento/SalesRule/Setup/Patch/Data/ConvertSerializedDataToJson.php b/app/code/Magento/SalesRule/Setup/Patch/Data/ConvertSerializedDataToJson.php new file mode 100644 index 0000000000000..8a8c51e9d349a --- /dev/null +++ b/app/code/Magento/SalesRule/Setup/Patch/Data/ConvertSerializedDataToJson.php @@ -0,0 +1,113 @@ +metadataPool = $metadataPool; + $this->aggregatedFieldConverter = $aggregatedFieldConverter; + $this->moduleDataSetup = $moduleDataSetup; + } + + /** + * Do Upgrade + * + * @return void + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + $this->convertSerializedDataToJson(); + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + PrepareRuleModelSerializedData::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.2'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Convert native serialized data to json. + * + * @return void + */ + private function convertSerializedDataToJson() + { + $metadata = $this->metadataPool->getMetadata(\Magento\SalesRule\Api\Data\RuleInterface::class); + $this->aggregatedFieldConverter->convert( + [ + new \Magento\Framework\DB\FieldToConvert( + \Magento\Framework\DB\DataConverter\SerializedToJson::class, + $this->moduleDataSetup->getTable('salesrule'), + $metadata->getLinkField(), + 'conditions_serialized' + ), + new \Magento\Framework\DB\FieldToConvert( + \Magento\Framework\DB\DataConverter\SerializedToJson::class, + $this->moduleDataSetup->getTable('salesrule'), + $metadata->getLinkField(), + 'actions_serialized' + ), + ], + $this->moduleDataSetup->getConnection() + ); + } +} diff --git a/app/code/Magento/SalesRule/Setup/Patch/Data/FillSalesRuleProductAttributeTable.php b/app/code/Magento/SalesRule/Setup/Patch/Data/FillSalesRuleProductAttributeTable.php new file mode 100644 index 0000000000000..625d5769fddf5 --- /dev/null +++ b/app/code/Magento/SalesRule/Setup/Patch/Data/FillSalesRuleProductAttributeTable.php @@ -0,0 +1,129 @@ +ruleColletionFactory = $ruleColletionFactory; + $this->serializer = $serializer; + $this->resourceModelRule = $resourceModelRule; + $this->moduleDataSetup = $moduleDataSetup; + $this->appState = $appState; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + $this->appState->emulateAreaCode( + \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE, + [$this, 'fillSalesRuleProductAttributeTable'] + ); + $this->fillSalesRuleProductAttributeTable(); + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * Fill attribute table for sales rule + */ + public function fillSalesRuleProductAttributeTable() + { + /** @var \Magento\SalesRule\Model\ResourceModel\Rule\Collection $ruleCollection */ + $ruleCollection = $this->ruleColletionFactory->create(); + /** @var \Magento\SalesRule\Model\Rule $rule */ + foreach ($ruleCollection as $rule) { + // Save product attributes used in rule + $conditions = $rule->getConditions()->asArray(); + $actions = $rule->getActions()->asArray(); + $serializedConditions = $this->serializer->serialize($conditions); + $serializedActions = $this->serializer->serialize($actions); + $conditionAttributes = $this->resourceModelRule->getProductAttributes($serializedConditions); + $actionAttributes = $this->resourceModelRule->getProductAttributes($serializedActions); + $ruleProductAttributes = array_merge($conditionAttributes, $actionAttributes); + if ($ruleProductAttributes) { + $this->resourceModelRule->setActualProductAttributes($rule, $ruleProductAttributes); + } + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + ConvertSerializedDataToJson::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.3'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/SalesRule/Setup/Patch/Data/PrepareRuleModelSerializedData.php b/app/code/Magento/SalesRule/Setup/Patch/Data/PrepareRuleModelSerializedData.php new file mode 100644 index 0000000000000..2387f5f1ed714 --- /dev/null +++ b/app/code/Magento/SalesRule/Setup/Patch/Data/PrepareRuleModelSerializedData.php @@ -0,0 +1,84 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $installer = $this->moduleDataSetup->createMigrationSetup(); + $this->moduleDataSetup->startSetup(); + + $installer->appendClassAliasReplace( + 'salesrule', + 'conditions_serialized', + \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_MODEL, + \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_SERIALIZED, + ['rule_id'] + ); + $installer->appendClassAliasReplace( + 'salesrule', + 'actions_serialized', + \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_MODEL, + \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_SERIALIZED, + ['rule_id'] + ); + $installer->doUpdateClassAliases(); + $this->moduleDataSetup->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/SalesRule/Setup/UpgradeData.php b/app/code/Magento/SalesRule/Setup/UpgradeData.php deleted file mode 100644 index 9a34d85bba995..0000000000000 --- a/app/code/Magento/SalesRule/Setup/UpgradeData.php +++ /dev/null @@ -1,150 +0,0 @@ -aggregatedFieldConverter = $aggregatedFieldConverter; - $this->metadataPool = $metadataPool; - $this->resourceModelRule = $resourceModelRule; - $this->serializer = $serializer; - $this->state = $state; - $this->ruleColletionFactory = $ruleColletionFactory; - } - - /** - * @inheritdoc - */ - public function upgrade( - \Magento\Framework\Setup\ModuleDataSetupInterface $setup, - \Magento\Framework\Setup\ModuleContextInterface $context - ) { - $setup->startSetup(); - if (version_compare($context->getVersion(), '2.0.2', '<')) { - $this->convertSerializedDataToJson($setup); - } - if (version_compare($context->getVersion(), '2.0.3', '<')) { - $this->state->emulateAreaCode( - \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE, - [$this, 'fillSalesRuleProductAttributeTable'], - [$setup] - ); - $this->fillSalesRuleProductAttributeTable(); - } - $setup->endSetup(); - } - - /** - * Convert metadata from serialized to JSON format: - * - * @param \Magento\Framework\Setup\ModuleDataSetupInterface $setup * - * @return void - */ - public function convertSerializedDataToJson($setup) - { - $metadata = $this->metadataPool->getMetadata(\Magento\SalesRule\Api\Data\RuleInterface::class); - $this->aggregatedFieldConverter->convert( - [ - new \Magento\Framework\DB\FieldToConvert( - \Magento\Framework\DB\DataConverter\SerializedToJson::class, - $setup->getTable('salesrule'), - $metadata->getLinkField(), - 'conditions_serialized' - ), - new \Magento\Framework\DB\FieldToConvert( - \Magento\Framework\DB\DataConverter\SerializedToJson::class, - $setup->getTable('salesrule'), - $metadata->getLinkField(), - 'actions_serialized' - ), - ], - $setup->getConnection() - ); - } - - /** - * Fills blank table salesrule_product_attribute with data. - * - * @return void - */ - public function fillSalesRuleProductAttributeTable() - { - /** @var \Magento\SalesRule\Model\ResourceModel\Rule\Collection $ruleCollection */ - $ruleCollection = $this->ruleColletionFactory->create(); - /** @var \Magento\SalesRule\Model\Rule $rule */ - foreach ($ruleCollection as $rule) { - // Save product attributes used in rule - $conditions = $rule->getConditions()->asArray(); - $actions = $rule->getActions()->asArray(); - $serializedConditions = $this->serializer->serialize($conditions); - $serializedActions = $this->serializer->serialize($actions); - $conditionAttributes = $this->resourceModelRule->getProductAttributes($serializedConditions); - $actionAttributes = $this->resourceModelRule->getProductAttributes($serializedActions); - $ruleProductAttributes = array_merge($conditionAttributes, $actionAttributes); - if ($ruleProductAttributes) { - $this->resourceModelRule->setActualProductAttributes($rule, $ruleProductAttributes); - } - } - } -} diff --git a/app/code/Magento/SalesRule/etc/db_schema.xml b/app/code/Magento/SalesRule/etc/db_schema.xml index ed205d88d9a2d..3d882ee2eae67 100644 --- a/app/code/Magento/SalesRule/etc/db_schema.xml +++ b/app/code/Magento/SalesRule/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/SalesRule/etc/module.xml b/app/code/Magento/SalesRule/etc/module.xml index f3f160eb7d40b..4344e00b6f840 100644 --- a/app/code/Magento/SalesRule/etc/module.xml +++ b/app/code/Magento/SalesRule/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/SalesSequence/Setup/InstallData.php b/app/code/Magento/SalesSequence/Setup/InstallData.php deleted file mode 100644 index 5c07c37908760..0000000000000 --- a/app/code/Magento/SalesSequence/Setup/InstallData.php +++ /dev/null @@ -1,38 +0,0 @@ -sequenceCreator = $sequenceCreator; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $this->sequenceCreator->create(); - } -} diff --git a/app/code/Magento/SalesSequence/Setup/Patch/Schema/CreateSequence.php b/app/code/Magento/SalesSequence/Setup/Patch/Schema/CreateSequence.php new file mode 100644 index 0000000000000..875817a973a94 --- /dev/null +++ b/app/code/Magento/SalesSequence/Setup/Patch/Schema/CreateSequence.php @@ -0,0 +1,68 @@ +sequenceCreator = $sequenceCreator; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->sequenceCreator->create(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + \Magento\Store\Setup\Patch\Schema\InitializeStoresAndWebsites::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/SalesSequence/composer.json b/app/code/Magento/SalesSequence/composer.json index 37b562420383d..1a3c00373a775 100644 --- a/app/code/Magento/SalesSequence/composer.json +++ b/app/code/Magento/SalesSequence/composer.json @@ -6,7 +6,8 @@ }, "require": { "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", - "magento/framework": "100.3.*" + "magento/framework": "100.3.*", + "magento/module-store": "100.3.*" }, "type": "magento2-module", "version": "100.3.0-dev", diff --git a/app/code/Magento/SalesSequence/etc/db_schema.xml b/app/code/Magento/SalesSequence/etc/db_schema.xml index 1f63c1c93a18a..0a2d1cb9e0cbb 100644 --- a/app/code/Magento/SalesSequence/etc/db_schema.xml +++ b/app/code/Magento/SalesSequence/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/SalesSequence/etc/module.xml b/app/code/Magento/SalesSequence/etc/module.xml index d896811611254..e200d84a3145e 100644 --- a/app/code/Magento/SalesSequence/etc/module.xml +++ b/app/code/Magento/SalesSequence/etc/module.xml @@ -6,6 +6,9 @@ */ --> - + + + + diff --git a/app/code/Magento/SampleData/Setup/InstallData.php b/app/code/Magento/SampleData/Setup/InstallData.php deleted file mode 100644 index edb1bd76cc978..0000000000000 --- a/app/code/Magento/SampleData/Setup/InstallData.php +++ /dev/null @@ -1,36 +0,0 @@ -state = $state; - } - - /** - * @inheritdoc - */ - public function install(Setup\ModuleDataSetupInterface $setup, Setup\ModuleContextInterface $moduleContext) - { - $this->state->clearState(); - } -} diff --git a/app/code/Magento/SampleData/Setup/Patch/Data/ClearSampleDataState.php b/app/code/Magento/SampleData/Setup/Patch/Data/ClearSampleDataState.php new file mode 100644 index 0000000000000..2725573b1ab99 --- /dev/null +++ b/app/code/Magento/SampleData/Setup/Patch/Data/ClearSampleDataState.php @@ -0,0 +1,73 @@ +moduleDataSetup = $moduleDataSetup; + $this->state = $state; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->state->clearState(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/SampleData/etc/module.xml b/app/code/Magento/SampleData/etc/module.xml index 965a78871e54f..6746aadc4b408 100644 --- a/app/code/Magento/SampleData/etc/module.xml +++ b/app/code/Magento/SampleData/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Search/Model/SynonymAnalyzer.php b/app/code/Magento/Search/Model/SynonymAnalyzer.php index 6d5daf6115c0d..a63c10da169d7 100644 --- a/app/code/Magento/Search/Model/SynonymAnalyzer.php +++ b/app/code/Magento/Search/Model/SynonymAnalyzer.php @@ -3,10 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +declare(strict_types=1); namespace Magento\Search\Model; use Magento\Search\Api\SynonymAnalyzerInterface; +/** + * SynonymAnalyzer responsible for search of synonyms matching a word or a phrase. + */ class SynonymAnalyzer implements SynonymAnalyzerInterface { /** @@ -39,58 +44,125 @@ public function __construct(SynonymReader $synReader) * ] * @param string $phrase * @return array + * @throws \Magento\Framework\Exception\LocalizedException */ public function getSynonymsForPhrase($phrase) { - $synGroups = []; + $result = []; - if (empty($phrase)) { - return $synGroups; + if (empty(trim($phrase))) { + return $result; } - $rows = $this->synReaderModel->loadByPhrase($phrase)->getData(); - $synonyms = []; - foreach ($rows as $row) { - $synonyms [] = $row['synonyms']; - } + $synonymGroups = $this->getSynonymGroupsByPhrase($phrase); + + // Replace multiple spaces in a row with the only one space + $phrase = preg_replace("/ {2,}/", " ", $phrase); // Go through every returned record looking for presence of the actual phrase. If there were no matching // records found in DB then create a new entry for it in the returned array $words = explode(' ', $phrase); - foreach ($words as $w) { - $position = $this->findInArray($w, $synonyms); - if ($position !== false) { - $synGroups[] = explode(',', $synonyms[$position]); - } else { - // No synonyms were found. Return the original word in this position - $synGroups[] = [$w]; + + foreach ($words as $offset => $word) { + $synonyms = [$word]; + + if ($synonymGroups) { + $pattern = $this->getSearchPattern(\array_slice($words, $offset)); + $position = $this->findInArray($pattern, $synonymGroups); + if ($position !== null) { + $synonyms = explode(',', $synonymGroups[$position]); + } } + + $result[] = $synonyms; } - return $synGroups; + + return $result; } /** - * Helper method to find the presence of $word in $wordsArray. If found, the particular array index is returned. + * Helper method to find the matching of $pattern to $synonymGroupsToExamine. + * If matches, the particular array index is returned. * Otherwise false will be returned. * - * @param string $word - * @param $array $wordsArray - * @return boolean | int + * @param string $pattern + * @param array $synonymGroupsToExamine + * @return int|null */ - private function findInArray($word, $wordsArray) + private function findInArray(string $pattern, array $synonymGroupsToExamine) { - if (empty($wordsArray)) { - return false; - } $position = 0; - foreach ($wordsArray as $wordsLine) { - $pattern = '/^' . $word . ',|,' . $word . ',|,' . $word . '$/'; - $rv = preg_match($pattern, $wordsLine); - if ($rv != 0) { + foreach ($synonymGroupsToExamine as $synonymGroup) { + $matchingResultCode = preg_match($pattern, $synonymGroup); + if ($matchingResultCode === 1) { return $position; } $position++; } - return false; + return null; + } + + /** + * Returns a regular expression to search for synonyms of the phrase represented as the list of words. + * + * Returned pattern contains expression to search for a part of the phrase from the beginning. + * + * For example, in the phrase "Elizabeth is the English queen" with subset from the very first word, + * the method will build an expression which looking for synonyms for all these patterns: + * - Elizabeth is the English queen + * - Elizabeth is the English + * - Elizabeth is the + * - Elizabeth is + * - Elizabeth + * + * For the same phrase on the second iteration with the first word "is" it will match for these synonyms: + * - is the English queen + * - is the English + * - is the + * - is + * + * The pattern looking for exact match and will not find these phrases as synonyms: + * - Is there anybody in the room? + * - Is the English is most popular language? + * - Is the English queen Elizabeth? + * + * Take into account that returned pattern expects that data will be represented as comma-separated value. + * + * @param array $words + * @return string + */ + private function getSearchPattern(array $words): string + { + $patterns = []; + for ($lastItem = count($words); $lastItem > 0; $lastItem--) { + $phrase = implode("\s+", \array_slice($words, 0, $lastItem)); + $patterns[] = '^' . $phrase . ','; + $patterns[] = ',' . $phrase . ','; + $patterns[] = ',' . $phrase . '$'; + } + + $pattern = '/' . implode('|', $patterns) . '/i'; + return $pattern; + } + + /** + * Get all synonym groups for the phrase + * + * Returns an array of synonyms which are represented as comma-separated value for each item in the list + * + * @param string $phrase + * @return string[] + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function getSynonymGroupsByPhrase(string $phrase): array + { + $result = []; + + /** @var array $synonymGroups */ + $synonymGroups = $this->synReaderModel->loadByPhrase($phrase)->getData(); + foreach ($synonymGroups as $row) { + $result[] = $row['synonyms']; + } + return $result; } } diff --git a/app/code/Magento/Search/Model/SynonymReader.php b/app/code/Magento/Search/Model/SynonymReader.php index 202931665f493..078a3eb178cbe 100644 --- a/app/code/Magento/Search/Model/SynonymReader.php +++ b/app/code/Magento/Search/Model/SynonymReader.php @@ -78,6 +78,7 @@ protected function _construct() * * @param string $phrase * @return $this + * @throws \Magento\Framework\Exception\LocalizedException * @since 100.1.0 */ public function loadByPhrase($phrase) diff --git a/app/code/Magento/Search/etc/db_schema.xml b/app/code/Magento/Search/etc/db_schema.xml index 54fac0778d469..9b2dfb493dbb8 100644 --- a/app/code/Magento/Search/etc/db_schema.xml +++ b/app/code/Magento/Search/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Search/etc/module.xml b/app/code/Magento/Search/etc/module.xml index 12c5591109591..2acbc54254eb0 100644 --- a/app/code/Magento/Search/etc/module.xml +++ b/app/code/Magento/Search/etc/module.xml @@ -7,7 +7,7 @@ --> - + diff --git a/app/code/Magento/Security/etc/db_schema.xml b/app/code/Magento/Security/etc/db_schema.xml index 017cdd551dc8a..f14e6de79e894 100644 --- a/app/code/Magento/Security/etc/db_schema.xml +++ b/app/code/Magento/Security/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Security/etc/module.xml b/app/code/Magento/Security/etc/module.xml index e1f0239be3fdd..9141c4ddbea66 100644 --- a/app/code/Magento/Security/etc/module.xml +++ b/app/code/Magento/Security/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/SendFriend/etc/db_schema.xml b/app/code/Magento/SendFriend/etc/db_schema.xml index f3c0fb8d06e8f..7537f67cf552a 100644 --- a/app/code/Magento/SendFriend/etc/db_schema.xml +++ b/app/code/Magento/SendFriend/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/SendFriend/etc/module.xml b/app/code/Magento/SendFriend/etc/module.xml index fae2b90f710a3..01c267b3c4fcb 100644 --- a/app/code/Magento/SendFriend/etc/module.xml +++ b/app/code/Magento/SendFriend/etc/module.xml @@ -7,7 +7,7 @@ --> - + diff --git a/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php b/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php index 0c6be6fd57756..c4094a63ec527 100644 --- a/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php +++ b/app/code/Magento/Shipping/Controller/Adminhtml/Order/ShipmentLoader.php @@ -6,6 +6,16 @@ namespace Magento\Shipping\Controller\Adminhtml\Order; use Magento\Framework\DataObject; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Message\ManagerInterface; +use Magento\Framework\Registry; +use Magento\Sales\Api\Data\ShipmentTrackCreationInterface; +use Magento\Sales\Api\Data\ShipmentTrackCreationInterfaceFactory; +use Magento\Sales\Api\Data\ShipmentItemCreationInterfaceFactory; +use Magento\Sales\Api\ShipmentRepositoryInterface; +use Magento\Sales\Api\OrderRepositoryInterface; +use Magento\Sales\Model\Order\ShipmentDocumentFactory; +use Magento\Sales\Api\Data\ShipmentItemCreationInterface; /** * Class ShipmentLoader @@ -17,80 +27,77 @@ * @method ShipmentLoader setTracking($tracking) * @method int getOrderId() * @method int getShipmentId() - * @method array getShipment() * @method array getTracking() */ class ShipmentLoader extends DataObject { + const SHIPMENT = 'shipment'; + /** - * @var \Magento\Framework\Message\ManagerInterface + * @var ManagerInterface */ - protected $messageManager; + private $messageManager; /** - * @var \Magento\Framework\Registry + * @var Registry */ - protected $registry; + private $registry; /** - * @var \Magento\Sales\Api\ShipmentRepositoryInterface + * @var ShipmentRepositoryInterface */ - protected $shipmentRepository; + private $shipmentRepository; /** - * @var \Magento\Sales\Model\Order\ShipmentFactory + * @var OrderRepositoryInterface */ - protected $shipmentFactory; + private $orderRepository; /** - * @var \Magento\Sales\Model\Order\Shipment\TrackFactory + * @var ShipmentDocumentFactory */ - protected $trackFactory; + private $documentFactory; /** - * @var \Magento\Sales\Api\OrderRepositoryInterface + * @var ShipmentTrackCreationInterfaceFactory */ - protected $orderRepository; + private $trackFactory; /** - * @param \Magento\Framework\Message\ManagerInterface $messageManager - * @param \Magento\Framework\Registry $registry - * @param \Magento\Sales\Api\ShipmentRepositoryInterface $shipmentRepository - * @param \Magento\Sales\Model\Order\ShipmentFactory $shipmentFactory - * @param \Magento\Sales\Model\Order\Shipment\TrackFactory $trackFactory - * @param \Magento\Sales\Api\OrderRepositoryInterface $orderRepository + * @var ShipmentItemCreationInterfaceFactory + */ + private $itemFactory; + + /** + * @param ManagerInterface $messageManager + * @param Registry $registry + * @param ShipmentRepositoryInterface $shipmentRepository + * @param OrderRepositoryInterface $orderRepository + * @param ShipmentDocumentFactory $documentFactory + * @param ShipmentTrackCreationInterfaceFactory $trackFactory + * @param ShipmentItemCreationInterfaceFactory $itemFactory * @param array $data */ public function __construct( - \Magento\Framework\Message\ManagerInterface $messageManager, - \Magento\Framework\Registry $registry, - \Magento\Sales\Api\ShipmentRepositoryInterface $shipmentRepository, - \Magento\Sales\Model\Order\ShipmentFactory $shipmentFactory, - \Magento\Sales\Model\Order\Shipment\TrackFactory $trackFactory, - \Magento\Sales\Api\OrderRepositoryInterface $orderRepository, + ManagerInterface $messageManager, + Registry $registry, + ShipmentRepositoryInterface $shipmentRepository, + OrderRepositoryInterface $orderRepository, + ShipmentDocumentFactory $documentFactory, + ShipmentTrackCreationInterfaceFactory $trackFactory, + ShipmentItemCreationInterfaceFactory $itemFactory, array $data = [] ) { $this->messageManager = $messageManager; $this->registry = $registry; $this->shipmentRepository = $shipmentRepository; - $this->shipmentFactory = $shipmentFactory; - $this->trackFactory = $trackFactory; $this->orderRepository = $orderRepository; + $this->documentFactory = $documentFactory; + $this->trackFactory = $trackFactory; + $this->itemFactory = $itemFactory; parent::__construct($data); } - /** - * Initialize shipment items QTY - * - * @return array - */ - protected function getItemQtys() - { - $data = $this->getShipment(); - - return isset($data['items']) ? $data['items'] : []; - } - /** * Initialize shipment model instance * @@ -129,14 +136,73 @@ public function load() return false; } - $shipment = $this->shipmentFactory->create( + $shipmentItems = $this->getShipmentItems($this->getShipment()); + + $shipment = $this->documentFactory->create( $order, - $this->getItemQtys(), - $this->getTracking() + $shipmentItems, + $this->getTrackingArray() ); } $this->registry->register('current_shipment', $shipment); return $shipment; } + + /** + * Convert UI-generated tracking array to Data Object array + * + * @return ShipmentTrackCreationInterface[] + * @throws LocalizedException + */ + private function getTrackingArray() + { + $tracks = $this->getTracking() ?: []; + $trackingCreation = []; + foreach ($tracks as $track) { + if (!isset($track['number']) || !isset($track['title']) || !isset($track['carrier_code'])) { + throw new LocalizedException( + __('Tracking information must contain title, carrier code, and tracking number') + ); + } + /** @var ShipmentTrackCreationInterface $trackCreation */ + $trackCreation = $this->trackFactory->create(); + $trackCreation->setTrackNumber($track['number']); + $trackCreation->setTitle($track['title']); + $trackCreation->setCarrierCode($track['carrier_code']); + $trackingCreation[] = $trackCreation; + } + + return $trackingCreation; + } + + /** + * Extract product id => product quantity array from shipment data. + * + * @param array $shipmentData + * @return int[] + */ + private function getShipmentItems(array $shipmentData) + { + $shipmentItems = []; + $itemQty = isset($shipmentData['items']) ? $shipmentData['items'] : []; + foreach ($itemQty as $itemId => $quantity) { + /** @var ShipmentItemCreationInterface $item */ + $item = $this->itemFactory->create(); + $item->setOrderItemId($itemId); + $item->setQty($quantity); + $shipmentItems[] = $item; + } + return $shipmentItems; + } + + /** + * Retrieve shipment + * + * @return array + */ + public function getShipment() + { + return $this->getData(self::SHIPMENT) ?: []; + } } diff --git a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php index 29e861cca891f..5575792c346d3 100644 --- a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php +++ b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php @@ -453,7 +453,7 @@ protected function _updateFreeMethodQuote($request) */ public function getFinalPriceWithHandlingFee($cost) { - $handlingFee = $this->getConfigData('handling_fee'); + $handlingFee = (float)$this->getConfigData('handling_fee'); $handlingType = $this->getConfigData('handling_type'); if (!$handlingType) { $handlingType = self::HANDLING_TYPE_FIXED; diff --git a/app/code/Magento/Shipping/Model/Info.php b/app/code/Magento/Shipping/Model/Info.php index 31d39fb80410b..ed4c1c3f6d127 100644 --- a/app/code/Magento/Shipping/Model/Info.php +++ b/app/code/Magento/Shipping/Model/Info.php @@ -114,7 +114,7 @@ protected function _initOrder() /** @var \Magento\Sales\Model\Order $order */ $order = $this->_orderFactory->create()->load($this->getOrderId()); - if (!$order->getId() || $this->getProtectCode() != $order->getProtectCode()) { + if (!$order->getId() || $this->getProtectCode() !== $order->getProtectCode()) { return false; } @@ -130,7 +130,7 @@ protected function _initShipment() { /* @var $model Shipment */ $ship = $this->shipmentRepository->get($this->getShipId()); - if (!$ship->getEntityId() || $this->getProtectCode() != $ship->getProtectCode()) { + if (!$ship->getEntityId() || $this->getProtectCode() !== $ship->getProtectCode()) { return false; } @@ -195,7 +195,7 @@ public function getTrackingInfoByTrackId() { /** @var \Magento\Shipping\Model\Order\Track $track */ $track = $this->_trackFactory->create()->load($this->getTrackId()); - if ($track->getId() && $this->getProtectCode() == $track->getProtectCode()) { + if ($track->getId() && $this->getProtectCode() === $track->getProtectCode()) { $this->_trackingInfo = [[$track->getNumberDetail()]]; } return $this->_trackingInfo; diff --git a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/ShipmentLoaderTest.php b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/ShipmentLoaderTest.php index 39c960e933d45..83dd9595cc43b 100644 --- a/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/ShipmentLoaderTest.php +++ b/app/code/Magento/Shipping/Test/Unit/Controller/Adminhtml/Order/ShipmentLoaderTest.php @@ -5,55 +5,67 @@ */ namespace Magento\Shipping\Test\Unit\Controller\Adminhtml\Order; +use Magento\Sales\Api\Data\ShipmentItemCreationInterface; +use Magento\Sales\Api\Data\ShipmentTrackCreationInterface; +use Magento\Sales\Api\Data\ShipmentTrackCreationInterfaceFactory; +use Magento\Sales\Api\Data\ShipmentItemCreationInterfaceFactory; +use Magento\Sales\Model\Order\ShipmentDocumentFactory; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader; + /** - * Class ShipmentLoaderTest - * - * @package Magento\Shipping\Controller\Adminhtml\Order + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class ShipmentLoaderTest extends \PHPUnit\Framework\TestCase { /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var ObjectManager */ - protected $objectManagerMock; + private $objectManagerMock; /** * @var \PHPUnit_Framework_MockObject_MockObject */ - protected $registryMock; + private $registryMock; /** * @var \PHPUnit_Framework_MockObject_MockObject */ - protected $messageManagerMock; + private $messageManagerMock; /** * @var \Magento\Sales\Model\Order\ShipmentRepository|\PHPUnit_Framework_MockObject_MockObject */ - protected $shipmentRepositoryMock; + private $shipmentRepositoryMock; /** - * @var \Magento\Sales\Model\Order\ShipmentFactory|\PHPUnit_Framework_MockObject_MockObject + * @var ShipmentDocumentFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $shipmentFactory; + private $documentFactoryMock; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var ShipmentTrackCreationInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $trackFactoryMock; + + /** + * @var ShipmentItemCreationInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject */ - protected $trackFactoryMock; + private $itemFactoryMock; /** * @var \PHPUnit_Framework_MockObject_MockObject */ - protected $orderRepository; + private $orderRepositoryMock; /** * @var \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader */ - protected $loader; + private $loader; protected function setUp() { + $this->objectManagerMock = new ObjectManager($this); $this->shipmentRepositoryMock = $this->getMockBuilder(\Magento\Sales\Model\Order\ShipmentRepository::class) ->disableOriginalConstructor() ->setMethods(['get']) @@ -62,19 +74,23 @@ protected function setUp() ->disableOriginalConstructor() ->setMethods([]) ->getMock(); - $this->shipmentFactory = $this->getMockBuilder(\Magento\Sales\Model\Order\ShipmentFactory::class) + $this->trackFactoryMock = $this->getMockBuilder(ShipmentTrackCreationInterfaceFactory::class) ->disableOriginalConstructor() ->setMethods(['create']) ->getMock(); - $this->trackFactoryMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\TrackFactory::class) + $this->messageManagerMock = $this->getMockBuilder(\Magento\Framework\Message\Manager::class) ->disableOriginalConstructor() - ->setMethods(['create']) + ->setMethods([]) ->getMock(); - $this->messageManagerMock = $this->getMockBuilder(\Magento\Framework\Message\Manager::class) + $this->orderRepositoryMock = $this->getMockBuilder(\Magento\Sales\Api\OrderRepositoryInterface::class) ->disableOriginalConstructor() ->setMethods([]) ->getMock(); - $this->orderRepository = $this->getMockBuilder(\Magento\Sales\Api\OrderRepositoryInterface::class) + $this->itemFactoryMock = $this->getMockBuilder(ShipmentItemCreationInterfaceFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->documentFactoryMock = $this->getMockBuilder(ShipmentDocumentFactory::class) ->disableOriginalConstructor() ->setMethods([]) ->getMock(); @@ -84,19 +100,23 @@ protected function setUp() 'shipment_id' => 1000065, 'shipment' => ['items' => [1 => 1, 2 => 2]], 'tracking' => [ - ['number' => 'jds0395'], - ['number' => 'lsk984g'], + ['number' => 'jds0395', 'title' => 'DHL', 'carrier_code' => 'dhl'], + ['number' => 'lsk984g', 'title' => 'UPS', 'carrier_code' => 'ups'], ], ]; - $this->loader = new \Magento\Shipping\Controller\Adminhtml\Order\ShipmentLoader( - $this->messageManagerMock, - $this->registryMock, - $this->shipmentRepositoryMock, - $this->shipmentFactory, - $this->trackFactoryMock, - $this->orderRepository, - $data + $this->loader = $this->objectManagerMock->getObject( + ShipmentLoader::class, + [ + 'messageManager' => $this->messageManagerMock, + 'registry' => $this->registryMock, + 'shipmentRepository' => $this->shipmentRepositoryMock, + 'orderRepository' => $this->orderRepositoryMock, + 'documentFactory' => $this->documentFactoryMock, + 'trackFactory' => $this->trackFactoryMock, + 'itemFactory' => $this->itemFactoryMock, + 'data' => $data + ] ); } @@ -123,7 +143,7 @@ public function testLoadOrderId() ->disableOriginalConstructor() ->setMethods(['getForcedShipmentWithInvoice', 'getId', 'canShip']) ->getMock(); - $this->orderRepository->expects($this->once()) + $this->orderRepositoryMock->expects($this->once()) ->method('get') ->will($this->returnValue($orderMock)); $orderMock->expects($this->once()) @@ -139,27 +159,13 @@ public function testLoadOrderId() ->disableOriginalConstructor() ->setMethods([]) ->getMock(); - $this->shipmentFactory->expects($this->once()) - ->method('create') - ->with($orderMock, $this->loader->getShipment()['items']) - ->willReturn($shipmentModelMock); - $trackMock = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\Track::class) + $trackMock = $this->getMockBuilder(ShipmentTrackCreationInterface::class) ->disableOriginalConstructor() - ->setMethods([]) - ->getMock(); + ->setMethods(['setCarrierCode', 'setTrackNumber', 'setTitle']) + ->getMockForAbstractClass(); $this->trackFactoryMock->expects($this->any()) ->method('create') ->will($this->returnValue($trackMock)); - $trackMock->expects($this->any()) - ->method('addData') - ->will( - $this->returnValueMap( - [ - [$this->loader->getTracking()[0], $trackMock], - [$this->loader->getTracking()[1], $trackMock], - ] - ) - ); $shipmentModelMock->expects($this->any()) ->method('addTrack') ->with($this->equalTo($trackMock)) @@ -167,6 +173,13 @@ public function testLoadOrderId() $this->registryMock->expects($this->once()) ->method('register') ->with('current_shipment', $shipmentModelMock); + $itemMock = $this->getMockBuilder(ShipmentItemCreationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->itemFactoryMock->expects($this->any()) + ->method('create') + ->will($this->returnValue($itemMock)); + $this->documentFactoryMock->expects($this->once())->method('create')->willReturn($shipmentModelMock); $this->assertEquals($shipmentModelMock, $this->loader->load()); } diff --git a/app/code/Magento/Shipping/Test/Unit/Model/InfoTest.php b/app/code/Magento/Shipping/Test/Unit/Model/InfoTest.php new file mode 100644 index 0000000000000..6bc95993bfde6 --- /dev/null +++ b/app/code/Magento/Shipping/Test/Unit/Model/InfoTest.php @@ -0,0 +1,312 @@ +helper = $this->getMockBuilder(\Magento\Shipping\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderFactory = $this->getMockBuilder(\Magento\Sales\Model\OrderFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->shipmentRepository = $this->getMockBuilder(\Magento\Sales\Api\ShipmentRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->trackFactory = $this->getMockBuilder(\Magento\Shipping\Model\Order\TrackFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->trackCollectionFactory = $this->getMockBuilder(CollectionFactory::class) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + + $objectManagerHelper = new ObjectManager($this); + $this->info = $objectManagerHelper->getObject( + Info::class, + [ + 'shippingData' => $this->helper, + 'orderFactory' => $this->orderFactory, + 'shipmentRepository' => $this->shipmentRepository, + 'trackFactory' => $this->trackFactory, + 'trackCollectionFactory' => $this->trackCollectionFactory, + ] + ); + } + + public function testLoadByHashWithOrderId() + { + $hash = strtr(base64_encode('order_id:1:protected_code'), '+/=', '-_,'); + $decodedHash = [ + 'key' => 'order_id', + 'id' => 1, + 'hash' => 'protected_code', + ]; + $shipmentId = 1; + $shipmentIncrementId = 3; + $trackDetails = 'track_details'; + + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $shipmentCollection = $this->getMockBuilder(\Magento\Sales\Model\ResourceModel\Order\Shipment\Collection::class) + ->disableOriginalConstructor() + ->setMethods(['getIterator']) + ->getMock(); + + $order = $this->getMockBuilder(\Magento\Sales\Model\Order::class) + ->disableOriginalConstructor() + ->setMethods(['load', 'getId', 'getProtectCode', 'getShipmentsCollection']) + ->getMock(); + $order->expects($this->atLeastOnce())->method('load')->with($decodedHash['id'])->willReturnSelf(); + $order->expects($this->atLeastOnce())->method('getId')->willReturn($decodedHash['id']); + $order->expects($this->atLeastOnce())->method('getProtectCode')->willReturn($decodedHash['hash']); + $order->expects($this->atLeastOnce())->method('getShipmentsCollection')->willReturn($shipmentCollection); + $this->orderFactory->expects($this->atLeastOnce())->method('create')->willReturn($order); + + $shipment = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class) + ->disableOriginalConstructor() + ->setMethods(['getIncrementId', 'getId']) + ->getMock(); + $shipment->expects($this->atLeastOnce())->method('getIncrementId')->willReturn($shipmentIncrementId); + $shipment->expects($this->atLeastOnce())->method('getId')->willReturn($shipmentId); + $shipmentCollection->expects($this->any())->method('getIterator')->willReturn(new \ArrayIterator([$shipment])); + + $track = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\Track::class) + ->disableOriginalConstructor() + ->setMethods(['setShipment', 'getNumberDetail']) + ->getMock(); + $track->expects($this->atLeastOnce())->method('setShipment')->with($shipment)->willReturnSelf(); + $track->expects($this->atLeastOnce())->method('getNumberDetail')->willReturn($trackDetails); + $trackCollection = $this->getMockBuilder(\Magento\Shipping\Model\ResourceModel\Order\Track\Collection::class) + ->disableOriginalConstructor() + ->setMethods(['getIterator', 'setShipmentFilter']) + ->getMock(); + $trackCollection->expects($this->atLeastOnce()) + ->method('setShipmentFilter') + ->with($shipmentId) + ->willReturnSelf(); + $trackCollection->expects($this->atLeastOnce()) + ->method('getIterator') + ->willReturn(new \ArrayIterator([$track])); + + $this->trackCollectionFactory->expects($this->atLeastOnce())->method('create')->willReturn($trackCollection); + $this->info->loadByHash($hash); + + $this->assertEquals([$shipmentIncrementId => [$trackDetails]], $this->info->getTrackingInfo()); + } + + public function testLoadByHashWithOrderIdWrongCode() + { + $hash = strtr(base64_encode('order_id:1:0'), '+/=', '-_,'); + $decodedHash = [ + 'key' => 'order_id', + 'id' => 1, + 'hash' => '0', + ]; + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $order = $this->getMockBuilder(\Magento\Sales\Model\Order::class) + ->disableOriginalConstructor() + ->setMethods(['load', 'getId', 'getProtectCode']) + ->getMock(); + $order->expects($this->atLeastOnce())->method('load')->with($decodedHash['id'])->willReturnSelf(); + $order->expects($this->atLeastOnce())->method('getId')->willReturn($decodedHash['id']); + $order->expects($this->atLeastOnce())->method('getProtectCode')->willReturn('0e123123123'); + $this->orderFactory->expects($this->atLeastOnce())->method('create')->willReturn($order); + $this->info->loadByHash($hash); + + $this->assertEmpty($this->info->getTrackingInfo()); + } + + public function testLoadByHashWithShipmentId() + { + $hash = strtr(base64_encode('ship_id:1:protected_code'), '+/=', '-_,'); + $decodedHash = [ + 'key' => 'ship_id', + 'id' => 1, + 'hash' => 'protected_code', + ]; + $shipmentIncrementId = 3; + $trackDetails = 'track_details'; + + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $shipment = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class) + ->disableOriginalConstructor() + ->setMethods(['getEntityId', 'getProtectCode', 'getIncrementId', 'getId']) + ->getMock(); + $shipment->expects($this->atLeastOnce())->method('getIncrementId')->willReturn($shipmentIncrementId); + $shipment->expects($this->atLeastOnce())->method('getId')->willReturn($decodedHash['id']); + $shipment->expects($this->atLeastOnce())->method('getEntityId')->willReturn(3); + $shipment->expects($this->atLeastOnce())->method('getProtectCode')->willReturn($decodedHash['hash']); + $this->shipmentRepository->expects($this->atLeastOnce()) + ->method('get') + ->with($decodedHash['id']) + ->willReturn($shipment); + $track = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\Track::class) + ->disableOriginalConstructor() + ->setMethods(['setShipment', 'getNumberDetail']) + ->getMock(); + $track->expects($this->atLeastOnce())->method('setShipment')->with($shipment)->willReturnSelf(); + $track->expects($this->atLeastOnce())->method('getNumberDetail')->willReturn($trackDetails); + $trackCollection = $this->getMockBuilder(\Magento\Shipping\Model\ResourceModel\Order\Track\Collection::class) + ->disableOriginalConstructor() + ->setMethods(['getIterator', 'setShipmentFilter']) + ->getMock(); + $trackCollection->expects($this->atLeastOnce()) + ->method('setShipmentFilter') + ->with($decodedHash['id']) + ->willReturnSelf(); + $trackCollection->expects($this->atLeastOnce()) + ->method('getIterator') + ->willReturn(new \ArrayIterator([$track])); + $this->trackCollectionFactory->expects($this->atLeastOnce())->method('create')->willReturn($trackCollection); + + $this->info->loadByHash($hash); + + $this->assertEquals([$shipmentIncrementId => [$trackDetails]], $this->info->getTrackingInfo()); + } + + public function testLoadByHashWithShipmentIdWrongCode() + { + $hash = strtr(base64_encode('ship_id:1:0'), '+/=', '-_,'); + $decodedHash = [ + 'key' => 'ship_id', + 'id' => 1, + 'hash' => '0', + ]; + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $shipment = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment::class) + ->disableOriginalConstructor() + ->setMethods(['getEntityId', 'getProtectCode']) + ->getMock(); + $shipment->expects($this->atLeastOnce())->method('getEntityId')->willReturn(3); + $shipment->expects($this->atLeastOnce())->method('getProtectCode')->willReturn('0e123123123'); + $this->shipmentRepository->expects($this->atLeastOnce()) + ->method('get') + ->with($decodedHash['id']) + ->willReturn($shipment); + + $this->info->loadByHash($hash); + + $this->assertEmpty($this->info->getTrackingInfo()); + } + + /** + * @dataProvider loadByHashWithTrackIdDataProvider + * @param string $protectCodeHash + * @param string $protectCode + * @param string $numberDetail + * @param array $trackDetails + * @return void + */ + public function testLoadByHashWithTrackId( + string $protectCodeHash, + string $protectCode, + string $numberDetail, + array $trackDetails + ) { + $hash = base64_encode('hash'); + $decodedHash = [ + 'key' => 'track_id', + 'id' => 1, + 'hash' => $protectCodeHash, + ]; + $this->helper->expects($this->atLeastOnce()) + ->method('decodeTrackingHash') + ->with($hash) + ->willReturn($decodedHash); + $track = $this->getMockBuilder(\Magento\Sales\Model\Order\Shipment\Track::class) + ->disableOriginalConstructor() + ->setMethods(['load', 'getId', 'getProtectCode', 'getNumberDetail']) + ->getMock(); + $track->expects($this->atLeastOnce())->method('load')->with($decodedHash['id'])->willReturnSelf(); + $track->expects($this->atLeastOnce())->method('getId')->willReturn($decodedHash['id']); + $track->expects($this->atLeastOnce())->method('getProtectCode')->willReturn($protectCode); + $track->expects($this->any())->method('getNumberDetail')->willReturn($numberDetail); + + $this->trackFactory->expects($this->atLeastOnce())->method('create')->willReturn($track); + $this->info->loadByHash($hash); + + $this->assertEquals($trackDetails, $this->info->getTrackingInfo()); + } + + /** + * @return array + */ + public function loadByHashWithTrackIdDataProvider() + { + return [ + [ + 'hash' => 'protected_code', + 'protect_code' => 'protected_code', + 'number_detail' => 'track_details', + 'track_details' => [['track_details']], + ], + [ + 'hash' => '0', + 'protect_code' => '0e6640', + 'number_detail' => '', + 'track_details' => [], + ], + ]; + } +} diff --git a/app/code/Magento/Shipping/etc/module.xml b/app/code/Magento/Shipping/etc/module.xml index af78f43d77644..1a54ecd64b38e 100644 --- a/app/code/Magento/Shipping/etc/module.xml +++ b/app/code/Magento/Shipping/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Shipping/view/adminhtml/templates/create/items.phtml b/app/code/Magento/Shipping/view/adminhtml/templates/create/items.phtml index 89cc760bb8290..35e36aa5584c9 100644 --- a/app/code/Magento/Shipping/view/adminhtml/templates/create/items.phtml +++ b/app/code/Magento/Shipping/view/adminhtml/templates/create/items.phtml @@ -27,7 +27,7 @@ getShipment()->getAllItems() ?> - getOrderItem()->getIsVirtual() || $_item->getOrderItem()->getParentItem()): continue; endif; $_i++ ?> + getOrderItem()->getParentItem()): continue; endif; $_i++ ?> getItemHtml($_item) ?> getItemExtraInfoHtml($_item->getOrderItem()) ?> diff --git a/app/code/Magento/Shipping/view/adminhtml/templates/view/items.phtml b/app/code/Magento/Shipping/view/adminhtml/templates/view/items.phtml index 202e96bc425c9..8dddfaedda4e5 100644 --- a/app/code/Magento/Shipping/view/adminhtml/templates/view/items.phtml +++ b/app/code/Magento/Shipping/view/adminhtml/templates/view/items.phtml @@ -16,7 +16,7 @@ getShipment()->getAllItems() ?> - getOrderItem()->getIsVirtual() || $_item->getOrderItem()->getParentItem()): continue; endif; $_i++ ?> + getOrderItem()->getParentItem()): continue; endif; $_i++ ?> getItemHtml($_item) ?> getItemExtraInfoHtml($_item->getOrderItem()) ?> diff --git a/app/code/Magento/Shipping/view/frontend/templates/tracking/details.phtml b/app/code/Magento/Shipping/view/frontend/templates/tracking/details.phtml index 344ad2a87e4f4..9253b47f82f5d 100644 --- a/app/code/Magento/Shipping/view/frontend/templates/tracking/details.phtml +++ b/app/code/Magento/Shipping/view/frontend/templates/tracking/details.phtml @@ -21,7 +21,7 @@ $fields = [ ]; $number = is_object($track) ? $track->getTracking() : $track['number']; ?> -
+
diff --git a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml index 8a9d5fc0fe371..84126d8eeb636 100644 --- a/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml +++ b/app/code/Magento/Shipping/view/frontend/templates/tracking/progress.phtml @@ -11,7 +11,7 @@ $parentBlock = $block->getParentBlock(); $track = $block->getData('track'); ?>
-
escapeHtml(__('Order tracking')) ?>
+
diff --git a/app/code/Magento/Signifyd/etc/db_schema.xml b/app/code/Magento/Signifyd/etc/db_schema.xml index 731ae1e94b2bb..d416112c20d70 100644 --- a/app/code/Magento/Signifyd/etc/db_schema.xml +++ b/app/code/Magento/Signifyd/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
escapeHtml(__('Track history')) ?>
diff --git a/app/code/Magento/Signifyd/etc/module.xml b/app/code/Magento/Signifyd/etc/module.xml index d5adcba88ad9a..264f295e8c528 100644 --- a/app/code/Magento/Signifyd/etc/module.xml +++ b/app/code/Magento/Signifyd/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Sitemap/etc/db_schema.xml b/app/code/Magento/Sitemap/etc/db_schema.xml index 4abc9a2fbe035..82a9b8ef5148c 100644 --- a/app/code/Magento/Sitemap/etc/db_schema.xml +++ b/app/code/Magento/Sitemap/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Sitemap/etc/module.xml b/app/code/Magento/Sitemap/etc/module.xml index 0cfe3d551d162..cf6327ac94e2c 100644 --- a/app/code/Magento/Sitemap/etc/module.xml +++ b/app/code/Magento/Sitemap/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Store/Model/Config/Placeholder.php b/app/code/Magento/Store/Model/Config/Placeholder.php index b08e58c59c1a7..4e4139d47bd92 100644 --- a/app/code/Magento/Store/Model/Config/Placeholder.php +++ b/app/code/Magento/Store/Model/Config/Placeholder.php @@ -91,8 +91,9 @@ protected function _processPlaceholders($value, $data) if ($url) { $value = str_replace('{{' . $placeholder . '}}', $url, $value); } elseif (strpos($value, $this->urlPlaceholder) !== false) { - // localhost is replaced for cli requests, for http requests method getDistroBaseUrl is used - $value = str_replace($this->urlPlaceholder, 'http://localhost/', $value); + $distroBaseUrl = $this->request->getDistroBaseUrl(); + + $value = str_replace($this->urlPlaceholder, $distroBaseUrl, $value); } if (null !== $this->_getPlaceholder($value)) { diff --git a/app/code/Magento/Store/Setup/Patch/Data/UpdateStoreGroupCodes.php b/app/code/Magento/Store/Setup/Patch/Data/UpdateStoreGroupCodes.php new file mode 100644 index 0000000000000..43fd3f84c2ab1 --- /dev/null +++ b/app/code/Magento/Store/Setup/Patch/Data/UpdateStoreGroupCodes.php @@ -0,0 +1,103 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->updateStoreGroupCodes(); + } + + /** + * Upgrade codes for store groups + */ + private function updateStoreGroupCodes() + { + $connection = $this->moduleDataSetup->getConnection(); + $storeGroupTable = $this->moduleDataSetup->getTable('store_group'); + $select = $connection->select()->from( + $storeGroupTable, + ['group_id', 'name'] + ); + + $groupList = $connection->fetchPairs($select); + + $codes = []; + foreach ($groupList as $groupId => $groupName) { + $code = preg_replace('/\s+/', '_', $groupName); + $code = preg_replace('/[^a-z0-9-_]/', '', strtolower($code)); + $code = preg_replace('/^[^a-z]+/', '', $code); + + if (empty($code)) { + $code = 'store_group'; + } + + if (array_key_exists($code, $codes)) { + $codes[$code]++; + $code = $code . $codes[$code]; + } + $codes[$code] = 1; + + $connection->update( + $storeGroupTable, + ['code' => $code], + ['group_id = ?' => $groupId] + ); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.1.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Store/Setup/Patch/Schema/InitializeStoresAndWebsites.php b/app/code/Magento/Store/Setup/Patch/Schema/InitializeStoresAndWebsites.php new file mode 100644 index 0000000000000..a282f2c21ef0e --- /dev/null +++ b/app/code/Magento/Store/Setup/Patch/Schema/InitializeStoresAndWebsites.php @@ -0,0 +1,178 @@ +schemaSetup = $schemaSetup; + $this->defaultCategoryFactory = $defaultCategoryFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->schemaSetup->startSetup(); + $connection = $this->schemaSetup->getConnection(); + $select = $connection->select() + ->from($this->schemaSetup->getTable('store_website')) + ->where('website_id = ?', 0); + + if ($connection->fetchOne($select) === false) { + /** + * Insert websites + */ + $connection->insertForce( + $this->schemaSetup->getTable('store_website'), + [ + 'website_id' => 0, + 'code' => 'admin', + 'name' => 'Admin', + 'sort_order' => 0, + 'default_group_id' => 0, + 'is_default' => 0 + ] + ); + $connection->insertForce( + $this->schemaSetup->getTable('store_website'), + [ + 'website_id' => 1, + 'code' => 'base', + 'name' => 'Main Website', + 'sort_order' => 0, + 'default_group_id' => 1, + 'is_default' => 1 + ] + ); + + /** + * Insert store groups + */ + $connection->insertForce( + $this->schemaSetup->getTable('store_group'), + [ + 'group_id' => 0, + 'website_id' => 0, + 'name' => 'Default', + 'root_category_id' => 0, + 'default_store_id' => 0 + ] + ); + $connection->insertForce( + $this->schemaSetup->getTable('store_group'), + [ + 'group_id' => 1, + 'website_id' => 1, + 'name' => 'Main Website Store', + 'root_category_id' => $this->getDefaultCategory()->getId(), + 'default_store_id' => 1 + ] + ); + + /** + * Insert stores + */ + $connection->insertForce( + $this->schemaSetup->getTable('store'), + [ + 'store_id' => 0, + 'code' => 'admin', + 'website_id' => 0, + 'group_id' => 0, + 'name' => 'Admin', + 'sort_order' => 0, + 'is_active' => 1 + ] + ); + $connection->insertForce( + $this->schemaSetup->getTable('store'), + [ + 'store_id' => 1, + 'code' => 'default', + 'website_id' => 1, + 'group_id' => 1, + 'name' => 'Default Store View', + 'sort_order' => 0, + 'is_active' => 1 + ] + ); + $this->schemaSetup->endSetup(); + } + } + + /** + * Get default category. + * + * @deprecated 100.1.0 + * @return DefaultCategory + */ + private function getDefaultCategory() + { + if ($this->defaultCategory === null) { + $this->defaultCategory = $this->defaultCategoryFactory->create(); + } + return $this->defaultCategory; + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Store/Setup/Recurring.php b/app/code/Magento/Store/Setup/Recurring.php deleted file mode 100644 index c4ab9196d9f46..0000000000000 --- a/app/code/Magento/Store/Setup/Recurring.php +++ /dev/null @@ -1,136 +0,0 @@ -defaultCategory === null) { - $this->defaultCategory = \Magento\Framework\App\ObjectManager::getInstance() - ->get(DefaultCategory::class); - } - return $this->defaultCategory; - } - - /** - * {@inheritdoc} - * @throws \Exception - */ - public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) - { - $installer = $setup; - - $installer->startSetup(); - $connection = $installer->getConnection(); - $select = $connection->select() - ->from($installer->getTable('store_website')) - ->where('website_id = ?', 0); - - if ($connection->fetchOne($select) === false) { - /** - * Insert websites - */ - $connection->insertForce( - $installer->getTable('store_website'), - [ - 'website_id' => 0, - 'code' => 'admin', - 'name' => 'Admin', - 'sort_order' => 0, - 'default_group_id' => 0, - 'is_default' => 0 - ] - ); - $connection->insertForce( - $installer->getTable('store_website'), - [ - 'website_id' => 1, - 'code' => 'base', - 'name' => 'Main Website', - 'sort_order' => 0, - 'default_group_id' => 1, - 'is_default' => 1 - ] - ); - - /** - * Insert store groups - */ - $connection->insertForce( - $installer->getTable('store_group'), - [ - 'group_id' => 0, - 'website_id' => 0, - 'name' => 'Default', - 'root_category_id' => 0, - 'default_store_id' => 0 - ] - ); - $connection->insertForce( - $installer->getTable('store_group'), - [ - 'group_id' => 1, - 'website_id' => 1, - 'name' => 'Main Website Store', - 'root_category_id' => $this->getDefaultCategory()->getId(), - 'default_store_id' => 1 - ] - ); - - /** - * Insert stores - */ - $connection->insertForce( - $installer->getTable('store'), - [ - 'store_id' => 0, - 'code' => 'admin', - 'website_id' => 0, - 'group_id' => 0, - 'name' => 'Admin', - 'sort_order' => 0, - 'is_active' => 1 - ] - ); - $connection->insertForce( - $installer->getTable('store'), - [ - 'store_id' => 1, - 'code' => 'default', - 'website_id' => 1, - 'group_id' => 1, - 'name' => 'Default Store View', - 'sort_order' => 0, - 'is_active' => 1 - ] - ); - $setup->endSetup(); - } - } -} diff --git a/app/code/Magento/Store/Setup/UpgradeData.php b/app/code/Magento/Store/Setup/UpgradeData.php deleted file mode 100644 index c4b2a595c5332..0000000000000 --- a/app/code/Magento/Store/Setup/UpgradeData.php +++ /dev/null @@ -1,68 +0,0 @@ -getVersion(), '2.1.0', '<')) { - $this->updateStoreGroupCodes($setup); - } - } - - /** - * Update column 'code' in store_group table. - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function updateStoreGroupCodes($setup) - { - $storeGroupTable = $setup->getTable('store_group'); - $select = $setup->getConnection()->select()->from( - $storeGroupTable, - ['group_id', 'name'] - ); - - $groupList = $setup->getConnection()->fetchPairs($select); - - $codes = []; - foreach ($groupList as $groupId => $groupName) { - $code = preg_replace('/\s+/', '_', $groupName); - $code = preg_replace('/[^a-z0-9-_]/', '', strtolower($code)); - $code = preg_replace('/^[^a-z]+/', '', $code); - - if (empty($code)) { - $code = 'store_group'; - } - - if (array_key_exists($code, $codes)) { - $codes[$code]++; - $code = $code . $codes[$code]; - } - $codes[$code] = 1; - - $setup->getConnection()->update( - $storeGroupTable, - ['code' => $code], - ['group_id = ?' => $groupId] - ); - } - } -} diff --git a/app/code/Magento/Store/Test/Unit/Model/Config/PlaceholderTest.php b/app/code/Magento/Store/Test/Unit/Model/Config/PlaceholderTest.php index fd42be4cb8f6c..e44eacc79b82f 100644 --- a/app/code/Magento/Store/Test/Unit/Model/Config/PlaceholderTest.php +++ b/app/code/Magento/Store/Test/Unit/Model/Config/PlaceholderTest.php @@ -23,7 +23,7 @@ protected function setUp() { $this->_requestMock = $this->createMock(\Magento\Framework\App\Request\Http::class); $this->_requestMock->expects( - $this->any() + $this->once() )->method( 'getDistroBaseUrl' )->will( diff --git a/app/code/Magento/Store/Test/Unit/Setup/UpgradeDataTest.php b/app/code/Magento/Store/Test/Unit/Setup/UpgradeDataTest.php deleted file mode 100644 index 0dc7de4224c43..0000000000000 --- a/app/code/Magento/Store/Test/Unit/Setup/UpgradeDataTest.php +++ /dev/null @@ -1,148 +0,0 @@ -objectManagerHelper = new ObjectManager($this); - - $this->connectionMock = $this->getMockBuilder(AdapterInterface::class) - ->getMockForAbstractClass(); - $this->setupMock = $this->getMockBuilder(ModuleDataSetupInterface::class) - ->getMockForAbstractClass(); - $this->setupMock->expects($this->any()) - ->method('getConnection') - ->willReturn($this->connectionMock); - $this->contextMock = $this->getMockBuilder(ModuleContextInterface::class) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - - $this->model = new UpgradeData(); - } - - /** - * @param array $groupList - * @param array $expectedCodes - * @dataProvider upgradeDataProvider - */ - public function testUpgradeToVersion210(array $groupList, array $expectedCodes) - { - $tableName = 'store_group'; - $this->setupMock->expects($this->once()) - ->method('getTable') - ->willReturn($tableName); - $selectMock = $this->getMockBuilder(Select::class) - ->setMethods(['from']) - ->disableOriginalConstructor() - ->getMockForAbstractClass(); - $this->contextMock->expects($this->once()) - ->method('getVersion') - ->willReturn('2.0.0'); - $this->connectionMock->expects($this->any()) - ->method('select') - ->willReturn($selectMock); - $selectMock->expects($this->once()) - ->method('from') - ->with('store_group', ['group_id', 'name']) - ->willReturnSelf(); - $this->connectionMock->expects($this->once()) - ->method('fetchPairs') - ->with($selectMock) - ->willReturn($groupList); - - $i = 2; - foreach ($expectedCodes as $groupId => $code) { - $this->connectionMock->expects($this->at($i++)) - ->method('update') - ->with( - $tableName, - ['code' => $code], - ['group_id = ?' => $groupId] - ); - } - - $this->model->upgrade($this->setupMock, $this->contextMock); - } - - public function upgradeDataProvider() - { - return [ - [ - [ - 1 => 'Test Group' - ], - [ - 1 => 'test_group' - ] - ], - [ - [ - 1 => 'Test Group', - 2 => 'Test Group', - 3 => 'Test Group', - ], - [ - 1 => 'test_group', - 2 => 'test_group2', - 3 => 'test_group3' - ] - ], - [ - [ - 1 => '123 Group', - 2 => '12345', - 3 => '123456', - 4 => '123456', - 5 => '12Group34', - 6 => '&#*@#&_group' - ], - [ - 1 => 'group', - 2 => 'store_group', - 3 => 'store_group2', - 4 => 'store_group3', - 5 => 'group34', - 6 => 'group2' - ] - ] - ]; - } -} diff --git a/app/code/Magento/Store/etc/config.xml b/app/code/Magento/Store/etc/config.xml index 470337a97dcd9..d69fcad7aac61 100644 --- a/app/code/Magento/Store/etc/config.xml +++ b/app/code/Magento/Store/etc/config.xml @@ -21,13 +21,13 @@ 0 0 - /tiny_mce/ + /tiny_mce/ 0 - /tiny_mce/ + /tiny_mce/ @@ -115,6 +115,10 @@ php + php3 + php4 + php5 + php7 htaccess jsp pl diff --git a/app/code/Magento/Store/etc/db_schema.xml b/app/code/Magento/Store/etc/db_schema.xml index e3cd8c8e816b6..3c2bc3e3c117b 100644 --- a/app/code/Magento/Store/etc/db_schema.xml +++ b/app/code/Magento/Store/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Store/etc/module.xml b/app/code/Magento/Store/etc/module.xml index 644520f9a9e28..b034d18b0a310 100644 --- a/app/code/Magento/Store/etc/module.xml +++ b/app/code/Magento/Store/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/Swagger/etc/module.xml b/app/code/Magento/Swagger/etc/module.xml index 8f1086057b57e..fce24b61b4f86 100644 --- a/app/code/Magento/Swagger/etc/module.xml +++ b/app/code/Magento/Swagger/etc/module.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/app/code/Magento/Swatches/Helper/Media.php b/app/code/Magento/Swatches/Helper/Media.php index baa90343cc4ab..f3694515ecb26 100644 --- a/app/code/Magento/Swatches/Helper/Media.php +++ b/app/code/Magento/Swatches/Helper/Media.php @@ -211,7 +211,7 @@ protected function setupImageProperties(\Magento\Framework\Image $image, $isSwat if ($isSwatch) { $image->keepFrame(true); $image->keepTransparency(true); - $image->backgroundColor('#FFF'); + $image->backgroundColor([255, 255, 255]); } return $this; } diff --git a/app/code/Magento/Swatches/Setup/InstallData.php b/app/code/Magento/Swatches/Setup/InstallData.php deleted file mode 100644 index eab2fd68607bd..0000000000000 --- a/app/code/Magento/Swatches/Setup/InstallData.php +++ /dev/null @@ -1,67 +0,0 @@ -eavSetupFactory = $eavSetupFactory; - } - - /** - * Install new Swatch entity - * - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - * @param ModuleDataSetupInterface $setup - * @param ModuleContextInterface $context - * @return void - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - - /** - * Install eav entity types to the eav/entity_type table - */ - $eavSetup->addAttribute( - 'catalog_product', - 'swatch_image', - [ - 'type' => 'varchar', - 'label' => 'Swatch', - 'input' => 'media_image', - 'frontend' => \Magento\Catalog\Model\Product\Attribute\Frontend\Image::class, - 'required' => false, - 'sort_order' => 3, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_STORE, - 'used_in_product_listing' => true - ] - ); - } -} diff --git a/app/code/Magento/Swatches/Setup/Patch/Data/AddSwatchImageAttribute.php b/app/code/Magento/Swatches/Setup/Patch/Data/AddSwatchImageAttribute.php new file mode 100644 index 0000000000000..2dbfeba3a2e67 --- /dev/null +++ b/app/code/Magento/Swatches/Setup/Patch/Data/AddSwatchImageAttribute.php @@ -0,0 +1,96 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + + /** + * Install eav entity types to the eav/entity_type table + */ + $eavSetup->addAttribute( + 'catalog_product', + 'swatch_image', + [ + 'type' => 'varchar', + 'label' => 'Swatch', + 'input' => 'media_image', + 'frontend' => Image::class, + 'required' => false, + 'sort_order' => 3, + 'global' => ScopedAttributeInterface::SCOPE_STORE, + 'used_in_product_listing' => true + ] + ); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Swatches/Setup/Patch/Data/AddSwatchImageToDefaultAttribtueSet.php b/app/code/Magento/Swatches/Setup/Patch/Data/AddSwatchImageToDefaultAttribtueSet.php new file mode 100644 index 0000000000000..ca5a0d38e15c3 --- /dev/null +++ b/app/code/Magento/Swatches/Setup/Patch/Data/AddSwatchImageToDefaultAttribtueSet.php @@ -0,0 +1,89 @@ +moduleDataSetup = $moduleDataSetup; + $this->eavSetupFactory = $eavSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + + /** @var \Magento\Eav\Setup\EavSetup $eavSetup */ + $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]); + $attributeSetId = $eavSetup->getDefaultAttributeSetId(Product::ENTITY); + $groupId = (int)$eavSetup->getAttributeGroupByCode( + Product::ENTITY, + $attributeSetId, + 'image-management', + 'attribute_group_id' + ); + $eavSetup->addAttributeToGroup(Product::ENTITY, $attributeSetId, $groupId, 'swatch_image'); + + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + AddSwatchImageAttribute::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Swatches/Setup/Patch/Data/ConvertAdditionalDataToJson.php b/app/code/Magento/Swatches/Setup/Patch/Data/ConvertAdditionalDataToJson.php new file mode 100644 index 0000000000000..0a37e846c8f77 --- /dev/null +++ b/app/code/Magento/Swatches/Setup/Patch/Data/ConvertAdditionalDataToJson.php @@ -0,0 +1,93 @@ +moduleDataSetup = $moduleDataSetup; + $this->fieldDataConverterFactory = $fieldDataConverterFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + $this->convertAddDataToJson(); + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateAdminTextSwatchValues::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.3'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Convert serialized additional data to json. + */ + private function convertAddDataToJson() + { + $fieldConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $fieldConverter->convert( + $this->moduleDataSetup->getConnection(), + $this->moduleDataSetup->getTable('catalog_eav_attribute'), + 'attribute_id', + 'additional_data' + ); + } +} diff --git a/app/code/Magento/Swatches/Setup/Patch/Data/UpdateAdminTextSwatchValues.php b/app/code/Magento/Swatches/Setup/Patch/Data/UpdateAdminTextSwatchValues.php new file mode 100644 index 0000000000000..d63fbf1425648 --- /dev/null +++ b/app/code/Magento/Swatches/Setup/Patch/Data/UpdateAdminTextSwatchValues.php @@ -0,0 +1,120 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + $this->updateAdminTextSwatchValues(); + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + AddSwatchImageToDefaultAttribtueSet::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.2'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Update text swatch values for admin panel. + */ + private function updateAdminTextSwatchValues() + { + $connection = $this->moduleDataSetup->getConnection(); + $storeData = $connection + ->select() + ->from($this->moduleDataSetup->getTable('store')) + ->where(Store::STORE_ID . "<> ? ", Store::DEFAULT_STORE_ID) + ->order("sort_order desc") + ->limit(1) + ->query(Zend_Db::FETCH_ASSOC) + ->fetch(); + + if (is_array($storeData)) { + + /** + * update eav_attribute_option_swatch as s + * left join eav_attribute_option_swatch as ls on ls.option_id = s.option_id and ls.store_id = 1 + * set + * + * s.value = ls.value + * where s.store_id = 0 and s.`type` = 0 and s.value = "" + */ + + /** @var \Magento\Framework\DB\Select $select */ + $select = $connection + ->select() + ->joinLeft( + ["ls" => $this->moduleDataSetup->getTable('eav_attribute_option_swatch')], + new Zend_Db_Expr("ls.option_id = s.option_id AND ls.store_id = " . $storeData[Store::STORE_ID]), + ["value"] + ) + ->where("s.store_id = ? ", Store::DEFAULT_STORE_ID) + ->where("s.type = ? ", Swatch::SWATCH_TYPE_TEXTUAL) + ->where("s.value = ? or s.value is null", ""); + + $connection->query( + $connection->updateFromSelect( + $select, + ["s" => $this->moduleDataSetup->getTable('eav_attribute_option_swatch')] + ) + ); + } + } +} diff --git a/app/code/Magento/Swatches/Setup/UpgradeData.php b/app/code/Magento/Swatches/Setup/UpgradeData.php deleted file mode 100644 index 880422a371abd..0000000000000 --- a/app/code/Magento/Swatches/Setup/UpgradeData.php +++ /dev/null @@ -1,149 +0,0 @@ -eavSetupFactory = $eavSetupFactory; - $this->fieldDataConverterFactory = $fieldDataConverterFactory - ?: ObjectManager::getInstance()->get(FieldDataConverterFactory::class); - } - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - - if (version_compare($context->getVersion(), '2.0.1', '<')) { - /** @var \Magento\Eav\Setup\EavSetup $eavSetup */ - $eavSetup = $this->eavSetupFactory->create(['setup' => $setup]); - $attributeSetId = $eavSetup->getDefaultAttributeSetId(Product::ENTITY); - $groupId = (int)$eavSetup->getAttributeGroupByCode( - Product::ENTITY, - $attributeSetId, - 'image-management', - 'attribute_group_id' - ); - $eavSetup->addAttributeToGroup(Product::ENTITY, $attributeSetId, $groupId, 'swatch_image'); - } - - if (version_compare($context->getVersion(), '2.0.2', '<')) { - $this->updateAdminTextSwatchValues($setup); - } - if (version_compare($context->getVersion(), '2.0.3', '<')) { - $this->convertAddDataToJson($setup); - } - - $setup->endSetup(); - } - - /** - * Add fallback for default scope. - * - * @param ModuleDataSetupInterface $setup - * - * @return void - */ - private function updateAdminTextSwatchValues(ModuleDataSetupInterface $setup) - { - $storeData = $setup->getConnection() - ->select() - ->from($setup->getTable('store')) - ->where(Store::STORE_ID . "<> ? ", Store::DEFAULT_STORE_ID) - ->order("sort_order desc") - ->limit(1) - ->query(Zend_Db::FETCH_ASSOC) - ->fetch(); - - if (is_array($storeData)) { - - /** - * update eav_attribute_option_swatch as s - * left join eav_attribute_option_swatch as ls on ls.option_id = s.option_id and ls.store_id = 1 - * set - * - * s.value = ls.value - * where s.store_id = 0 and s.`type` = 0 and s.value = "" - */ - - /** @var \Magento\Framework\DB\Select $select */ - $select = $setup->getConnection() - ->select() - ->joinLeft( - ["ls" => $setup->getTable('eav_attribute_option_swatch')], - new Zend_Db_Expr("ls.option_id = s.option_id AND ls.store_id = " . $storeData[Store::STORE_ID]), - ["value"] - ) - ->where("s.store_id = ? ", Store::DEFAULT_STORE_ID) - ->where("s.type = ? ", Swatch::SWATCH_TYPE_TEXTUAL) - ->where("s.value = ? or s.value is null", ""); - - $setup->getConnection()->query( - $setup->getConnection()->updateFromSelect( - $select, - ["s" => $setup->getTable('eav_attribute_option_swatch')] - ) - ); - } - } - - /** - * Convert additional data column from serialized view to JSON for swatch attributes. - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function convertAddDataToJson(ModuleDataSetupInterface $setup) - { - $fieldConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); - $fieldConverter->convert( - $setup->getConnection(), - $setup->getTable('catalog_eav_attribute'), - 'attribute_id', - 'additional_data' - ); - } -} diff --git a/app/code/Magento/Swatches/Test/Unit/Helper/MediaTest.php b/app/code/Magento/Swatches/Test/Unit/Helper/MediaTest.php index 7ecfeab53b90d..9602291df4838 100644 --- a/app/code/Magento/Swatches/Test/Unit/Helper/MediaTest.php +++ b/app/code/Magento/Swatches/Test/Unit/Helper/MediaTest.php @@ -158,6 +158,7 @@ public function testGenerateSwatchVariations() $this->imageFactoryMock->expects($this->any())->method('create')->willReturn($image); $this->generateImageConfig(); $image->expects($this->any())->method('resize')->will($this->returnSelf()); + $image->expects($this->atLeastOnce())->method('backgroundColor')->with([255, 255, 255])->willReturnSelf(); $this->mediaHelperObject->generateSwatchVariations('/e/a/earth.png'); } diff --git a/app/code/Magento/Swatches/etc/db_schema.xml b/app/code/Magento/Swatches/etc/db_schema.xml index 6613c412744e9..c960f27b0fb54 100644 --- a/app/code/Magento/Swatches/etc/db_schema.xml +++ b/app/code/Magento/Swatches/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Swatches/etc/module.xml b/app/code/Magento/Swatches/etc/module.xml index 1faec3b2792cb..4c97d8e0d8d1c 100644 --- a/app/code/Magento/Swatches/etc/module.xml +++ b/app/code/Magento/Swatches/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Swatches/view/adminhtml/ui_component/design_config_form.xml b/app/code/Magento/Swatches/view/adminhtml/ui_component/design_config_form.xml index 66626add3f671..1c58243be3262 100644 --- a/app/code/Magento/Swatches/view/adminhtml/ui_component/design_config_form.xml +++ b/app/code/Magento/Swatches/view/adminhtml/ui_component/design_config_form.xml @@ -15,12 +15,11 @@
- Allowed file types: jpeg, gif, png. - fileUploader + imageUploader - + jpg jpeg gif png 2097152 @@ -28,7 +27,7 @@ theme/design_config_fileUploader/save - + diff --git a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js index d1f7c477ba8d7..a24c72c473fe9 100644 --- a/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js +++ b/app/code/Magento/Swatches/view/frontend/web/js/swatch-renderer.js @@ -90,7 +90,7 @@ define([ $title, $corner; - if (!$element.size()) { + if (!$element.length) { $element = $('
' @@ -810,7 +810,7 @@ define([ $widget._Rewind(controls); // done if nothing selected - if (selected.size() <= 0) { + if (selected.length <= 0) { return; } @@ -820,7 +820,7 @@ define([ id = $this.attr('attribute-id'), products = $widget._CalcProducts(id); - if (selected.size() === 1 && selected.first().attr('attribute-id') === id) { + if (selected.length === 1 && selected.first().attr('attribute-id') === id) { return; } @@ -1016,7 +1016,7 @@ define([ _EnableProductMediaLoader: function ($this) { var $widget = this; - if ($('body.catalog-product-view').size() > 0) { + if ($('body.catalog-product-view').length > 0) { $this.parents('.column.main').find('.photo.image') .addClass($widget.options.classes.loader); } else { @@ -1035,7 +1035,7 @@ define([ _DisableProductMediaLoader: function ($this) { var $widget = this; - if ($('body.catalog-product-view').size() > 0) { + if ($('body.catalog-product-view').length > 0) { $this.parents('.column.main').find('.photo.image') .removeClass($widget.options.classes.loader); } else { diff --git a/app/code/Magento/SwatchesGraphQl/etc/module.xml b/app/code/Magento/SwatchesGraphQl/etc/module.xml index c57d1c4510189..de2baeee94c57 100644 --- a/app/code/Magento/SwatchesGraphQl/etc/module.xml +++ b/app/code/Magento/SwatchesGraphQl/etc/module.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/app/code/Magento/SwatchesLayeredNavigation/etc/module.xml b/app/code/Magento/SwatchesLayeredNavigation/etc/module.xml index fb0ac8f1a0685..5b042ef434ddb 100644 --- a/app/code/Magento/SwatchesLayeredNavigation/etc/module.xml +++ b/app/code/Magento/SwatchesLayeredNavigation/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Tax/Setup/InstallData.php b/app/code/Magento/Tax/Setup/InstallData.php deleted file mode 100644 index 31d0798847db5..0000000000000 --- a/app/code/Magento/Tax/Setup/InstallData.php +++ /dev/null @@ -1,132 +0,0 @@ -taxSetupFactory = $taxSetupFactory; - $this->directoryRegionFactory = $directoryRegionFactory; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var TaxSetup $taxSetup */ - $taxSetup = $this->taxSetupFactory->create(['resourceName' => 'tax_setup', 'setup' => $setup]); - - /** - * Add tax_class_id attribute to the 'eav_attribute' table - */ - $taxSetup->addAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'tax_class_id', - [ - 'group' => 'Product Details', - 'sort_order' => 40, - 'type' => 'int', - 'backend' => '', - 'frontend' => '', - 'label' => 'Tax Class', - 'input' => 'select', - 'class' => '', - 'source' => \Magento\Tax\Model\TaxClass\Source\Product::class, - 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, - 'visible' => true, - 'required' => false, - 'user_defined' => false, - 'default' => '2', - 'searchable' => true, - 'filterable' => false, - 'comparable' => false, - 'visible_on_front' => false, - 'visible_in_advanced_search' => false, - 'used_in_product_listing' => true, - 'unique' => false, - 'apply_to' => implode(',', $taxSetup->getTaxableItems()), - 'is_used_in_grid' => true, - 'is_visible_in_grid' => false, - 'is_filterable_in_grid' => true, - ] - ); - - /** - * install tax classes - */ - $data = [ - [ - 'class_id' => 2, - 'class_name' => 'Taxable Goods', - 'class_type' => \Magento\Tax\Model\ClassModel::TAX_CLASS_TYPE_PRODUCT, - ], - [ - 'class_id' => 3, - 'class_name' => 'Retail Customer', - 'class_type' => \Magento\Tax\Model\ClassModel::TAX_CLASS_TYPE_CUSTOMER - ], - ]; - foreach ($data as $row) { - $setup->getConnection()->insertForce($setup->getTable('tax_class'), $row); - } - - /** - * install tax calculation rates - */ - /** @var \Magento\Directory\Model\Region $region */ - $region = $this->directoryRegionFactory->create(); - $data = [ - [ - 'tax_calculation_rate_id' => 1, - 'tax_country_id' => 'US', - 'tax_region_id' => $region->loadByCode('CA', 'US')->getRegionId(), - 'tax_postcode' => '*', - 'code' => 'US-CA-*-Rate 1', - 'rate' => '8.2500', - ], - [ - 'tax_calculation_rate_id' => 2, - 'tax_country_id' => 'US', - 'tax_region_id' => $region->loadByCode('NY', 'US')->getRegionId(), - 'tax_postcode' => '*', - 'code' => 'US-NY-*-Rate 1', - 'rate' => '8.3750' - ], - ]; - foreach ($data as $row) { - $setup->getConnection()->insertForce($setup->getTable('tax_calculation_rate'), $row); - } - } -} diff --git a/app/code/Magento/Tax/Setup/Patch/Data/AddTaxAttributeAndTaxClasses.php b/app/code/Magento/Tax/Setup/Patch/Data/AddTaxAttributeAndTaxClasses.php new file mode 100644 index 0000000000000..8b7b9df936009 --- /dev/null +++ b/app/code/Magento/Tax/Setup/Patch/Data/AddTaxAttributeAndTaxClasses.php @@ -0,0 +1,170 @@ +taxSetupFactory = $taxSetupFactory; + $this->directoryRegionFactory = $directoryRegionFactory; + $this->moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var TaxSetup $taxSetup */ + $taxSetup = $this->taxSetupFactory->create(['resourceName' => 'tax_setup', 'setup' => $this->moduleDataSetup]); + + /** + * Add tax_class_id attribute to the 'eav_attribute' table + */ + $taxSetup->addAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'tax_class_id', + [ + 'group' => 'Product Details', + 'sort_order' => 40, + 'type' => 'int', + 'backend' => '', + 'frontend' => '', + 'label' => 'Tax Class', + 'input' => 'select', + 'class' => '', + 'source' => \Magento\Tax\Model\TaxClass\Source\Product::class, + 'global' => \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_WEBSITE, + 'visible' => true, + 'required' => false, + 'user_defined' => false, + 'default' => '2', + 'searchable' => true, + 'filterable' => false, + 'comparable' => false, + 'visible_on_front' => false, + 'visible_in_advanced_search' => false, + 'used_in_product_listing' => true, + 'unique' => false, + 'apply_to' => implode(',', $taxSetup->getTaxableItems()), + 'is_used_in_grid' => true, + 'is_visible_in_grid' => false, + 'is_filterable_in_grid' => true, + ] + ); + /** + * install tax classes + */ + $data = [ + [ + 'class_id' => 2, + 'class_name' => 'Taxable Goods', + 'class_type' => \Magento\Tax\Model\ClassModel::TAX_CLASS_TYPE_PRODUCT, + ], + [ + 'class_id' => 3, + 'class_name' => 'Retail Customer', + 'class_type' => \Magento\Tax\Model\ClassModel::TAX_CLASS_TYPE_CUSTOMER + ], + ]; + foreach ($data as $row) { + $this->moduleDataSetup->getConnection()->insertForce( + $this->moduleDataSetup->getTable('tax_class'), + $row + ); + } + /** + * install tax calculation rates + */ + /** @var \Magento\Directory\Model\Region $region */ + $region = $this->directoryRegionFactory->create(); + $data = [ + [ + 'tax_calculation_rate_id' => 1, + 'tax_country_id' => 'US', + 'tax_region_id' => $region->loadByCode('CA', 'US')->getRegionId(), + 'tax_postcode' => '*', + 'code' => 'US-CA-*-Rate 1', + 'rate' => '8.2500', + ], + [ + 'tax_calculation_rate_id' => 2, + 'tax_country_id' => 'US', + 'tax_region_id' => $region->loadByCode('NY', 'US')->getRegionId(), + 'tax_postcode' => '*', + 'code' => 'US-NY-*-Rate 1', + 'rate' => '8.3750' + ], + ]; + foreach ($data as $row) { + $this->moduleDataSetup->getConnection()->insertForce( + $this->moduleDataSetup->getTable('tax_calculation_rate'), + $row + ); + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Tax/Setup/Patch/Data/UpdateTaxClassAttributeVisibility.php b/app/code/Magento/Tax/Setup/Patch/Data/UpdateTaxClassAttributeVisibility.php new file mode 100644 index 0000000000000..24d21d513ca23 --- /dev/null +++ b/app/code/Magento/Tax/Setup/Patch/Data/UpdateTaxClassAttributeVisibility.php @@ -0,0 +1,89 @@ +moduleDataSetup = $moduleDataSetup; + $this->taxSetupFactory = $taxSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var TaxSetup $taxSetup */ + $taxSetup = $this->taxSetupFactory->create(['resourceName' => 'tax_setup', 'setup' => $this->moduleDataSetup]); + + $this->moduleDataSetup->getConnection()->startSetup(); + + //Update the tax_class_id attribute in the 'catalog_eav_attribute' table + $taxSetup->updateAttribute( + \Magento\Catalog\Model\Product::ENTITY, + 'tax_class_id', + 'is_visible_in_advanced_search', + false + ); + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + AddTaxAttributeAndTaxClasses::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Tax/Setup/Patch/Data/UpdateTaxRegionId.php b/app/code/Magento/Tax/Setup/Patch/Data/UpdateTaxRegionId.php new file mode 100644 index 0000000000000..d2f5aac442609 --- /dev/null +++ b/app/code/Magento/Tax/Setup/Patch/Data/UpdateTaxRegionId.php @@ -0,0 +1,127 @@ +moduleDataSetup = $moduleDataSetup; + $this->taxRateRepository = $taxRateRepository; + $this->searchCriteriaFactory = $searchCriteriaFactory; + $this->regionFactory = $regionFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + + //Update the tax_region_id + $taxRateList = $this->taxRateRepository->getList($this->searchCriteriaFactory->create()); + /** @var \Magento\Tax\Api\Data\TaxRateInterface $taxRateData */ + foreach ($taxRateList->getItems() as $taxRateData) { + $regionCode = $this->parseRegionFromTaxCode($taxRateData->getCode()); + if ($regionCode) { + /** @var \Magento\Directory\Model\Region $region */ + $region = $this->regionFactory->create(); + $region->loadByCode($regionCode, $taxRateData->getTaxCountryId()); + if ($taxRateData->getTaxPostcode() === null) { + $taxRateData->setTaxPostcode('*'); + } + $taxRateData->setTaxRegionId($region->getRegionId()); + $this->taxRateRepository->save($taxRateData); + } + } + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpdateTaxClassAttributeVisibility::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.3'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Parse region from tax code. + * + * @param string $taxCode + * @return string + */ + private function parseRegionFromTaxCode($taxCode) + { + $result = ''; + $parts = explode('-', $taxCode, 3); + + if (isset($parts[1])) { + $result = $parts[1]; + } + + return $result; + } +} diff --git a/app/code/Magento/Tax/Setup/UpgradeData.php b/app/code/Magento/Tax/Setup/UpgradeData.php deleted file mode 100644 index 5ede9cb6180e4..0000000000000 --- a/app/code/Magento/Tax/Setup/UpgradeData.php +++ /dev/null @@ -1,122 +0,0 @@ -taxSetupFactory = $taxSetupFactory; - $this->taxRateRepository = $taxRateRepository; - $this->searchCriteriaFactory = $searchCriteriaFactory; - $this->directoryRegionFactory = $directoryRegionFactory; - } - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var TaxSetup $taxSetup */ - $taxSetup = $this->taxSetupFactory->create(['resourceName' => 'tax_setup', 'setup' => $setup]); - - $setup->startSetup(); - - if (version_compare($context->getVersion(), '2.0.1', '<')) { - //Update the tax_class_id attribute in the 'catalog_eav_attribute' table - $taxSetup->updateAttribute( - \Magento\Catalog\Model\Product::ENTITY, - 'tax_class_id', - 'is_visible_in_advanced_search', - false - ); - } - if (version_compare($context->getVersion(), '2.0.3', '<')) { - //Update the tax_region_id - $taxRateList = $this->taxRateRepository->getList($this->searchCriteriaFactory->create()); - /** @var \Magento\Tax\Api\Data\TaxRateInterface $taxRateData */ - foreach ($taxRateList->getItems() as $taxRateData) { - $regionCode = $this->parseRegionFromTaxCode($taxRateData->getCode()); - if ($regionCode) { - /** @var \Magento\Directory\Model\Region $region */ - $region = $this->directoryRegionFactory->create(); - $region->loadByCode($regionCode, $taxRateData->getTaxCountryId()); - if ($taxRateData->getTaxPostcode() === null) { - $taxRateData->setTaxPostcode('*'); - } - $taxRateData->setTaxRegionId($region->getRegionId()); - $this->taxRateRepository->save($taxRateData); - } - } - } - $setup->endSetup(); - } - - /** - * Parse region code from tax code - * - * @param string $taxCode - * @return string - */ - private function parseRegionFromTaxCode($taxCode) - { - $result = ''; - $parts = explode('-', $taxCode, 3); - - if (isset($parts[1])) { - $result = $parts[1]; - } - - return $result; - } -} diff --git a/app/code/Magento/Tax/etc/db_schema.xml b/app/code/Magento/Tax/etc/db_schema.xml index bde6879c073d6..6cc4041f75a6d 100644 --- a/app/code/Magento/Tax/etc/db_schema.xml +++ b/app/code/Magento/Tax/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> diff --git a/app/code/Magento/Tax/etc/module.xml b/app/code/Magento/Tax/etc/module.xml index a100b0ac01181..6233161192ab9 100644 --- a/app/code/Magento/Tax/etc/module.xml +++ b/app/code/Magento/Tax/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml b/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml index d16c4faeede28..fced077015f4e 100644 --- a/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml +++ b/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml @@ -111,6 +111,7 @@ require([ TaxRateEditableMultiselect.prototype.init = function () { var options = { + mselectContainer: '#tax_rate + section.mselect-list', toggleAddButton:false, addText: '', parse: null, diff --git a/app/code/Magento/Tax/view/frontend/templates/checkout/discount.phtml b/app/code/Magento/Tax/view/frontend/templates/checkout/discount.phtml deleted file mode 100644 index 75f04eae82159..0000000000000 --- a/app/code/Magento/Tax/view/frontend/templates/checkout/discount.phtml +++ /dev/null @@ -1,5 +0,0 @@ - helper('Magento\Tax\Helper\Data')->displayFullSummary() && $_value != 0): ?> - getTotal()->getFullInfo() as $info): ?> - diff --git a/app/code/Magento/TaxGraphQl/etc/module.xml b/app/code/Magento/TaxGraphQl/etc/module.xml index 9a7906f84d273..b8a7a3aaeb79c 100644 --- a/app/code/Magento/TaxGraphQl/etc/module.xml +++ b/app/code/Magento/TaxGraphQl/etc/module.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/app/code/Magento/TaxImportExport/etc/module.xml b/app/code/Magento/TaxImportExport/etc/module.xml index 192c817c29087..6df24c959d9c2 100644 --- a/app/code/Magento/TaxImportExport/etc/module.xml +++ b/app/code/Magento/TaxImportExport/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Theme/Block/Html/Footer.php b/app/code/Magento/Theme/Block/Html/Footer.php index 4cd63462ec754..cdb350336f38f 100644 --- a/app/code/Magento/Theme/Block/Html/Footer.php +++ b/app/code/Magento/Theme/Block/Html/Footer.php @@ -57,7 +57,6 @@ protected function _construct() { $this->addData( [ - 'cache_lifetime' => false, 'cache_tags' => [\Magento\Store\Model\Store::CACHE_TAG, \Magento\Cms\Model\Block::CACHE_TAG], ] ); @@ -123,4 +122,14 @@ public function getIdentities() { return [\Magento\Store\Model\Store::CACHE_TAG, \Magento\Cms\Model\Block::CACHE_TAG]; } + + /** + * Get block cache life time + * + * @return int + */ + protected function getCacheLifetime() + { + return parent::getCacheLifetime() ?: 3600; + } } diff --git a/app/code/Magento/Theme/Setup/InstallData.php b/app/code/Magento/Theme/Setup/InstallData.php deleted file mode 100644 index 51d5cd23f6e94..0000000000000 --- a/app/code/Magento/Theme/Setup/InstallData.php +++ /dev/null @@ -1,41 +0,0 @@ -themeRegistration = $themeRegistration; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $this->themeRegistration->register(); - } -} diff --git a/app/code/Magento/Theme/Setup/Patch/Data/ConvertSerializedData.php b/app/code/Magento/Theme/Setup/Patch/Data/ConvertSerializedData.php new file mode 100644 index 0000000000000..0e132eb429f60 --- /dev/null +++ b/app/code/Magento/Theme/Setup/Patch/Data/ConvertSerializedData.php @@ -0,0 +1,113 @@ +moduleDataSetup = $moduleDataSetup; + $this->fieldDataConverterFactory = $fieldDataConverterFactory; + $this->queryModifierFactory = $queryModifierFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + $this->convertSerializedData(); + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + RegisterThemes::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.2'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Convert native php serialized data to json. + */ + private function convertSerializedData() + { + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $queryModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'path' => [ + 'design/theme/ua_regexp', + ] + ] + ] + ); + $fieldDataConverter->convert( + $this->moduleDataSetup->getConnection(), + $this->moduleDataSetup->getTable('core_config_data'), + 'config_id', + 'value', + $queryModifier + ); + } +} diff --git a/app/code/Magento/Theme/Setup/Patch/Data/RegisterThemes.php b/app/code/Magento/Theme/Setup/Patch/Data/RegisterThemes.php new file mode 100644 index 0000000000000..31b6c6b47773e --- /dev/null +++ b/app/code/Magento/Theme/Setup/Patch/Data/RegisterThemes.php @@ -0,0 +1,73 @@ +moduleDataSetup = $moduleDataSetup; + $this->themeRegistration = $themeRegistration; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->themeRegistration->register(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Theme/Setup/UpgradeData.php b/app/code/Magento/Theme/Setup/UpgradeData.php deleted file mode 100644 index ade0e9d3f6c39..0000000000000 --- a/app/code/Magento/Theme/Setup/UpgradeData.php +++ /dev/null @@ -1,85 +0,0 @@ -fieldDataConverterFactory = $fieldDataConverterFactory; - $this->queryModifierFactory = $queryModifierFactory; - } - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - if (version_compare($context->getVersion(), '2.0.2', '<')) { - $this->upgradeToVersionTwoZeroTwo($setup); - } - $setup->endSetup(); - } - - /** - * Upgrade to version 2.0.2, convert data for `value` field in `core_config_data table` - * from php-serialized to JSON format - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function upgradeToVersionTwoZeroTwo(ModuleDataSetupInterface $setup) - { - $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); - $queryModifier = $this->queryModifierFactory->create( - 'in', - [ - 'values' => [ - 'path' => [ - 'design/theme/ua_regexp', - ] - ] - ] - ); - $fieldDataConverter->convert( - $setup->getConnection(), - $setup->getTable('core_config_data'), - 'config_id', - 'value', - $queryModifier - ); - } -} diff --git a/app/code/Magento/Theme/Test/Unit/Block/Html/FooterTest.php b/app/code/Magento/Theme/Test/Unit/Block/Html/FooterTest.php index 8451e9c5aee6a..52175cc669bbd 100644 --- a/app/code/Magento/Theme/Test/Unit/Block/Html/FooterTest.php +++ b/app/code/Magento/Theme/Test/Unit/Block/Html/FooterTest.php @@ -30,4 +30,18 @@ public function testGetIdentities() $this->block->getIdentities() ); } + + /** + * Check Footer block has cache lifetime. + * + * @throws \ReflectionException + * @return void + */ + public function testGetCacheLifetime() + { + $reflection = new \ReflectionClass($this->block); + $method = $reflection->getMethod('getCacheLifetime'); + $method->setAccessible(true); + $this->assertEquals(3600, $method->invoke($this->block)); + } } diff --git a/app/code/Magento/Theme/etc/db_schema.xml b/app/code/Magento/Theme/etc/db_schema.xml index 62f7135d7b94d..ee1185e6e576d 100644 --- a/app/code/Magento/Theme/etc/db_schema.xml +++ b/app/code/Magento/Theme/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Theme/etc/module.xml b/app/code/Magento/Theme/etc/module.xml index 8353ee2a46564..ace0df3b92ef8 100644 --- a/app/code/Magento/Theme/etc/module.xml +++ b/app/code/Magento/Theme/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Theme/i18n/en_US.csv b/app/code/Magento/Theme/i18n/en_US.csv index daa5c27e75fcc..2b8765c36d24a 100644 --- a/app/code/Magento/Theme/i18n/en_US.csv +++ b/app/code/Magento/Theme/i18n/en_US.csv @@ -107,7 +107,7 @@ Remove,Remove "For the best experience on our site, be sure to turn on Javascript in your browser.","For the best experience on our site, be sure to turn on Javascript in your browser." "Local Storage seems to be disabled in your browser.","Local Storage seems to be disabled in your browser." "For the best experience on our site, be sure to turn on Local Storage in your browser.","For the best experience on our site, be sure to turn on Local Storage in your browser." -"This is demo store. No orders will be fulfilled.","This is demo store. No orders will be fulfilled." +"This is a demo store. No orders will be fulfilled.","This is a demo store. No orders will be fulfilled." "Items %1 to %2 of %3 total","Items %1 to %2 of %3 total" "%1 Item","%1 Item" "%1 Item(s)","%1 Item(s)" diff --git a/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml b/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml index ac734699e4d71..48adca3b1a12e 100644 --- a/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml +++ b/app/code/Magento/Theme/view/adminhtml/ui_component/design_config_form.xml @@ -56,12 +56,12 @@ - Allowed file types: ico, png, gif, jpg, jpeg, apng. Not all browsers support all these formats! + Not all browsers support all these formats! - fileUploader + imageUploader - + jpg jpeg gif png ico apng 2097152 @@ -69,7 +69,7 @@ theme/design_config_fileUploader/save - + @@ -153,12 +153,11 @@ - Allowed file types: png, gif, jpg, jpeg. - fileUploader + imageUploader - + jpg jpeg gif png 2097152 @@ -166,7 +165,7 @@ theme/design_config_fileUploader/save - + diff --git a/app/code/Magento/Theme/view/frontend/templates/html/notices.phtml b/app/code/Magento/Theme/view/frontend/templates/html/notices.phtml index 3e74362851cfe..720ee44007954 100644 --- a/app/code/Magento/Theme/view/frontend/templates/html/notices.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/html/notices.phtml @@ -54,7 +54,7 @@ require(['jquery'], function(jQuery){ displayDemoNotice()): ?>
-

+

diff --git a/app/code/Magento/Tinymce3/etc/module.xml b/app/code/Magento/Tinymce3/etc/module.xml index add50fbd609e1..5180aa2ed4cb4 100644 --- a/app/code/Magento/Tinymce3/etc/module.xml +++ b/app/code/Magento/Tinymce3/etc/module.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/app/code/Magento/Translation/Model/Js/DataProvider.php b/app/code/Magento/Translation/Model/Js/DataProvider.php index 06da0c7c0af05..a73d4ee99b5d6 100644 --- a/app/code/Magento/Translation/Model/Js/DataProvider.php +++ b/app/code/Magento/Translation/Model/Js/DataProvider.php @@ -113,7 +113,7 @@ public function getData($themePath) } } catch (\Exception $e) { throw new LocalizedException( - sprintf(__('Error while translating phrase "%s" in file %s.'), $phrase, $filePath[0]) + __('Error while translating phrase "%s" in file %s.', $phrase, $filePath[0]) ); } } @@ -145,7 +145,7 @@ protected function getPhrases($content) } if (false === $result) { throw new LocalizedException( - sprintf(__('Error while generating js translation dictionary: "%s"'), error_get_last()) + __('Error while generating js translation dictionary: "%s"', error_get_last()) ); } } diff --git a/app/code/Magento/Translation/Test/Unit/Model/Js/DataProviderTest.php b/app/code/Magento/Translation/Test/Unit/Model/Js/DataProviderTest.php index 26ea51babc591..021709bdda1f6 100644 --- a/app/code/Magento/Translation/Test/Unit/Model/Js/DataProviderTest.php +++ b/app/code/Magento/Translation/Test/Unit/Model/Js/DataProviderTest.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Translation\Test\Unit\Model\Js; use Magento\Framework\App\State; @@ -148,4 +149,39 @@ public function testGetData() $this->assertEquals($expectedResult, $this->model->getData($themePath)); } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testGetDataThrowingException() + { + $themePath = 'blank'; + $areaCode = 'adminhtml'; + + $patterns = ['~\$\.mage\.__\(([\'"])(.+?)\1\)~']; + + $this->fileReadMock->expects($this->once()) + ->method('readAll') + ->willReturn('content1$.mage.__("hello1")content1'); + + $this->appStateMock->expects($this->once()) + ->method('getAreaCode') + ->willReturn($areaCode); + $this->filesUtilityMock->expects($this->any()) + ->method('getJsFiles') + ->willReturn(['test']); + $this->filesUtilityMock->expects($this->any()) + ->method('getStaticHtmlFiles') + ->willReturn(['test']); + + $this->configMock->expects($this->any()) + ->method('getPatterns') + ->willReturn($patterns); + + $this->translateMock->expects($this->once()) + ->method('render') + ->willThrowException(new \Exception('Test exception')); + + $this->model->getData($themePath); + } } diff --git a/app/code/Magento/Translation/etc/db_schema.xml b/app/code/Magento/Translation/etc/db_schema.xml index 633a7a6d3dd8c..523ef3a1279d0 100644 --- a/app/code/Magento/Translation/etc/db_schema.xml +++ b/app/code/Magento/Translation/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Translation/etc/module.xml b/app/code/Magento/Translation/etc/module.xml index f45ddeb28a8ec..23ebfe1b0751d 100644 --- a/app/code/Magento/Translation/etc/module.xml +++ b/app/code/Magento/Translation/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/Ui/Component/Filters/Type/Input.php b/app/code/Magento/Ui/Component/Filters/Type/Input.php index cbcb33ffcca04..9cc060ae58172 100644 --- a/app/code/Magento/Ui/Component/Filters/Type/Input.php +++ b/app/code/Magento/Ui/Component/Filters/Type/Input.php @@ -65,7 +65,7 @@ public function prepare() protected function applyFilter() { if (isset($this->filterData[$this->getName()])) { - $value = $this->filterData[$this->getName()]; + $value = str_replace(['%', '_'], ['\%', '\_'], $this->filterData[$this->getName()]); if (!empty($value)) { $filter = $this->filterBuilder->setConditionType('like') diff --git a/app/code/Magento/Ui/Component/Form/Element/DataType/Media/Image.php b/app/code/Magento/Ui/Component/Form/Element/DataType/Media/Image.php new file mode 100644 index 0000000000000..7b923bdbf84bf --- /dev/null +++ b/app/code/Magento/Ui/Component/Form/Element/DataType/Media/Image.php @@ -0,0 +1,83 @@ +storeManager = $storeManager; + $this->fileSize = $fileSize; + parent::__construct($context, $components, $data); + } + + /** + * {@inheritdoc} + */ + public function getComponentName() + { + return static::NAME; + } + + /** + * {@inheritdoc} + */ + public function prepare() + { + // dynamically set max file size based on php ini config if not present in XML + $maxFileSize = $this->getConfiguration()['maxFileSize'] ?? $this->fileSize->getMaxFileSize(); + + $data = array_replace_recursive( + $this->getData(), + [ + 'config' => [ + 'maxFileSize' => $maxFileSize, + 'mediaGallery' => [ + 'openDialogUrl' => $this->getContext()->getUrl('cms/wysiwyg_images/index'), + 'openDialogTitle' => $this->getConfiguration()['openDialogTitle'] ?? __('Insert Images...'), + 'storeId' => $this->storeManager->getStore()->getId(), + ], + ], + ] + ); + + $this->setData($data); + parent::prepare(); + } +} diff --git a/app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php b/app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php index 4df9198c0b95d..a985c9aca4375 100644 --- a/app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php +++ b/app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php @@ -10,6 +10,9 @@ use Magento\Framework\View\Element\UiComponentFactory; use Magento\Framework\View\Element\UiComponentInterface; use Magento\Ui\Model\UiComponentTypeResolver; +use Psr\Log\LoggerInterface; +use Magento\Framework\Escaper; +use Magento\Framework\Controller\Result\JsonFactory; class Render extends AbstractAction { @@ -18,39 +21,97 @@ class Render extends AbstractAction */ private $contentTypeResolver; + /** + * @var JsonFactory + */ + private $resultJsonFactory; + + /** + * @var Escaper + */ + private $escaper; + + /** + * @var LoggerInterface + */ + private $logger; + /** * @param Context $context * @param UiComponentFactory $factory * @param UiComponentTypeResolver $contentTypeResolver + * @param JsonFactory|null $resultJsonFactory + * @param Escaper|null $escaper + * @param LoggerInterface|null $logger */ public function __construct( Context $context, UiComponentFactory $factory, - UiComponentTypeResolver $contentTypeResolver + UiComponentTypeResolver $contentTypeResolver, + JsonFactory $resultJsonFactory = null, + Escaper $escaper = null, + LoggerInterface $logger = null ) { parent::__construct($context, $factory); $this->contentTypeResolver = $contentTypeResolver; + $this->resultJsonFactory = $resultJsonFactory ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Controller\Result\JsonFactory::class); + $this->escaper = $escaper ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Escaper::class); + $this->logger = $logger ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Psr\Log\LoggerInterface::class); } /** - * Action for AJAX request - * - * @return void + * @inheritdoc */ public function execute() { if ($this->_request->getParam('namespace') === null) { $this->_redirect('admin/noroute'); + return; } - $component = $this->factory->create($this->getRequest()->getParam('namespace')); - if ($this->validateAclResource($component->getContext()->getDataProvider()->getConfigData())) { - $this->prepareComponent($component); - $this->getResponse()->appendBody((string) $component->render()); + try { + $component = $this->factory->create($this->getRequest()->getParam('namespace')); + if ($this->validateAclResource($component->getContext()->getDataProvider()->getConfigData())) { + $this->prepareComponent($component); + $this->getResponse()->appendBody((string)$component->render()); + + $contentType = $this->contentTypeResolver->resolve($component->getContext()); + $this->getResponse()->setHeader('Content-Type', $contentType, true); + } + } catch (\Magento\Framework\Exception\LocalizedException $e) { + $this->logger->critical($e); + $result = [ + 'error' => $this->escaper->escapeHtml($e->getMessage()), + 'errorcode' => $this->escaper->escapeHtml($e->getCode()) + ]; + /** @var \Magento\Framework\Controller\Result\Json $resultJson */ + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setStatusHeader( + \Zend\Http\Response::STATUS_CODE_400, + \Zend\Http\AbstractMessage::VERSION_11, + 'Bad Request' + ); + + return $resultJson->setData($result); + } catch (\Exception $e) { + $this->logger->critical($e); + $result = [ + 'error' => _('UI component could not be rendered because of system exception'), + 'errorcode' => $this->escaper->escapeHtml($e->getCode()) + ]; + /** @var \Magento\Framework\Controller\Result\Json $resultJson */ + $resultJson = $this->resultJsonFactory->create(); + $resultJson->setStatusHeader( + \Zend\Http\Response::STATUS_CODE_400, + \Zend\Http\AbstractMessage::VERSION_11, + 'Bad Request' + ); - $contentType = $this->contentTypeResolver->resolve($component->getContext()); - $this->getResponse()->setHeader('Content-Type', $contentType, true); + return $resultJson->setData($result); } } diff --git a/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php b/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php index cda3106a14f49..e249a64861d43 100644 --- a/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php +++ b/app/code/Magento/Ui/TemplateEngine/Xhtml/Result.php @@ -80,7 +80,9 @@ public function getDocumentElement() */ public function appendLayoutConfiguration() { - $layoutConfiguration = $this->wrapContent(json_encode($this->structure->generate($this->component))); + $layoutConfiguration = $this->wrapContent( + json_encode($this->structure->generate($this->component), JSON_HEX_TAG) + ); $this->template->append($layoutConfiguration); } diff --git a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php index ed571f44dd6e9..d814fdcd153da 100644 --- a/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php +++ b/app/code/Magento/Ui/Test/Unit/Component/Filters/Type/InputTest.php @@ -111,8 +111,7 @@ public function testPrepare($name, $filterData, $expectedCondition) ->method('addComponentDefinition') ->with(Input::NAME, ['extends' => Input::NAME]); $this->contextMock->expects($this->any()) - ->method('getRequestParam') - ->with(UiContext::FILTER_VAR) + ->method('getFiltersParams') ->willReturn($filterData); $dataProvider = $this->getMockForAbstractClass( \Magento\Framework\View\Element\UiComponent\DataProvider\DataProviderInterface::class, @@ -120,20 +119,41 @@ public function testPrepare($name, $filterData, $expectedCondition) '', false ); + $this->contextMock->expects($this->any()) ->method('getDataProvider') ->willReturn($dataProvider); - if ($expectedCondition !== null) { - $dataProvider->expects($this->any()) - ->method('addFilter') - ->with($expectedCondition, $name); - } $this->uiComponentFactory->expects($this->any()) ->method('create') ->with($name, Input::COMPONENT, ['context' => $this->contextMock]) ->willReturn($uiComponent); + if ($expectedCondition !== null) { + $this->filterBuilderMock->expects($this->once()) + ->method('setConditionType') + ->with('like') + ->willReturnSelf(); + + $this->filterBuilderMock->expects($this->once()) + ->method('setField') + ->with($name) + ->willReturnSelf(); + + $this->filterBuilderMock->expects($this->once()) + ->method('setValue') + ->with($expectedCondition['like']) + ->willReturnSelf(); + + $filterMock = $this->getMockBuilder(\Magento\Framework\Api\Filter::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->filterBuilderMock->expects($this->once()) + ->method('create') + ->willReturn($filterMock); + } + $date = new Input( $this->contextMock, $this->uiComponentFactory, @@ -160,7 +180,12 @@ public function getPrepareDataProvider() [ 'test_date', ['test_date' => 'some_value'], - ['like' => '%some_value%'], + ['like' => '%some\_value%'], + ], + [ + 'test_date', + ['test_date' => '%'], + ['like' => '%\%%'], ], ]; } diff --git a/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/RenderTest.php b/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/RenderTest.php index d41c90bfa760a..05b35fb017b4b 100644 --- a/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/RenderTest.php +++ b/app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/RenderTest.php @@ -8,9 +8,11 @@ use Magento\Ui\Controller\Adminhtml\Index\Render; use Magento\Ui\Model\UiComponentTypeResolver; use Magento\Framework\View\Element\UiComponent\ContextInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyFields) */ class RenderTest extends \PHPUnit\Framework\TestCase { @@ -19,6 +21,11 @@ class RenderTest extends \PHPUnit\Framework\TestCase */ private $render; + /** + * @var ObjectManagerHelper + */ + private $objectManagerHelper; + /** * @var \PHPUnit_Framework_MockObject_MockObject */ @@ -80,6 +87,16 @@ class RenderTest extends \PHPUnit\Framework\TestCase */ private $uiComponentTypeResolverMock; + /** + * @var \Magento\Framework\Controller\Result\JsonFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $resultJsonFactoryMock; + + /** + * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $loggerMock; + protected function setUp() { $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class) @@ -121,6 +138,14 @@ protected function setUp() ['render'] ); + $this->resultJsonFactoryMock = $this->getMockBuilder( + \Magento\Framework\Controller\Result\JsonFactory::class + ) + ->disableOriginalConstructor() + ->getMock(); + + $this->loggerMock = $this->getMockForAbstractClass(\Psr\Log\LoggerInterface::class); + $this->contextMock->expects($this->any()) ->method('getRequest') ->willReturn($this->requestMock); @@ -146,7 +171,71 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->render = new Render($this->contextMock, $this->uiFactoryMock, $this->uiComponentTypeResolverMock); + $this->objectManagerHelper = new ObjectManagerHelper($this); + + $this->render = $this->objectManagerHelper->getObject( + \Magento\Ui\Controller\Adminhtml\Index\Render::class, + [ + 'context' => $this->contextMock, + 'factory' => $this->uiFactoryMock, + 'contentTypeResolver' => $this->uiComponentTypeResolverMock, + 'resultJsonFactory' => $this->resultJsonFactoryMock, + 'logger' => $this->loggerMock, + ] + ); + } + + public function testExecuteAjaxRequestException() + { + $name = 'test-name'; + $renderedData = 'data'; + + $this->requestMock->expects($this->any()) + ->method('getParam') + ->with('namespace') + ->willReturn($name); + $this->requestMock->expects($this->any()) + ->method('getParams') + ->willReturn([]); + $this->responseMock->expects($this->once()) + ->method('appendBody') + ->willThrowException(new \Exception('exception')); + + $jsonResultMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Json::class) + ->disableOriginalConstructor() + ->setMethods(['setData']) + ->getMock(); + + $this->resultJsonFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($jsonResultMock); + + $jsonResultMock->expects($this->once()) + ->method('setData') + ->willReturnSelf(); + + $this->loggerMock->expects($this->once()) + ->method('critical') + ->willReturnSelf(); + + $this->dataProviderMock->expects($this->once()) + ->method('getConfigData') + ->willReturn([]); + + $this->uiComponentMock->expects($this->once()) + ->method('render') + ->willReturn($renderedData); + $this->uiComponentMock->expects($this->once()) + ->method('getChildComponents') + ->willReturn([]); + $this->uiComponentMock->expects($this->once()) + ->method('getContext') + ->willReturn($this->uiComponentContextMock); + $this->uiFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->uiComponentMock); + + $this->render->executeAjaxRequest(); } public function testExecuteAjaxRequest() diff --git a/app/code/Magento/Ui/composer.json b/app/code/Magento/Ui/composer.json index e9ace8bb159c0..2edcc3507970d 100644 --- a/app/code/Magento/Ui/composer.json +++ b/app/code/Magento/Ui/composer.json @@ -10,6 +10,7 @@ "magento/module-authorization": "100.3.*", "magento/module-backend": "100.3.*", "magento/module-eav": "100.3.*", + "magento/module-store": "100.3.*", "magento/module-user": "100.3.*" }, "suggest": { diff --git a/app/code/Magento/Ui/etc/db_schema.xml b/app/code/Magento/Ui/etc/db_schema.xml index c5e5392277490..d07329df9eb21 100644 --- a/app/code/Magento/Ui/etc/db_schema.xml +++ b/app/code/Magento/Ui/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Ui/etc/module.xml b/app/code/Magento/Ui/etc/module.xml index 20bd9de1567ee..967c33ae1648c 100644 --- a/app/code/Magento/Ui/etc/module.xml +++ b/app/code/Magento/Ui/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Ui/etc/ui_components.xsd b/app/code/Magento/Ui/etc/ui_components.xsd index 9a8ede09d59e0..3d3c0d11bb454 100644 --- a/app/code/Magento/Ui/etc/ui_components.xsd +++ b/app/code/Magento/Ui/etc/ui_components.xsd @@ -36,6 +36,7 @@ + diff --git a/app/code/Magento/Ui/etc/ui_configuration.xsd b/app/code/Magento/Ui/etc/ui_configuration.xsd index 5deba03a03b3f..5783323b53188 100644 --- a/app/code/Magento/Ui/etc/ui_configuration.xsd +++ b/app/code/Magento/Ui/etc/ui_configuration.xsd @@ -34,6 +34,7 @@ + @@ -180,6 +181,7 @@ + @@ -615,6 +617,14 @@ + + + + Adds image gallery functionality alongside file uploader functionality. + See fileUploader component documentation for more information. + + + diff --git a/app/code/Magento/Ui/etc/ui_definition.xsd b/app/code/Magento/Ui/etc/ui_definition.xsd index d22605398571d..d1787309d051e 100644 --- a/app/code/Magento/Ui/etc/ui_definition.xsd +++ b/app/code/Magento/Ui/etc/ui_definition.xsd @@ -53,6 +53,7 @@ + diff --git a/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml b/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml index 06c9312468f89..713cf2217d168 100644 --- a/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml +++ b/app/code/Magento/Ui/view/base/ui_component/etc/definition.map.xml @@ -359,6 +359,9 @@ formElements/*[name(.)=../../@formElement]/settings/allowedExtensions + + formElements/*[name(.)=../../@formElement]/settings/openDialogTitle + formElements/*[name(.)=../../@formElement]/settings/customEntry @@ -419,6 +422,15 @@ + + + + + settings/openDialogTitle + + + + diff --git a/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml b/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml index 0f708e4d138dd..88997f4e4cba7 100755 --- a/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml +++ b/app/code/Magento/Ui/view/base/ui_component/etc/definition.xml @@ -144,6 +144,7 @@ + diff --git a/app/code/Magento/Ui/view/base/ui_component/etc/definition/imageUploader.xsd b/app/code/Magento/Ui/view/base/ui_component/etc/definition/imageUploader.xsd new file mode 100644 index 0000000000000..b78defa668a0e --- /dev/null +++ b/app/code/Magento/Ui/view/base/ui_component/etc/definition/imageUploader.xsd @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Defines the title that appears when opening media browser dialog slideout. + + + + + + diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js b/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js index 4641ae96c9ece..bbac27141ba22 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js @@ -119,7 +119,7 @@ define([ * Adds provided file to the files list. * * @param {Object} file - * @returns {FileUploder} Chainable. + * @returns {FileUploader} Chainable. */ addFile: function (file) { file = this.processFile(file); diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js b/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js new file mode 100644 index 0000000000000..dabb9783abefd --- /dev/null +++ b/app/code/Magento/Ui/view/base/web/js/form/element/image-uploader.js @@ -0,0 +1,99 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'jquery', + 'underscore', + 'mageUtils', + 'Magento_Ui/js/modal/alert', + 'Magento_Ui/js/lib/validation/validator', + 'Magento_Ui/js/form/element/file-uploader', + 'mage/adminhtml/browser' +], function ($, _, utils, uiAlert, validator, Element, browser) { + 'use strict'; + + return Element.extend({ + + /** + * Assign uid for media gallery + * + * @return {ImageUploader} Chainable. + */ + initConfig: function () { + var mediaGalleryUid = utils.uniqueid(); + + this._super(); + + _.extend(this, { + mediaGalleryUid: mediaGalleryUid + }); + + return this; + }, + + /** + * Add file event callback triggered from media gallery + * + * @param {ImageUploader} imageUploader - UI Class + * @param {Event} e + */ + addFileFromMediaGallery: function (imageUploader, e) { + var $buttonEl = $(e.target), + fileSize = $buttonEl.data('size'), + fileMimeType = $buttonEl.data('mime-type'), + filePathname = $buttonEl.val(), + fileBasename = filePathname.split('/').pop(); + + this.addFile({ + type: fileMimeType, + name: fileBasename, + size: fileSize, + url: filePathname + }); + }, + + /** + * Open the media browser dialog using the + * + * @param {ImageUploader} imageUploader - UI Class + * @param {Event} e + */ + openMediaBrowserDialog: function (imageUploader, e) { + var $buttonEl = $(e.target), + openDialogUrl = this.mediaGallery.openDialogUrl + + 'target_element_id/' + $buttonEl.attr('id') + + '/store/' + this.mediaGallery.storeId + + '/type/image/use_storage_root/1?isAjax=true'; + + browser.openDialog(openDialogUrl, null, null, this.mediaGallery.openDialogTitle); + }, + + /** + * Trigger native browser file upload UI via clicking on 'Upload' button + * + * @param {ImageUploader} imageUploader - UI Class + * @param {Event} e + */ + triggerImageUpload: function (imageUploader, e) { + $(e.target).closest('.file-uploader').find('input[type="file"]').click(); + }, + + /** + * Get list of file extensions allowed in comma delimited format + * + * @return {String} + */ + getAllowedFileExtensionsInCommaDelimitedFormat: function () { + var allowedExtensions = this.allowedExtensions.toUpperCase().split(' '); + + // if jpg and jpeg in allowed extensions, remove jpeg from list + if (allowedExtensions.indexOf('JPG') !== -1 && allowedExtensions.indexOf('JPEG') !== -1) { + allowedExtensions.splice(allowedExtensions.indexOf('JPEG'), 1); + } + + return allowedExtensions.join(', '); + } + }); +}); diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js index dc5c2389ba8e5..de899fd8f2eff 100644 --- a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js +++ b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js @@ -23,12 +23,10 @@ define([ value: '', $wysiwygEditorButton: '', links: { - value: '${ $.provider }:${ $.dataScope }', - stageActive: false + value: '${ $.provider }:${ $.dataScope }' }, template: 'ui/form/field', elementTmpl: 'ui/form/element/wysiwyg', - stageActive: false, content: '', showSpinner: false, loading: false, @@ -49,7 +47,8 @@ define([ component: this, selector: 'button' }, function (element) { - this.$wysiwygEditorButton = $(element); + this.$wysiwygEditorButton = this.$wysiwygEditorButton ? + this.$wysiwygEditorButton.add($(element)) : $(element); }.bind(this)); // disable editor completely after initialization is field is disabled @@ -110,7 +109,6 @@ define([ /* eslint-disable no-undef */ if (typeof wysiwyg !== 'undefined' && wysiwyg.activeEditor()) { - if (wysiwyg && disabled) { wysiwyg.setEnabledStatus(false); wysiwyg.getPluginButtons().prop('disabled', 'disabled'); diff --git a/app/code/Magento/Ui/view/base/web/js/grid/filters/filters.js b/app/code/Magento/Ui/view/base/web/js/grid/filters/filters.js index 22ba19657168d..ecc4ec1902d87 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/filters/filters.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/filters/filters.js @@ -10,8 +10,10 @@ define([ 'underscore', 'mageUtils', 'uiLayout', - 'uiCollection' -], function (_, utils, layout, Collection) { + 'uiCollection', + 'mage/translate', + 'jquery' +], function (_, utils, layout, Collection, $t, $) { 'use strict'; /** @@ -48,6 +50,7 @@ define([ stickyTmpl: 'ui/grid/sticky/filters', _processed: [], columnsProvider: 'ns = ${ $.ns }, componentType = columns', + bookmarksProvider: 'ns = ${ $.ns }, componentType = bookmark', applied: { placeholder: true }, @@ -102,7 +105,9 @@ define([ applied: '${ $.provider }:params.filters' }, imports: { - 'onColumnsUpdate': '${ $.columnsProvider }:elems' + onColumnsUpdate: '${ $.columnsProvider }:elems', + onBackendError: '${ $.provider }:lastError', + bookmarksActiveIndex: '${ $.bookmarksProvider }:activeIndex' }, modules: { columns: '${ $.columnsProvider }', @@ -371,6 +376,37 @@ define([ */ onColumnsUpdate: function (columns) { columns.forEach(this.addFilter, this); + }, + + /** + * Provider ajax error listener. + * + * @param {bool} isError - Selected index of the filter. + */ + onBackendError: function (isError) { + var defaultMessage = 'Something went wrong with processing the default view and we have restored the ' + + 'filter to its original state.', + customMessage = 'Something went wrong with processing current custom view and filters have been ' + + 'reset to its original state. Please edit filters then click apply.'; + + if (isError) { + this.clear(); + + $('body').notification('clear') + .notification('add', { + error: true, + message: $.mage.__(this.bookmarksActiveIndex !== 'default' ? customMessage : defaultMessage), + + /** + * @param {String} message + */ + insertMethod: function (message) { + var $wrapper = $('
').html(message); + + $('.page-main-actions').after($wrapper); + } + }); + } } }); }); diff --git a/app/code/Magento/Ui/view/base/web/js/grid/provider.js b/app/code/Magento/Ui/view/base/web/js/grid/provider.js index 14a64216ef597..25bf25e6f65c0 100644 --- a/app/code/Magento/Ui/view/base/web/js/grid/provider.js +++ b/app/code/Magento/Ui/view/base/web/js/grid/provider.js @@ -21,6 +21,7 @@ define([ return Element.extend({ defaults: { firstLoad: true, + lastError: false, storageConfig: { component: 'Magento_Ui/js/grid/data-storage', provider: '${ $.storageConfig.name }', @@ -120,7 +121,7 @@ define([ request .done(this.onReload) - .fail(this.onError); + .fail(this.onError.bind(this)); return request; }, @@ -144,6 +145,10 @@ define([ return; } + this.set('lastError', true); + + this.firstLoad = false; + alert({ content: $t('Something went wrong.') }); @@ -157,6 +162,8 @@ define([ onReload: function (data) { this.firstLoad = false; + this.set('lastError', false); + this.setData(data) .trigger('reloaded'); }, diff --git a/app/code/Magento/Ui/view/base/web/templates/form/element/uploader/image.html b/app/code/Magento/Ui/view/base/web/templates/form/element/uploader/image.html new file mode 100644 index 0000000000000..8ae85b567fc5a --- /dev/null +++ b/app/code/Magento/Ui/view/base/web/templates/form/element/uploader/image.html @@ -0,0 +1,53 @@ + +
+ + +
+
+
+ +
+ + + +
+ +
+ +
+
diff --git a/app/code/Magento/Ups/etc/module.xml b/app/code/Magento/Ups/etc/module.xml index b0500b9aa4f90..cc4599627ffb9 100644 --- a/app/code/Magento/Ups/etc/module.xml +++ b/app/code/Magento/Ups/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/UrlRewrite/Setup/Patch/Data/ConvertSerializedDataToJson.php b/app/code/Magento/UrlRewrite/Setup/Patch/Data/ConvertSerializedDataToJson.php new file mode 100644 index 0000000000000..badd645b85f7d --- /dev/null +++ b/app/code/Magento/UrlRewrite/Setup/Patch/Data/ConvertSerializedDataToJson.php @@ -0,0 +1,91 @@ +moduleDataSetup = $moduleDataSetup; + $this->fieldDataConverterFactory = $fieldDataConverterFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + $this->convertSerializedDataToJson(); + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Convert native php serialized data to json. + */ + private function convertSerializedDataToJson() + { + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $fieldDataConverter->convert( + $this->moduleDataSetup->getConnection(), + $this->moduleDataSetup->getTable('url_rewrite'), + 'url_rewrite_id', + 'metadata' + ); + } +} diff --git a/app/code/Magento/UrlRewrite/Setup/UpgradeData.php b/app/code/Magento/UrlRewrite/Setup/UpgradeData.php deleted file mode 100644 index 7b9bc2020e60c..0000000000000 --- a/app/code/Magento/UrlRewrite/Setup/UpgradeData.php +++ /dev/null @@ -1,63 +0,0 @@ -fieldDataConverterFactory = $fieldDataConverterFactory; - } - - /** - * @inheritdoc - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $this->convertSerializedDataToJson($setup); - } - - $setup->endSetup(); - } - - /** - * Convert metadata from serialized to JSON format: - * - * @param ModuleDataSetupInterface $setup - * - * @return void - */ - public function convertSerializedDataToJson($setup) - { - $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); - $fieldDataConverter->convert( - $setup->getConnection(), - $setup->getTable('url_rewrite'), - 'url_rewrite_id', - 'metadata' - ); - } -} diff --git a/app/code/Magento/UrlRewrite/etc/db_schema.xml b/app/code/Magento/UrlRewrite/etc/db_schema.xml index a4f73a6a3a786..af328873deee7 100644 --- a/app/code/Magento/UrlRewrite/etc/db_schema.xml +++ b/app/code/Magento/UrlRewrite/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/UrlRewrite/etc/module.xml b/app/code/Magento/UrlRewrite/etc/module.xml index b8845ad04fb5f..eb314b71bc377 100644 --- a/app/code/Magento/UrlRewrite/etc/module.xml +++ b/app/code/Magento/UrlRewrite/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/UrlRewriteGraphQl/etc/module.xml b/app/code/Magento/UrlRewriteGraphQl/etc/module.xml index 17b04648630f7..689a792def0dc 100644 --- a/app/code/Magento/UrlRewriteGraphQl/etc/module.xml +++ b/app/code/Magento/UrlRewriteGraphQl/etc/module.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/app/code/Magento/User/Setup/Patch/Data/UpgradePasswordHashes.php b/app/code/Magento/User/Setup/Patch/Data/UpgradePasswordHashes.php new file mode 100644 index 0000000000000..0359d9b049940 --- /dev/null +++ b/app/code/Magento/User/Setup/Patch/Data/UpgradePasswordHashes.php @@ -0,0 +1,98 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + $this->upgradeHash(); + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Upgrade password hashes. + */ + private function upgradeHash() + { + $connection = $this->moduleDataSetup->getConnection(); + $customerEntityTable = $this->moduleDataSetup->getTable('admin_user'); + + $select = $connection->select()->from( + $customerEntityTable, + ['user_id', 'password'] + ); + + $customers = $connection->fetchAll($select); + foreach ($customers as $customer) { + list($hash, $salt) = explode(Encryptor::DELIMITER, $customer['password']); + + $newHash = $customer['password']; + if (strlen($hash) === 32) { + $newHash = implode(Encryptor::DELIMITER, [$hash, $salt, Encryptor::HASH_VERSION_MD5]); + } elseif (strlen($hash) === 64) { + $newHash = implode(Encryptor::DELIMITER, [$hash, $salt, Encryptor::HASH_VERSION_SHA256]); + } + + $bind = ['password' => $newHash]; + $where = ['user_id = ?' => (int)$customer['user_id']]; + $connection->update($customerEntityTable, $bind, $where); + } + } +} diff --git a/app/code/Magento/User/Setup/Patch/Data/UpgradeSerializedFields.php b/app/code/Magento/User/Setup/Patch/Data/UpgradeSerializedFields.php new file mode 100644 index 0000000000000..78c250e441406 --- /dev/null +++ b/app/code/Magento/User/Setup/Patch/Data/UpgradeSerializedFields.php @@ -0,0 +1,93 @@ +moduleDataSetup = $moduleDataSetup; + $this->fieldDataConverterFactory = $fieldDataConverterFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + $this->upgradeSerializedFields(); + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + UpgradePasswordHashes::class + ]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.2'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Convert serialized data to json. + */ + private function upgradeSerializedFields() + { + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $fieldDataConverter->convert( + $this->moduleDataSetup->getConnection(), + $this->moduleDataSetup->getTable('admin_user'), + 'user_id', + 'extra' + ); + } +} diff --git a/app/code/Magento/User/Setup/UpgradeData.php b/app/code/Magento/User/Setup/UpgradeData.php deleted file mode 100644 index 805eb152e77e6..0000000000000 --- a/app/code/Magento/User/Setup/UpgradeData.php +++ /dev/null @@ -1,99 +0,0 @@ -fieldDataConverterFactory = $fieldDataConverterFactory; - } - - /** - * @inheritdoc - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $this->upgradeHash($setup); - } - - if (version_compare($context->getVersion(), '2.0.2', '<')) { - $this->upgradeSerializedFields($setup); - } - - $setup->endSetup(); - } - - /** - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function upgradeHash($setup) - { - $customerEntityTable = $setup->getTable('admin_user'); - - $select = $setup->getConnection()->select()->from( - $customerEntityTable, - ['user_id', 'password'] - ); - - $customers = $setup->getConnection()->fetchAll($select); - foreach ($customers as $customer) { - list($hash, $salt) = explode(Encryptor::DELIMITER, $customer['password']); - - $newHash = $customer['password']; - if (strlen($hash) === 32) { - $newHash = implode(Encryptor::DELIMITER, [$hash, $salt, Encryptor::HASH_VERSION_MD5]); - } elseif (strlen($hash) === 64) { - $newHash = implode(Encryptor::DELIMITER, [$hash, $salt, Encryptor::HASH_VERSION_SHA256]); - } - - $bind = ['password' => $newHash]; - $where = ['user_id = ?' => (int)$customer['user_id']]; - $setup->getConnection()->update($customerEntityTable, $bind, $where); - } - } - - /** - * Convert serialized data in fields to json format - * - * @param ModuleDataSetupInterface $setup - * - * @return void - */ - private function upgradeSerializedFields($setup) - { - $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); - - $fieldDataConverter->convert( - $setup->getConnection(), - $setup->getTable('admin_user'), - 'user_id', - 'extra' - ); - } -} diff --git a/app/code/Magento/User/etc/db_schema.xml b/app/code/Magento/User/etc/db_schema.xml index 030df49ac3634..df9b39a27883d 100644 --- a/app/code/Magento/User/etc/db_schema.xml +++ b/app/code/Magento/User/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/User/etc/module.xml b/app/code/Magento/User/etc/module.xml index d3d5f52eddc60..ad4c972ae79d3 100644 --- a/app/code/Magento/User/etc/module.xml +++ b/app/code/Magento/User/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Usps/Setup/Patch/Data/UpdateAllowedMethods.php b/app/code/Magento/Usps/Setup/Patch/Data/UpdateAllowedMethods.php new file mode 100644 index 0000000000000..913819a5c1ac4 --- /dev/null +++ b/app/code/Magento/Usps/Setup/Patch/Data/UpdateAllowedMethods.php @@ -0,0 +1,141 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $connection = $this->moduleDataSetup->getConnection(); + $configDataTable = $this->moduleDataSetup->getTable('core_config_data'); + $oldToNewMethodCodesMap = [ + 'First-Class' => '0_FCLE', + 'First-Class Mail International Large Envelope' => 'INT_14', + 'First-Class Mail International Letter' => 'INT_13', + 'First-Class Mail International Letters' => 'INT_13', + 'First-Class Mail International Package' => 'INT_15', + 'First-Class Mail International Parcel' => 'INT_13', + 'First-Class Package International Service' => 'INT_15', + 'First-Class Mail' => '0_FCLE', + 'First-Class Mail Flat' => '0_FCLE', + 'First-Class Mail Large Envelope' => '0_FCLE', + 'First-Class Mail International' => 'INT_14', + 'First-Class Mail Letter' => '0_FCL', + 'First-Class Mail Parcel' => '0_FCP', + 'First-Class Mail Package' => '0_FCP', + 'First-Class Package Service - Retail' => '0_FCP', + 'Parcel Post' => '4', + 'Retail Ground' => '4', + 'Media Mail' => '6', + 'Library Mail' => '7', + 'Express Mail' => '3', + 'Express Mail PO to PO' => '3', + 'Express Mail Flat Rate Envelope' => '13', + 'Express Mail Flat-Rate Envelope Sunday/Holiday Guarantee' => '25', + 'Express Mail Sunday/Holiday Guarantee' => '23', + 'Express Mail Flat Rate Envelope Hold For Pickup' => '27', + 'Express Mail Hold For Pickup' => '2', + 'Global Express Guaranteed (GXG)' => 'INT_4', + 'Global Express Guaranteed Non-Document Rectangular' => 'INT_6', + 'Global Express Guaranteed Non-Document Non-Rectangular' => 'INT_7', + 'USPS GXG Envelopes' => 'INT_12', + 'Express Mail International' => 'INT_1', + 'Express Mail International Flat Rate Envelope' => 'INT_10', + 'Priority Mail' => '1', + 'Priority Mail Small Flat Rate Box' => '28', + 'Priority Mail Medium Flat Rate Box' => '17', + 'Priority Mail Large Flat Rate Box' => '22', + 'Priority Mail Flat Rate Envelope' => '16', + 'Priority Mail International' => 'INT_2', + 'Priority Mail International Flat Rate Envelope' => 'INT_8', + 'Priority Mail International Small Flat Rate Box' => 'INT_16', + 'Priority Mail International Medium Flat Rate Box' => 'INT_9', + 'Priority Mail International Large Flat Rate Box' => 'INT_11', + ]; + + $select = $connection->select() + ->from($configDataTable) + ->where( + 'path IN (?)', + ['carriers/usps/free_method', 'carriers/usps/allowed_methods'] + ); + $oldConfigValues = $connection->fetchAll($select); + + foreach ($oldConfigValues as $oldValue) { + if (stripos($oldValue['path'], 'free_method') !== false + && isset($oldToNewMethodCodesMap[$oldValue['value']]) + ) { + $newValue = $oldToNewMethodCodesMap[$oldValue['value']]; + } elseif (stripos($oldValue['path'], 'allowed_methods') !== false) { + $newValuesList = []; + foreach (explode(',', $oldValue['value']) as $shippingMethod) { + if (isset($oldToNewMethodCodesMap[$shippingMethod])) { + $newValuesList[] = $oldToNewMethodCodesMap[$shippingMethod]; + } + } + $newValue = implode(',', $newValuesList); + } else { + continue; + } + + if ($newValue && $newValue != $oldValue['value']) { + $whereConfigId = $connection->quoteInto('config_id = ?', $oldValue['config_id']); + $connection->update($configDataTable, ['value' => $newValue], $whereConfigId); + } + } + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Usps/Setup/UpgradeData.php b/app/code/Magento/Usps/Setup/UpgradeData.php deleted file mode 100644 index bc29d46836640..0000000000000 --- a/app/code/Magento/Usps/Setup/UpgradeData.php +++ /dev/null @@ -1,113 +0,0 @@ -getVersion(), '2.0.1', '<')) { - $this->updateAllowedMethods($setup); - } - } - - /** - * Replaces titles of allowed shipping methods to their codes. - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function updateAllowedMethods(ModuleDataSetupInterface $setup) - { - $installer = $setup; - $configDataTable = $installer->getTable('core_config_data'); - $connection = $installer->getConnection(); - - $oldToNewMethodCodesMap = [ - 'First-Class' => '0_FCLE', - 'First-Class Mail International Large Envelope' => 'INT_14', - 'First-Class Mail International Letter' => 'INT_13', - 'First-Class Mail International Letters' => 'INT_13', - 'First-Class Mail International Package' => 'INT_15', - 'First-Class Mail International Parcel' => 'INT_13', - 'First-Class Package International Service' => 'INT_15', - 'First-Class Mail' => '0_FCLE', - 'First-Class Mail Flat' => '0_FCLE', - 'First-Class Mail Large Envelope' => '0_FCLE', - 'First-Class Mail International' => 'INT_14', - 'First-Class Mail Letter' => '0_FCL', - 'First-Class Mail Parcel' => '0_FCP', - 'First-Class Mail Package' => '0_FCP', - 'First-Class Package Service - Retail' => '0_FCP', - 'Parcel Post' => '4', - 'Retail Ground' => '4', - 'Media Mail' => '6', - 'Library Mail' => '7', - 'Express Mail' => '3', - 'Express Mail PO to PO' => '3', - 'Express Mail Flat Rate Envelope' => '13', - 'Express Mail Flat-Rate Envelope Sunday/Holiday Guarantee' => '25', - 'Express Mail Sunday/Holiday Guarantee' => '23', - 'Express Mail Flat Rate Envelope Hold For Pickup' => '27', - 'Express Mail Hold For Pickup' => '2', - 'Global Express Guaranteed (GXG)' => 'INT_4', - 'Global Express Guaranteed Non-Document Rectangular' => 'INT_6', - 'Global Express Guaranteed Non-Document Non-Rectangular' => 'INT_7', - 'USPS GXG Envelopes' => 'INT_12', - 'Express Mail International' => 'INT_1', - 'Express Mail International Flat Rate Envelope' => 'INT_10', - 'Priority Mail' => '1', - 'Priority Mail Small Flat Rate Box' => '28', - 'Priority Mail Medium Flat Rate Box' => '17', - 'Priority Mail Large Flat Rate Box' => '22', - 'Priority Mail Flat Rate Envelope' => '16', - 'Priority Mail International' => 'INT_2', - 'Priority Mail International Flat Rate Envelope' => 'INT_8', - 'Priority Mail International Small Flat Rate Box' => 'INT_16', - 'Priority Mail International Medium Flat Rate Box' => 'INT_9', - 'Priority Mail International Large Flat Rate Box' => 'INT_11', - ]; - - $select = $connection->select() - ->from($configDataTable) - ->where( - 'path IN (?)', - ['carriers/usps/free_method', 'carriers/usps/allowed_methods'] - ); - $oldConfigValues = $connection->fetchAll($select); - - foreach ($oldConfigValues as $oldValue) { - if (stripos($oldValue['path'], 'free_method') !== false - && isset($oldToNewMethodCodesMap[$oldValue['value']]) - ) { - $newValue = $oldToNewMethodCodesMap[$oldValue['value']]; - } elseif (stripos($oldValue['path'], 'allowed_methods') !== false) { - $newValuesList = []; - foreach (explode(',', $oldValue['value']) as $shippingMethod) { - if (isset($oldToNewMethodCodesMap[$shippingMethod])) { - $newValuesList[] = $oldToNewMethodCodesMap[$shippingMethod]; - } - } - $newValue = implode(',', $newValuesList); - } else { - continue; - } - - if ($newValue && $newValue != $oldValue['value']) { - $whereConfigId = $connection->quoteInto('config_id = ?', $oldValue['config_id']); - $connection->update($configDataTable, ['value' => $newValue], $whereConfigId); - } - } - } -} diff --git a/app/code/Magento/Usps/etc/module.xml b/app/code/Magento/Usps/etc/module.xml index 8a1ec284c6333..0752b0dfe0efd 100644 --- a/app/code/Magento/Usps/etc/module.xml +++ b/app/code/Magento/Usps/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/Variable/Model/ResourceModel/Variable/Collection.php b/app/code/Magento/Variable/Model/ResourceModel/Variable/Collection.php index 3b74849352274..64c541e8c70b9 100644 --- a/app/code/Magento/Variable/Model/ResourceModel/Variable/Collection.php +++ b/app/code/Magento/Variable/Model/ResourceModel/Variable/Collection.php @@ -62,7 +62,7 @@ public function addValuesToResult() $this->getSelect()->join( ['value_table' => $this->getTable('variable_value')], 'value_table.variable_id = main_table.variable_id', - ['value_table.value'] + ['value_table.plain_value', 'value_table.html_value'] ); $this->addFieldToFilter('value_table.store_id', ['eq' => $this->getStoreId()]); return $this; diff --git a/app/code/Magento/Variable/Test/Unit/Model/ResourceModel/Variable/CollectionTest.php b/app/code/Magento/Variable/Test/Unit/Model/ResourceModel/Variable/CollectionTest.php new file mode 100644 index 0000000000000..38cf2fefcef97 --- /dev/null +++ b/app/code/Magento/Variable/Test/Unit/Model/ResourceModel/Variable/CollectionTest.php @@ -0,0 +1,94 @@ +getMockBuilder(Select::class) + ->disableOriginalConstructor() + ->getMock(); + $select->expects($this->once()) + ->method('from') + ->with($this->identicalTo(['main_table' => $mainTableName])) + ->willReturnSelf(); + $select->expects($this->once()) + ->method('join') + ->with( + $this->identicalTo(['value_table' => $tableName]), + $this->identicalTo('value_table.variable_id = main_table.variable_id'), + $this->identicalTo(['value_table.plain_value', 'value_table.html_value']) + )->willReturnSelf(); + + $connection = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->setMethods(['select', 'prepareSqlCondition', 'quoteIdentifier']) + ->getMockForAbstractClass(); + $connection->expects($this->any()) + ->method('select') + ->willReturn($select); + $connection->expects($this->once()) + ->method('quoteIdentifier') + ->with($this->identicalTo($field)) + ->willReturn($field); + $connection->expects($this->once()) + ->method('prepareSqlCondition') + ->with( + $this->identicalTo($field), + $this->identicalTo(['eq' => 0]) + )->willReturn('testResultCondition'); + + $resource = $this->getMockBuilder(AbstractDb::class) + ->setMethods(['getTable', 'getMainTable', 'getConnection']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $resource->expects($this->any()) + ->method('getConnection') + ->willReturn($connection); + $resource->expects($this->once()) + ->method('getMainTable') + ->willReturn('testMainTable'); + $resource->expects($this->exactly(2)) + ->method('getTable') + ->withConsecutive( + [$mainTableName], + [$tableName] + )->willReturnOnConsecutiveCalls( + $mainTableName, + $tableName + ); + + $objectManager = new ObjectManager($this); + $collection = $objectManager->getObject( + Collection::class, + [ + 'resource' => $resource, + ] + ); + $this->assertInstanceOf(Collection::class, $collection->addValuesToResult()); + } +} diff --git a/app/code/Magento/Variable/etc/db_schema.xml b/app/code/Magento/Variable/etc/db_schema.xml index 506034cd3a4c5..d89bdb7e710b7 100644 --- a/app/code/Magento/Variable/etc/db_schema.xml +++ b/app/code/Magento/Variable/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Variable/etc/module.xml b/app/code/Magento/Variable/etc/module.xml index d85388d46fcbd..50a5afde34992 100644 --- a/app/code/Magento/Variable/etc/module.xml +++ b/app/code/Magento/Variable/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/Vault/Setup/Patch/Data/SetCreditCardAsDefaultTokenType.php b/app/code/Magento/Vault/Setup/Patch/Data/SetCreditCardAsDefaultTokenType.php new file mode 100644 index 0000000000000..dbea50fc9c5eb --- /dev/null +++ b/app/code/Magento/Vault/Setup/Patch/Data/SetCreditCardAsDefaultTokenType.php @@ -0,0 +1,79 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->moduleDataSetup->getConnection()->startSetup(); + + // data update for Vault module < 2.0.1 + // update sets credit card as default token type + $this->moduleDataSetup->getConnection()->update( + $this->moduleDataSetup->getTable('vault_payment_token'), + [ + PaymentTokenInterface::TYPE => CreditCardTokenFactory::TOKEN_TYPE_CREDIT_CARD + ], + PaymentTokenInterface::TYPE . ' = ""' + ); + + $this->moduleDataSetup->getConnection()->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Vault/Setup/UpgradeData.php b/app/code/Magento/Vault/Setup/UpgradeData.php deleted file mode 100644 index 7609a28d7f052..0000000000000 --- a/app/code/Magento/Vault/Setup/UpgradeData.php +++ /dev/null @@ -1,36 +0,0 @@ -startSetup(); - - // data update for Vault module < 2.0.1 - if (version_compare($context->getVersion(), '2.0.1', '<')) { - // update sets credit card as default token type - $setup->getConnection()->update($setup->getTable('vault_payment_token'), [ - PaymentTokenInterface::TYPE => CreditCardTokenFactory::TOKEN_TYPE_CREDIT_CARD - ], PaymentTokenInterface::TYPE . ' = ""'); - } - - $setup->endSetup(); - } -} diff --git a/app/code/Magento/Vault/etc/db_schema.xml b/app/code/Magento/Vault/etc/db_schema.xml index 8c53e06c18b59..6975369145776 100644 --- a/app/code/Magento/Vault/etc/db_schema.xml +++ b/app/code/Magento/Vault/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Vault/etc/module.xml b/app/code/Magento/Vault/etc/module.xml index 253e7f13aaadc..a6d44d333fc02 100644 --- a/app/code/Magento/Vault/etc/module.xml +++ b/app/code/Magento/Vault/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Version/etc/module.xml b/app/code/Magento/Version/etc/module.xml index 8108aaa038aee..fe8ace51ea07d 100644 --- a/app/code/Magento/Version/etc/module.xml +++ b/app/code/Magento/Version/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + diff --git a/app/code/Magento/Webapi/etc/module.xml b/app/code/Magento/Webapi/etc/module.xml index cda30887d0a22..093895b6e0a7a 100644 --- a/app/code/Magento/Webapi/etc/module.xml +++ b/app/code/Magento/Webapi/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/WebapiSecurity/etc/module.xml b/app/code/Magento/WebapiSecurity/etc/module.xml index 5fed15fb373b8..64dc439ad3fdd 100644 --- a/app/code/Magento/WebapiSecurity/etc/module.xml +++ b/app/code/Magento/WebapiSecurity/etc/module.xml @@ -4,5 +4,5 @@ ~ See COPYING.txt for license details. --> - + diff --git a/app/code/Magento/Weee/Setup/InstallData.php b/app/code/Magento/Weee/Setup/InstallData.php deleted file mode 100644 index dd4218cceb99a..0000000000000 --- a/app/code/Magento/Weee/Setup/InstallData.php +++ /dev/null @@ -1,99 +0,0 @@ -salesSetupFactory = $salesSetupFactory; - $this->quoteSetupFactory = $quoteSetupFactory; - } - - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - /** @var QuoteSetup $quoteSetup */ - $quoteSetup = $this->quoteSetupFactory->create(['setup' => $setup]); - $quoteSetup->addAttribute('quote_item', 'weee_tax_applied', ['type' => 'text']); - $quoteSetup->addAttribute('quote_item', 'weee_tax_applied_amount', ['type' => 'decimal']); - $quoteSetup->addAttribute('quote_item', 'weee_tax_applied_row_amount', ['type' => 'decimal']); - $quoteSetup->addAttribute('quote_item', 'weee_tax_disposition', ['type' => 'decimal']); - $quoteSetup->addAttribute('quote_item', 'weee_tax_row_disposition', ['type' => 'decimal']); - $quoteSetup->addAttribute('quote_item', 'base_weee_tax_applied_amount', ['type' => 'decimal']); - $quoteSetup->addAttribute('quote_item', 'base_weee_tax_applied_row_amnt', ['type' => 'decimal']); - $quoteSetup->addAttribute('quote_item', 'base_weee_tax_disposition', ['type' => 'decimal']); - $quoteSetup->addAttribute('quote_item', 'base_weee_tax_row_disposition', ['type' => 'decimal']); - - /** @var SalesSetup $salesSetup */ - $salesSetup = $this->salesSetupFactory->create(['setup' => $setup]); - $salesSetup->addAttribute('order_item', 'weee_tax_applied', ['type' => 'text']); - $salesSetup->addAttribute('order_item', 'weee_tax_applied_amount', ['type' => 'decimal']); - $salesSetup->addAttribute('order_item', 'weee_tax_applied_row_amount', ['type' => 'decimal']); - $salesSetup->addAttribute('order_item', 'weee_tax_disposition', ['type' => 'decimal']); - $salesSetup->addAttribute('order_item', 'weee_tax_row_disposition', ['type' => 'decimal']); - $salesSetup->addAttribute('order_item', 'base_weee_tax_applied_amount', ['type' => 'decimal']); - $salesSetup->addAttribute('order_item', 'base_weee_tax_applied_row_amnt', ['type' => 'decimal']); - $salesSetup->addAttribute('order_item', 'base_weee_tax_disposition', ['type' => 'decimal']); - $salesSetup->addAttribute('order_item', 'base_weee_tax_row_disposition', ['type' => 'decimal']); - - $salesSetup->addAttribute('invoice_item', 'weee_tax_applied', ['type' => 'text']); - $salesSetup->addAttribute('invoice_item', 'weee_tax_applied_amount', ['type' => 'decimal']); - $salesSetup->addAttribute('invoice_item', 'weee_tax_applied_row_amount', ['type' => 'decimal']); - $salesSetup->addAttribute('invoice_item', 'weee_tax_disposition', ['type' => 'decimal']); - $salesSetup->addAttribute('invoice_item', 'weee_tax_row_disposition', ['type' => 'decimal']); - $salesSetup->addAttribute('invoice_item', 'base_weee_tax_applied_amount', ['type' => 'decimal']); - $salesSetup->addAttribute('invoice_item', 'base_weee_tax_applied_row_amnt', ['type' => 'decimal']); - $salesSetup->addAttribute('invoice_item', 'base_weee_tax_disposition', ['type' => 'decimal']); - $salesSetup->addAttribute('invoice_item', 'base_weee_tax_row_disposition', ['type' => 'decimal']); - - $salesSetup->addAttribute('creditmemo_item', 'weee_tax_applied', ['type' => 'text']); - $salesSetup->addAttribute('creditmemo_item', 'weee_tax_applied_amount', ['type' => 'decimal']); - $salesSetup->addAttribute('creditmemo_item', 'weee_tax_applied_row_amount', ['type' => 'decimal']); - $salesSetup->addAttribute('creditmemo_item', 'weee_tax_disposition', ['type' => 'decimal']); - $salesSetup->addAttribute('creditmemo_item', 'weee_tax_row_disposition', ['type' => 'decimal']); - $salesSetup->addAttribute('creditmemo_item', 'base_weee_tax_applied_amount', ['type' => 'decimal']); - $salesSetup->addAttribute('creditmemo_item', 'base_weee_tax_applied_row_amnt', ['type' => 'decimal']); - $salesSetup->addAttribute('creditmemo_item', 'base_weee_tax_disposition', ['type' => 'decimal']); - $salesSetup->addAttribute('creditmemo_item', 'base_weee_tax_row_disposition', ['type' => 'decimal']); - } -} diff --git a/app/code/Magento/Weee/Setup/Patch/Data/InitQuoteAndOrderAttributes.php b/app/code/Magento/Weee/Setup/Patch/Data/InitQuoteAndOrderAttributes.php new file mode 100644 index 0000000000000..c89b6b590bc02 --- /dev/null +++ b/app/code/Magento/Weee/Setup/Patch/Data/InitQuoteAndOrderAttributes.php @@ -0,0 +1,124 @@ +moduleDataSetup = $moduleDataSetup; + $this->quoteSetupFactory = $quoteSetupFactory; + $this->salesSetupFactory = $salesSetupFactory; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + /** @var QuoteSetup $quoteSetup */ + $quoteSetup = $this->quoteSetupFactory->create(['setup' => $this->moduleDataSetup]); + $quoteSetup->addAttribute('quote_item', 'weee_tax_applied', ['type' => 'text']); + $quoteSetup->addAttribute('quote_item', 'weee_tax_applied_amount', ['type' => 'decimal']); + $quoteSetup->addAttribute('quote_item', 'weee_tax_applied_row_amount', ['type' => 'decimal']); + $quoteSetup->addAttribute('quote_item', 'weee_tax_disposition', ['type' => 'decimal']); + $quoteSetup->addAttribute('quote_item', 'weee_tax_row_disposition', ['type' => 'decimal']); + $quoteSetup->addAttribute('quote_item', 'base_weee_tax_applied_amount', ['type' => 'decimal']); + $quoteSetup->addAttribute('quote_item', 'base_weee_tax_applied_row_amnt', ['type' => 'decimal']); + $quoteSetup->addAttribute('quote_item', 'base_weee_tax_disposition', ['type' => 'decimal']); + $quoteSetup->addAttribute('quote_item', 'base_weee_tax_row_disposition', ['type' => 'decimal']); + + /** @var SalesSetup $salesSetup */ + $salesSetup = $this->salesSetupFactory->create(['setup' => $this->moduleDataSetup]); + $salesSetup->addAttribute('order_item', 'weee_tax_applied', ['type' => 'text']); + $salesSetup->addAttribute('order_item', 'weee_tax_applied_amount', ['type' => 'decimal']); + $salesSetup->addAttribute('order_item', 'weee_tax_applied_row_amount', ['type' => 'decimal']); + $salesSetup->addAttribute('order_item', 'weee_tax_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('order_item', 'weee_tax_row_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('order_item', 'base_weee_tax_applied_amount', ['type' => 'decimal']); + $salesSetup->addAttribute('order_item', 'base_weee_tax_applied_row_amnt', ['type' => 'decimal']); + $salesSetup->addAttribute('order_item', 'base_weee_tax_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('order_item', 'base_weee_tax_row_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('invoice_item', 'weee_tax_applied', ['type' => 'text']); + $salesSetup->addAttribute('invoice_item', 'weee_tax_applied_amount', ['type' => 'decimal']); + $salesSetup->addAttribute('invoice_item', 'weee_tax_applied_row_amount', ['type' => 'decimal']); + $salesSetup->addAttribute('invoice_item', 'weee_tax_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('invoice_item', 'weee_tax_row_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('invoice_item', 'base_weee_tax_applied_amount', ['type' => 'decimal']); + $salesSetup->addAttribute('invoice_item', 'base_weee_tax_applied_row_amnt', ['type' => 'decimal']); + $salesSetup->addAttribute('invoice_item', 'base_weee_tax_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('invoice_item', 'base_weee_tax_row_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('creditmemo_item', 'weee_tax_applied', ['type' => 'text']); + $salesSetup->addAttribute('creditmemo_item', 'weee_tax_applied_amount', ['type' => 'decimal']); + $salesSetup->addAttribute('creditmemo_item', 'weee_tax_applied_row_amount', ['type' => 'decimal']); + $salesSetup->addAttribute('creditmemo_item', 'weee_tax_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('creditmemo_item', 'weee_tax_row_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('creditmemo_item', 'base_weee_tax_applied_amount', ['type' => 'decimal']); + $salesSetup->addAttribute('creditmemo_item', 'base_weee_tax_applied_row_amnt', ['type' => 'decimal']); + $salesSetup->addAttribute('creditmemo_item', 'base_weee_tax_disposition', ['type' => 'decimal']); + $salesSetup->addAttribute('creditmemo_item', 'base_weee_tax_row_disposition', ['type' => 'decimal']); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Weee/etc/db_schema.xml b/app/code/Magento/Weee/etc/db_schema.xml index b53cf51a593ee..71d957ecaf5b8 100644 --- a/app/code/Magento/Weee/etc/db_schema.xml +++ b/app/code/Magento/Weee/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Weee/etc/module.xml b/app/code/Magento/Weee/etc/module.xml index 01fa4fa5fd69e..8064f84577720 100644 --- a/app/code/Magento/Weee/etc/module.xml +++ b/app/code/Magento/Weee/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/WeeeGraphQl/etc/module.xml b/app/code/Magento/WeeeGraphQl/etc/module.xml index c91836164480e..90a5636071f35 100644 --- a/app/code/Magento/WeeeGraphQl/etc/module.xml +++ b/app/code/Magento/WeeeGraphQl/etc/module.xml @@ -6,5 +6,5 @@ */ --> - + diff --git a/app/code/Magento/Widget/Setup/InstallData.php b/app/code/Magento/Widget/Setup/InstallData.php deleted file mode 100644 index 76c2154215290..0000000000000 --- a/app/code/Magento/Widget/Setup/InstallData.php +++ /dev/null @@ -1,46 +0,0 @@ -createMigrationSetup(); - $setup->startSetup(); - - $installer->appendClassAliasReplace( - 'widget_instance', - 'instance_type', - \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_BLOCK, - \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_PLAIN, - ['instance_id'] - ); - - $installer->appendClassAliasReplace( - 'layout_update', - 'xml', - \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_BLOCK, - \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_XML, - ['layout_update_id'] - ); - - $installer->doUpdateClassAliases(); - - $setup->endSetup(); - } -} diff --git a/app/code/Magento/Widget/Setup/Patch/Data/ConvertSerializedData.php b/app/code/Magento/Widget/Setup/Patch/Data/ConvertSerializedData.php new file mode 100644 index 0000000000000..b72e024c93480 --- /dev/null +++ b/app/code/Magento/Widget/Setup/Patch/Data/ConvertSerializedData.php @@ -0,0 +1,117 @@ +moduleDataSetup = $moduleDataSetup; + $this->queryModifierFactory = $queryModifierFactory; + $this->aggregatedFieldDataConverter = $aggregatedFieldDataConverter; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->convertSerializedData(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [UpgradeModelInstanceClassAliases::class]; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * Convert native serialized data to json. + */ + private function convertSerializedData() + { + $layoutUpdateQueryModifier = $this->queryModifierFactory->create( + 'like', + [ + 'values' => [ + 'xml' => '%conditions_encoded%' + ] + ] + ); + $this->aggregatedFieldDataConverter->convert( + [ + new FieldToConvert( + SerializedToJson::class, + $this->moduleDataSetup->getTable('widget_instance'), + 'instance_id', + 'widget_parameters' + ), + new FieldToConvert( + LayoutUpdateConverter::class, + $this->moduleDataSetup->getTable('layout_update'), + 'layout_update_id', + 'xml', + $layoutUpdateQueryModifier + ), + ], + $this->moduleDataSetup->getConnection() + ); + } +} diff --git a/app/code/Magento/Widget/Setup/Patch/Data/UpgradeModelInstanceClassAliases.php b/app/code/Magento/Widget/Setup/Patch/Data/UpgradeModelInstanceClassAliases.php new file mode 100644 index 0000000000000..d9890c98a8d2d --- /dev/null +++ b/app/code/Magento/Widget/Setup/Patch/Data/UpgradeModelInstanceClassAliases.php @@ -0,0 +1,83 @@ +moduleDataSetup = $moduleDataSetup; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $installer = $this->moduleDataSetup->createMigrationSetup(); + $this->moduleDataSetup->startSetup(); + + $installer->appendClassAliasReplace( + 'widget_instance', + 'instance_type', + \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_BLOCK, + \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_PLAIN, + ['instance_id'] + ); + $installer->appendClassAliasReplace( + 'layout_update', + 'xml', + \Magento\Framework\Module\Setup\Migration::ENTITY_TYPE_BLOCK, + \Magento\Framework\Module\Setup\Migration::FIELD_CONTENT_TYPE_XML, + ['layout_update_id'] + ); + $installer->doUpdateClassAliases(); + $this->moduleDataSetup->endSetup(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } +} diff --git a/app/code/Magento/Widget/Setup/UpgradeData.php b/app/code/Magento/Widget/Setup/UpgradeData.php deleted file mode 100644 index de3928d1fb5b8..0000000000000 --- a/app/code/Magento/Widget/Setup/UpgradeData.php +++ /dev/null @@ -1,89 +0,0 @@ -aggregatedFieldConverter = $aggregatedFieldConverter; - $this->queryModifierFactory = $queryModifierFactory; - } - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $this->upgradeVersionTwoZeroOne($setup); - } - } - - /** - * Upgrade data to version 2.0.1 - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function upgradeVersionTwoZeroOne(ModuleDataSetupInterface $setup) - { - $layoutUpdateQueryModifier = $this->queryModifierFactory->create( - 'like', - [ - 'values' => [ - 'xml' => '%conditions_encoded%' - ] - ] - ); - $this->aggregatedFieldConverter->convert( - [ - new FieldToConvert( - SerializedToJson::class, - $setup->getTable('widget_instance'), - 'instance_id', - 'widget_parameters' - ), - new FieldToConvert( - LayoutUpdateConverter::class, - $setup->getTable('layout_update'), - 'layout_update_id', - 'xml', - $layoutUpdateQueryModifier - ), - ], - $setup->getConnection() - ); - } -} diff --git a/app/code/Magento/Widget/etc/db_schema.xml b/app/code/Magento/Widget/etc/db_schema.xml index c92d63b4063fd..149bb27fcdb2a 100644 --- a/app/code/Magento/Widget/etc/db_schema.xml +++ b/app/code/Magento/Widget/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Widget/etc/module.xml b/app/code/Magento/Widget/etc/module.xml index 69467a38d47f5..4a163a641a290 100644 --- a/app/code/Magento/Widget/etc/module.xml +++ b/app/code/Magento/Widget/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/Wishlist/Setup/Patch/Data/ConvertSerializedData.php b/app/code/Magento/Wishlist/Setup/Patch/Data/ConvertSerializedData.php new file mode 100644 index 0000000000000..76f27756d8270 --- /dev/null +++ b/app/code/Magento/Wishlist/Setup/Patch/Data/ConvertSerializedData.php @@ -0,0 +1,153 @@ +moduleDataSetup = $moduleDataSetup; + $this->fieldDataConverterFactory = $fieldDataConverterFactory; + $this->queryModifierFactory = $queryModifierFactory; + $this->queryGenerator = $queryGenerator; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + $this->convertSerializedData(); + } + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.1'; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + private function convertSerializedData() + { + $connection = $this->moduleDataSetup->getConnection(); + $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); + $queryModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'code' => [ + 'parameters', + 'info_buyRequest', + 'bundle_option_ids', + 'bundle_selection_ids', + 'attributes', + 'bundle_selection_attributes', + ] + ] + ] + ); + $fieldDataConverter->convert( + $connection, + $this->moduleDataSetup->getTable('wishlist_item_option'), + 'option_id', + 'value', + $queryModifier + ); + $select = $connection + ->select() + ->from( + $this->moduleDataSetup->getTable('catalog_product_option'), + ['option_id'] + ) + ->where('type = ?', 'file'); + $iterator = $this->queryGenerator->generate('option_id', $select); + foreach ($iterator as $selectByRange) { + $codes = $connection->fetchCol($selectByRange); + $codes = array_map( + function ($id) { + return 'option_' . $id; + }, + $codes + ); + $queryModifier = $this->queryModifierFactory->create( + 'in', + [ + 'values' => [ + 'code' => $codes + ] + ] + ); + $fieldDataConverter->convert( + $connection, + $this->moduleDataSetup->getTable('wishlist_item_option'), + 'option_id', + 'value', + $queryModifier + ); + } + } +} diff --git a/app/code/Magento/Wishlist/Setup/UpgradeData.php b/app/code/Magento/Wishlist/Setup/UpgradeData.php deleted file mode 100644 index 10ce3469afe4f..0000000000000 --- a/app/code/Magento/Wishlist/Setup/UpgradeData.php +++ /dev/null @@ -1,126 +0,0 @@ -fieldDataConverterFactory = $fieldDataConverterFactory; - $this->queryModifierFactory = $queryModifierFactory; - $this->queryGenerator = $queryGenerator; - } - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - if (version_compare($context->getVersion(), '2.0.1', '<')) { - $this->upgradeToVersionTwoZeroOne($setup); - } - } - - /** - * Upgrade to version 2.0.1, convert data for `value` field in `wishlist_item_option table` - * from php-serialized to JSON format - * - * @param ModuleDataSetupInterface $setup - * @return void - */ - private function upgradeToVersionTwoZeroOne(ModuleDataSetupInterface $setup) - { - $fieldDataConverter = $this->fieldDataConverterFactory->create(SerializedToJson::class); - $queryModifier = $this->queryModifierFactory->create( - 'in', - [ - 'values' => [ - 'code' => [ - 'parameters', - 'info_buyRequest', - 'bundle_option_ids', - 'bundle_selection_ids', - 'attributes', - 'bundle_selection_attributes', - ] - ] - ] - ); - $fieldDataConverter->convert( - $setup->getConnection(), - $setup->getTable('wishlist_item_option'), - 'option_id', - 'value', - $queryModifier - ); - $select = $setup->getConnection() - ->select() - ->from( - $setup->getTable('catalog_product_option'), - ['option_id'] - ) - ->where('type = ?', 'file'); - $iterator = $this->queryGenerator->generate('option_id', $select); - foreach ($iterator as $selectByRange) { - $codes = $setup->getConnection()->fetchCol($selectByRange); - $codes = array_map( - function ($id) { - return 'option_' . $id; - }, - $codes - ); - $queryModifier = $this->queryModifierFactory->create( - 'in', - [ - 'values' => [ - 'code' => $codes - ] - ] - ); - $fieldDataConverter->convert( - $setup->getConnection(), - $setup->getTable('wishlist_item_option'), - 'option_id', - 'value', - $queryModifier - ); - } - } -} diff --git a/app/code/Magento/Wishlist/etc/db_schema.xml b/app/code/Magento/Wishlist/etc/db_schema.xml index d837037c4466c..73fcb7ce0cab4 100644 --- a/app/code/Magento/Wishlist/etc/db_schema.xml +++ b/app/code/Magento/Wishlist/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd">
diff --git a/app/code/Magento/Wishlist/etc/module.xml b/app/code/Magento/Wishlist/etc/module.xml index e7626f504e1f1..c5ece20d7956b 100644 --- a/app/code/Magento/Wishlist/etc/module.xml +++ b/app/code/Magento/Wishlist/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/code/Magento/WishlistAnalytics/etc/module.xml b/app/code/Magento/WishlistAnalytics/etc/module.xml index 159ed86ee171a..4acd600b66a7b 100644 --- a/app/code/Magento/WishlistAnalytics/etc/module.xml +++ b/app/code/Magento/WishlistAnalytics/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/app/design/adminhtml/Magento/backend/web/css/source/_components.less b/app/design/adminhtml/Magento/backend/web/css/source/_components.less index ac80ba9ef90d9..3f9f0ed00c5ed 100644 --- a/app/design/adminhtml/Magento/backend/web/css/source/_components.less +++ b/app/design/adminhtml/Magento/backend/web/css/source/_components.less @@ -20,4 +20,5 @@ @import 'components/_media-gallery.less'; @import 'components/_resizable-block.less'; @import 'components/_file-uploader.less'; +@import 'components/_image-uploader.less'; @import 'components/_slider.less'; diff --git a/app/design/adminhtml/Magento/backend/web/css/source/components/_image-uploader.less b/app/design/adminhtml/Magento/backend/web/css/source/components/_image-uploader.less new file mode 100644 index 0000000000000..f187697281252 --- /dev/null +++ b/app/design/adminhtml/Magento/backend/web/css/source/components/_image-uploader.less @@ -0,0 +1,45 @@ +// /** +// * Copyright © Magento, Inc. All rights reserved. +// * See COPYING.txt for license details. +// */ + +// +// Components -> Image Uploader +// _____________________________________________ + +.image-uploader { + .image-upload-requirements { + margin-top: 8px; + font-size: .9em; + } + + .image-placeholder { + margin-left: 0; + margin-right: 0; + } + + .image-uploader-spinner { + width: 50%; + height: 50%; + background-size: auto; + margin: 0; + transform: translate(50%, 50%); + position: absolute; + } + + .image-uploader-preview { + width: auto; + } + + .image-uploader-preview-link, + .image-uploader-preview-link .preview-image { + height: inherit; + } +} + +.image-uploader._loading { + .image-placeholder-text, + .product-image-wrapper:before { + display: none; + } +} diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less index 5364c48acb516..2db39c8c8b2da 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/_minicart.less @@ -106,6 +106,11 @@ .lib-dropdown( @_toggle-selector: ~'.action.showcart', @_options-selector: ~'.block-minicart', + @_dropdown-list-width: 320px, + @_dropdown-list-position-right: 0px, + @_dropdown-list-pointer-position: right, + @_dropdown-list-pointer-position-left-right: 26px, + @_dropdown-list-z-index: 101, @_dropdown-toggle-icon-content: @icon-cart, @_dropdown-toggle-active-icon-content: @icon-cart, @_dropdown-list-item-padding: false, @@ -121,23 +126,10 @@ .block-minicart { .lib-css(padding, 25px @minicart__padding-horizontal); - right: 0; - width: 320px; - z-index: 101; .block-title { display: none; } - - &:after { - left: auto; - right: 25px; - } - - &:before { - left: auto; - right: 26px; - } } .product { diff --git a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less index c58cfcd734e7d..5f8134193c67f 100644 --- a/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less +++ b/app/design/frontend/Magento/blank/Magento_Checkout/web/css/source/module/checkout/_payments.less @@ -162,6 +162,11 @@ .lib-css(margin, 0 -(@checkout-payment-method-title-mobile__padding)); } + .step-title { + .lib-css(padding-left, @checkout-payment-method-title-mobile__padding); + .lib-css(padding-right, @checkout-payment-method-title-mobile__padding) + } + .payment-method-title { .lib-css(padding, @checkout-payment-method-title-mobile__padding) } diff --git a/app/design/frontend/Magento/blank/web/css/source/_navigation.less b/app/design/frontend/Magento/blank/web/css/source/_navigation.less index d2a770815861b..4499886ef0f10 100644 --- a/app/design/frontend/Magento/blank/web/css/source/_navigation.less +++ b/app/design/frontend/Magento/blank/web/css/source/_navigation.less @@ -93,7 +93,7 @@ .switcher { border-top: 1px solid @color-gray82; font-size: 1.6rem; - font-weight: 700; + font-weight: @font-weight__bold; margin: 0; padding: .8rem 3.5rem .8rem 2rem; @@ -147,7 +147,7 @@ &.greet.welcome { border-top: 1px solid @color-gray82; - font-weight: 700; + font-weight: @font-weight__bold; padding: .8rem @indent__base; } @@ -161,7 +161,7 @@ .lib-css(color, @navigation-level0-item__color); .lib-css(text-decoration, @navigation-level0-item__text-decoration); display: block; - font-weight: 700; + font-weight: @font-weight__bold; padding: .8rem @indent__base; } diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less index 1765ef65f95b3..7cd3eed53d3d5 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/_minicart.less @@ -109,6 +109,11 @@ .lib-dropdown( @_toggle-selector: ~'.action.showcart', @_options-selector: ~'.block-minicart', + @_dropdown-list-width: 320px, + @_dropdown-list-position-right: 0px, + @_dropdown-list-pointer-position: right, + @_dropdown-list-pointer-position-left-right: 26px, + @_dropdown-list-z-index: 101, @_dropdown-toggle-icon-content: @icon-cart, @_dropdown-toggle-active-icon-content: @icon-cart, @_dropdown-list-item-padding: false, @@ -124,23 +129,10 @@ .block-minicart { .lib-css(padding, 25px @minicart__padding-horizontal); - right: 0; - width: 320px; - z-index: 101; - + .block-title { display: none; } - - &:after { - left: auto; - right: 25px; - } - - &:before { - left: auto; - right: 26px; - } } .product { diff --git a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less index 087f9c9fe6554..3136056d9426d 100644 --- a/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less +++ b/app/design/frontend/Magento/luma/Magento_Checkout/web/css/source/module/checkout/_payments.less @@ -162,6 +162,11 @@ .lib-css(margin, 0 -(@checkout-payment-method-title-mobile__padding)); } + .step-title { + .lib-css(padding-left, @checkout-payment-method-title-mobile__padding); + .lib-css(padding-right, @checkout-payment-method-title-mobile__padding) + } + .payment-method-title { .lib-css(padding, @checkout-payment-method-title-mobile__padding) } diff --git a/app/etc/NonComposerComponentRegistration.php b/app/etc/NonComposerComponentRegistration.php new file mode 100755 index 0000000000000..c7c1f675463c6 --- /dev/null +++ b/app/etc/NonComposerComponentRegistration.php @@ -0,0 +1,33 @@ + + + +
+ + + + + +
+
diff --git a/app/etc/di.xml b/app/etc/di.xml index 3d883801513ee..e43a019697bba 100755 --- a/app/etc/di.xml +++ b/app/etc/di.xml @@ -43,6 +43,8 @@ + + system/currency/installed @@ -174,9 +176,32 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -204,6 +229,10 @@ Magento\Framework\Communication\Config\Reader\EnvReader 20 + + Magento\Framework\MessageQueue\Code\Generator\Config\RemoteServiceReader\Communication + 5 + @@ -694,6 +723,7 @@ \Magento\Framework\Api\Code\Generator\SearchResults \Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator \Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator + \Magento\Framework\MessageQueue\Code\Generator\RemoteServiceGenerator @@ -1350,117 +1380,116 @@ - + - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Table - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Real - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Real - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Real - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Integer - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Integer - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Integer - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Integer - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Date - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Timestamp - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Timestamp - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\LongText - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\MediumText - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Text - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\StringBinary - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\StringBinary - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Blob - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\MediumBlob - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\LongBlob - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Boolean - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Unique - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Primary - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Foreign - \Magento\Setup\Model\Declaration\Schema\Dto\Factories\Index + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Table + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Real + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Real + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Real + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Integer + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Integer + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Integer + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Integer + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Date + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Timestamp + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Timestamp + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\LongText + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\MediumText + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Text + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\StringBinary + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\StringBinary + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Blob + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\MediumBlob + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\LongBlob + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Boolean + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Unique + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Primary + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Foreign + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Index - + - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Integer - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Integer - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Integer - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Integer - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Real - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Real - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Real - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Blob - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Blob - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Blob - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Blob - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Blob - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Blob - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Timestamp - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Date - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Timestamp - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\StringBinary - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\StringBinary - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\StringBinary - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\StringBinary - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Index - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Constraints\Internal - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Constraints\Internal - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Constraints\Internal - \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Constraints\ForeignKey - - - - - - - Magento\Setup\Model\Declaration\Schema\Db\MySQL\DDL\Triggers\MigrateDataFrom - Magento\Setup\Model\Declaration\Schema\Db\MySQL\DDL\Triggers\MigrateDataFromAnotherTable + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Integer + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Integer + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Integer + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Integer + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Real + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Real + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Real + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Blob + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Blob + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Blob + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Blob + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Blob + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Blob + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Timestamp + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Date + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Timestamp + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\StringBinary + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\StringBinary + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\StringBinary + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\StringBinary + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Index + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Constraints\Internal + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Constraints\Internal + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Constraints\Internal + \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Constraints\ForeignKey - + - Magento\Setup\Model\Declaration\Schema\Db\MySQL\DDL\Triggers\MigrateDataFromAnotherTable + Magento\Framework\Setup\Declaration\Schema\Db\MySQL\DDL\Triggers\MigrateDataFrom - + - Magento\Setup\Model\Declaration\Schema\FileSystem\XmlReader + Magento\Framework\Setup\Declaration\Schema\FileSystem\XmlReader - + - Magento\Setup\Model\Declaration\Schema\Operations\ReCreateTable - Magento\Setup\Model\Declaration\Schema\Operations\DropTable - Magento\Setup\Model\Declaration\Schema\Operations\CreateTable - Magento\Setup\Model\Declaration\Schema\Operations\DropReference - Magento\Setup\Model\Declaration\Schema\Operations\ModifyColumn - Magento\Setup\Model\Declaration\Schema\Operations\AddColumn - Magento\Setup\Model\Declaration\Schema\Operations\DropElement - Magento\Setup\Model\Declaration\Schema\Operations\AddComplexElement - Magento\Setup\Model\Declaration\Schema\Operations\ModifyTable + Magento\Framework\Setup\Declaration\Schema\Operations\ReCreateTable + Magento\Framework\Setup\Declaration\Schema\Operations\DropTable + Magento\Framework\Setup\Declaration\Schema\Operations\CreateTable + Magento\Framework\Setup\Declaration\Schema\Operations\DropReference + Magento\Framework\Setup\Declaration\Schema\Operations\ModifyColumn + Magento\Framework\Setup\Declaration\Schema\Operations\AddColumn + Magento\Framework\Setup\Declaration\Schema\Operations\DropElement + Magento\Framework\Setup\Declaration\Schema\Operations\AddComplexElement + Magento\Framework\Setup\Declaration\Schema\Operations\ModifyTable + + + Magento\Framework\Setup\Declaration\Schema\DataSavior\TableSavior + Magento\Framework\Setup\Declaration\Schema\DataSavior\ColumnSavior - + default - + - Magento\Setup\Model\Declaration\Schema\Declaration\ValidationRules\CheckReferenceColumnHasIndex - Magento\Setup\Model\Declaration\Schema\Declaration\ValidationRules\RealTypes + Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules\CheckReferenceColumnHasIndex + Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules\RealTypes + Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules\PrimaryKeyCanBeCreated + Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules\IncosistentReferenceDefinition + Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules\AutoIncrementColumnValidation @@ -1490,4 +1519,132 @@ + + + schema + + + + + data + + + + + \Magento\Framework\Setup\Patch\DataPatchReader + \Magento\Framework\Setup\Patch\SchemaPatchReader + + + + + \Magento\Framework\Setup\Patch\DataPatchReader + + + + + + + Magento\Framework\MessageQueue\Config\Reader\Xml + 10 + + + Magento\Framework\MessageQueue\Config\Reader\Env + 20 + + + + + + + + + Magento\Framework\MessageQueue\Config\Reader\Xml\Converter\TopicConfig + 20 + + + + + + + Magento\Framework\MessageQueue\Consumer\Config\CompositeReader + + + + + + Magento\Framework\MessageQueue\Consumer\Config\Xml\Reader + Magento\Framework\MessageQueue\Consumer\Config\Env\Reader + + + + + + + Magento\Framework\MessageQueue\Consumer\Config\Validator\RequiredFields + Magento\Framework\MessageQueue\Consumer\Config\Validator\FieldsTypes + Magento\Framework\MessageQueue\Consumer\Config\Validator\Handlers + Magento\Framework\MessageQueue\Consumer\Config\Validator\ConsumerInstance + + + + + + + Magento\Framework\MessageQueue\Publisher\Config\Validator\Format + Magento\Framework\MessageQueue\Publisher\Config\Validator\EnabledConnection + + + + + + + Magento\Framework\MessageQueue\Publisher\Config\RemoteService\Reader + Magento\Framework\MessageQueue\Publisher\Config\Xml\Reader + Magento\Framework\MessageQueue\Publisher\Config\Env\Reader + + + + + + + Magento\Framework\MessageQueue\Topology\Config\Validator\Format + Magento\Framework\MessageQueue\Topology\Config\Validator\FieldsTypes + Magento\Framework\MessageQueue\Topology\Config\Validator\DependentFields + + + + + + + Magento\Framework\MessageQueue\Topology\Config\RemoteService\Reader + Magento\Framework\MessageQueue\Topology\Config\Xml\Reader + + + + + + + Magento\Framework\Amqp\Topology\BindingInstallerType\Queue + Magento\Framework\Amqp\Topology\BindingInstallerType\Exchange + + + + + + + magento + magento-db + + + + + + + amqp + db + + + + +
diff --git a/app/registration.php b/app/registration.php deleted file mode 100755 index fdfe4aa45b49d..0000000000000 --- a/app/registration.php +++ /dev/null @@ -1,33 +0,0 @@ -=0.1.11", @@ -42,14 +42,15 @@ "monolog/monolog": "^1.17", "oyejorge/less.php": "~1.7.0", "pelago/emogrifier": "^2.0.0", + "php-amqplib/php-amqplib": "2.5.*", "phpseclib/phpseclib": "2.0.*", "ramsey/uuid": "3.6.1", - "sjparkinson/static-review": "~4.1", "symfony/console": "~2.3, !=2.7.0", "symfony/event-dispatcher": "~2.1", "symfony/process": "~2.1", "tedivm/jshrink": "~1.1.0", "tubalmartin/cssmin": "4.1.0", + "webonyx/graphql-php": "^0.11.1", "zendframework/zend-captcha": "^2.7.1", "zendframework/zend-code": "^3.1.0", "zendframework/zend-config": "^2.6.0", @@ -58,6 +59,7 @@ "zendframework/zend-db": "^2.8.2", "zendframework/zend-di": "^2.6.1", "zendframework/zend-eventmanager": "^2.6.3", + "zendframework/zend-feed": "^2.9.0", "zendframework/zend-form": "^2.10.0", "zendframework/zend-http": "^2.6.0", "zendframework/zend-i18n": "^2.7.3", @@ -75,8 +77,7 @@ "zendframework/zend-text": "^2.6.0", "zendframework/zend-uri": "^2.5.1", "zendframework/zend-validator": "^2.6.0", - "zendframework/zend-view": "^2.8.1", - "webonyx/graphql-php": "^0.11.1" + "zendframework/zend-view": "^2.8.1" }, "require-dev": { "friendsofphp/php-cs-fixer": "~2.1.1", @@ -91,7 +92,9 @@ "magento/module-marketplace": "100.3.0-dev", "magento/module-admin-notification": "100.3.0-dev", "magento/module-advanced-pricing-import-export": "100.3.0-dev", + "magento/module-amqp": "100.3.0-dev", "magento/module-analytics": "100.3.0-dev", + "magento/module-asynchronous-operations": "100.3.0-dev", "magento/module-authorization": "100.3.0-dev", "magento/module-authorizenet": "100.3.0-dev", "magento/module-backend": "100.3.0-dev", @@ -161,8 +164,10 @@ "magento/module-integration": "100.3.0-dev", "magento/module-layered-navigation": "100.3.0-dev", "magento/module-media-storage": "100.3.0-dev", + "magento/module-message-queue": "100.3.0-dev", "magento/module-msrp": "100.3.0-dev", "magento/module-multishipping": "100.3.0-dev", + "magento/module-mysql-mq": "100.3.0-dev", "magento/module-new-relic-reporting": "100.3.0-dev", "magento/module-newsletter": "100.3.0-dev", "magento/module-offline-payments": "100.3.0-dev", @@ -229,6 +234,9 @@ "magento/language-pt_br": "100.3.0-dev", "magento/language-zh_hans_cn": "100.3.0-dev", "magento/framework": "100.3.0-dev", + "magento/framework-amqp": "100.1.0-dev", + "magento/framework-bulk": "100.3.0-dev", + "magento/framework-message-queue": "100.3.0-dev", "trentrichardson/jquery-timepicker-addon": "1.4.3", "components/jquery": "1.11.0", "blueimp/jquery-file-upload": "5.6.14", @@ -267,7 +275,7 @@ ] }, "files": [ - "app/registration.php" + "app/etc/NonComposerComponentRegistration.php" ], "exclude-from-classmap": [ "**/dev/**", diff --git a/composer.lock b/composer.lock index ee6328ed75bb4..8509554e81739 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "9114dbda66ca0958916c9e26caf374ce", + "content-hash": "03ece269ddc8227e813e176dad41a986", "packages": [ { "name": "braintree/braintree_php", @@ -166,21 +166,21 @@ }, { "name": "colinmollenhour/php-redis-session-abstract", - "version": "v1.2.2", + "version": "v1.3.8", "source": { "type": "git", "url": "https://github.com/colinmollenhour/php-redis-session-abstract.git", - "reference": "46968f06eeed7d16e8476d8a1397e224047ac6ff" + "reference": "9f69f5c1be512d5ff168e731e7fa29ab2905d847" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/colinmollenhour/php-redis-session-abstract/zipball/46968f06eeed7d16e8476d8a1397e224047ac6ff", - "reference": "46968f06eeed7d16e8476d8a1397e224047ac6ff", + "url": "https://api.github.com/repos/colinmollenhour/php-redis-session-abstract/zipball/9f69f5c1be512d5ff168e731e7fa29ab2905d847", + "reference": "9f69f5c1be512d5ff168e731e7fa29ab2905d847", "shasum": "" }, "require": { - "colinmollenhour/credis": "1.6", - "php": "~5.5.0|~5.6.0|~7.0.0|~7.1.0" + "colinmollenhour/credis": "~1.6", + "php": "~5.5.0|~5.6.0|~7.0.0|~7.1.0|~7.2.0" }, "type": "library", "autoload": { @@ -199,7 +199,7 @@ ], "description": "A Redis-based session handler with optimistic locking", "homepage": "https://github.com/colinmollenhour/php-redis-session-abstract", - "time": "2017-04-19T14:21:43+00:00" + "time": "2018-01-08T14:53:13+00:00" }, { "name": "composer/ca-bundle", @@ -554,55 +554,6 @@ ], "time": "2017-10-21T13:15:38+00:00" }, - { - "name": "league/climate", - "version": "2.6.1", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/climate.git", - "reference": "28851c909017424f61cc6a62089316313c645d1c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/climate/zipball/28851c909017424f61cc6a62089316313c645d1c", - "reference": "28851c909017424f61cc6a62089316313c645d1c", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "require-dev": { - "mockery/mockery": "dev-master", - "phpunit/phpunit": "4.1.*" - }, - "type": "library", - "autoload": { - "psr-4": { - "League\\CLImate\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Joe Tannenbaum", - "email": "hey@joe.codes", - "homepage": "http://joe.codes/", - "role": "Developer" - } - ], - "description": "PHP's best friend for the terminal. CLImate allows you to easily output colored text, special formats, and more.", - "keywords": [ - "cli", - "colors", - "command", - "php", - "terminal" - ], - "time": "2015-01-18T14:31:58+00:00" - }, { "name": "magento/composer", "version": "1.2.0", @@ -1022,6 +973,60 @@ ], "time": "2018-01-05T23:30:21+00:00" }, + { + "name": "php-amqplib/php-amqplib", + "version": "v2.5.2", + "source": { + "type": "git", + "url": "https://github.com/php-amqplib/php-amqplib.git", + "reference": "eb8f94d97c8e79900accf77343dbd7eca7f58506" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/eb8f94d97c8e79900accf77343dbd7eca7f58506", + "reference": "eb8f94d97c8e79900accf77343dbd7eca7f58506", + "shasum": "" + }, + "require": { + "ext-bcmath": "*", + "ext-mbstring": "*", + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "suggest": { + "ext-sockets": "Use AMQPSocketConnection" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-4": { + "PhpAmqpLib\\": "PhpAmqpLib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1" + ], + "authors": [ + { + "name": "Alvaro Videla" + } + ], + "description": "This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.", + "homepage": "https://github.com/videlalvaro/php-amqplib/", + "keywords": [ + "message", + "queue", + "rabbitmq" + ], + "time": "2015-08-11T12:30:09+00:00" + }, { "name": "phpseclib/phpseclib", "version": "2.0.9", @@ -1433,60 +1438,6 @@ ], "time": "2015-10-13T18:44:15+00:00" }, - { - "name": "sjparkinson/static-review", - "version": "4.1.1", - "source": { - "type": "git", - "url": "https://github.com/sjparkinson/static-review.git", - "reference": "493c3410cf146a12fca84209bad126c494e125f0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sjparkinson/static-review/zipball/493c3410cf146a12fca84209bad126c494e125f0", - "reference": "493c3410cf146a12fca84209bad126c494e125f0", - "shasum": "" - }, - "require": { - "league/climate": "~2.0", - "php": ">=5.4.0", - "symfony/console": "~2.0", - "symfony/process": "~2.0" - }, - "require-dev": { - "mockery/mockery": "~0.9", - "phpunit/phpunit": "~4.0", - "sensiolabs/security-checker": "~2.0", - "squizlabs/php_codesniffer": "~1.0" - }, - "suggest": { - "sensiolabs/security-checker": "Required for ComposerSecurityReview.", - "squizlabs/php_codesniffer": "Required for PhpCodeSnifferReview." - }, - "bin": [ - "bin/static-review.php" - ], - "type": "library", - "autoload": { - "psr-4": { - "StaticReview\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Samuel Parkinson", - "email": "sam.james.parkinson@gmail.com", - "homepage": "http://samp.im" - } - ], - "description": "An extendable framework for version control hooks.", - "abandoned": "phpro/grumphp", - "time": "2014-09-22T08:40:36+00:00" - }, { "name": "symfony/console", "version": "v2.8.34", @@ -2482,6 +2433,67 @@ ], "time": "2017-12-12T17:48:56+00:00" }, + { + "name": "zendframework/zend-feed", + "version": "2.9.0", + "source": { + "type": "git", + "url": "https://github.com/zendframework/zend-feed.git", + "reference": "abe88686124d492e0a2a84656f15e5482bfbe030" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/zendframework/zend-feed/zipball/abe88686124d492e0a2a84656f15e5482bfbe030", + "reference": "abe88686124d492e0a2a84656f15e5482bfbe030", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0", + "zendframework/zend-escaper": "^2.5.2", + "zendframework/zend-stdlib": "^2.7.7 || ^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.23 || ^6.4.3", + "psr/http-message": "^1.0.1", + "zendframework/zend-cache": "^2.7.2", + "zendframework/zend-coding-standard": "~1.0.0", + "zendframework/zend-db": "^2.8.2", + "zendframework/zend-http": "^2.7", + "zendframework/zend-servicemanager": "^2.7.8 || ^3.3", + "zendframework/zend-validator": "^2.10.1" + }, + "suggest": { + "psr/http-message": "PSR-7 ^1.0.1, if you wish to use Zend\\Feed\\Reader\\Http\\Psr7ResponseDecorator", + "zendframework/zend-cache": "Zend\\Cache component, for optionally caching feeds between requests", + "zendframework/zend-db": "Zend\\Db component, for use with PubSubHubbub", + "zendframework/zend-http": "Zend\\Http for PubSubHubbub, and optionally for use with Zend\\Feed\\Reader", + "zendframework/zend-servicemanager": "Zend\\ServiceManager component, for easily extending ExtensionManager implementations", + "zendframework/zend-validator": "Zend\\Validator component, for validating email addresses used in Atom feeds and entries when using the Writer subcomponent" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.9-dev", + "dev-develop": "2.10-dev" + } + }, + "autoload": { + "psr-4": { + "Zend\\Feed\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "provides functionality for consuming RSS and Atom feeds", + "keywords": [ + "ZendFramework", + "feed", + "zf" + ], + "time": "2017-12-04T17:59:38+00:00" + }, { "name": "zendframework/zend-filter", "version": "2.7.2", diff --git a/dev/tests/acceptance/.env.example b/dev/tests/acceptance/.env.example index fd4537bdd5f9f..432851acbf286 100644 --- a/dev/tests/acceptance/.env.example +++ b/dev/tests/acceptance/.env.example @@ -1,35 +1,6 @@ #Copyright © Magento, Inc. All rights reserved. #See COPYING.txt for license details. -#*** Start of example .env ***# -# -# MAGENTO_BASE_URL=http://127.0.0.1:32772/ -# -# MAGENTO_BACKEND_NAME=admin -# MAGENTO_ADMIN_USERNAME=admin -# MAGENTO_ADMIN_PASSWORD=123123q -# -# MAGENTO_CLI_COMMAND_PATH=dev/tests/functional/utils/command.php -# MAGENTO_CLI_COMMAND_PARAMETER=command -# -# SELENIUM_HOST=127.0.0.1 -# SELENIUM_PORT=4444 -# SELENIUM_PROTOCOL=http -# SELENIUM_PATH=/wd/hub -# -# MAGENTO_RESTAPI_SERVER_HOST=127.0.0.1 -# MAGENTO_RESTAPI_SERVER_PORT=32769 -# -# TESTS_BP=/Users/First_Last/GitHub/magento2ce/dev/tests/acceptance/tests/functional -# FW_BP=/Users/First_Last/GitHub/magento2-functional-testing-framework -# TESTS_MODULE_PATH=/Users/First_Last/GitHub/magento2ce/dev/tests/acceptance/tests/functional/Magento/FunctionalTest -# MODULE_WHITELIST=Magento_NewModule -# -#*** End of example .env ***# - - -#*** Start of .env ***# - #*** Set the base URL for your Magento instance ***# MAGENTO_BASE_URL= @@ -58,9 +29,9 @@ MAGENTO_ADMIN_PASSWORD= #TESTS_MODULE_PATH= #*** These properties impact the modules loaded into MFTF, you can point to your own full path, or a custom set of modules located with the core set -#MODULE_WHITELIST= +MODULE_WHITELIST=Magento_Framework,Magento_ConfigurableProductWishlist,Magento_ConfigurableProductCatalogSearch #CUSTOM_MODULE_PATHS= #*** Bool property which allows the user to toggle debug output during test execution #MFTF_DEBUG= -#*** End of .env ***# \ No newline at end of file +#*** End of .env ***# diff --git a/dev/tests/acceptance/RoboFile.php b/dev/tests/acceptance/RoboFile.php index 51fe3e546a0be..be9be5a2cc878 100644 --- a/dev/tests/acceptance/RoboFile.php +++ b/dev/tests/acceptance/RoboFile.php @@ -43,10 +43,17 @@ function buildProject() * @param array $opts * @return void */ - function generateTests($opts = ['config' => null]) + function generateTests($opts = ['config' => null, 'force' => false, 'nodes' => null]) { + $GLOBALS['GENERATE_TESTS'] = true; + + if ($opts['force']) + { + $GLOBALS['FORCE_PHP_GENERATE'] = true; + } + require 'tests'. DIRECTORY_SEPARATOR . 'functional' . DIRECTORY_SEPARATOR . '_bootstrap.php'; - \Magento\FunctionalTestingFramework\Util\TestGenerator::getInstance()->createAllTestFiles($opts['config']); + \Magento\FunctionalTestingFramework\Util\TestGenerator::getInstance()->createAllTestFiles($opts['config'], $opts['nodes']); $this->say("Generate Tests Command Run"); } diff --git a/dev/tests/acceptance/composer.json b/dev/tests/acceptance/composer.json index 5df5b2391d257..a46b9c8ae9187 100755 --- a/dev/tests/acceptance/composer.json +++ b/dev/tests/acceptance/composer.json @@ -1,5 +1,4 @@ { - "name": "magento/magento2ce-functional-tests", "description": "Magento 2 (Open Source) Functional Tests", "type": "project", "version": "1.0.0-dev", @@ -17,124 +16,15 @@ } ], "require": { - "allure-framework/allure-codeception": "dev-master#af40af5ae2b717618a42fe3e137d75878508c75d", + "allure-framework/allure-codeception": "~1.2.6", "codeception/codeception": "~2.3.4", "consolidation/robo": "^1.0.0", "symfony/process": ">=2.7 <3.4", "henrikbjorn/lurker": "^1.2", - "magento/magento2-functional-testing-framework": "~2.0.2", - "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/magento2-functional-testing-framework": "~2.1.1", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0|~7.2.0", "vlucas/phpdotenv": "~2.4" }, - "replace": { - "magento/magento2-functional-test-module-marketplace": "100.0.0-dev", - "magento/magento2-functional-test-module-admin-notification": "100.0.0-dev", - "magento/magento2-functional-test-module-advanced-pricing-import-export": "100.0.0-dev", - "magento/magento2-functional-test-module-authorization": "100.0.0-dev", - "magento/magento2-functional-test-module-authorizenet": "100.0.0-dev", - "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-backup": "100.0.0-dev", - "magento/magento2-functional-test-module-braintree": "100.0.0-dev", - "magento/magento2-functional-test-module-bundle": "100.0.0-dev", - "magento/magento2-functional-test-module-bundle-import-export": "100.0.0-dev", - "magento/magento2-functional-test-module-cache-invalidate": "100.0.0-dev", - "magento/magento2-functional-test-module-captcha": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog-import-export": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog-rule": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog-rule-configurable": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog-search": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog-url-rewrite": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog-widget": "100.0.0-dev", - "magento/magento2-functional-test-module-checkout": "100.0.0-dev", - "magento/magento2-functional-test-module-checkout-agreements": "100.0.0-dev", - "magento/magento2-functional-test-module-cms": "100.0.0-dev", - "magento/magento2-functional-test-module-cms-url-rewrite": "100.0.0-dev", - "magento/magento2-functional-test-module-config": "100.0.0-dev", - "magento/magento2-functional-test-module-configurable-import-export": "100.0.0-dev", - "magento/magento2-functional-test-module-configurable-product": "100.0.0-dev", - "magento/magento2-functional-test-module-configurable-product-sales": "100.0.0-dev", - "magento/magento2-functional-test-module-contact": "100.0.0-dev", - "magento/magento2-functional-test-module-cookie": "100.0.0-dev", - "magento/magento2-functional-test-module-cron": "100.0.0-dev", - "magento/magento2-functional-test-module-currency-symbol": "100.0.0-dev", - "magento/magento2-functional-test-module-customer": "100.0.0-dev", - "magento/magento2-functional-test-module-customer-import-export": "100.0.0-dev", - "magento/magento2-functional-test-module-deploy": "100.0.0-dev", - "magento/magento2-functional-test-module-developer": "100.0.0-dev", - "magento/magento2-functional-test-module-dhl": "100.0.0-dev", - "magento/magento2-functional-test-module-directory": "100.0.0-dev", - "magento/magento2-functional-test-module-downloadable": "100.0.0-dev", - "magento/magento2-functional-test-module-downloadable-import-export": "100.0.0-dev", - "magento/magento2-functional-test-module-eav": "100.0.0-dev", - "magento/magento2-functional-test-module-email": "100.0.0-dev", - "magento/magento2-functional-test-module-encryption-key": "100.0.0-dev", - "magento/magento2-functional-test-module-fedex": "100.0.0-dev", - "magento/magento2-functional-test-module-gift-message": "100.0.0-dev", - "magento/magento2-functional-test-module-google-adwords": "100.0.0-dev", - "magento/magento2-functional-test-module-google-analytics": "100.0.0-dev", - "magento/magento2-functional-test-module-google-optimizer": "100.0.0-dev", - "magento/magento2-functional-test-module-graph-ql": "100.0.0-dev", - "magento/magento2-functional-test-module-grouped-import-export": "100.0.0-dev", - "magento/magento2-functional-test-module-grouped-product": "100.0.0-dev", - "magento/magento2-functional-test-module-import-export": "100.0.0-dev", - "magento/magento2-functional-test-module-indexer": "100.0.0-dev", - "magento/magento2-functional-test-module-instant-purchase": "100.0.0-dev", - "magento/magento2-functional-test-module-integration": "100.0.0-dev", - "magento/magento2-functional-test-module-layered-navigation": "100.0.0-dev", - "magento/magento2-functional-test-module-media-storage": "100.0.0-dev", - "magento/magento2-functional-test-module-msrp": "100.0.0-dev", - "magento/magento2-functional-test-module-multishipping": "100.0.0-dev", - "magento/magento2-functional-test-module-new-relic-reporting": "100.0.0-dev", - "magento/magento2-functional-test-module-newsletter": "100.0.0-dev", - "magento/magento2-functional-test-module-offline-payments": "100.0.0-dev", - "magento/magento2-functional-test-module-offline-shipping": "100.0.0-dev", - "magento/magento2-functional-test-module-page-cache": "100.0.0-dev", - "magento/magento2-functional-test-module-payment": "100.0.0-dev", - "magento/magento2-functional-test-module-paypal": "100.0.0-dev", - "magento/magento2-functional-test-module-persistent": "100.0.0-dev", - "magento/magento2-functional-test-module-product-alert": "100.0.0-dev", - "magento/magento2-functional-test-module-product-video": "100.0.0-dev", - "magento/magento2-functional-test-module-quote": "100.0.0-dev", - "magento/magento2-functional-test-module-reports": "100.0.0-dev", - "magento/magento2-functional-test-module-require-js": "100.0.0-dev", - "magento/magento2-functional-test-module-review": "100.0.0-dev", - "magento/magento2-functional-test-module-robots": "100.0.0-dev", - "magento/magento2-functional-test-module-rss": "100.0.0-dev", - "magento/magento2-functional-test-module-rule": "100.0.0-dev", - "magento/magento2-functional-test-module-sales": "100.0.0-dev", - "magento/magento2-functional-test-module-sales-inventory": "100.0.0-dev", - "magento/magento2-functional-test-module-sales-rule": "100.0.0-dev", - "magento/magento2-functional-test-module-sales-sequence": "100.0.0-dev", - "magento/magento2-functional-test-module-sample-data": "100.0.0-dev", - "magento/magento2-functional-test-module-search": "100.0.0-dev", - "magento/magento2-functional-test-module-security": "100.0.0-dev", - "magento/magento2-functional-test-module-send-friend": "100.0.0-dev", - "magento/magento2-functional-test-module-shipping": "100.0.0-dev", - "magento/magento2-functional-test-module-sitemap": "100.0.0-dev", - "magento/magento2-functional-test-module-store": "100.0.0-dev", - "magento/magento2-functional-test-module-swagger": "100.0.0-dev", - "magento/magento2-functional-test-module-swatches": "100.0.0-dev", - "magento/magento2-functional-test-module-swatches-layered-navigation": "100.0.0-dev", - "magento/magento2-functional-test-module-tax": "100.0.0-dev", - "magento/magento2-functional-test-module-tax-import-export": "100.0.0-dev", - "magento/magento2-functional-test-module-theme": "100.0.0-dev", - "magento/magento2-functional-test-module-translation": "100.0.0-dev", - "magento/magento2-functional-test-module-ui": "100.0.0-dev", - "magento/magento2-functional-test-module-ups": "100.0.0-dev", - "magento/magento2-functional-test-module-url-rewrite": "100.0.0-dev", - "magento/magento2-functional-test-module-user": "100.0.0-dev", - "magento/magento2-functional-test-module-usps": "100.0.0-dev", - "magento/magento2-functional-test-module-variable": "100.0.0-dev", - "magento/magento2-functional-test-module-vault": "100.0.0-dev", - "magento/magento2-functional-test-module-version": "100.0.0-dev", - "magento/magento2-functional-test-module-webapi": "100.0.0-dev", - "magento/magento2-functional-test-module-webapi-security": "100.0.0-dev", - "magento/magento2-functional-test-module-weee": "100.0.0-dev", - "magento/magento2-functional-test-module-widget": "100.0.0-dev", - "magento/magento2-functional-test-module-wishlist": "100.0.0-dev" - }, "autoload": { "psr-4": { "Magento\\": "tests/functional/Magento" diff --git a/dev/tests/acceptance/composer.lock b/dev/tests/acceptance/composer.lock index 29cfc59adce97..0870217c962c6 100644 --- a/dev/tests/acceptance/composer.lock +++ b/dev/tests/acceptance/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "8549e85c50597c0494002f415527fcad", + "content-hash": "2771fad0a15e2894a259dca0ced002f3", "packages": [ { "name": "allure-framework/allure-codeception", - "version": "dev-master", + "version": "1.2.6", "source": { "type": "git", "url": "https://github.com/allure-framework/allure-codeception.git", - "reference": "af40af5ae2b717618a42fe3e137d75878508c75d" + "reference": "e2672e57e6839edb770fa5de5f2b3fcc47917aa1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/af40af5ae2b717618a42fe3e137d75878508c75d", - "reference": "af40af5ae2b717618a42fe3e137d75878508c75d", + "url": "https://api.github.com/repos/allure-framework/allure-codeception/zipball/e2672e57e6839edb770fa5de5f2b3fcc47917aa1", + "reference": "e2672e57e6839edb770fa5de5f2b3fcc47917aa1", "shasum": "" }, "require": { @@ -55,7 +55,7 @@ "steps", "testing" ], - "time": "2017-03-30T09:01:00+00:00" + "time": "2017-12-27T11:38:21+00:00" }, { "name": "allure-framework/allure-php-api", @@ -1641,11 +1641,11 @@ }, { "name": "magento/magento2-functional-testing-framework", - "version": "2.0.3", + "version": "2.1.2", "source": { "type": "git", "url": "git@github.com:magento/magento2-functional-testing-framework.git", - "reference": "22c803fc16024d417d920d03fdd95dea84779dd6" + "reference": "10d547a984cde1e1e9d9100c658011b467b10010" }, "require": { "codeception/codeception": "~2.3.4", @@ -1653,17 +1653,19 @@ "flow/jsonpath": ">0.2", "fzaninotto/faker": "^1.6", "mustache/mustache": "~2.5", - "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0|~7.2.0" }, "require-dev": { "brainmaestro/composer-git-hooks": "^2.3", "codacy/coverage": "^1.4", "codeception/aspect-mock": "^2.0", "goaop/framework": "2.1.2", + "php-coveralls/php-coveralls": "^1.0", "phpmd/phpmd": "^2.6.0", "rregeer/phpunit-coverage-check": "^0.1.4", "sebastian/phpcpd": "~3.0", - "squizlabs/php_codesniffer": "1.5.3" + "squizlabs/php_codesniffer": "1.5.3", + "symfony/stopwatch": "~3.4.6" }, "type": "library", "extra": { @@ -1699,7 +1701,7 @@ "magento", "testing" ], - "time": "2018-01-30T15:17:13+00:00" + "time": "2018-03-14T19:09:58+00:00" }, { "name": "moontoast/math", @@ -4420,13 +4422,11 @@ "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "allure-framework/allure-codeception": 20 - }, + "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0|~7.2.0" }, "platform-dev": [] } diff --git a/dev/tests/acceptance/tests/_bootstrap.php b/dev/tests/acceptance/tests/_bootstrap.php index 4313999476197..ee1b588ca2e87 100644 --- a/dev/tests/acceptance/tests/_bootstrap.php +++ b/dev/tests/acceptance/tests/_bootstrap.php @@ -21,6 +21,14 @@ defined($key) || define($key, $var); } } +if (!defined('MAGENTO_CLI_COMMAND_PATH')) { + define('MAGENTO_CLI_COMMAND_PATH', 'dev/tests/acceptance/utils/command.php'); + $env->setEnvironmentVariable('MAGENTO_CLI_COMMAND_PATH', 'dev/tests/acceptance/utils/command.php'); +} +if (!defined('MAGENTO_CLI_COMMAND_PARAMETER')) { + define('MAGENTO_CLI_COMMAND_PARAMETER', 'command'); + $env->setEnvironmentVariable('MAGENTO_CLI_COMMAND_PARAMETER', 'command'); +} defined('FW_BP') || define('FW_BP', PROJECT_ROOT . $RELATIVE_FW_PATH); // add the debug flag here diff --git a/dev/tests/acceptance/tests/_data/magento-again.jpg b/dev/tests/acceptance/tests/_data/magento-again.jpg new file mode 100644 index 0000000000000..c377daf8fb0b3 Binary files /dev/null and b/dev/tests/acceptance/tests/_data/magento-again.jpg differ diff --git a/dev/tests/acceptance/tests/_data/magento3.jpg b/dev/tests/acceptance/tests/_data/magento3.jpg new file mode 100644 index 0000000000000..79ed12ec0aea4 Binary files /dev/null and b/dev/tests/acceptance/tests/_data/magento3.jpg differ diff --git a/dev/tests/acceptance/tests/_suite/sampleSuite.xml b/dev/tests/acceptance/tests/_suite/sampleSuite.xml index 372dc19b13663..4c6a78afd40d0 100644 --- a/dev/tests/acceptance/tests/_suite/sampleSuite.xml +++ b/dev/tests/acceptance/tests/_suite/sampleSuite.xml @@ -6,58 +6,20 @@ */ --> - + - - - - + - - + - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/dev/tests/acceptance/tests/functional.suite.dist.yml b/dev/tests/acceptance/tests/functional.suite.dist.yml index 432151bdf565c..e01c46ea7c649 100644 --- a/dev/tests/acceptance/tests/functional.suite.dist.yml +++ b/dev/tests/acceptance/tests/functional.suite.dist.yml @@ -21,6 +21,7 @@ modules: depends: PhpBrowser part: Json - \Magento\FunctionalTestingFramework\Module\MagentoSequence + - \Magento\FunctionalTestingFramework\Module\MagentoAssert - Asserts config: \Magento\FunctionalTestingFramework\Module\MagentoWebDriver: diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Amqp/README.md b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Amqp/README.md new file mode 100644 index 0000000000000..49028ae41818b --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Amqp/README.md @@ -0,0 +1,3 @@ +# Magento 2 Functional Tests + +The Functional Tests Module for **Magento_Amqp** Module. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Amqp/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Amqp/composer.json new file mode 100644 index 0000000000000..87071431219cb --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Amqp/composer.json @@ -0,0 +1,29 @@ +{ + "name": "magento/magento2-functional-test-module-amqp", + "description": "Magento 2 Functional Test Module Amqp", + "type": "magento2-test-module", + "version": "100.0.0-dev", + "license": [ + "proprietary" + ], + "config": { + "sort-packages": true + }, + "require": { + "magento/magento2-functional-testing-framework": "1.0.0", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "autoload": { + "psr-4": { + "Magento\\FunctionalTest\\Amqp\\": "" + } + }, + "extra": { + "map": [ + [ + "*", + "dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Amqp" + ] + ] + } +} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationBlankIndustryCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationBlankIndustryCest.xml index 6f2f7b5782342..cd0ee19fc4971 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationBlankIndustryCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationBlankIndustryCest.xml @@ -13,7 +13,7 @@ <description value="An admin user cannot save a blank industry setting on the Advanced Reporting configuration page."/> - <severity value="NORMAL"/> + <severity value="MAJOR"/> <testCaseId value="MAGETWO-63981"/> <group value="analytics"/> <group value="skip"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationEnableDisableAnalyticsCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationEnableDisableAnalyticsCest.xml index c7ca8b799d243..bcf715ca17303 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationEnableDisableAnalyticsCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationEnableDisableAnalyticsCest.xml @@ -13,7 +13,7 @@ <stories value="Enable/disable Advanced Reporting"/> <title value="Enable Disable Advanced Reporting"/> <description value="An admin user can enable/disable Advanced Reporting."/> - <severity value="NORMAL"/> + <severity value="MAJOR"/> <testCaseId value="MAGETWO-66465"/> <group value="analytics"/> </annotations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationIndustryCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationIndustryCest.xml index 046cc17c43272..1678a563170ac 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationIndustryCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Analytics/Test/AdminConfigurationIndustryCest.xml @@ -14,7 +14,7 @@ <stories value="Set Magento Advanced reporting industry"/> <title value="Set Magento Advanced reporting industry"/> <description value="An admin user can change the industry setting on the Advanced Reporting configuration page."/> - <severity value="NORMAL"/> + <severity value="MAJOR"/> <testCaseId value="MAGETWO-63898"/> <group value="analytics"/> </annotations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/AsynchronousOperations/README.md b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/AsynchronousOperations/README.md new file mode 100644 index 0000000000000..39f11e663cf01 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/AsynchronousOperations/README.md @@ -0,0 +1,3 @@ +# Magento 2 Functional Tests + +The Functional Tests Module for **Magento_AsynchronousOperations** Module. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/AsynchronousOperations/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/AsynchronousOperations/composer.json new file mode 100644 index 0000000000000..5f13cad7fbb52 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/AsynchronousOperations/composer.json @@ -0,0 +1,36 @@ +{ + "name": "magento/magento2-functional-test-module-asynchronous-operations", + "description": "Magento 2 Functional Test Module Asynchronous Operations", + "type": "magento2-test-module", + "version": "100.0.0-dev", + "license": [ + "proprietary" + ], + "config": { + "sort-packages": true + }, + "require": { + "magento/magento2-functional-testing-framework": "1.0.0", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "suggest": { + "magento/magento2-functional-test-module-authorization": "100.0.0-dev", + "magento/magento2-functional-test-module-backend": "100.0.0-dev", + "magento/magento2-functional-test-module-logging": "100.0.0-dev", + "magento/magento2-functional-test-module-ui": "100.0.0-dev", + "magento/magento2-functional-test-module-user": "100.0.0-dev" + }, + "autoload": { + "psr-4": { + "Magento\\FunctionalTest\\AsynchronousOperations\\": "" + } + }, + "extra": { + "map": [ + [ + "*", + "dev/tests/acceptance/tests/functional/Magento/FunctionalTest/AsynchronousOperations" + ] + ] + } +} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Backend/Section/AdminConfirmationModalSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Backend/Section/AdminConfirmationModalSection.xml new file mode 100644 index 0000000000000..f7b2f246b55be --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Backend/Section/AdminConfirmationModalSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminConfirmationModalSection"> + <element name="title" type="text" selector="aside.confirm .modal-title"/> + <element name="message" type="text" selector="aside.confirm .modal-content"/> + <element name="cancel" type="button" selector="aside.confirm .modal-footer button.action-dismiss" timeout="30"/> + <element name="ok" type="button" selector="aside.confirm .modal-footer button.action-accept" timeout="60"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Backend/Section/AdminMessagesSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Backend/Section/AdminMessagesSection.xml index 4c10fbce0fb6a..d072f4aecb576 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Backend/Section/AdminMessagesSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Backend/Section/AdminMessagesSection.xml @@ -7,8 +7,8 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../../../../../magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="AdminMessagesSection"> - <element name="test" type="input" selector=".test"/> + <element name="success" type="text" selector="#messages div.message-success"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/EndToEndB2CAdminTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/EndToEndB2CAdminTest.xml index 6bc4594bce44f..34132defab88f 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/EndToEndB2CAdminTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/Test/EndToEndB2CAdminTest.xml @@ -9,7 +9,7 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> <test name="EndToEndB2CAdminTest"> <!--Create Bundle Product--> - <amOnPage url="{{AdminProductIndexPage}}" stepKey="visitAdminProductPageBundle" after="viewVirtualProductInGrid"/> + <amOnPage url="{{AdminProductIndexPage}}" stepKey="visitAdminProductPageBundle" after="seeSimpleProductInGrid"/> <waitForPageLoad stepKey="waitForProductPageLoadBundle" after="visitAdminProductPageBundle"/> <actionGroup ref="goToCreateProductPage" stepKey="goToCreateBundleProduct" after="waitForProductPageLoadBundle"> <argument name="product" value="BundleProduct"/> @@ -32,11 +32,12 @@ <fillField selector="{{AdminProductFormBundleSection.firstProductQuantity}}" userInput="{{BundleProduct.defaultQuantity}}" stepKey="fillProductDefaultQty" after="clickAddSelectedBundleProducts"/> <actionGroup ref="saveProductForm" stepKey="saveBundleProduct" after="fillProductDefaultQty"/> <actionGroup ref="viewBundleProductInAdminGrid" stepKey="viewBundleProductInGrid" after="saveBundleProduct"> - <argument name="product" value="BundleProduct"/> + <argument name="product" value="BundleProduct"/> </actionGroup> - <!--TODO - Move to 'after' block when MQE-732 is fixed--> - <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteBundleProduct" after="deleteVirtualProduct"> + <!--@TODO Move cleanup to "after" when MQE-830 is resolved--> + <comment userInput="Clean up bundle product" stepKey="cleanUpBundleProduct" after="deleteSimpleProduct"/> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteBundleProduct" after="cleanUpBundleProduct"> <argument name="product" value="BundleProduct"/> </actionGroup> </test> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/composer.json index 4a724336f1d2c..d76fd5195c3f3 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Bundle/composer.json @@ -12,11 +12,11 @@ }, "require": { "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-rule": "100.0.0-dev", "magento/magento2-functional-test-module-checkout": "100.0.0-dev", diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminCategoryActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminCategoryActionGroup.xml index 8d87d768e1545..48f21affb8697 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminCategoryActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminCategoryActionGroup.xml @@ -13,7 +13,6 @@ <arguments> <argument name="categoryEntity" defaultValue="_defaultCategory"/> </arguments> - <seeInCurrentUrl url="{{AdminCategoryPage}}" stepKey="seeOnCategoryPage"/> <click selector="{{AdminCategorySidebarActionSection.AddSubcategoryButton}}" stepKey="clickOnAddSubCategory"/> <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Category" stepKey="seeCategoryPageTitle"/> @@ -31,7 +30,6 @@ <arguments> <argument name="categoryEntity" defaultValue="_defaultCategory"/> </arguments> - <amOnPage url="/{{categoryEntity.name_lwr}}.html" stepKey="goToCategoryFrontPage"/> <waitForPageLoad stepKey="waitForPageLoad1"/> <see selector="{{StorefrontCategoryMainSection.CategoryTitle}}" userInput="{{categoryEntity.name_lwr}}" stepKey="assertCategoryOnStorefront"/> @@ -43,13 +41,14 @@ <arguments> <argument name="categoryEntity" defaultValue="_defaultCategory"/> </arguments> - <seeInCurrentUrl url="{{AdminCategoryPage}}" stepKey="seeOnCategoryPage"/> + <amOnPage url="{{AdminCategoryPage}}" stepKey="goToCategoryPage"/> + <waitForPageLoad time="60" stepKey="waitForCategoryPageLoad"/> <click selector="{{AdminCategorySidebarTreeSection.categoryInTree(categoryEntity.name)}}" stepKey="clickCategoryLink"/> <click selector="{{AdminCategoryMainActionsSection.DeleteButton}}" stepKey="clickDelete"/> <waitForElementVisible selector="{{AdminCategoryModalSection.message}}" stepKey="waitForConfirmationModal"/> <see selector="{{AdminCategoryModalSection.message}}" userInput="Are you sure you want to delete this category?" stepKey="seeDeleteConfirmationMessage"/> <click selector="{{AdminCategoryModalSection.ok}}" stepKey="confirmDelete"/> - <waitForPageLoad stepKey="waitForDeleteToFinish"/> + <waitForPageLoad time="60" stepKey="waitForDeleteToFinish"/> <see selector="You deleted the category." stepKey="seeDeleteSuccess"/> <click selector="{{AdminCategorySidebarTreeSection.expandAll}}" stepKey="expandToSeeAllCategories"/> <dontSee selector="{{AdminCategorySidebarTreeSection.categoryInTree(categoryEntity.name)}}" stepKey="dontSeeCategoryInTree"/> @@ -64,4 +63,15 @@ <seeInCurrentUrl url="{{AdminCategoryPage.url}}add" stepKey="seeBackOnCreateCategoryPage"/> <see selector="{{AdminCategoryBasicFieldSection.FieldError('uid')}}" userInput="This is a required field." stepKey="seeErrorMessage"/> </actionGroup> -</actionGroups> \ No newline at end of file + + <actionGroup name="navigateToCreatedCategory"> + <arguments> + <argument name="Category"/> + </arguments> + <amOnPage url="{{AdminCategoryPage.page}}" stepKey="amOnCategoryPage"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <click selector="{{AdminCategorySidebarTreeSection.categoryInTree(Category.Name)}}" stepKey="navigateToCreatedCategory" /> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <waitForLoadingMaskToDisappear stepKey="waitForSpinner" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductActionGroup.xml index e67a4a1a443c0..436d7cf5a8d17 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductActionGroup.xml @@ -57,7 +57,46 @@ <argument name="image" defaultValue="ImageUpload"/> </arguments> <conditionalClick selector="{{AdminProductImagesSection.productImagesToggle}}" dependentSelector="{{AdminProductImagesSection.imageUploadButton}}" visible="false" stepKey="openProductImagesSection"/> + <waitForPageLoad time="30" stepKey="waitForPageRefresh"/> + <waitForElementVisible selector="{{AdminProductImagesSection.imageUploadButton}}" stepKey="seeImageSectionIsReady"/> <attachFile selector="{{AdminProductImagesSection.imageFileUpload}}" userInput="{{image.file}}" stepKey="uploadFile"/> - <waitForAjaxLoad stepKey="waitForAjaxUpload"/> + <waitForAjaxLoad time="30" stepKey="waitForAjaxUpload"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoading"/> + </actionGroup> + + <!--Fill fields for simple product in a category in Admin--> + <actionGroup name="FillAdminSimpleProductForm"> + <arguments> + <argument name="category"/> + <argument name="simpleProduct"/> + </arguments> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickAddProductDropdown"/> + <click selector="{{AdminProductGridActionSection.addSimpleProduct}}" stepKey="clickAddSimpleProduct"/> + <fillField userInput="{{simpleProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillName"/> + <fillField userInput="{{simpleProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="fillSKU"/> + <fillField userInput="{{simpleProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="fillPrice"/> + <fillField userInput="{{simpleProduct.quantity}}" selector="{{AdminProductFormSection.productQuantity}}" stepKey="fillQuantity"/> + <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[{{category.name}}]" stepKey="searchAndSelectCategory"/> + <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSeoSection"/> + <fillField userInput="{{simpleProduct.urlKey}}" selector="{{AdminProductSEOSection.urlKeyInput}}" stepKey="fillUrlKey"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> + <seeElement selector="{{AdminProductMessagesSection.successMessage}}" stepKey="assertSaveMessageSuccess"/> + <seeInField userInput="{{simpleProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="assertFieldName"/> + <seeInField userInput="{{simpleProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="assertFieldSku"/> + <seeInField userInput="{{simpleProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="assertFieldPrice"/> + <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSeoSectionAssert"/> + <seeInField userInput="{{simpleProduct.urlKey}}" selector="{{AdminProductSEOSection.urlKeyInput}}" stepKey="assertFieldUrlKey"/> + </actionGroup> + + <!--Assert text in Related, Up-Sell or Cross-Sell section in Admin Product page--> + <actionGroup name="AssertTextInAdminProductRelatedUpSellCrossSellSection"> + <arguments> + <argument name="element" defaultValue="AdminProductFormRelatedUpSellCrossSellSection.relatedProductSectionText"/> + <argument name="expectedText"/> + </arguments> + <conditionalClick selector="{{AdminProductFormSection.productFormTab('Related Products')}}" dependentSelector="{{AdminProductFormSection.productFormTabState('Related Products', 'closed')}}" visible="true" stepKey="openTab"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad"/> + <see selector="{{element}}" userInput="{{expectedText}}" stepKey="AssertText"/> </actionGroup> </actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductAttributeActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductAttributeActionGroup.xml new file mode 100644 index 0000000000000..d3d6f13386856 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductAttributeActionGroup.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="navigateToCreatedProductAttribute"> + <arguments> + <argument name="ProductAttribute"/> + </arguments> + <amOnPage url="{{AdminProductAttributeGridPage.url}}" stepKey="navigateToProductAttributeGrid"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <click selector="{{AdminProductAttributeGridSection.AttributeCode(ProductAttribute.attribute_code)}}" stepKey="navigateToAttributeEditPage1" /> + <waitForPageLoad stepKey="waitForPageLoad2" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductGridActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductGridActionGroup.xml index 52ae266915aea..b153cf4a5b538 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductGridActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AdminProductGridActionGroup.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> <!--Reset the product grid to the default view--> <actionGroup name="resetProductGridToDefaultView"> + <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> <click selector="{{AdminProductGridFilterSection.viewDropdown}}" stepKey="openViewBookmarksTab"/> <click selector="{{AdminProductGridFilterSection.viewBookmark('Default View')}}" stepKey="resetToDefaultGridView"/> <waitForPageLoad stepKey="waitForProductGridLoad"/> @@ -71,6 +72,16 @@ <waitForElementNotVisible selector="{{AdminProductGridSection.loadingMask}}" stepKey="waitForFilteredGridLoad" time="30"/> </actionGroup> + <!--Search product grid with keyword search--> + <actionGroup name="searchProductGridByKeyword"> + <arguments> + <argument name="keyword"/> + </arguments> + <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial"/> + <fillField selector="{{AdminProductGridFilterSection.keywordSearch}}" userInput="{{keyword}}" stepKey="fillKeywordSearchField"/> + <click selector="{{AdminProductGridFilterSection.keywordSearchButton}}" stepKey="clickKeywordSearch"/> + </actionGroup> + <!--Filter product grid by name, sku, and type; and see expected product--> <actionGroup name="viewProductInAdminGrid"> <arguments> @@ -96,7 +107,7 @@ </arguments> <!--TODO use other action group for filtering grid when MQE-539 is implemented --> <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="visitAdminProductPage"/> - <waitForPageLoad stepKey="waitForPageLoadInitial"/> + <waitForPageLoad time="60" stepKey="waitForPageLoadInitial"/> <conditionalClick selector="{{AdminProductGridFilterSection.clearFilters}}" dependentSelector="{{AdminProductGridFilterSection.clearFilters}}" visible="true" stepKey="clickClearFiltersInitial"/> <click selector="{{AdminProductGridFilterSection.filters}}" stepKey="openProductFilters"/> <fillField selector="{{AdminProductGridFilterSection.skuFilter}}" userInput="{{product.sku}}" stepKey="fillProductSkuFilter"/> @@ -106,7 +117,7 @@ <click selector="{{AdminProductGridSection.multicheckOption('Select All')}}" stepKey="selectAllProductInFilteredGrid"/> <click selector="{{AdminProductGridSection.bulkActionDropdown}}" stepKey="clickActionDropdown"/> <click selector="{{AdminProductGridSection.bulkActionOption('Delete')}}" stepKey="clickDeleteAction"/> - <waitForElementVisible selector="{{AdminProductGridConfirmActionSection.ok}}" stepKey="waitForConfirmModal"/> + <waitForElementVisible selector="{{AdminProductGridConfirmActionSection.title}}" stepKey="waitForConfirmModal"/> <click selector="{{AdminProductGridConfirmActionSection.ok}}" stepKey="confirmProductDelete"/> </actionGroup> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AssertProductInStorefrontCategoryPageActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AssertProductInStorefrontCategoryPageActionGroup.xml new file mode 100644 index 0000000000000..cfaf91e4788a8 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AssertProductInStorefrontCategoryPageActionGroup.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertProductInStorefrontCategoryPage"> + <arguments> + <argument name="category"/> + <argument name="product"/> + </arguments> + <!-- Go to storefront category page, assert product visibility --> + <amOnPage url="{{StorefrontCategoryPage.url(category.name)}}" stepKey="navigateToCategoryPage"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <see userInput="{{product.name}}" stepKey="assertProductPresent"/> + <see userInput="{{product.price}}" stepKey="assertProductPricePresent"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AssertProductInStorefrontProductPageActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AssertProductInStorefrontProductPageActionGroup.xml new file mode 100644 index 0000000000000..6b9310cb95f53 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/AssertProductInStorefrontProductPageActionGroup.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssertProductInStorefrontProductPage"> + <arguments> + <argument name="product"/> + </arguments> + <!-- Go to storefront product page, assert product visibility --> + <amOnPage url="{{product.urlKey}}.html" stepKey="navigateToProductPage"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <seeInTitle userInput="{{product.name}}" stepKey="assertProductNameTitle"/> + <see userInput="{{product.name}}" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="assertProductName"/> + <see userInput="{{product.price}}" selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="assertProductPrice"/> + <see userInput="{{product.sku}}" selector="{{StorefrontProductInfoMainSection.productSku}}" stepKey="assertProductSku"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/NewProductActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/NewProductActionGroup.xml deleted file mode 100644 index 2f00168733df5..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/NewProductActionGroup.xml +++ /dev/null @@ -1,30 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> - <actionGroup name="createNewSimpleProduct"> - <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> - <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickAddProductDropdown"/> - <click selector="{{AdminProductGridActionSection.addSimpleProduct}}" stepKey="clickAddSimpleProduct"/> - <fillField userInput="{{_defaultProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillName"/> - <fillField userInput="{{_defaultProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="fillSKU"/> - <fillField userInput="{{_defaultProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="fillPrice"/> - <fillField userInput="{{_defaultProduct.quantity}}" selector="{{AdminProductFormSection.productQuantity}}" stepKey="fillQuantity"/> - <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createPreReqCategory.name$$]" stepKey="searchAndSelectCategory"/> - <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSeoSection"/> - <fillField userInput="{{_defaultProduct.urlKey}}" selector="{{AdminProductSEOSection.urlKeyInput}}" stepKey="fillUrlKey"/> - <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> - <seeElement selector="{{AdminProductMessagesSection.successMessage}}" stepKey="assertSaveMessageSuccess"/> - <seeInField userInput="{{_defaultProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="assertFieldName"/> - <seeInField userInput="{{_defaultProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="assertFieldSku"/> - <seeInField userInput="{{_defaultProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="assertFieldPrice"/> - <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSeoSectionAssert"/> - <seeInField userInput="{{_defaultProduct.urlKey}}" selector="{{AdminProductSEOSection.urlKeyInput}}" stepKey="assertFieldUrlKey"/> - </actionGroup> -</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/SearchAndMultiselectActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/SearchAndMultiselectActionGroup.xml new file mode 100644 index 0000000000000..a0546ec8bca0e --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/SearchAndMultiselectActionGroup.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="searchAndMultiSelectActionGroup"> + <arguments> + <argument name="dropDownSelector"/> + <argument name="options"/> + </arguments> + <waitForPageLoad stepKey="waitForPageLoad"/> + <waitForElementVisible selector="{{dropDownSelector}} .action-select.admin__action-multiselect" stepKey="waitForDropdown"/> + <click selector="{{dropDownSelector}} .action-select.admin__action-multiselect" stepKey="clickDropdown"/> + <selectMultipleOptions filterSelector="{{dropDownSelector}} .admin__action-multiselect-search-wrap>input[data-role='advanced-select-text']" optionSelector="{{dropDownSelector}} .admin__action-multiselect-label>span" stepKey="selectSpecifiedOptions"> + <array>[{{options}}]</array> + </selectMultipleOptions> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontCategoryActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontCategoryActionGroup.xml new file mode 100644 index 0000000000000..af71e1520bf44 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontCategoryActionGroup.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Check the category page --> + <actionGroup name="StorefrontCheckCategoryActionGroup"> + <arguments> + <argument name="category"/> + <argument name="productCount"/> + </arguments> + <seeInCurrentUrl url="/{{category.custom_attributes[url_key]}}.html" stepKey="checkUrl"/> + <seeInTitle userInput="{{category.name}}" stepKey="assertCategoryNameInTitle"/> + <see userInput="{{category.name}}" selector="{{StorefrontCategoryMainSection.CategoryTitle}}" stepKey="assertCategoryName"/> + <see userInput="{{productCount}}" selector="{{StorefrontCategoryMainSection.productCount}} span" stepKey="assertProductCount"/> + </actionGroup> + + <!-- Check simple product on the category page --> + <actionGroup name="StorefrontCheckCategorySimpleProduct"> + <arguments> + <argument name="product"/> + </arguments> + <seeElement selector="{{StorefrontCategoryProductSection.ProductTitleByName(product.name)}}" stepKey="assertProductName"/> + <see userInput="${{product.price}}.00" selector="{{StorefrontCategoryProductSection.ProductPriceByName(product.name)}}" stepKey="AssertProductPrice"/> + <!-- @TODO: MAGETWO-80272 Move to Magento_Checkout --> + <moveMouseOver selector="{{StorefrontCategoryProductSection.ProductInfoByName(product.name)}}" stepKey="moveMouseOverProduct" /> + <!-- @TODO: MAGETWO-80272 Move to Magento_Checkout --> + <seeElement selector="{{StorefrontCategoryProductSection.ProductAddToCartByName(product.name)}}" stepKey="AssertAddToCart" /> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontCompareActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontCompareActionGroup.xml new file mode 100644 index 0000000000000..9c80ce4b0b532 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontCompareActionGroup.xml @@ -0,0 +1,71 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Add Product to Compare from the category page and check message --> + <actionGroup name="StorefrontAddCategoryProductToCompareActionGroup"> + <arguments> + <argument name="productVar"/> + </arguments> + <moveMouseOver selector="{{StorefrontCategoryProductSection.ProductInfoByName(productVar.name)}}" stepKey="moveMouseOverProduct" /> + <click selector="{{StorefrontCategoryProductSection.ProductAddToCompareByName(productVar.name)}}" stepKey="clickAddProductToCompare"/> + <waitForElement selector="{{StorefrontMessagesSection.success}}" time="30" stepKey="waitForAddCategoryProductToCompareSuccessMessage"/> + <see selector="{{StorefrontMessagesSection.success}}" userInput="You added product {{productVar.name}} to the comparison list." stepKey="assertAddCategoryProductToCompareSuccessMessage"/> + </actionGroup> + + <!-- Add Product to Compare from the product page and check message --> + <actionGroup name="StorefrontAddProductToCompareActionGroup"> + <arguments> + <argument name="productVar"/> + </arguments> + <click selector="{{StorefrontProductInfoMainSection.productAddToCompare}}" stepKey="clickAddToCompare" /> + <waitForElement selector="{{StorefrontMessagesSection.success}}" time="30" stepKey="waitForAddProductToCompareSuccessMessage"/> + <see selector="{{StorefrontMessagesSection.success}}" userInput="You added product {{productVar.name}} to the comparison list." stepKey="assertAddProductToCompareSuccessMessage"/> + </actionGroup> + + <!-- Check the product in compare sidebar --> + <actionGroup name="StorefrontCheckCompareSidebarProductActionGroup"> + <arguments> + <argument name="productVar"/> + </arguments> + <waitForElement selector="{{StorefrontComparisonSidebarSection.ProductTitleByName(productVar.name)}}" stepKey="waitForProduct"/> + </actionGroup> + + <!-- Open and check comparison page --> + <actionGroup name="StorefrontOpenAndCheckComparisionActionGroup"> + <click selector="{{StorefrontComparisonSidebarSection.Compare}}" stepKey="clickCompare"/> + <waitForLoadingMaskToDisappear stepKey="waitForComparePageloaded" /> + <seeInCurrentUrl url="{{StorefrontProductComparePage.url}}" stepKey="checkUrl"/> + <seeInTitle userInput="Products Comparison List" stepKey="assertPageNameInTitle"/> + <see userInput="Compare Products" selector="{{StorefrontProductCompareMainSection.PageName}}" stepKey="assertPageName"/> + </actionGroup> + + <!-- Check the simple product in comparison page --> + <actionGroup name="StorefrontCheckCompareSimpleProductActionGroup"> + <arguments> + <argument name="productVar"/> + </arguments> + <seeElement selector="{{StorefrontProductCompareMainSection.ProductLinkByName(productVar.name)}}" stepKey="assertProductName"/> + <see userInput="${{productVar.price}}.00" selector="{{StorefrontProductCompareMainSection.ProductPriceByName(productVar.name)}}" stepKey="assertProductPrice"/> + <see userInput="{{productVar.sku}}" selector="{{StorefrontProductCompareMainSection.ProductAttributeByCodeAndProductName('SKU', productVar.name)}}" stepKey="assertProductPrice"/> + <!-- @TODO: MAGETWO-80272 Move to Magento_Checkout --> + <seeElement selector="{{StorefrontProductCompareMainSection.ProductAddToCartByName(productVar.name)}}" stepKey="assertProductAddToCart"/> + </actionGroup> + + <!-- Clear the compare list --> + <actionGroup name="StorefrontClearCompareActionGroup"> + <waitForElementVisible selector="{{StorefrontComparisonSidebarSection.ClearAll}}" time="30" stepKey="waitForClearAll"/> + <click selector="{{StorefrontComparisonSidebarSection.ClearAll}}" stepKey="clickClearAll"/> + <waitForElementVisible selector="{{ModalConfirmationSection.OkButton}}" time="30" stepKey="waitForClearOk"/> + <scrollTo selector="{{ModalConfirmationSection.OkButton}}" stepKey="scrollToClearOk"/> + <click selector="{{ModalConfirmationSection.OkButton}}" stepKey="clickClearOk"/> + <waitForElement selector="{{StorefrontMessagesSection.message('You cleared the comparison list.')}}" time="30" stepKey="AssertMessageCleared"/> + <waitForElement selector="{{StorefrontComparisonSidebarSection.NoItemsMessage}}" time="30" stepKey="assertNoItems"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontProductActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontProductActionGroup.xml new file mode 100644 index 0000000000000..ffc1687bc9f58 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontProductActionGroup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Check the simple product on the product page --> + <actionGroup name="StorefrontCheckSimpleProduct"> + <arguments> + <argument name="product"/> + </arguments> + <seeInCurrentUrl url="/{{product.custom_attributes[url_key]}}.html" stepKey="checkUrl"/> + <seeInTitle userInput="{{product.name}}" stepKey="AssertProductNameInTitle"/> + <see userInput="{{product.name}}" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="assertProductName"/> + <see userInput="{{product.sku}}" selector="{{StorefrontProductInfoMainSection.productSku}}" stepKey="assertProductSku"/> + <see userInput="${{product.price}}.00" selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="assertProductPrice"/> + <see userInput="IN STOCK" selector="{{StorefrontProductInfoMainSection.productStockStatus}}" stepKey="assertInStock"/> + <seeElement selector="{{StorefrontProductInfoMainSection.AddToCart}}" stepKey="assertAddToCart" /> + <see userInput="{{product.custom_attributes[description]}}" selector="{{StorefrontProductInfoMainSection.productDescription}}" stepKey="assertProductDescription"/> + <see userInput="{{product.custom_attributes[short_description]}}" selector="{{StorefrontProductInfoMainSection.productShortDescription}}" stepKey="assertProductShortDescription"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontProductPageActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontProductPageActionGroup.xml new file mode 100644 index 0000000000000..0644cdf3cc07c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/ActionGroup/StorefrontProductPageActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!--Click Add to Cart button in storefront product page--> + <actionGroup name="addToCartFromStorefrontProductPage"> + <arguments> + <argument name="productName"/> + </arguments> + <click selector="{{StorefrontProductActionSection.addToCart}}" stepKey="addToCart"/> + <waitForElementVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdding}}" stepKey="waitForElementVisibleAddToCartButtonTitleIsAdding"/> + <waitForElementNotVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdding}}" stepKey="waitForElementNotVisibleAddToCartButtonTitleIsAdding"/> + <waitForElementVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdded}}" stepKey="waitForElementVisibleAddToCartButtonTitleIsAdded"/> + <waitForElementNotVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAdded}}" stepKey="waitForElementNotVisibleAddToCartButtonTitleIsAdded"/> + <waitForElementVisible selector="{{StorefrontProductActionSection.addToCartButtonTitleIsAddToCart}}" stepKey="waitForElementVisibleAddToCartButtonTitleIsAddToCart"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <see selector="{{StorefrontMessagesSection.success}}" userInput="You added {{productName}} to your shopping cart." stepKey="seeAddToCartSuccessMessage"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CategoryData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CategoryData.xml index b734ffff46c47..5de996809b704 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CategoryData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CategoryData.xml @@ -13,6 +13,10 @@ <data key="name_lwr" unique="suffix">simplecategory</data> <data key="is_active">true</data> </entity> + <entity name="ApiCategory" type="category"> + <data key="name" unique="suffix">Api Category</data> + <data key="is_active">true</data> + </entity> <entity name="SimpleSubCategory" type="category"> <data key="name" unique="suffix">SimpleSubCategory</data> <data key="name_lwr" unique="suffix">simplesubcategory</data> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ConstData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ConstData.xml new file mode 100644 index 0000000000000..b26fa64bceae9 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ConstData.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <!-- @TODO: Get rid off this workaround and its usages after MQE-498 is implemented --> + <entity name="CONST" type="CONST"> + <data key="one">1</data> + <data key="two">2</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CustomAttributeData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CustomAttributeData.xml index f309665ba50f8..86e8ce17dc641 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CustomAttributeData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/CustomAttributeData.xml @@ -23,7 +23,13 @@ <entity name="CustomAttributeProductAttribute" type="custom_attribute"> <var key="attribute_code" entityKey="attribute_code" entityType="ProductAttribute"/> <var key="value" entityKey="value" entityType="ProductAttributeOption"/> - <data key="value">test product attribute</data> - <data key="attribute_code">test_product_attribute</data> + </entity> + <entity name="ApiProductDescription" type="custom_attribute"> + <data key="attribute_code">description</data> + <data key="value" unique="suffix">API Product Description</data> + </entity> + <entity name="ApiProductShortDescription" type="custom_attribute"> + <data key="attribute_code">short_description</data> + <data key="value" unique="suffix">API Product Short Description</data> </entity> </entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ImageContentData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ImageContentData.xml new file mode 100644 index 0000000000000..79842ccb47e31 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ImageContentData.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="TestImageContent" type="ImageContent"> + <data key="base64_encoded_data">/9j/4AAQSkZJRgABAQAAAQABAAD/2wCEAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDIBCQkJDAsMGA0NGDIhHCEyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMv/AABEIAGAAYAMBIgACEQEDEQH/xACXAAEBAAMBAQEBAAAAAAAAAAAABgMEBQgCAQcQAAEDAQUFBgQDCQAAAAAAAAABAgMEBQYRFpESMTZV0QchcnOzwhMUIkEygaE1QlFSYXGCsbIBAAEFAQAAAAAAAAAAAAAAAAACAwQGBwERAAECAwMLBAMBAAAAAAAAAAEAAgMEERMhkRQxMzRBUVJTcXKxBRJhoSKBwUL/2gAMAwEAAhEDEQA/AP7+AYKysp7Po5aurlbFBEmL3u3NQ6ASaBdArcFnBN5/urzqn0d0Gf7q86p9HdCRkUzy3YFOWEXhOCpATef7q86p9HdBn+6vOqfR3QMimeW7AosIvCcFSAm8/wB1edU+jugz/dXnVPo7oGRTPLdgUWEXhOCpATef7q86p9HdBn+6vOqfR3QMimeW7AosIvCcFSA1bPtGktWiZWUM7Z6d6qjZG7lwXBf1Q2iO5paaOFCmyCDQoTd/uBLX8n3IUhN3+4EtfyfchIk9Zh9w8pyBpW9QvN4Bwbcsujis+pq2Q4Tq5HbW0u9XJj3Y4fc0ibjPgQjEY0GgJNTS4brj/FaIz3Q2FwFafNP4V3gc1aWz7FY+rjhVrsNjBrlcrsV3Iir/ABPxtqzRyM+boJKeJ7kakm2jkRV3Yom4TlbYf4xrnfFSBuqaCn7ouWwbc+4/FT90XTBz57RlbVvpqWjdUSRoiyfWjUbju71MUlqSyWdVPjpnsqIUVJI3ORFZ3fix+4OnoLSRU3V2HZnANKEjcEGOwVG74OxdUGjZM1RNQROqIlYuw3Zcr9pXpgn1f0xN4kQYgiww8bU4xwe0OG1eg+y7gCg8cvqOLEjuy7gCg8cvqOLEzT1HXIvcfKq0zpn9ShN3+4EtfyfchSE3f7gS1/J9yCJPWYfcPKTA0reoXm85l4P2HUf4/wDSHTPmSOOZiskY17F3tcmKKaXMwjGgvhj/AECMQrTFZ72ObvC5lvxq+gjeivRsUzXvVn4kb34qmpozxWc+NjVtWtqPiOREjbMj1Vf7YFHvMMdLTxP244ImP/maxEUhzMhaxC8UvABrXZuoR9pmLL+9xddfvXNrfkVtJyPqJaOpRiL8VHbKPT8+5THFVS1FnWnE+VKhsUbmsmamG3i1e78jsSwQzoiTRRyIm5HtRf8AZ9MjZGxGMY1rU/damCHTJPMQuDgAa5q31G0VpdnrnuRYO9xNaA1+/r9rUsmeGazqdscrHuZExHo1cVauH30U3THFBDBtfBijj2t+w1Ex0MhMgMcyG1r843J+GC1oDs69B9l3AFB45fUcWJHdl3AFB45fUcWJm3qOuRe4+VV5nTP6lCbv9wJa/k+5CkJu/wBwJa/k+5BEnrMPuHlJgaVvULzeADUlbUAAIQAAhAACF6D7LuAKDxy+o4sSO7LuAKDxy+o4sTMPUdci9x8qqTOmf1KE3f7gS1/J9yFITd/uBLX8n3IIk9Zh9w8pMDSt6hebwAakragABCAAEIAAQvQfZdwBQeOX1HFiR3ZdwBQeOX1HFiZh6jrkXuPlVSZ0z+pQwVlHT2hRy0lXE2WCVMHsduchnBEBINQmQaXhTeQLq8lp9XdRkC6vJafV3UpASMtmeY7Epy3i8RxU3kC6vJafV3UZAuryWn1d1KQBlszzHYlFvF4jipvIF1eS0+ruoyBdXktPq7qUgDLZnmOxKLeLxHFTeQLq8lp9XdRkC6vJafV3UpAGWzPMdiUW8XiOK1bPs6ksqiZR0MDYKdiqrY27kxXFf1U2gCO5xcauNSmySTUr/9k=</data> + <data key="type">image/jpeg</data> + <data key="name" unique="prefix">test_image.jpg</data> + </entity> + <entity name="MagentoLogoImageContent" type="ImageContent"> + <data key="base64_encoded_data">iVBORw0KGgoAAAANSUhEUgAAAP8AAAEsCAYAAAAM1WX/AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAACY7SURBVHhe7Z0LlBxXnd6HXWyWhx9g8HS3pJFGPVU1klmC2RB28frBIbY00y2NpBnN9GMkG4JJcOJsgCVrszZg56wJuxj2BTjLY8FsADsb20kwmEc4WYgNxPYuiwX2yg9ZxrKsefS7R5IlufP/qm+N76hbo5qa7p6qru875zs6M5quvvd/76/q3lt1/9VDhU/7Ll79ikrauL66y8pVUsZ1ezf1nan+i6KoblV+bP22uUlrT+1dG2vlycEa/pWfH5kej4+oP6Eoqpt0aGx9vJqxvnF892Dt2JUbavmMNW/8fEx+X81aXy9MxNerj1AUFWQ9eGHPy4sp4wOHJ60ZXOWLWauW08CH8TN+r0YBM8W0+f47B3vOUIegKCpoyo/HL6tkzAcA9eFdgw3Qn2z8/5z8Hf6+krEeyE/EL1WHoigqCHo+2X9+MW18dm5y8MSLV25sCvrpfEI+V520TuA4h4b6etWhKYryqwTWXTJ3fxpXbyzone5qfyrjc+WsjALeLSeBrPl0MWNOqq+gKMpPmh3rf2Mpbdxbu2pj7ejuDZ6hP9k4Do6HEUQpY34zl+r/TfWVFEWtpH52ee+rZF7/kbmsVQb4hZPgbZVxXBx/btIqldLmjQeSkVeqIlAU1Wnl0gNJAf/nGOJXlzHEd2scH99jLwhmzX8sTgwkVFEoiuqEcjvW9pWzxleO7hqsHT/pnn2njO/F95cz5pefk/KoolEU1S5VM+Y1law1hatvqck9+04Z34vvr48CrEMolyoiRVGtVG5n/0Vylf07zLvd3LPvlFEOlAflkqnA/5kdX/92VWSKopajZ8Zir53LGrdWJ61jL161oW0Lest1fUFwQ60i5ZxLG7fuT/Sdq6pAUdRSVU4ZqXLGenK59+w7ZZTP2SxUzlpPlNPGhKoKRVFuND22zpQh9N+euHJD7YXdK7Ogt1yj3Ch/JWv97fSOPktVjaKoZsK++krGuK6cNUu4emKzTTOwgmJns5CcyIqVtPkH9zJvAEU1amZi3eXVjPkQYMHmGr8P8d0a9XA2C1Wz5oOFsXX/UlWZosKt6a1rotWs9XmsmGOY3AygbjHqd3hysFbNWH+1X+qtQkBR4VMpZbynOmkewFWxlO2eq/2pjPqhnvboJms+i/qrUFBUOFRI9f+WdP7v4tbYkRZuwgmKUV/UG/WXqcB3Cjvjb1Ghoaju1L6RtedUM8YtMsw/2s5NOEGxs1moOmkdKWeMjyM+KlQU1T3KTxjb57LWL+3V7wDcs++UEQfEoz4VsH6RT63fpkJGUcFWPXGm+V+PyzD35MSZ9EI7iUQrGetriJsKIUUFS0icmU8ZH0BCTFzVmiXOpBca8XGeDTictaaLqYH/gDiqkFKU/1VKxy+Zy1h24sxuumffKSNe9mYhiV81a92fG4tfokJLUf7UoZ19vcWM8ZnqMhJn0guNONqJRFPGXyIxqQo1RflHFSTOnLT24WoVhE04QTHiaG8Werf9bMBTchLYrUJOUSurfCr+5lLG+taLV25oaeJMeqER13oi0Q21Ytr4Vn7nwD9TTUBRndWeS899dTltfFSu9hXes++cnWcD5iTuiP/By3tfpZqEotqvysRAopOJM+mFRrz1RKKVlDGsmoai2qN64kzzS0d3r1ziTHqh0Q5HdtmJRP86t7N/jWoqimqdyinj31Wz1iFcbVYycSa90GgHJ5GotM/zTCRKtUzFifjvyBDfTpyJKwyh96fRLmgftBMSiRbT639bNSFFLU3PXBF7bSVdT5yJ3WfNOhztPzuJRKXdXqhkjE8ykSi1JBVSRqqStR7nPftgGu3lPBuAdkR7qqalqOY6OBrfKJ3l7iAnzqQXGu2IRUEZBdw1s3XNBtXUFFXXnrHBM2SIf305Y5ZxtecmnO4x2lFLJFpCO+8ZHDxDNT0VZs2MDlxezVh24sxqiBb0AASemMO/zf6/24x2RfvW7woMPjjDRKLh1dT2NZG5tHkbEkqeCNEmHEAA6Oek3vm0+Rh2z4XtsWS0t51INGv+F2zGUl2CCoNKE8bV1UkrNIkzYdSxrJJnYgNSLjWQrSUjr5wZj++qZq2n8Xv8f1hi8VIiUetXTCQaAk3vjL9FzvahTJyJ9/xVZIg/lzH//Int/W9QIbF1UH6uZI2/kJOA/XfNPt+NRvs7iUQlLt/Jj8cvVCGhukUzm/vPKmaMj8sV70iYNuGgc9svzJA6y0nv/unR+KUqJE01PR6/rDpp3m9fEUO0/uFsFqpI/yimjFv2Sn9RIaGCrPzEeiTO/AU6dFgSZ6KO8yvcGTNXThkfuGN7z6+pkCyqj17c8+tyovygjBJy+HxY7nygjkwk2iWa2rbOqGSsO5AQMmyJM+uJMDfgzTjfOLTFWyLMqR39A3LiuBPHCWf87ESi30AcVEgovwsJH4sTxgfDljhTv3LJVfuX+fTADhWSZamUGhiVk8Cj9nFDOHJCP5KpwAd+ICMiFRLKj8qND1wcxsSZzpy1nDXx8otbprec8xoVkpZoZvPZZ1UzxsflpBLONZN32W8Wuh/9S4WE8ouwWl1MG39RnbSOvyids1lDdqPROZ3VagHzu+1+7RVeM1bJGN8L590S3CIdPI5+hv6mQkKtpJDQ8XDIEmeijs596nLGPFDp8H1qGQVcXZXvxfeH6jkJNa2qZq19chLYpcJBdVpI4FhKG6FMnGm/6lqGo5W0eRte8a1C0lHNjK2OyRTjr7CHvttfLa4b/cxJJCr9716ZCrxJhYRqtw4kI68sp4yPze2y7E04YZp/Os+mlzLmQ4Xx+BUqJCuqQmr9JinPw/YVMSQjL9hZZ5nLWmUkEkW/VCGh2qFieiCJhI2h62hq5bmaNYtytf+DvZt6zlQh8YX2buo7s5IxrkP57BOylLdZPbrN9glZTQWQ0LWYGUiokFCtUn5i7dpqxrr9qFz5wpQ4E50L+9ExrC6nzXtmR+MbVUh8qdlUfGM5Y/4PJx9CWE7OMPol+mc5bX0lP7J2rQoJtRzJvPLasCXORB21xaXHZVg5ocIRCMm0DJmQnkAmnXAtwjojNOsQEr6qcFBLVXE8/rZKxrITZ2JxKyxXEWcuiRx0hbRxq8wlz1MhCZRQ7lLa+BTqgfo0q2s3Gv3Ufsmo1BmJRGfHmEjUtZBwsZoxPilXjtB1Gjv7rP1AidU1nWYW2Y8n5SQu9QrfSdx+/uKFatb8k30ja89RIaGaqTAxkLaHizJ0CuNw8fCkdbCcMq+pqXh0i27o6XlZQYbBc1nr+bBO36RfM5FoM81MGIMSnLvCmDgTC0Uv7FZvnMms7VMh6Uqphdsvo75hWriFnYXbSsb879M7DEuFJLy6F7eI0sb1SKyIs2OYNuE4t4jkavgPsyF711xR6iv1/hnqH5Zbtqijs1mojESiGeM69H8VknBpdjx+hcyFHrQBCNtc0O70VjXMb5nFW47lJHBTNWvNIR5helirvlkIdwXMB5FAVoWk+4XEmdWM+QUs/oT1sVC56n0zlzJ+U4Uk1Do0PvAmice9oX1MW0Y+1bT1eXChQtKdKqSN91YnQ7ghRG3Ckavc0/kJ40oVDkpTfnzgKonPfsQpnIlEzWcLE8bVKhzdI2zCkcp9J6yJM6VT42r/508m+89XIaGa6HmJTyVj/aVMicKbSHTSvC8/Gn+zCklw9eTYurPLKeMW6fyHcc8+TPM650EPmdfdPzUWv0SFhHKh6Yn4pQJBaJOyVLODh8tp84/AjwpJsITEmQL9L9GAoUycmbVmkTiT6Z+8CXGrMJFosBKJHhpbH0fiyOOhTpxpfu35HX39KiTUMnRoIr5eLiJfC3MiUan/1wsSBxUS/8lOnClXusMhT5xZmjC2q5BQLRQSkoY+kWjafD84UyHxh/Lj8cukYew5Whg34eBlD9WMccujLU6cSS3U9BbzNSqR6NGwrSFpzwbcn59Y/OUrHRFWZ4tp47Nzk4MnXgzZyy6d1VkZkn13Zqz/rSokVAdUSPe/VaaW9USiu0J290g4q05aJ8op4zPgT4Wks0ICQ+n49Rc8hmgYNp84M2s9V8p04X3ZAKmUNt4ro4CDaI/QJRJ9tz0KeLqYMSdVONqv2bH+NyJxIYZdYU2cicSV0ylzRRJnUgs1M2bEymnj8+F9YtTO6fjNXKq/fU+M/uzy3lfJvP4jc1mrHNb5VhmJMydC9Cx2gFRIx6+Q9rETiYbx2YC5SatUSps3tjyRaA6JMzPmzxHYMCXOdFZaZY5VkCH+dX5LnEkt1A8uXv0KGZVeLyAU0G5ov2bt2m0Gj/OJRLPmPxYnWpBINLdjbV85a3wlbIkz4fnEmRnjLuQbUCGhAiC0l0wF7kb7hTE/hJ1INGN++TnhV4VkaapmzGsqWWsKZ5PQJs6cMMdVOKgAqpA2JtCOaM8wZoYSfg+BYxWO0yu3s/8iOWuEMnFm/X1s1jEZOt5aGIu9VoWECrCeHYm+TqZsn0a7on3DtFbl7C+xE4mOr3+7CkmjnpHOPpc1bq0HaUP4gvQupFiy/m7RIFGBVS5tXlS1s0GHNJGocD0nFzUkyFUhqQt54csZ68nwDY/qQ/w5GR4VJox/i0STKiRUF+qOnp5fU4lE7fdAhOkRdGc6W85aT8y/ByI3MXDHcRkahHJhROosQ/yvYGHTDgYVCiGRqEwFbg9lIlGpL3gH9z3Ht6+pFXbG6/8pV8KT/7ibjDOgljjzZ8VxY0j1ByqEQuJU9AP0h1DcwlZ8g3dw3zM7FKnZ3rq6lhuXkwD+oAtPAvbcB42ctSphTpxJLdSesXNfXcZbnyetStc+vKaYBt/g3GG+Z3Y4WrPtnAS29dXyKUN9oMmBAmaczecTZ05a/2t2vP8C1e4UNS88ti6jgO5KJAp+wbHwDK7nGVfMvwS/Y/Wfue1ra/m0Wf9wswP73PoiR3XS2ldMx3epdqaoU6qYMnZ3xYY1cCv8gmOda92N8DvGHyditdxo/0sHO/kLfOwT9tbHwVolY3zmudH1r1dtS1GnFfpLJWt9Zk76T+A2CylOwS34bQa941PDD+OD8JZVtRwWBXFgH58EcJaef7AhYz4wvSN+mWpPilqypsf63yH96MeBeOBNsQlOwes8u824Vl4cfsfqQLmta2r58QHfnQTQKM4mHDlj54oZ44NMnEm1QrchPV3a+H3pV3n0L989G+CwKFyCTzfQO3YHv2N10Ny2tbWcsyjYrEAd9nzizKz5tUPbfJzokAqs7MS0WevreC7AN4lEhT9wCB51Pt16afA7xpdgPWDHuhVbFMTZ10mcKY3CxJlUR2QnEp1c4USi4A2LecLf6eb1i9kb/I7xpUk5CYytf6lQJxe0Da4/r2xDf1iu9n/ExJlUJ7V389lnlTPGx/FyjY4+G6D4Am/gziv0jpcHP4wCwFva/5AQzrK4B2tvVMia353eGX+Lag+K6rimR/t/q+IkEm3nswGKKfshHZeLeW68fPgd2wWSf0fW1PITrV0URFDnE2dmzAOllPEeFf/QSaY3g7WxwTPUj77Q3k19Z6Jc6sfQqZoxrm7LC2gdhoQncGXz1QLoHbcOfseqcDn7ScHWrAfgXuuRXYO1ctr6/MzY6piKeah0aGdfbylrfTmXMp6ckWGn+rUvlHvnWWdLuZ4qZ80voZzq16HSzLboKrkwfQH9tCXPBoAbezGvbwFXrXTr4XeMwi5jURBnTydxZiljPlwYj1+h4hw6VVLWu8oZ61e1q9+IWD7+zGjsN9R/+UJIGjmbMp9C+UpSzkp64Cr1X6FTJR2/opQ2/x791lMiUXDSgsU8N24f/I5R+OSqJS0KOvfs5yatfCVtXI/EjCq2odLUePzCatb8NuaUWOuA82njsZZnaF2msEkqlzL3Yt7rrMlUs9a9U93wqmkP2if9Vfrth5eUSFRxUV/MU/P6Zjy10O2HH0ZFxDkXi4J64sywziORJr2aMf9T5aRXmwcBfpTTuRtTxt2YtHmz38rbKc2OxjeeNpGoYgFcgA+HlaYctdidgd+xU7GRNbXchLNzsD400l52+bjMnUKbOLM0Ed9azVh77FicdB85KPDDepvKKOCRXCq+Rf156FRIGSmJweN4y878ZiGn7wsH9cW8zkHvuLPwO1aVxI4j6TS1Oek0MkQ6WkoZn0TCRRWzUCk/tmadDPH/BleIUz1BFiT4daM+yJojo5mv5kfWrlUfC5Wkzc5DYlj0c/R39PvFdtx1wisDv2OpdHnLqlppbN3B2XEjlIkzsQehOGG+v5I1T/tq86DCj/q8tPfCnC6nzN9DPj318VAJiUQr0t/R71cKescrC7/4ha2x2vRQ5CcqNqGSDPl+V672/xdQuNk1FlT4HaN+zq5LGQb/KLfTvEgdIlSaHer9Kfp9Mx466RWH/6gEYWY48pCKSyj0mAwBKxnzzypZ6wTSpDcDpZmDDr9u5NAvS/0rafNPwzTVq4lnhyMPo98346GTJvwdVmFiIF2dtJ7A1X6pmWK6CX7U28m0JPPgx2dTRkodrqtF+DWHBX7kDpzLmPcgRxwW9ZYCveNugt8x4uDc3pXR0D2zqfhGddiuFOHX3O3wA9RCeuBGmeOWcZUruHng4xTuRvgdIy6IT3XSLEm8bnjIZ3VslQi/5m6Gf3Zi/WYZ0tqPerYiL3w3ww8jPtp7FR6eHVu/SX1F14jwa+5G+PFq5HLG/GKrX23e7fDrRtywSaYkcczt7F+jvirwIvyauw3+UnrgfXLVeg5Xr5Zu7xSHCX7Ebf5dipPWgVJq4F+rrwu0CL/mboFfhqi/Xc2a/9tO7LCrPYkdwgS/Y8QR8bQ3C2Ws7xfH429TXxtIEX7NQYd/38jac0pp84/l6nSk3Smdwgi/4/nUbRLnUsr8xJNj685WXx8oEX7NQYa/PGGNVTuYzDHM8MOIr7ZZ6JcyFRhVRQiMCL/mIMI/vcOwyhnzv9lpnNvc4XWHHX7d2CyE+JfT5p3TY5apiuJ7EX7NQYL/wQt7Xl7JmB+Sq878Cxyadcx2mfAvtLNZSNojV0kbv4/2UUXyrQi/5qDAXxg33ilX+/9nrz57Sc/UAhP+RqMdnHRv5Yz103LKfIcqli9F+DX7Hf79W9dEK1nzs/ZLG5ewCacdJvyLG5ukqpPWCbyc9entayKqeL4S4dfsZ/grafNflbPms7iqtPqevRcT/sWN9nGeDShlzGdlivZuVUTfiPBr9iP8eBmInjhzpaF3TPjdGe2FWKlnA76FRKiqqCsuwq/ZT/Dnd7/pHJnXNyTO9IsJ/9LsPBsg7TlXTps3o31VkVdMhF+zn+DP7ej/cO09F9SqbXpCb7km/Es32hHtiXadGe2/XhV5xUT4NfsJ/unNvTfXRvtquZ2dffGoWxP+JVq1H3Lh10bX1KR9b1JFXjERfs1+gn92KPrR2og0ylCkltu6ppYbb+07B5drwu/Sqs3Qfrmt9Vz4aFfpZx9RRV4xEX7NvoN/26p62VRmVbwrLZdy3jHQpKN10IT/NEb7APoJo5YbWfiOO7Qr4V9owq9pAfyOnZPAdm/vHGylCf8iRrvgHXfSTnq7OSb8jSb8mprC7xidCS8eHe1/qbOd3AHbbMLfxKod0C6LvdiS8Dea8GtaFH4YHQvesqq+KKiGmQ0dsk0m/JoRd4k/2gHtMd82zdpNTPgbTfg1nRZ+x05H27pa5pedWxQk/GIVa8Qd8T8d9I4Jf6MJvybX8DtWnQ6LgnlnUbBZh22RQw8/4itxRrz1+Lsx4W804de0ZPgdOyeBHe1dFAwt/IgnFvMkvnq8l2LC32jCr8kz/I7RKZOxWm6sPYuCoYNfxQ/xRFy9QO+Y8Dea8GtaNvwwOii8ZXUttzNe78AtOgmEBn4VM8QPcZyPabN4uzThbzTh19QS+B2rDpsbWWM/dNKKk0DXw+9APzFgx60V0Dsm/I0m/JpaCr9j1Xlz29Yue1Gwq+FHXOzFvLUL4tYqE/5GE35NbYHfsXMSsBcFVWdvBsEi7kr4EQeJx3IW89yY8Dea8GtqK/yO0bmTq+ydZvOd/2QgTuGugl/VG3FAPNoFvWPC32jCr6kj8MPo6DAWBcfdLwp2Bfyqrqh3qxbz3JjwN5rwa+oY/I5Vx8fiVn5+UbAJMMqBht95FNrecdfaxTw3JvyNJvyaOg6/YwVBbjsWBU/9kFBg4Ud9pF6on17fTprwN5rwa1ox+B0DikV2DgYOflX+3Oi6RXfcdcKEv9GEX9OKww8PwQIJFgXxkJAGUWDgd6DHQzrOYh7q1ay+HTLhbzTh1+QL+B3bwIixc1AtCh69cqO/4Uf5pJz2Yt4Sdtx1woS/0YRfk6/gd+wAtK2vdnQSw2nznwCbKrIvdOjSc1+dy1iPH8ladjn9BL1jwt9owq/Jl/A7FpiObJWpwLa+R2pjg2eoIvtCezf1nZnbtmbPYSmf36B3TPgbTfg1+Rp+sR2rod4HVXF9pdmh3of80KFPZcLfaMKvKRDw+yRWuvzUoU9lwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt9owq+J8HsT4Xcvwq+Z8Ls34fduwt/onmNbV9UKiagEpvkftNuE370Jv3cT/rrBOXgH9z0zQ9HPVZKx2gsrVBjC796E37sJf93gHLyDe7tAUphNpUT04drIqloZ/9HkQ+0y4Xdvwu/dYYYfPINr8F1KxB4C7/XSKO27ePUrSsnYHxYT0fKL8kd59aFmB2ulCb97E37vDiP84DcvQ3zwLBf3Umk48uEfCOf1kjTRbKL3AjlL3I3hwZEt7S8g4Xdvwu/dYYQf/ILjciJ218Et52+sl8CFColoRkYB+xA0+dc+izT7guWa8Ls34ffusMAPTsGr4vap2WQ0Xf/mJepAMnKeTAU+XU5GXzjepsISfvcm/N4dBvhz4uMjsVpJeBVuP/WY8Fv/1mUol4xcVEzEfoS5Q7XFC4KE370Jv3d3M/zgsSpDfPBZTER+ODsUeXv921qkG3p6XiYjgGtl/jCFQGIhoRUnAcLv3oTfu7sRfvAHDlE34fJQcTh6LTitf1MbdHBL77ricOyrWExoRQUIv3sTfu/uRvidRflSInp7ftMb1ta/oQMqJqJbxHvss84ypgKE370Jv3d3C/zgzL5nL/UR/h4pJqPJ+pE7rL2bzz6rOBS9uZKIVU7IfAMLDs0KvJgJv3sTfu/uBvjBF+b1MsSvCPgf23Ppua+uH3UFld8ce3N+OHLfiZFY7bAMQ5YyCiD87k34vTvo8IMrrOTLHP9bU8Jb/Wg+Un4odlUlGd2vhiSuTgKE370Jv3cHEX7wA45Q9nIiuj+XiO2uH8Wnmtq0JiKjgNuweQA7h5pVSjfhd2/C791BhB/8gKPcUPRzh4bO660fIQDKD/W+o5yM/gRBt3cRNakcTPjdm/B7d1DgByfgxd5kl4j+OD98/mX1TwZMezf1nSlzlA9JJXIIfrNnAwi/exN+7w4C/M49e5k6z+aHYx/cMzZ4Rv1TAdb0pqgpo4A7m20WIvzuTfi92+/wH1XPzQgnd0wNRY36X3eR8oneUTmrPYaGKCXrowDC796E37v9CD/6f0nds5fR8aP5ZGRH/a+6VPsTfeeWEtE/LiaiR/FsAEYDhN+dCb93+w1+9Hv0f2HhSCER/cTPhYv6X4RAM1esfmslEf1+bXR1TaD7hfr1iorwexPhX5okVo+i30v//9705t5/rn4dLqHTlJOR908PR+6rXX3hy+u/XTkRfm8i/O5VGxs8Q2J1nwzzf0/9Ktya3nLOa2oX9/y6+nHFRPi9ifC7F/o5+rv6kfKLCL83EX4q8CL83kT4qcCL8HsT4acCL8LvTYSfCrwIvzcRfirwIvzeRPipwIvwexPhpwIvwu9NhJ8KvAi/NxF+KvAi/N5E+KnAi/B7E+GnAi/C702Enwq8CL83EX4q8CL83kT4qcDL7/Aj+8v0cPQnqri+kpTvpyjfyWX2iwk/taj8Dj/e0VZIRA9ODUcuVkX2hXKbey8pSrlQvmbl9oMJP7Wo/A6/k9O9lIgeKyVif3rgksh5qugrouc29b5eyvFnUp7ji72bwQ8m/NSi8jv8MABzXuEk0D1ZHI5kVfE7qmIyMinf/xTK4fbVbCtpwk8tqunN0Zv8Dr9uvAPhmMyzy8noPQcv771AVaOten7oDW8sJ6L/89hI4zsY/Gy7XYd6P6aqQVELJVf+j9XGVmNe7fsrmWPntc1yFS6XEpEb9l28+hWqOi3VA2+L/UZpOHKjjDQq+D4vr2NfCaMd0Z5oV175qVNqZnh1TK6iX6jKFc3PK9cnGx0ci232VCAZ/fupzb1Dqkot0dRw77Ac9x9wfHxPUE6MMNqxIu1ZGI58YXrrmqiqEkU11+xwZFM5EXsoqJ29KmWWofkXf7U5ukpVyZOevSK6Wo7zpSCfDNGOU0ORzapKFHV64SWjpUTshqIMpwM5zMUoIBE9WBiOvU9VaUnKDcWukc8/j+MEaRqUF6O90G6lZOQP0Y6qShS1NB1M9F5QTMTuxsLa4QAtcAHWOSmvWg/4/kxi9VtVlRbVzPCqf1FJRr+PV0nh80Ea9WABEiMUmaLcM7vp/I2qShS1POGWmlxNAnNryzFGLOqdcEcLw9E/2XNF7LWqSgv0jPy+JP+Pv8PfB2mkg/ZQ7fJkLhHNqCpRVOt0IBk5T4aSn5J58LHjI8EaBeCtyACkkog+NpvoHVNVslUY7t0pV/t/sqcK6u3JzY7jN+MEhXYoJ6MvlJKxTz/7zujrVJUoqj2Sq8vvlhORH9bkConFtSAOjWeGIt+Y2Ry5fHYoegd+DtI9e8QbcX9RwC9KO+SSkYtU01BU+1W7oedlxWT02nIiNhXERTEAjxVx/Iufg1B2lNFZzETci0PRf3+DtINqEorqrA5tfv364nDsq1gM9POW1mbOC0jNfu9X40SFOMsJ4PbnE2/oV01AUSsrmQpsKSVij9TnzcGaCvjZiKNzz76SjP08NxzZqkJOUf4RXr0sV9Oby4loNUgr5n414odblTLEr8jU5KZHf4evtqZ8rvzm2JuLyci3j0vHxTCVo4ClGfFC3BC/4nDk24inCi1FBUP5odhVMgrYjyFrkJ4NWCkjPs49e7naP50f7r1ShZKigqepTa+L5Iain0Oyi2NyJWvW6em6ER+Z35/IS7yelripEFJUsJXfsuod5WT0x3g2wO9ZbzppxAHxQFxklPRAfvj8y1TIKKp7hE0m+eHof5ROnsNCVtButbXaqL+9oJeMzs4moh/aMzZ4hgoVRXWnnt0UNYvJ6J32k3UBezagVcYzEbDM8e+YGooaKjQUFQ4VEr1jlWT00fqzAd2/IIj6OXsM5Gr/aH5z76gKBUWFT/sTfeeWEtFPBG033VKNejm7C4vJ2H9GvVUIKCrcOhjgffSLGfVAfVCvaiL6Pbd5BSgqdJpN9P4bGRo/h6FxkDYLnWyU29mEI/U5UBqOvFdVkaKoUwm592R4/EVcMbEo2AwuvxvlRvmREPWZ4dUxVTWKotxodiiyWU4CD9v3wAPwbADK52zCKSViDyERqqoKRVFLFfLwF4ajNxZ9nEgU0DuJM+VkVSokIjf8oE3vD6Co0Gk20XuBXFXvxiOwfsu6g/LYj+YmYncd3MLEmRTVFqlEovswtF7JzUL4XmcTjvz7VIGJMymq/aonEo19WubVx4+vwIIgph524sxE7JiU41OPSXlU0SiK6oRyw5GLi4nYjzDX7kQiURy/njgTV/vID0tMnElRK6cbenpeVtYSiWKzTKtPAjgejovj43uKw9Fr8b2qCBRFraScRKJYfGt1IlF7A5Ict5SI3l5g4kyK8qeKiegW8R77Kr2MqQA+59yzl+M9UkxGk+orKIryq/ZuPvus4lD05koiVvGyWcjZhCND/IoM8W96dAsTZ1JUoITEl/nhyH0nRur57t2MAuqJM/Eij8i3p5g4k6KCLSQSrSRPnUgUP+P39QW96P5iIrZbfZSiqKBratOaiFzNb7MTiW5dmEgUP+P3SDR6aOi8XvURiqK6SfmhXiQS/Qnu1QN4/CtX+x8zcSZFhUC4R19I9l5THYk9kRuOvE/9mgqVenr+P+OvTjWo+kMRAAAAAElFTkSuQmCC</data> + <data key="type">image/png</data> + <data key="name" unique="prefix">magento-logo.png</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductAttributeData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductAttributeData.xml index 9f6c9f44e63be..0adf1e91ae853 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductAttributeData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductAttributeData.xml @@ -8,7 +8,7 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="productAttributeWithTwoOptions" type="ProductAttribute"> + <entity name="productAttributeWysiwyg" type="ProductAttribute"> <data key="attribute_code" unique="suffix">attribute</data> <data key="frontend_input">textarea</data> <data key="scope">global</data> @@ -31,4 +31,46 @@ <data key="used_for_sort_by">true</data> <requiredEntity type="FrontendLabel">ProductAttributeFrontendLabel</requiredEntity> </entity> + <entity name="productAttributeWithTwoOptions" type="ProductAttribute"> + <data key="attribute_code" unique="suffix">attribute</data> + <data key="frontend_input">select</data> + <data key="scope">global</data> + <data key="is_required">false</data> + <data key="is_unique">false</data> + <data key="is_searchable">true</data> + <data key="is_visible">true</data> + <data key="is_visible_in_advanced_search">true</data> + <data key="is_visible_on_front">true</data> + <data key="is_filterable">true</data> + <data key="is_filterable_in_search">true</data> + <data key="used_in_product_listing">true</data> + <data key="is_used_for_promo_rules">true</data> + <data key="is_comparable">true</data> + <data key="is_used_in_grid">true</data> + <data key="is_visible_in_grid">true</data> + <data key="is_filterable_in_grid">true</data> + <data key="used_for_sort_by">true</data> + <requiredEntity type="FrontendLabel">ProductAttributeFrontendLabel</requiredEntity> + </entity> + <entity name="productDropDownAttribute" type="ProductAttribute"> + <data key="attribute_code" unique="suffix">attribute</data> + <data key="frontend_input">select</data> + <data key="scope">global</data> + <data key="is_required">false</data> + <data key="is_unique">false</data> + <data key="is_searchable">true</data> + <data key="is_visible">true</data> + <data key="is_visible_in_advanced_search">true</data> + <data key="is_visible_on_front">true</data> + <data key="is_filterable">true</data> + <data key="is_filterable_in_search">true</data> + <data key="used_in_product_listing">true</data> + <data key="is_used_for_promo_rules">true</data> + <data key="is_comparable">true</data> + <data key="is_used_in_grid">true</data> + <data key="is_visible_in_grid">true</data> + <data key="is_filterable_in_grid">true</data> + <data key="used_for_sort_by">true</data> + <requiredEntity type="FrontendLabel">ProductAttributeFrontendLabel</requiredEntity> + </entity> </entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductAttributeMediaGalleryEntryData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductAttributeMediaGalleryEntryData.xml new file mode 100644 index 0000000000000..5dee0651064a3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductAttributeMediaGalleryEntryData.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="ApiProductAttributeMediaGalleryEntryTestImage" type="ProductAttributeMediaGalleryEntry"> + <data key="media_type">image</data> + <data key="label" unique="suffix">Test Image </data> + <data key="position">1</data> + <array key="types"> + <item>image</item> + <item>small_image</item> + <item>thumbnail</item> + </array> + <data key="disabled">false</data> + <requiredEntity type="ImageContent">TestImageContent</requiredEntity> + </entity> + <entity name="ApiProductAttributeMediaGalleryEntryMagentoLogo" type="ProductAttributeMediaGalleryEntry"> + <data key="media_type">image</data> + <data key="label" unique="suffix">Magento Logo </data> + <data key="position">1</data> + <array key="types"> + <item>small_image</item> + </array> + <data key="disabled">false</data> + <requiredEntity type="ImageContent">MagentoLogoImageContent</requiredEntity> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductData.xml index 704d2dd2743d4..231bcd5b427d2 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Data/ProductData.xml @@ -21,6 +21,23 @@ <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> + <entity name="ApiSimpleProduct" type="product"> + <data key="sku" unique="suffix">api-simple-product</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">Api Simple Product</data> + <data key="price">123.00</data> + <data key="urlKey" unique="suffix">api-simple-product</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> + <entity name="ApiSimpleProductUpdateDescription" type="product2"> + <requiredEntity type="custom_attribute">ApiProductDescription</requiredEntity> + <requiredEntity type="custom_attribute">ApiProductShortDescription</requiredEntity> + </entity> <entity name="SimpleProduct" type="product"> <data key="sku" unique="suffix">SimpleProduct</data> <data key="type_id">simple</data> @@ -48,6 +65,32 @@ <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> <requiredEntity type="custom_attribute">CustomAttributeProductAttribute</requiredEntity> </entity> + <entity name="ApiSimpleOne" type="product2"> + <data key="sku" unique="suffix">api-simple-product</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">Api Simple Product</data> + <data key="price">123.00</data> + <data key="urlKey" unique="suffix">api-simple-product</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute">CustomAttributeProductAttribute</requiredEntity> + </entity> + <entity name="ApiSimpleTwo" type="product2"> + <data key="sku" unique="suffix">api-simple-product-two</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">Api Simple Product Two</data> + <data key="price">234.00</data> + <data key="urlKey" unique="suffix">api-simple-product-two</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute">CustomAttributeProductAttribute</requiredEntity> + </entity> <entity name="VirtualProduct" type="product"> <data key="sku" unique="suffix">virtualproduct</data> <data key="type_id">virtual</data> @@ -59,11 +102,35 @@ <data key="status">1</data> <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> </entity> + <entity name="SimpleTwo" type="product2"> + <data key="sku" unique="suffix">SimpleTwo</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="name" unique="suffix">SimpleProduct</data> + <data key="price">1.23</data> + <data key="visibility">4</data> + <data key="status">1</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute">CustomAttributeProductUrlKey</requiredEntity> + </entity> <entity name="ImageUpload" type="uploadImage"> <data key="title" unique="suffix">Image1</data> <data key="price">1.00</data> <data key="file_type">Upload File</data> <data key="shareable">Yes</data> - <data key="file">logo.png</data> + <data key="file">magento-logo.png</data> + </entity> + <entity name="ProductWithUnicode" type="product"> + <data key="sku" unique="suffix">霁产品</data> + <data key="type_id">simple</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">霁产品</data> + <data key="price">123.00</data> + <data key="urlKey" unique="suffix">testurlkey</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> </entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Metadata/product_attribute_media_gallery_entry-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Metadata/product_attribute_media_gallery_entry-meta.xml new file mode 100644 index 0000000000000..1697941013156 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Metadata/product_attribute_media_gallery_entry-meta.xml @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateProductAttributeMediaGalleryEntry" dataType="ProductAttributeMediaGalleryEntry" type="create" auth="adminOauth" url="/V1/products/{sku}/media" method="POST"> + <contentType>application/json</contentType> + <object key="entry" dataType="ProductAttributeMediaGalleryEntry"> + <field key="id">integer</field> + <field key="media_type" required="true">string</field> + <field key="label" required="true">string</field> + <field key="position" required="true">integer</field> + <field key="disabled" required="true">boolean</field> + <array key="types"> + <value>string</value> + </array> + <field key="file">string</field> + <field key="content">ImageContent</field> + <field key="extension_attributes">empty_extension_attribute</field> + </object> + </operation> + <operation name="UpdateProductAttributeMediaGalleryEntry" dataType="ProductAttributeMediaGalleryEntry" type="update" auth="adminOauth" url="/V1/products/{sku}/media/{id}" method="PUT"> + <contentType>application/json</contentType> + <object key="entry" dataType="ProductAttributeMediaGalleryEntry"> + <field key="id" required="true">integer</field> + <field key="media_type" required="true">string</field> + <field key="label" required="true">string</field> + <field key="position" required="true">integer</field> + <field key="disabled" required="true">boolean</field> + <array key="types"> + <value>string</value> + </array> + <field key="file">string</field> + <field key="content">ImageContent</field> + <field key="extension_attributes">empty_extension_attribute</field> + </object> + </operation> + <operation name="DeleteProductAttributeMediaGalleryEntry" dataType="ProductAttributeMediaGalleryEntry" type="delete" auth="adminOauth" url="/V1/products/{sku}/media/{id}" method="DELETE"> + <contentType>application/json</contentType> + </operation> +</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/AdminProductCreatePage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/AdminProductCreatePage.xml index 2a0a9baae4071..305dcb59704f8 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/AdminProductCreatePage.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/AdminProductCreatePage.xml @@ -15,5 +15,6 @@ <section name="AdminProductImagesSection"/> <section name="AdminAddProductsToOptionPanel"/> <section name="AdminProductMessagesSection"/> + <section name="AdminProductFormRelatedUpSellCrossSellSection"/> </page> </pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/AdminProductPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/AdminProductPage.xml deleted file mode 100644 index b811a65a5b621..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/AdminProductPage.xml +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="AdminProductPage" url="catalog/product/view" area="admin" module="Magento_Catalog"> - <section name="StorefrontProductInfoMainSection" /> - <section name="StorefrontProductInfoDetailsSection" /> - <section name="StorefrontProductImageSection" /> - <section name="StorefrontMessagesSection" /> - </page> -</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/StorefrontCategoryPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/StorefrontCategoryPage.xml index b3e3400d8773a..ac699e55f45b2 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/StorefrontCategoryPage.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/StorefrontCategoryPage.xml @@ -8,7 +8,7 @@ <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="StorefrontCategoryPage" url="/{{var1}}.html" area="storefront" module="Category" parameterized="true"> + <page name="StorefrontCategoryPage" url="/{{var1}}.html" area="storefront" module="Catalog" parameterized="true"> <section name="StorefrontCategoryMainSection"/> <section name="WYSIWYGToolbarSection"/> </page> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/StorefrontProductComparePage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/StorefrontProductComparePage.xml new file mode 100644 index 0000000000000..e110ee7f3bc61 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/StorefrontProductComparePage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="StorefrontProductComparePage" url="catalog/product_compare/index" module="Magento_Catalog" area="storefront"> + <section name="StorefrontProductCompareMainSection" /> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/StorefrontProductPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/StorefrontProductPage.xml new file mode 100644 index 0000000000000..d6e135e9af24f --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Page/StorefrontProductPage.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="StorefrontProductPage" url="/{{var1}}.html" area="storefront" module="Catalog" parameterized="true"> + <section name="StorefrontProductInfoMainSection" /> + <section name="StorefrontProductInfoDetailsSection" /> + <section name="WYSIWYGToolbarSection"/> + <section name="StorefrontProductImageSection" /> + <section name="StorefrontMessagesSection" /> + <section name="StorefrontProductRelatedProductsSection"/> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategoryBasicFieldSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategoryBasicFieldSection.xml index 92d90c9b8a46c..e905bfd01c711 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategoryBasicFieldSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCategoryBasicFieldSection.xml @@ -15,6 +15,11 @@ <element name="ContentTab" type="input" selector="input[name='name']"/> <element name="FieldError" type="text" selector=".admin__field-error[data-bind='attr: {for: {{field}}}, text: error']" parameterized="true"/> </section> + <section name="CategoryContentSection"> + <element name="SelectFromGalleryBtn" type="button" selector="//label[text()='Select from Gallery']"/> + <element name="ImagePlaceHolder" type="button" selector=".file-uploader-summary.product-image-wrapper"/> + <element name="Upload" type="button" selector=".file-uploader-area input"/> + </section> <section name="CatalogWYSIWYGSection"> <element name="ShowHideBtn" type="button" selector="#togglecategory_form_description"/> <element name="TinyMCE4" type="text" selector=".mce-branding-powered-by"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCreateProductAttributeSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCreateProductAttributeSection.xml index 003957c56ee9a..362a039e34122 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCreateProductAttributeSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminCreateProductAttributeSection.xml @@ -13,8 +13,9 @@ <element name="InputType" type="select" selector="#frontend_input"/> <element name="ValueRequired" type="select" selector="#is_required"/> <element name="AdvancedProperties" type="button" selector="#advanced_fieldset-wrapper"/> - <element name="Default Value" type="input" selector="#default_value_text"/> + <element name="DefaultValue" type="input" selector="#default_value_text"/> <element name="Save" type="button" selector="#save"/> + <element name="SaveAndEdit" type="button" selector="#save_and_edit_button"/> <element name="TinyMCE4" type="button" selector="//span[text()='Default Value']/parent::label/following-sibling::div//div[@class='mce-branding-powered-by']"/> <element name="checkIfTabOpen" selector="//div[@id='advanced_fieldset-wrapper' and not(contains(@class,'opened'))]" type="button"/> </section> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductAttributeGridSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductAttributeGridSection.xml index 86bb7321a0710..97e8a913e6010 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductAttributeGridSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductAttributeGridSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="AdminProductAttributeGridSection"> <element name="AttributeCode" type="text" selector="//td[contains(text(),'{{var1}}')]" parameterized="true"/> + <element name="createNewAttributeBtn" type="button" selector="button[data-index='add_new_attribute_button']"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormSection.xml index 1516850c79260..2599116bcc469 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductFormSection.xml @@ -19,6 +19,20 @@ <element name="contentTab" type="button" selector="//strong[@class='admin__collapsible-title']/span[text()='Content']"/> <element name="fieldError" type="text" selector="//input[@name='product[{{fieldName}}]']/following-sibling::label[@class='admin__field-error']" parameterized="true"/> <element name="priceFieldError" type="text" selector="//input[@name='product[price]']/parent::div/parent::div/label[@class='admin__field-error']"/> + <element name="addAttributeBtn" type="button" selector="#addAttribute"/> + <element name="createNewAttributeBtn" type="button" selector="button[data-index='add_new_attribute_button']"/> + <element name="save" type="button" selector="#save"/> + <element name="attributeTab" type="button" selector="//strong[@class='admin__collapsible-title']/span[text()='Attributes']"/> + <element name="attributeLabel" type="input" selector="//input[@name='frontend_label[0]']"/> + <element name="frontendInput" type="select" selector="select[name = 'frontend_input']"/> + <element name="productFormTab" type="button" selector="//strong[@class='admin__collapsible-title']/span[contains(text(), '{{tabName}}')]" parameterized="true"/> + <element name="productFormTabState" type="text" selector="//strong[@class='admin__collapsible-title']/span[contains(text(), '{{tabName}}')]/parent::*/parent::*[@data-state-collapsible='{{state}}']" parameterized="true"/> + </section> + <section name="AdminProductFormRelatedUpSellCrossSellSection"> + <element name="AddRelatedProductsButton" type="button" selector="button[data-index='button_related']" timeout="30"/> + </section> + <section name="AdminAddRelatedProductsModalSection"> + <element name="AddSelectedProductsButton" type="button" selector="//aside[contains(@class, 'product_form_product_form_related_related_modal')]//button/span[contains(text(), 'Add Selected Products')]" timeout="30"/> </section> <section name="ProductWYSIWYGSection"> <element name="Switcher" type="button" selector="//select[@id='dropdown-switcher']"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridConfirmActionSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridConfirmActionSection.xml index 0b3982d788047..c9ea9993c7bd3 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridConfirmActionSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridConfirmActionSection.xml @@ -12,6 +12,6 @@ <element name="title" type="text" selector=".modal-popup.confirm h1.modal-title"/> <element name="message" type="text" selector=".modal-popup.confirm div.modal-content"/> <element name="cancel" type="button" selector=".modal-popup.confirm button.action-dismiss"/> - <element name="ok" type="button" selector=".modal-popup.confirm button.action-accept" timeout="30"/> + <element name="ok" type="button" selector=".modal-popup.confirm button.action-accept" timeout="60"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridFilterSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridFilterSection.xml index 0bc82c8bcdd84..ea822d223e4a2 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridFilterSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridFilterSection.xml @@ -10,6 +10,10 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="AdminProductGridFilterSection"> <element name="filters" type="button" selector="button[data-action='grid-filter-expand']"/> + <element name="clearAll" type="button" selector=".admin__data-grid-header .admin__data-grid-filters-current._show .action-clear"/> + <element name="enabledFilters" type="textarea" selector=".admin__data-grid-header .admin__data-grid-filters-current._show"/> + <element name="basicSearchFilter" type="textarea" selector=".admin__control-text.data-grid-search-control"/> + <element name="basicSearchFilterButton" type="button" selector=".data-grid-search-control-wrap button.action-submit"/> <element name="viewDropdown" type="button" selector=".admin__data-grid-action-bookmarks button.admin__action-dropdown"/> <element name="viewBookmark" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/> <element name="columnsDropdown" type="button" selector=".admin__data-grid-action-columns button.admin__action-dropdown"/> @@ -24,5 +28,7 @@ <element name="priceFilterTo" type="input" selector="input.admin__control-text[name='price[to]']"/> <element name="typeFilter" type="select" selector="select.admin__control-select[name='type_id']"/> <element name="statusFilter" type="select" selector="select.admin__control-select[name='status']"/> + <element name="keywordSearch" type="input" selector="input#fulltext"/> + <element name="keywordSearchButton" type="button" selector=".data-grid-search-control-wrap button.action-submit" timeout="30"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridSection.xml index fc693d6aa1df8..7136dba2a1fbb 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductGridSection.xml @@ -11,6 +11,7 @@ <section name="AdminProductGridSection"> <element name="loadingMask" type="text" selector=".admin__data-grid-loading-mask[data-component*='product_listing']"/> <element name="columnHeader" type="button" selector="//div[@data-role='grid-wrapper']//table[contains(@class, 'data-grid')]/thead/tr/th[contains(@class, 'data-grid-th')]/span[text() = '{{label}}']" parameterized="true" timeout="30"/> + <element name="column" type="text" selector="//tr//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{column}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> <element name="productGridElement1" type="input" selector="#addselector" /> <element name="productGridElement2" type="text" selector="#addselector" /> <element name="productGridRows" type="text" selector="table.data-grid tr.data-row"/> @@ -22,5 +23,6 @@ <element name="multicheckOption" type="button" selector="//div[@data-role='grid-wrapper']//th[contains(@class, data-grid-multicheck-cell)]//li//span[text() = '{{label}}']" parameterized="true"/> <element name="bulkActionDropdown" type="button" selector="div.admin__data-grid-header-row.row div.action-select-wrap button.action-select"/> <element name="bulkActionOption" type="button" selector="//div[contains(@class,'admin__data-grid-header-row') and contains(@class, 'row')]//div[contains(@class, 'action-select-wrap')]//ul/li/span[text() = '{{label}}']" parameterized="true"/> + <element name="productGridXRowYColumnButton" type="input" selector="table.data-grid tr.data-row:nth-child({{row}}) td:nth-child({{column}})" parameterized="true" timeout="30"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductMessagesSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductMessagesSection.xml index f048027eaf322..f88f8c72c64e1 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductMessagesSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductMessagesSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="AdminProductMessagesSection"> <element name="successMessage" type="text" selector=".message-success"/> + <element name="errorMessage" type="text" selector=".message.message-error.error"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductModalSlideGridSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductModalSlideGridSection.xml new file mode 100644 index 0000000000000..746b95f4201ec --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductModalSlideGridSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminProductModalSlideGridSection"> + <element name="productGridXRowYColumnButton" type="input" selector=".modal-slide table.data-grid tr.data-row:nth-child({{row}}) td:nth-child({{column}})" parameterized="true" timeout="30"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductRelatedUpSellCrossSellSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductRelatedUpSellCrossSellSection.xml new file mode 100644 index 0000000000000..225bedb6fd2e6 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/AdminProductRelatedUpSellCrossSellSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminProductFormRelatedUpSellCrossSellSection"> + <element name="AddRelatedProductsButton" type="button" selector="button[data-index='button_related']" timeout="30"/> + <element name="relatedProductSectionText" type="text" selector=".fieldset-wrapper.admin__fieldset-section[data-index='related']"/> + <element name="upSellProductSectionText" type="text" selector=".fieldset-wrapper.admin__fieldset-section[data-index='upsell']"/> + <element name="crossSellProductSectionText" type="text" selector=".fieldset-wrapper.admin__fieldset-section[data-index='crosssell']"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontCategoryFilterSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontCategoryFilterSection.xml new file mode 100644 index 0000000000000..8f612e4d99e45 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontCategoryFilterSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontCategoryFilterSection"> + <element name="CategoryFilter" type="button" selector="//main//div[@class='filter-options']//div[contains(text(), 'Category')]"/> + <element name="CategoryByName" type="button" selector="//main//div[@class='filter-options']//li[@class='item']//a[contains(text(), '{{var1}}')]" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontCategoryMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontCategoryMainSection.xml index 4df917c4574fb..e2102ea351cab 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontCategoryMainSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontCategoryMainSection.xml @@ -16,5 +16,6 @@ <element name="productCount" type="text" selector="#toolbar-amount"/> <element name="CatalogDescription" type="text" selector="//div[@class='category-description']//p"/> <element name="mediaDescription" type="text" selector="img[alt='{{var1}}']" parameterized="true"/> + <element name="ImageSource" type="text" selector="//img[contains(@src,'{{var1}}') and not(contains(@src,'{{var2}}/'))]" parameterized="true"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontCategoryProductSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontCategoryProductSection.xml new file mode 100644 index 0000000000000..e736378ca8ca0 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontCategoryProductSection.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontCategoryProductSection"> + <element name="ProductTitleByNumber" type="button" selector="//main//li[{{var1}}]//a[@class='product-item-link']" parameterized="true"/> + <element name="ProductPriceByNumber" type="text" selector="//main//li[{{var1}}]//span[@class='price']" parameterized="true"/> + <element name="ProductInfoByNumber" type="text" selector="//main//li[{{var1}}]//div[@class='product-item-info']" parameterized="true"/> + <element name="ProductAddToCompareByNumber" type="text" selector="//main//li[{{var1}}]//a[contains(@class, 'tocompare')]" parameterized="true"/> + + <element name="ProductTitleByName" type="button" selector="//main//li//a[contains(text(), '{{var1}}')]" parameterized="true"/> + <element name="ProductPriceByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//span[@class='price']" parameterized="true"/> + <element name="ProductImageByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//img[@class='product-image-photo']" parameterized="true"/> + <element name="ProductInfoByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//div[@class='product-item-info']" parameterized="true"/> + <element name="ProductAddToCompareByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//a[contains(@class, 'tocompare')]" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontComparisonSidebarSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontComparisonSidebarSection.xml new file mode 100644 index 0000000000000..615d37f75cd48 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontComparisonSidebarSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontComparisonSidebarSection"> + <element name="Compare" type="button" selector="//main//div[contains(@class, 'block-compare')]//a[contains(@class, 'action compare')]"/> + <element name="ClearAll" type="button" selector="//main//div[contains(@class, 'block-compare')]//a[contains(@class, 'action clear')]"/> + <element name="ProductTitleByName" type="button" selector="//main//ol[@id='compare-items']//a[@class='product-item-link'][text()='{{var1}}']" parameterized="true"/> + <element name="NoItemsMessage" type="text" selector="//main//div[contains(@class, 'block-compare')]//div[@class='empty']"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontHeaderSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontHeaderSection.xml new file mode 100644 index 0000000000000..dbca5f06a1413 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontHeaderSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontHeaderSection"> + <element name="NavigationCategoryByName" type="button" selector="//nav//a[span[contains(., '{{var1}}')]]" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontMessagesSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontMessagesSection.xml index eae52608b379e..5f3851ad9b20d 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontMessagesSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontMessagesSection.xml @@ -9,6 +9,6 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontMessagesSection"> - <element name="test" type="input" selector=".test"/> + <element name="success" type="text" selector="div.message-success.success.message"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontMiniCartSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontMiniCartSection.xml deleted file mode 100644 index 9751251b67ca5..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontMiniCartSection.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="StorefrontMiniCartSection"> - <element name="quantity" type="button" selector="span.counter-number"/> - <element name="show" type="button" selector="a.showcart"/> - <element name="goToCheckout" type="button" selector="#top-cart-btn-checkout"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProducRelatedProductsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProducRelatedProductsSection.xml new file mode 100644 index 0000000000000..9165697051d0f --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProducRelatedProductsSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontProductRelatedProductsSection"> + <element name="relatedProductsActionsHeaderText" type="text" selector=".block.related .block-actions" /> + <element name="relatedProductsListSectionText" type="text" selector=".block.related .products.wrapper.grid.products-grid.products-related" /> + <element name="relatedProductName" type="button" selector="//*[@class='block related']//a[contains(text(), '{{productName}}')]" parameterized="true"/> + <element name="relatedProductCheckBoxButton" type="button" selector="//*[@class='block related']//a[contains(text(), '{{productName}}')]/parent::*/parent::*//input[@class='checkbox related']" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductActionSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductActionSection.xml index 976bd2adac217..337db47880c90 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductActionSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductActionSection.xml @@ -9,5 +9,8 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontProductActionSection"> <element name="addToCart" type="button" selector="#product-addtocart-button"/> + <element name="addToCartButtonTitleIsAdding" type="text" selector="//button/span[text()='Adding...']"/> + <element name="addToCartButtonTitleIsAdded" type="text" selector="//button/span[text()='Added']"/> + <element name="addToCartButtonTitleIsAddToCart" type="text" selector="//button/span[text()='Add to Cart']"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductCompareMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductCompareMainSection.xml new file mode 100644 index 0000000000000..cd7e7637b2766 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductCompareMainSection.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontProductCompareMainSection"> + <element name="PageName" type="text" selector="//*[@id='maincontent']//h1//span"/> + <element name="ProductLinkByName" type="button" selector="//*[@id='product-comparison']//tr//strong[@class='product-item-name']/a[contains(text(), '{{var1}}')]" parameterized="true"/> + <element name="ProductPriceByName" type="text" selector="//*[@id='product-comparison']//td[.//strong[@class='product-item-name']/a[contains(text(), '{{var1}}')]]//span[@class='price']" parameterized="true"/> + <element name="ProductImageByName" type="text" selector="//*[@id='product-comparison']//td[.//strong[@class='product-item-name']/a[contains(text(), '{{var1}}')]]//img[@class='product-image-photo']" parameterized="true"/> + <element name="ProductAttributeByCodeAndProductName" type="text" selector="//*[@id='product-comparison']//tr[.//th[./span[contains(text(), '{{var1}}')]]]//td[count(//*[@id='product-comparison']//tr//td[.//strong[@class='product-item-name']/a[contains(text(), '{{var2}}')]]/preceding-sibling::td)+1]/div" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductInfoMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductInfoMainSection.xml index 1f0c0721b6452..d87c97adf11e6 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductInfoMainSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Section/StorefrontProductInfoMainSection.xml @@ -12,13 +12,15 @@ <element name="stock" type="input" selector=".stock.available"/> <element name="productName" type="text" selector=".base"/> <element name="productSku" type="text" selector=".product.attribute.sku>.value"/> - <element name="productPrice" type="text" selector=".price"/> + <element name="productPrice" type="text" selector="div.price-box.price-final_price"/> <element name="productStockStatus" type="text" selector=".stock[title=Availability]>span"/> - <element name="productDescription" type="text" selector="//div[@id='product.info.description']//p[1]"/> - <element name="productShortDescription" type="text" selector="//div[@class='product attribute overview']//p"/> + <element name="productImage" type="text" selector="//*[@id='maincontent']//div[@class='gallery-placeholder']//img[@class='fotorama__img']"/> + <element name="productDescription" type="text" selector="//div[@id='product.info.description']//div[@class='value']"/> + <element name="productShortDescription" type="text" selector="//div[@class='product attribute overview']//div[@class='value']"/> <element name="productAttributeTitle1" type="text" selector="#product-options-wrapper div[tabindex='0'] label"/> <element name="productAttributeOptions1" type="select" selector="#product-options-wrapper div[tabindex='0'] option"/> <element name="mediaDescription" type="text" selector=".product.attribute.description>div>p>img"/> <element name="mediaShortDescription" type="text" selector=".product.attribute.overview>div>p>img"/> + <element name="productAddToCompare" type="button" selector="a.action.tocompare"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddImageToWYSIWYGCatalogCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddImageToWYSIWYGCatalogCest.xml index 62adf4573999b..8aa58cf1fb164 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddImageToWYSIWYGCatalogCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddImageToWYSIWYGCatalogCest.xml @@ -21,6 +21,8 @@ <description value="Admin should be able to add image to WYSIWYG Editor on Catalog Page"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-84373"/> + <!--Skip because of issue MAGETWO-88266--> + <group value="skip"/> </annotations> <amOnPage url="{{AdminCategoryPage.url}}" stepKey="navigateToNewCatalog"/> <waitForPageLoad stepKey="wait1"/> @@ -31,46 +33,25 @@ <waitForElementVisible selector="{{CatalogWYSIWYGSection.TinyMCE4}}" stepKey="waitForTinyMCE4" /> <click selector="{{CatalogWYSIWYGSection.InsertImageIcon}}" stepKey="clickInsertImageIcon" /> <waitForPageLoad stepKey="waitForPageLoad" /> - <click selector="{{CatalogWYSIWYGSection.Browse}}" stepKey="clickBrowse" /> - <waitForPageLoad stepKey="waitForPageLoad1" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading1" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading2" /> - <see selector="{{CatalogWYSIWYGSection.CancelBtn}}" userInput="Cancel" stepKey="seeCancelBtn" /> - <see selector="{{CatalogWYSIWYGSection.CreateFolder}}" userInput="Create Folder" stepKey="seeCreateFolderBtn" /> - <see selector="{{CatalogWYSIWYGSection.InsertFile}}" userInput="Add Selected" stepKey="seeAddSelectedBtn" /> - <click selector="{{CatalogWYSIWYGSection.CreateFolder}}" stepKey="createFolder"/> - <waitForElementVisible selector="{{CatalogWYSIWYGSection.FolderName}}" stepKey="waitForPopUp" /> - <fillField selector="{{CatalogWYSIWYGSection.FolderName}}" userInput="{{ImageFolder.name}}" stepKey="fillFolderName" /> - <click selector="{{CatalogWYSIWYGSection.AcceptFolderName}}" stepKey="acceptFolderName" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading3" /> - <conditionalClick selector="{{CatalogWYSIWYGSection.StorageRootArrow}}" dependentSelector="{{CatalogWYSIWYGSection.checkIfArrowExpand}}" stepKey="clickArrowIfCloses" visible="true"/> - <waitForText userInput="{{ImageFolder.name}}" stepKey="waitForNewFolder" /> - <click userInput="{{ImageFolder.name}}" stepKey="clickOnCreatedFolder" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading5" /> - <attachFile selector="{{CatalogWYSIWYGSection.BrowseUploadImage}}" userInput="{{ImageUpload.file}}" stepKey="uploadImage1"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading6" /> - <waitForElementVisible selector="{{CatalogWYSIWYGSection.image(ImageUpload.file)}}" stepKey="waitForUploadImage1" /> - <seeElement selector="{{CatalogWYSIWYGSection.imageSelected(ImageUpload.file)}}" stepKey="seeImageSelected" /> - <see selector="{{CatalogWYSIWYGSection.DeleteSelectedBtn}}" userInput="Delete Selected" stepKey="seeDeleteBtn"/> - <click selector="{{CatalogWYSIWYGSection.DeleteSelectedBtn}}" stepKey="clickDeleteSelected" /> - <waitForText userInput="OK" stepKey="waitForConfirm" /> - <click selector="{{CatalogWYSIWYGSection.confirmDelete}}" stepKey="confirmDelete" /> - <waitForElementNotVisible selector="{{CatalogWYSIWYGSection.image(ImageUpload.file)}}" stepKey="waitForImageDeleted" /> - <dontSeeElement selector="{{CatalogWYSIWYGSection.image(ImageUpload.file)}}" stepKey="dontSeeImage" /> - <attachFile selector="{{CatalogWYSIWYGSection.BrowseUploadImage}}" userInput="{{ImageUpload.file}}" stepKey="uploadImage2"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading9" /> - <waitForElementVisible selector="{{CatalogWYSIWYGSection.image(ImageUpload.file)}}" stepKey="waitForUploadImage2" /> - <click selector="{{CatalogWYSIWYGSection.InsertFile}}" stepKey="clickInsertBtn" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading7" /> - <waitForElementVisible selector="{{CatalogWYSIWYGSection.OkBtn}}" stepKey="waitForOkBtn" /> - <fillField selector="{{CatalogWYSIWYGSection.ImageDescription}}" userInput="{{ImageUpload.content}}" stepKey="fillImageDescription" /> - <fillField selector="{{CatalogWYSIWYGSection.Height}}" userInput="{{ImageUpload.height}}" stepKey="fillImageHeight" /> - <click selector="{{CatalogWYSIWYGSection.OkBtn}}" stepKey="clickOkBtn" /> - <waitForPageLoad stepKey="wait3"/> + <actionGroup ref="clickBrowseBtnOnUploadPopup" stepKey="clickBrowserBtn"/> + <actionGroup ref="VerifyMediaGalleryStorageActions" stepKey="VerifyMediaGalleryStorageBtn"/> + <actionGroup ref="CreateImageFolder" stepKey="CreateImageFolder"> + <argument name="ImageFolder" value="ImageFolder"/> + </actionGroup> + <actionGroup ref="attachImage" stepKey="attachImage1"> + <argument name="Image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="deleteImage" stepKey="deleteImage"/> + <actionGroup ref="attachImage" stepKey="attachImage2"> + <argument name="Image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="saveImage" stepKey="insertImage"/> + <actionGroup ref="fillOutUploadImagePopup" stepKey="fillOutUploadImagePopup" /> <click selector="{{AdminCategoryMainActionsSection.SaveButton}}" stepKey="saveCatalog"/> <amOnPage url="/{{SimpleSubCategory.name_lwr}}.html" stepKey="goToCategoryFrontPage"/> <waitForPageLoad stepKey="waitForPageLoad2"/> - <seeElement selector="{{StorefrontCategoryMainSection.mediaDescription(ImageUpload.content)}}" stepKey="assertMediaDescription"/> + <seeElement selector="{{StorefrontCategoryMainSection.mediaDescription(ImageUpload3.content)}}" stepKey="assertMediaDescription"/> + <seeElementInDOM selector="{{StorefrontCategoryMainSection.ImageSource(ImageUpload3.fileName,ImageUpload3.extension)}}" stepKey="assertMediaSource"/> <after> <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> <actionGroup ref="logout" stepKey="logout"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddImageToWYSIWYGProductCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddImageToWYSIWYGProductCest.xml index 572c535eabd54..ddc904d2ae396 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddImageToWYSIWYGProductCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminAddImageToWYSIWYGProductCest.xml @@ -16,6 +16,8 @@ <description value="Admin should be able to add image to WYSIWYG Editor on Product Page"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-84375"/> + <!--Skip because of issue MAGETWO-88266--> + <group value="skip"/> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="login"/> @@ -49,24 +51,24 @@ <waitForText userInput="{{ImageFolder.name}}" stepKey="waitForNewFolder1" /> <click userInput="{{ImageFolder.name}}" stepKey="clickOnCreatedFolder1" /> <waitForLoadingMaskToDisappear stepKey="waitForLoading4" /> - <attachFile selector="{{ProductDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload.file}}" stepKey="uploadImage1"/> + <attachFile selector="{{ProductDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload1.value}}" stepKey="uploadImage1"/> <waitForLoadingMaskToDisappear stepKey="waitForLoading5" /> - <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload.file)}}" stepKey="waitForUploadImage1" /> - <seeElement selector="{{ProductDescriptionWYSIWYGToolbarSection.imageSelected(ImageUpload.file)}}" stepKey="seeImageSelected1" /> + <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload1.value)}}" stepKey="waitForUploadImage1" /> + <seeElement selector="{{ProductDescriptionWYSIWYGToolbarSection.imageSelected(ImageUpload1.value)}}" stepKey="seeImageSelected1" /> <see selector="{{ProductDescriptionWYSIWYGToolbarSection.DeleteSelectedBtn}}" userInput="Delete Selected" stepKey="seeDeleteBtn1"/> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.DeleteSelectedBtn}}" stepKey="clickDeleteSelected1" /> <waitForText userInput="OK" stepKey="waitForConfirm1" /> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.confirmDelete}}" stepKey="confirmDelete1" /> - <waitForElementNotVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload.file)}}" stepKey="waitForImageDeleted1" /> - <dontSeeElement selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload.file)}}" stepKey="dontSeeImage1" /> - <attachFile selector="{{ProductDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload.file}}" stepKey="uploadImage2"/> + <waitForElementNotVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload1.value)}}" stepKey="waitForImageDeleted1" /> + <dontSeeElement selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload1.value)}}" stepKey="dontSeeImage1" /> + <attachFile selector="{{ProductDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload1.value}}" stepKey="uploadImage2"/> <waitForLoadingMaskToDisappear stepKey="waitForLoading6" /> - <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload.file)}}" stepKey="waitForUploadImage2" /> + <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.image(ImageUpload1.value)}}" stepKey="waitForUploadImage2" /> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.InsertFile}}" stepKey="clickInsertBtn1" /> <waitForLoadingMaskToDisappear stepKey="waitForLoading7" /> <waitForElementVisible selector="{{ProductDescriptionWYSIWYGToolbarSection.OkBtn}}" stepKey="waitForOkBtn1" /> - <fillField selector="{{ProductDescriptionWYSIWYGToolbarSection.ImageDescription}}" userInput="{{ImageUpload.content}}" stepKey="fillImageDescription1" /> - <fillField selector="{{ProductDescriptionWYSIWYGToolbarSection.Height}}" userInput="{{ImageUpload.height}}" stepKey="fillImageHeight1" /> + <fillField selector="{{ProductDescriptionWYSIWYGToolbarSection.ImageDescription}}" userInput="{{ImageUpload1.content}}" stepKey="fillImageDescription1" /> + <fillField selector="{{ProductDescriptionWYSIWYGToolbarSection.Height}}" userInput="{{ImageUpload1.height}}" stepKey="fillImageHeight1" /> <click selector="{{ProductDescriptionWYSIWYGToolbarSection.OkBtn}}" stepKey="clickOkBtn1" /> <waitForPageLoad stepKey="waitForPageLoad3"/> <scrollTo selector="{{ProductDescriptionWYSIWYGToolbarSection.TinyMCE4}}" stepKey="scrollToTinyMCE4" /> @@ -78,8 +80,8 @@ <see selector="{{ProductShortDescriptionWYSIWYGToolbarSection.CancelBtn}}" userInput="Cancel" stepKey="seeCancelBtn2" /> <see selector="{{ProductShortDescriptionWYSIWYGToolbarSection.CreateFolder}}" userInput="Create Folder" stepKey="seeCreateFolderBtn2" /> <see selector="{{ProductShortDescriptionWYSIWYGToolbarSection.InsertFile}}" userInput="Add Selected" stepKey="seeAddSelectedBtn2" /> - <attachFile selector="{{ProductShortDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload1.file}}" stepKey="uploadImage3"/> - <waitForElementVisible selector="{{ProductShortDescriptionWYSIWYGToolbarSection.image(ImageUpload1.file)}}" stepKey="waitForUploadImage3" /> + <attachFile selector="{{ProductShortDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload3.value}}" stepKey="uploadImage3"/> + <waitForElementVisible selector="{{ProductShortDescriptionWYSIWYGToolbarSection.image(ImageUpload3.value)}}" stepKey="waitForUploadImage3" /> <waitForLoadingMaskToDisappear stepKey="waitForLoading9" /> <wait time="3" stepKey="waitMore" /> <waitForElement selector="{{ProductShortDescriptionWYSIWYGToolbarSection.DeleteSelectedBtn}}" stepKey="waitForDeletebtn" /> @@ -87,14 +89,14 @@ <click selector="{{ProductShortDescriptionWYSIWYGToolbarSection.DeleteSelectedBtn}}" stepKey="clickDeleteSelected2" /> <waitForText userInput="OK" stepKey="waitForConfirm3" /> <click selector="{{ProductShortDescriptionWYSIWYGToolbarSection.confirmDelete}}" stepKey="confirmDelete2" /> - <attachFile selector="{{ProductShortDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload1.file}}" stepKey="uploadImage4"/> + <attachFile selector="{{ProductShortDescriptionWYSIWYGToolbarSection.BrowseUploadImage}}" userInput="{{ImageUpload3.value}}" stepKey="uploadImage4"/> <waitForLoadingMaskToDisappear stepKey="waitForLoading10" /> - <waitForElementVisible selector="{{ProductShortDescriptionWYSIWYGToolbarSection.image(ImageUpload1.file)}}" stepKey="waitForUploadImage4" /> + <waitForElementVisible selector="{{ProductShortDescriptionWYSIWYGToolbarSection.image(ImageUpload3.value)}}" stepKey="waitForUploadImage4" /> <click selector="{{ProductShortDescriptionWYSIWYGToolbarSection.InsertFile}}" stepKey="clickInsertBtn" /> <waitForLoadingMaskToDisappear stepKey="waitForLoading11" /> <waitForElementVisible selector="{{ProductShortDescriptionWYSIWYGToolbarSection.OkBtn}}" stepKey="waitForOkBtn2" /> - <fillField selector="{{ProductShortDescriptionWYSIWYGToolbarSection.ImageDescription}}" userInput="{{ImageUpload1.content}}" stepKey="fillImageDescription2" /> - <fillField selector="{{ProductShortDescriptionWYSIWYGToolbarSection.Height}}" userInput="{{ImageUpload1.height}}" stepKey="fillImageHeight2" /> + <fillField selector="{{ProductShortDescriptionWYSIWYGToolbarSection.ImageDescription}}" userInput="{{ImageUpload3.content}}" stepKey="fillImageDescription2" /> + <fillField selector="{{ProductShortDescriptionWYSIWYGToolbarSection.Height}}" userInput="{{ImageUpload3.height}}" stepKey="fillImageHeight2" /> <click selector="{{ProductShortDescriptionWYSIWYGToolbarSection.OkBtn}}" stepKey="clickOkBtn2" /> <waitForPageLoad stepKey="waitForPageLoad6"/> <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> @@ -102,7 +104,8 @@ <amOnPage url="{{_defaultProduct.name}}.html" stepKey="navigateToProductPage"/> <waitForPageLoad stepKey="waitForPageLoad7"/> <seeElement selector="{{StorefrontProductInfoMainSection.mediaDescription}}" stepKey="assertMediaDescription"/> - <seeElement selector="{{StorefrontProductInfoMainSection.mediaShortDescription}}" stepKey="assertMediaShortDescription"/> + <seeElementInDOM selector="{{StorefrontCategoryMainSection.ImageSource(ImageUpload3.fileName,ImageUpload3.extension)}}" stepKey="assertMediaSource3"/> + <seeElementInDOM selector="{{StorefrontCategoryMainSection.ImageSource(ImageUpload1.fileName,ImageUpload1.extension)}}" stepKey="assertMediaSource1"/> <after> <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> <actionGroup ref="logout" stepKey="logout"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateProductDuplicateUrlkeyTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateProductDuplicateUrlkeyTest.xml new file mode 100644 index 0000000000000..9a95ce7ddcfd4 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateProductDuplicateUrlkeyTest.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminCreateSimpleProductDuplicateUrlkeyTest"> + <annotations> + <features value="Product Creation Negative"/> + <stories value="Error when try to save project with duplicate URL key"/> + <title value="Error when try to save project with duplicate URL key."/> + <description value="Error when try to save project with duplicate URL key."/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-87586"/> + <!--useCaseId value="USECASE-114"/--> + <group value="product"/> + </annotations> + <before> + <createData entity="SimpleTwo" stepKey="simpleProduct"> + </createData> + </before> + <after> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="simpleProduct" stepKey="deleteProduct"/> + </after> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> + <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickAddProductDropdown"/> + <click selector="{{AdminProductGridActionSection.addSimpleProduct}}" stepKey="clickAddSimpleProduct"/> + <fillField userInput="$$simpleProduct.name$$new" selector="{{AdminProductFormSection.productName}}" stepKey="fillName"/> + <fillField userInput="$$simpleProduct.sku$$new" selector="{{AdminProductFormSection.productSku}}" stepKey="fillSKU"/> + <fillField userInput="$$simpleProduct.price$$" selector="{{AdminProductFormSection.productPrice}}" stepKey="fillPrice"/> + <fillField userInput="$$simpleProduct.quantity$$" selector="{{AdminProductFormSection.productQuantity}}" stepKey="fillQuantity"/> + <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSeoSection"/> + <fillField userInput="$$simpleProduct.custom_attributes[url_key]$$" selector="{{AdminProductSEOSection.urlKeyInput}}" stepKey="fillUrlKey"/> + <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> + <see userInput="The value specified in the URL Key field would generate a URL that already exists" selector="{{AdminProductMessagesSection.errorMessage}}" stepKey="assertErrorMessage"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductTest.xml index df6a1400c66f9..14e2478e9df14 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductTest.xml @@ -27,36 +27,16 @@ </after> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> - <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="navigateToProductIndex"/> - <click selector="{{AdminProductGridActionSection.addProductToggle}}" stepKey="clickAddProductDropdown"/> - <click selector="{{AdminProductGridActionSection.addSimpleProduct}}" stepKey="clickAddSimpleProduct"/> - <fillField userInput="{{_defaultProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="fillName"/> - <fillField userInput="{{_defaultProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="fillSKU"/> - <fillField userInput="{{_defaultProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="fillPrice"/> - <fillField userInput="{{_defaultProduct.quantity}}" selector="{{AdminProductFormSection.productQuantity}}" stepKey="fillQuantity"/> - <searchAndMultiSelectOption selector="{{AdminProductFormSection.categoriesDropdown}}" parameterArray="[$$createPreReqCategory.name$$]" stepKey="searchAndSelectCategory"/> - <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSeoSection"/> - <fillField userInput="{{_defaultProduct.urlKey}}" selector="{{AdminProductSEOSection.urlKeyInput}}" stepKey="fillUrlKey"/> - <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="saveProduct"/> - <seeElement selector="{{AdminProductMessagesSection.successMessage}}" stepKey="assertSaveMessageSuccess"/> - <seeInField userInput="{{_defaultProduct.name}}" selector="{{AdminProductFormSection.productName}}" stepKey="assertFieldName"/> - <seeInField userInput="{{_defaultProduct.sku}}" selector="{{AdminProductFormSection.productSku}}" stepKey="assertFieldSku"/> - <seeInField userInput="{{_defaultProduct.price}}" selector="{{AdminProductFormSection.productPrice}}" stepKey="assertFieldPrice"/> - <click selector="{{AdminProductSEOSection.sectionHeader}}" stepKey="openSeoSectionAssert"/> - <seeInField userInput="{{_defaultProduct.urlKey}}" selector="{{AdminProductSEOSection.urlKeyInput}}" stepKey="assertFieldUrlKey"/> - - <!-- Go to storefront category page, assert product visibility --> - <amOnPage url="{{StorefrontCategoryPage.url($$createPreReqCategory.name$$)}}" stepKey="navigateToCategoryPage"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> - <see userInput="{{_defaultProduct.name}}" stepKey="assertProductPresent"/> - <see userInput="{{_defaultProduct.price}}" stepKey="assertProductPricePresent"/> - - <!-- Go to storefront product page, assert product visibility --> - <amOnPage url="{{_defaultProduct.urlKey}}.html" stepKey="navigateToProductPage"/> - <waitForPageLoad stepKey="waitForPageLoad2"/> - <seeInTitle userInput="{{_defaultProduct.name}}" stepKey="assertProductNameTitle"/> - <see userInput="{{_defaultProduct.name}}" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="assertProductName"/> - <see userInput="{{_defaultProduct.price}}" selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="assertProductPrice"/> - <see userInput="{{_defaultProduct.sku}}" selector="{{StorefrontProductInfoMainSection.productSku}}" stepKey="assertProductSku"/> + <actionGroup ref="FillAdminSimpleProductForm" stepKey="fillProductFieldsInAdmin"> + <argument name="category" value="$$createPreReqCategory$$"/> + <argument name="simpleProduct" value="_defaultProduct"/> + </actionGroup> + <actionGroup ref="AssertProductInStorefrontCategoryPage" stepKey="assertProductInStorefront1"> + <argument name="category" value="$$createPreReqCategory$$"/> + <argument name="product" value="_defaultProduct"/> + </actionGroup> + <actionGroup ref="AssertProductInStorefrontProductPage" stepKey="assertProductInStorefront2"> + <argument name="product" value="_defaultProduct"/> + </actionGroup> </test> </tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductWithUnicodeTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductWithUnicodeTest.xml new file mode 100644 index 0000000000000..46cf809ce9d47 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminCreateSimpleProductWithUnicodeTest.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminCreateSimpleProductWithUnicodeTest"> + <annotations> + <features value="Product Creation"/> + <stories value="Create a Unicode Named Simple Product via Admin"/> + <title value="You should be able to create a unicode named simple product in admin."/> + <description value="You should be able to create a unicode named simple product in admin."/> + <severity value="MAJOR" /> + <testCaseId value="MAGETWO-87504"/> + <!--useCaseId value="USECASE-114"/--> + <group value="product"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createPreReqCategory"/> + </before> + <after> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="createPreReqCategory" stepKey="deletePreReqCategory"/> + </after> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + <actionGroup ref="FillAdminSimpleProductForm" stepKey="fillProductFieldsInAdmin"> + <argument name="category" value="$$createPreReqCategory$$"/> + <argument name="simpleProduct" value="ProductWithUnicode"/> + </actionGroup> + <actionGroup ref="AssertProductInStorefrontCategoryPage" stepKey="assertProductInStorefront1"> + <argument name="category" value="$$createPreReqCategory$$"/> + <argument name="product" value="ProductWithUnicode"/> + </actionGroup> + <actionGroup ref="AssertProductInStorefrontProductPage" stepKey="assertProductInStorefront2"> + <argument name="product" value="ProductWithUnicode"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminEditTextEditorProductAttributeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminEditTextEditorProductAttributeCest.xml index 370a331bc58ef..8d6159c0f8ce9 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminEditTextEditorProductAttributeCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/AdminEditTextEditorProductAttributeCest.xml @@ -16,12 +16,13 @@ <description value="Admin should be able to switch between 2 version of Tinymce in the admin back-end."/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-85745"/> + <group value="skip"/> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="loginGetFromGeneralFile"/> <actionGroup ref="EnabledWYSIWYG" stepKey="enableWYSIWYG"/> <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> - <createData stepKey="myProductAttributeCreation" entity="productAttributeWithTwoOptions"/> + <createData stepKey="myProductAttributeCreation" entity="productAttributeWysiwyg"/> <createData stepKey="myProductAttributeSetAssign" entity="AddToDefaultSet"> <requiredEntity createDataKey="myProductAttributeCreation"/> </createData> @@ -66,6 +67,11 @@ <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="amOnProductGrid" /> <waitForPageLoad stepKey="waitForPageLoad9"/> <actionGroup ref="SortByIdDescendingActionGroup" stepKey="sortByIdDescending" /> + <conditionalClick selector="{{AdminProductGridFilterSection.clearAll}}" dependentSelector="{{AdminProductGridFilterSection.enabledFilters}}" visible="true" stepKey="clearAllExistingFilter"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingAfterFilterIsCleared"/> + <fillField selector="{{AdminProductGridFilterSection.basicSearchFilter}}" userInput="{{_defaultProduct.name}}" stepKey="addSearchFilterForTestProduct"/> + <click selector="{{AdminProductGridFilterSection.basicSearchFilterButton}}" stepKey="clickOnBasicSearchFilterButton"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingAfterBasicFilter"/> <click selector="{{AdminProductGridActionSection.productName(_defaultProduct.name)}}" stepKey="navigateToEditProduct" /> <waitForPageLoad stepKey="waitForPageLoad10" /> <seeElement selector="{{ProductAttributeWYSIWYGSection.TinyMCE4($$myProductAttributeCreation.attribute_code$$)}}" stepKey="waitForPageLoad11"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/EndToEndB2CAdminTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/EndToEndB2CAdminTest.xml index 2feae54c43abe..027ffd59cdc93 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/EndToEndB2CAdminTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/EndToEndB2CAdminTest.xml @@ -10,27 +10,26 @@ <test name="EndToEndB2CAdminTest"> <annotations> <features value="End to End scenarios"/> - <stories value="B2C - Admin"/> + <stories value="B2C admin - MAGETWO-75412"/> <group value="e2e"/> + <!--Skipped; see MAGETWO-88963--> + <group value="skip"/> <title value="Pass End to End B2C Admin scenario"/> <description value="Admin creates products, creates and manages categories, creates promotions, creates an order, processes an order, processes a return, uses admin grids"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-87014"/> </annotations> - <before> - <!--Login to Admin Area--> - <actionGroup ref="LoginActionGroup" stepKey="loginToAdminArea"/> - </before> <after> - <!--Clean up products--> - - <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + <actionGroup ref="logout" stepKey="logoutOfAdmin"/> </after> - <!--Step 2. Admin create product--> + <!--Login to Admin Area--> + <actionGroup ref="LoginAsAdmin" stepKey="loginToAdminArea"/> + + <!--Admin creates product--> <!--Create Simple Product--> <amOnPage url="{{AdminProductIndexPage}}" stepKey="visitAdminProductPageSimple"/> - <waitForPageLoad stepKey="waitForProductPageLoadSimple"/> + <waitForPageLoad time="30" stepKey="waitForProductPageLoadSimple"/> <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial"/> <actionGroup ref="goToCreateProductPage" stepKey="goToCreateSimpleProduct"> <argument name="product" value="SimpleProduct"/> @@ -55,7 +54,7 @@ <!--Create Virtual Product--> <amOnPage url="{{AdminProductIndexPage}}" stepKey="visitAdminProductPageVirtual"/> - <waitForPageLoad stepKey="waitForProductPageLoadVirtual"/> + <waitForPageLoad time="30" stepKey="waitForProductPageLoadVirtual"/> <actionGroup ref="goToCreateProductPage" stepKey="goToCreateVirtualProduct"> <argument name="product" value="VirtualProduct"/> </actionGroup> @@ -68,10 +67,165 @@ <argument name="product" value="VirtualProduct"/> </actionGroup> - <!--TODO - Move to 'after' block when MQE-732 is fixed--> + <!--Admin uses product grid--> + <!--Start with default view--> + <amOnPage url="{{AdminProductIndexPage}}" stepKey="visitAdminProductPageGrid"/> + <waitForPageLoad stepKey="waitForProductGridPageLoad"/> + + <!--Search by keyword--> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetGridToDefaultKeywordSearch"/> + <actionGroup ref="searchProductGridByKeyword" stepKey="useKeywordSearchSimpleProduct"> + <argument name="keyword" value="SimpleProduct.name"/> + </actionGroup> + <seeNumberOfElements selector="{{AdminProductGridSection.productGridRows}}" userInput="1" stepKey="seeOnlyOneProductInGrid"/> + <see selector="{{AdminProductGridSection.productGridCell('1', 'Name')}}" userInput="{{SimpleProduct.name}}" stepKey="seeOnlySimpleProductInGrid"/> + + <!--Paging works--> + <actionGroup ref="resetProductGridToDefaultView" stepKey="setProductGridToDefaultPagination"/> + <comment userInput="Admin uses paging on product grid" stepKey="usePagingProductGridComment"/> + <click selector="{{AdminProductGridPaginationSection.perPageDropdown}}" stepKey="clickProductPerPageDropdown"/> + <click selector="{{AdminProductGridPaginationSection.perPageOption('50')}}" stepKey="selectProductsPerPage"/> + <waitForLoadingMaskToDisappear stepKey="waitForProductGridLoad50PerPage"/> + <seeNumberOfElements selector="{{AdminProductGridSection.productGridRows}}" parameterArray="[5,50]" stepKey="see50ProductsInGrid"/> + <click selector="{{AdminProductGridPaginationSection.perPageDropdown}}" stepKey="clickProductPerPageDropdownCustom"/> + <click selector="{{AdminProductGridPaginationSection.perPageOption('Custom')}}" stepKey="selectCustomPerPage"/> + <fillField selector="{{AdminProductGridPaginationSection.perPageInput}}" userInput="5" stepKey="fillCustomPerPage"/> + <click selector="{{AdminProductGridPaginationSection.perPageApplyInput}}" stepKey="applyCustomPerPage"/> + <waitForPageLoad stepKey="waitForPageRefreshCustomPerPage"/> + <seeInField selector="{{AdminProductGridPaginationSection.currentPage}}" userInput="1" stepKey="seeOnFirstProductPage"/> + <seeNumberOfElements selector="{{AdminProductGridSection.productGridRows}}" userInput="5" stepKey="seeProductsOnFirstPage"/> + <click selector="{{AdminProductGridPaginationSection.nextPage}}" stepKey="clickNextProductPage"/> + <seeInField selector="{{AdminProductGridPaginationSection.currentPage}}" userInput="2" stepKey="seeOnSecondProductPage"/> + <seeNumberOfElements selector="{{AdminProductGridSection.productGridRows}}" parameterArray="[1,5]" stepKey="seeProductsOnSecondPage"/> + + <!--Filtering works (by Name, By Price, by Status)--> + <actionGroup ref="resetProductGridToDefaultView" stepKey="setProductGridToDefaultFiltering"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridByGroupedSku"> + <argument name="product" value="GroupedProduct"/> + </actionGroup> + <seeNumberOfElements selector="{{AdminProductGridSection.productGridRows}}" userInput="1" stepKey="seeOneMatchingSkuInProductGrid"/> + <see selector="{{AdminProductGridSection.productGridCell('1','SKU')}}" userInput="{{GroupedProduct.sku}}" stepKey="seeProductInFilteredGridSku"/> + <!--Filter by price--> + <actionGroup ref="filterProductGridByPriceRange" stepKey="filterProductGridByPrice"> + <argument name="filter" value="PriceFilterRange"/> + </actionGroup> + <click selector="{{AdminProductGridSection.columnHeader('Price')}}" stepKey="clickPriceHeaderToSortAscForFilter"/> + <grabTextFrom selector="{{AdminProductGridSection.productGridCell('1', 'Price')}}" stepKey="getMinimumPriceInGrid"/> + <click selector="{{AdminProductGridSection.columnHeader('Price')}}" stepKey="clickPriceHeaderToSortDescForFilter"/> + <grabTextFrom selector="{{AdminProductGridSection.productGridCell('1', 'Price')}}" stepKey="getMaximumPriceInGrid"/> + <assertRegExp expected="'/\$[0-9]{2}\.[0-9]{2}/'" actual="$getMinimumPriceInGrid" stepKey="assertMinimumPriceIsCorrect"/> + <assertRegExp expected="'/\$[0-9]{2}\.[0-9]{2}/'" actual="$getMaximumPriceInGrid" stepKey="assertMaximumPriceIsCorrect"/> + <assertLessThan expected="$getMaximumPriceInGrid" actual="$getMinimumPriceInGrid" stepKey="checkPriceSortCorrect"/> + <!--Filter by status--> + <actionGroup ref="filterProductGridByEnabledStatus" stepKey="filterGridByEnabledProducts"/> + <seeNumberOfElements selector="{{AdminProductGridSection.productGridRows}}" parameterArray="[1,20]" stepKey="seeEnabledProductsNotEmpty"/> + <see selector="{{AdminProductGridSection.column('Status')}}" userInput="Enabled" stepKey="seeOnlyEnabledProducts"/> + <actionGroup ref="filterProductGridByDisabledStatus" stepKey="filterGridByDisabledProducts"/> + <dontSee selector="{{AdminProductGridSection.column('Status')}}" userInput="Enabled" stepKey="dontSeeEnabledProducts"/> + + <!--Sorting works (By Price, by ID)--> + <!--By Price--> + <actionGroup ref="resetProductGridToDefaultView" stepKey="setProductGridToDefaultSortingPrice"/> + <!--Filter by price so grid contains prices that we can compare correctly--> + <actionGroup ref="filterProductGridByPriceRange" stepKey="filterProductGridByPriceForCompare"> + <argument name="filter" value="PriceFilterRange"/> + </actionGroup> + <!--Sort Ascending--> + <click selector="{{AdminProductGridSection.columnHeader('Price')}}" stepKey="clickPriceHeaderToSortAsc"/> + <grabTextFrom selector="{{AdminProductGridSection.productGridCell('1', 'Price')}}" stepKey="getFirstPriceSortAsc"/> + <grabTextFrom selector="{{AdminProductGridSection.productGridCell('2', 'Price')}}" stepKey="getSecondPriceSortAsc"/> + <assertLessThanOrEqual expected="$getSecondPriceSortAsc" actual="$getFirstPriceSortAsc" stepKey="checkPriceAscSortCorrect"/> + <!--Sort Descending--> + <click selector="{{AdminProductGridSection.columnHeader('Price')}}" stepKey="clickPriceHeaderToSortDesc"/> + <grabTextFrom selector="{{AdminProductGridSection.productGridCell('1', 'Price')}}" stepKey="getFirstPriceSortDesc"/> + <grabTextFrom selector="{{AdminProductGridSection.productGridCell('2', 'Price')}}" stepKey="getSecondPriceSortDesc"/> + <assertGreaterThanOrEqual expected="$getSecondPriceSortDesc" actual="$getFirstPriceSortDesc" stepKey="checkPriceDescSortCorrect"/> + <!--By Product ID--> + <actionGroup ref="resetProductGridToDefaultView" stepKey="setProductGridToDefaultSortingId"/> + <!--Sort Ascending--> + <grabTextFrom selector="{{AdminProductGridSection.productGridCell('1', 'ID')}}" stepKey="getFirstProductIdSortAsc"/> + <grabTextFrom selector="{{AdminProductGridSection.productGridCell('2', 'ID')}}" stepKey="getSecondProductIdSortAsc"/> + <assertLessThan expected="$getSecondProductIdSortAsc" actual="$getFirstProductIdSortAsc" stepKey="checkProductIdAscSortCorrect"/> + <!--Sort Descending--> + <click selector="{{AdminProductGridSection.columnHeader('ID')}}" stepKey="clickIdHeaderToSortDesc"/> + <grabTextFrom selector="{{AdminProductGridSection.productGridCell('1', 'ID')}}" stepKey="getFirstProductIdSortDesc"/> + <grabTextFrom selector="{{AdminProductGridSection.productGridCell('2', 'ID')}}" stepKey="getSecondProductIdSortDesc"/> + <assertGreaterThan expected="$getSecondProductIdSortDesc" actual="$getFirstProductIdSortDesc" stepKey="checkProductIdDescSortCorrect"/> + + <!--Adding column works--> + <actionGroup ref="resetProductGridToDefaultView" stepKey="setProductGridToDefaultColumns"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="openColumnsDropdownToReset"/> + <click selector="{{AdminProductGridFilterSection.resetGridColumns}}" stepKey="resetProductGridColumns"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="closeColumnsDropdownAfterReset"/> + <!--Remove Price column--> + <seeElement selector="{{AdminProductGridSection.columnHeader('Price')}}" stepKey="seeProductPriceColumn"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="openColumnsDropdown"/> + <uncheckOption selector="{{AdminProductGridFilterSection.viewColumnOption('Price')}}" stepKey="hidePriceColumn"/> + <dontSeeElement selector="{{AdminProductGridSection.columnHeader('Price')}}" stepKey="dontSeeProductPriceColumn"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="closeColumnsDropdown"/> + <!--Add Weight column--> + <dontSeeElement selector="{{AdminProductGridSection.columnHeader('Weight')}}" stepKey="dontSeeWeightColumn"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="openColumnsDropdownWeight"/> + <checkOption selector="{{AdminProductGridFilterSection.viewColumnOption('Weight')}}" stepKey="showWeightColumn"/> + <click selector="{{AdminProductGridFilterSection.columnsDropdown}}" stepKey="closeColumnsDropdownWeight"/> + <seeElement selector="{{AdminProductGridSection.columnHeader('Weight')}}" stepKey="seeWeightColumn"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridToCheckWeightColumn"> + <argument name="product" value="SimpleProduct"/> + </actionGroup> + <see selector="{{AdminProductGridSection.productGridCell('1','Weight')}}" userInput="{{SimpleProduct.weight}}" stepKey="seeCorrectProductWeightInGrid"/> + <!--END Admin uses product grid--> + + <!--Admin creates category--> + <comment userInput="Admin creates category." stepKey="adminCreatesCategoryComment" before="navigateToCategoryPage"/> + <amOnPage url="{{AdminCategoryPage}}" stepKey="navigateToCategoryPage"/> + <waitForPageLoad time="30" stepKey="waitForCategoryPageLoad"/> + <!--Create category under Default Category--> + <click selector="{{AdminCategorySidebarTreeSection.categoryTreeRoot}}" stepKey="clickDefaultCategory"/> + <actionGroup ref="CheckCategoryNameIsRequiredField" stepKey="checkCategoryNameIsRequired"/> + <actionGroup ref="CreateCategory" stepKey="createCategory"> + <argument name="categoryEntity" value="_defaultCategory"/> + </actionGroup> + <!--Create category under newly created category--> + <click selector="{{AdminCategorySidebarTreeSection.categoryInTree(_defaultCategory.name)}}" stepKey="clickCreatedCategoryInTree"/> + <actionGroup ref="CreateCategory" stepKey="createSubCategory"> + <argument name="categoryEntity" value="SimpleSubCategory"/> + </actionGroup> + + <!--Admin moves category--> + <comment userInput="Admin moves category." stepKey="adminMovesCategoryComment" before="onCategoryPageToMoveCategory"/> + <amOnPage url="{{AdminCategoryPage}}" stepKey="onCategoryPageToMoveCategory"/> + <waitForPageLoad time="30" stepKey="waitForPageLoadMoveCategory"/> + <click selector="{{AdminCategorySidebarTreeSection.expandAll}}" stepKey="expandTree"/> + <dragAndDrop selector1="{{AdminCategorySidebarTreeSection.categoryInTree(SimpleSubCategory.name)}}" + selector2="{{AdminCategorySidebarTreeSection.categoryTreeRoot}}" + stepKey="dragAndDropCategory"/> + <waitForPageLoad time="30" stepKey="waitForMoveConfirmation"/> + <see selector="{{AdminCategoryModalSection.title}}" userInput="Warning Message" stepKey="seeMoveConfirmationModal"/> + <click selector="{{AdminCategoryModalSection.ok}}" stepKey="clickOkConfirmMove"/> + <waitForPageLoad time="30" stepKey="waitForMove"/> + <see selector="{{AdminCategoryMessagesSection.SuccessMessage}}" userInput="You moved the category." stepKey="seeCategoryMoveSuccessMessage"/> + <seeElement selector="{{AdminCategorySidebarTreeSection.categoryInTreeUnderRoot(SimpleSubCategory.name)}}" stepKey="seeSubcategoryIsUnderDefault"/> + + <!--Admin deletes category--> + <comment userInput="Admin deletes category" stepKey="deleteCategoryComment"/> + <amOnPage url="{{AdminCategoryPage}}" stepKey="onCategoryPageToDeleteCategory"/> + <waitForPageLoad time="30" stepKey="waitForCategoryPageDelete"/> + <actionGroup ref="DeleteCategory" stepKey="deleteCategory"> + <argument name="categoryEntity" value="_defaultCategory"/> + </actionGroup> + + <!--@TODO Move cleanup to "after" when MQE-830 is resolved--> + <!--Clean up categories--> + <comment userInput="Clean up categories" stepKey="cleanupCategoriesComment"/> + <actionGroup ref="DeleteCategory" stepKey="cleanSimpleSubCategory"> + <argument name="categoryEntity" value="SimpleSubCategory"/> + </actionGroup> + <!--Clean up products--> + <comment userInput="Clean up simple product" stepKey="cleanUpSimpleProduct"/> <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteSimpleProduct"> <argument name="product" value="SimpleProduct"/> </actionGroup> + <comment userInput="Clean up virtual product" stepKey="cleanUpVirtualProduct"/> <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteVirtualProduct"> <argument name="product" value="VirtualProduct"/> </actionGroup> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/EndToEndB2CGuestUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/EndToEndB2CGuestUserTest.xml new file mode 100644 index 0000000000000..818c538d015ca --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/EndToEndB2CGuestUserTest.xml @@ -0,0 +1,205 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CGuestUserTest"> + <annotations> + <features value="End to End scenarios"/> + <stories value="B2C guest user - MAGETWO-75411"/> + <group value="e2e"/> + <title value="You should be able to pass End to End B2C Guest User scenario"/> + <description value="User browses catalog, searches for product, adds product to cart, adds product to wishlist, compares products, uses coupon code and checks out."/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-87435"/> + </annotations> + <before> + <resetCookie userInput="PHPSESSID" stepKey="resetCookieForCart"/> + + <createData entity="ApiCategory" stepKey="createCategory"/> + + <createData entity="ApiSimpleProduct" stepKey="createSimpleProduct1"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryTestImage" stepKey="createSimpleProduct1Image"> + <requiredEntity createDataKey="createSimpleProduct1"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryMagentoLogo" stepKey="createSimpleProduct1Image1"> + <requiredEntity createDataKey="createSimpleProduct1"/> + </createData> + <updateData entity="ApiSimpleProductUpdateDescription" stepKey="updateSimpleProduct1" createDataKey="createSimpleProduct1"/> + + <createData entity="ApiSimpleProduct" stepKey="createSimpleProduct2"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryTestImage" stepKey="createSimpleProduct2Image"> + <requiredEntity createDataKey="createSimpleProduct2"/> + </createData> + <updateData entity="ApiSimpleProductUpdateDescription" stepKey="updateSimpleProduct2" createDataKey="createSimpleProduct2"/> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createSimpleProduct1Image" stepKey="deleteSimpleProduct1Image"/>--> + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createSimpleProduct1Image1" stepKey="deleteSimpleProduct1Image1"/>--> + <deleteData createDataKey="createSimpleProduct1" stepKey="deleteSimpleProduct1"/> + + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createSimpleProduct2Image" stepKey="deleteSimpleProduct2Image"/>--> + <deleteData createDataKey="createSimpleProduct2" stepKey="deleteSimpleProduct2"/> + </after> + + <!-- Step 1: User browses catalog --> + <comment userInput="Start of browsing catalog" stepKey="startOfBrowsingCatalog" /> + <amOnPage url="{{StorefrontHomePage}}" stepKey="amOnHomePage"/> + <waitForPageLoad stepKey="homeWaitForPageLoad"/> + <waitForElementVisible selector="{{StorefrontPanelHeaderSection.WelcomeMessage}}" stepKey="homeWaitForWelcomeMessage"/> + <see userInput="Default welcome msg!" selector="{{StorefrontPanelHeaderSection.WelcomeMessage}}" stepKey="homeCheckWelcome"/> + + <!-- Open Category --> + <comment userInput="Open category" stepKey="commentOpenCategory" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="browseClickCategory"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="browseAssertCategory"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <!-- Check simple product 1 in category --> + <comment userInput="Check simple product 1 in category" stepKey="commentCheckSimpleProductInCategory" /> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="browseAssertCategoryProduct1"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="browseGrabSimpleProduct1ImageSrc"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$browseGrabSimpleProduct1ImageSrc" stepKey="browseAssertSimpleProduct1ImageNotDefault"/> + <!-- Check simple product 2 in category --> + <comment userInput="Check simple product 2 in category" stepKey="commentCheckSimpleProduct2InCategory" /> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="browseAssertCategoryProduct2"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="browseGrabSimpleProduct2ImageSrc"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$browseGrabSimpleProduct2ImageSrc" stepKey="browseAssertSimpleProduct2ImageNotDefault"/> + + <!-- View Simple Product 1 --> + <comment userInput="View simple product 1" stepKey="commentViewSimpleProduct1" after="browseAssertSimpleProduct2ImageNotDefault"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct1.name$$)}}" stepKey="browseClickCategorySimpleProduct1View" after="commentViewSimpleProduct1"/> + <waitForLoadingMaskToDisappear stepKey="waitForSimpleProduct1Viewloaded" /> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="browseAssertProduct1Page"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="browseGrabSimpleProduct1PageImageSrc"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$browseGrabSimpleProduct1PageImageSrc" stepKey="browseAssertSimpleProduct1PageImageNotDefault"/> + + <!-- View Simple Product 2 --> + <comment userInput="View simple product 2" stepKey="commentViewSimpleProduct2" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="clickCategory1"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct2.name$$)}}" stepKey="browseClickCategorySimpleProduct2View"/> + <waitForLoadingMaskToDisappear stepKey="waitForSimpleProduct2ViewLoaded" /> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="browseAssertProduct2Page"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="browseGrabSimpleProduct2PageImageSrc"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$browseGrabSimpleProduct2PageImageSrc" stepKey="browseAssertSimpleProduct2PageImageNotDefault"/> + <comment userInput="End of browsing catalog" stepKey="endOfBrowsingCatalog" after="browseAssertSimpleProduct2PageImageNotDefault"/> + + <!-- Step 4: User compares products --> + <comment userInput="Start of comparing products" stepKey="startOfComparingProducts" after="endOfBrowsingCatalog"/> + <!-- Add Simple Product 1 to comparison --> + <comment userInput="Add simple product 1 to comparison" stepKey="commentAddSimpleProduct1ToComparison" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="compareClickCategory" /> + <waitForLoadingMaskToDisappear stepKey="waitForCategoryloaded" /> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="compareAssertCategory"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="compareAssertSimpleProduct1"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="compareGrabSimpleProduct1ImageSrc"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabSimpleProduct1ImageSrc" stepKey="compareAssertSimpleProduct1ImageNotDefault"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct1.name$$)}}" stepKey="compareClickSimpleProduct1"/> + <waitForLoadingMaskToDisappear stepKey="waitForCompareSimpleProduct1loaded" /> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="compareAssertProduct1Page"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="compareGrabSimpleProduct1PageImageSrc"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$compareGrabSimpleProduct1PageImageSrc" stepKey="compareAssertSimpleProduct2PageImageNotDefault"/> + <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="compareAddSimpleProduct1ToCompare"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + + <!-- Add Simple Product 2 to comparison --> + <comment userInput="Add simple product 2 to comparison" stepKey="commentAddSimpleProduct2ToComparison" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="compareClickCategory1"/> + <waitForLoadingMaskToDisappear stepKey="waitForCompareCategory1loaded" /> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="compareAssertCategory1"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="compareAssertSimpleProduct2"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="compareGrabSimpleProduct2ImageSrc"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabSimpleProduct2ImageSrc" stepKey="compareAssertSimpleProduct2ImageNotDefault"/> + <actionGroup ref="StorefrontAddCategoryProductToCompareActionGroup" stepKey="compareAddSimpleProduct2ToCompare"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + + <!-- Check products in comparison sidebar --> + <!-- Check simple product 1 in comparison sidebar --> + <comment userInput="Check simple product 1 in comparison sidebar" stepKey="commentCheckSimpleProduct1InComparisonSidebar" after="compareAddSimpleProduct2ToCompare"/> + <actionGroup ref="StorefrontCheckCompareSidebarProductActionGroup" stepKey="compareSimpleProduct1InSidebar" after="commentCheckSimpleProduct1InComparisonSidebar"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- Check simple product 2 in comparison sidebar --> + <comment userInput="Check simple product 2 in comparison sidebar" stepKey="commentCheckSimpleProduct2InComparisonSidebar" /> + <actionGroup ref="StorefrontCheckCompareSidebarProductActionGroup" stepKey="compareSimpleProduct2InSidebar"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + + <!-- Check products on comparison page --> + <!-- Check simple product 1 on comparison page --> + <comment userInput="Check simple product 1 on comparison page" stepKey="commentCheckSimpleProduct1OnComparisonPage" after="compareSimpleProduct2InSidebar"/> + <actionGroup ref="StorefrontOpenAndCheckComparisionActionGroup" stepKey="compareOpenComparePage" after="commentCheckSimpleProduct1OnComparisonPage"/> + <actionGroup ref="StorefrontCheckCompareSimpleProductActionGroup" stepKey="compareAssertSimpleProduct1InComparison"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductCompareMainSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="compareGrabSimpleProduct1ImageSrcInComparison"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabSimpleProduct1ImageSrcInComparison" stepKey="compareAssertSimpleProduct1ImageNotDefaultInComparison"/> + <!-- Check simple product2 on comparison page --> + <comment userInput="Check simple product 2 on comparison page" stepKey="commentCheckSimpleProduct2OnComparisonPage" /> + <actionGroup ref="StorefrontCheckCompareSimpleProductActionGroup" stepKey="compareAssertSimpleProduct2InComparison"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductCompareMainSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="compareGrabSimpleProduct2ImageSrcInComparison"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabSimpleProduct2ImageSrcInComparison" stepKey="compareAssertSimpleProduct2ImageNotDefaultInComparison"/> + + <!-- Clear comparison sidebar --> + <comment userInput="Clear comparison sidebar" stepKey="commentClearComparisonSidebar" after="compareAssertSimpleProduct2ImageNotDefaultInComparison"/> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="compareClickCategoryBeforeClear" after="commentClearComparisonSidebar"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="compareAssertCategory2"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontClearCompareActionGroup" stepKey="compareClearCompare"/> + <comment userInput="End of Comparing Products" stepKey="endOfComparingProducts" /> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/EndToEndB2CLoggedInUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/EndToEndB2CLoggedInUserTest.xml new file mode 100644 index 0000000000000..edf9c28c3acce --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/EndToEndB2CLoggedInUserTest.xml @@ -0,0 +1,192 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CLoggedInUserTest"> + <before> + <createData entity="ApiCategory" stepKey="createCategory"/> + + <createData entity="ApiSimpleProduct" stepKey="createSimpleProduct1"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryTestImage" stepKey="createSimpleProduct1Image"> + <requiredEntity createDataKey="createSimpleProduct1"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryMagentoLogo" stepKey="createSimpleProduct1Image1"> + <requiredEntity createDataKey="createSimpleProduct1"/> + </createData> + <updateData entity="ApiSimpleProductUpdateDescription" stepKey="updateSimpleProduct1" createDataKey="createSimpleProduct1"/> + + <createData entity="ApiSimpleProduct" stepKey="createSimpleProduct2"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryTestImage" stepKey="createSimpleProduct2Image"> + <requiredEntity createDataKey="createSimpleProduct2"/> + </createData> + <updateData entity="ApiSimpleProductUpdateDescription" stepKey="updateSimpleProduct2" createDataKey="createSimpleProduct2"/> + </before> + <after> + <deleteData createDataKey="createCategory" stepKey="deleteCategory"/> + + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createSimpleProduct1Image" stepKey="deleteSimpleProduct1Image"/>--> + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createSimpleProduct1Image1" stepKey="deleteSimpleProduct1Image1"/>--> + <deleteData createDataKey="createSimpleProduct1" stepKey="deleteSimpleProduct1"/> + + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createSimpleProduct2Image" stepKey="deleteSimpleProduct2Image"/>--> + <deleteData createDataKey="createSimpleProduct2" stepKey="deleteSimpleProduct2"/> + </after> + + <!-- Step 1: User browses catalog --> + <comment userInput="Start of browsing catalog" stepKey="startOfBrowsingCatalog" after="endOfSigningUpUserAccount"/> + <amOnPage url="{{StorefrontHomePage}}" stepKey="amOnHomePage" after="startOfBrowsingCatalog"/> + <waitForPageLoad stepKey="homeWaitForPageLoad" after="amOnHomePage"/> + <waitForElementVisible selector="{{StorefrontPanelHeaderSection.WelcomeMessage}}" stepKey="homeWaitForWelcomeMessage" after="homeWaitForPageLoad"/> + <see userInput="Welcome, John Doe!" selector="{{StorefrontPanelHeaderSection.WelcomeMessage}}" stepKey="homeCheckWelcome" after="homeWaitForWelcomeMessage"/> + + <!-- Open Category --> + <comment userInput="Open category" stepKey="commentOpenCategory" after="homeCheckWelcome"/> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="browseClickCategory" after="commentOpenCategory"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="browseAssertCategory" after="browseClickCategory"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <!-- Check simple product 1 in category --> + <comment userInput="Check simple product 1 in category" stepKey="commentCheckSimpleProductInCategory" after="browseAssertCategory"/> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="browseAssertCategoryProduct1" after="commentCheckSimpleProductInCategory"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="browseGrabSimpleProduct1ImageSrc" after="browseAssertCategoryProduct1"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$browseGrabSimpleProduct1ImageSrc" stepKey="browseAssertSimpleProduct1ImageNotDefault" after="browseGrabSimpleProduct1ImageSrc"/> + <!-- Check simple product 2 in category --> + <comment userInput="Check simple product 2 in category" stepKey="commentCheckSimpleProduct2InCategory" after="browseAssertSimpleProduct1ImageNotDefault"/> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="browseAssertCategoryProduct2" after="commentCheckSimpleProduct2InCategory"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="browseGrabSimpleProduct2ImageSrc" after="browseAssertCategoryProduct2"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$browseGrabSimpleProduct2ImageSrc" stepKey="browseAssertSimpleProduct2ImageNotDefault" after="browseGrabSimpleProduct2ImageSrc"/> + + <!-- View Simple Product 1 --> + <comment userInput="View simple product 1" stepKey="commentViewSimpleProduct1" after="browseAssertSimpleProduct2ImageNotDefault"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct1.name$$)}}" stepKey="browseClickCategorySimpleProduct1View" after="commentViewSimpleProduct1"/> + <waitForLoadingMaskToDisappear stepKey="waitForSimpleProduct1Viewloaded" after="browseClickCategorySimpleProduct1View"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="browseAssertProduct1Page" after="waitForSimpleProduct1Viewloaded"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="browseGrabSimpleProduct1PageImageSrc" after="browseAssertProduct1Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$browseGrabSimpleProduct1PageImageSrc" stepKey="browseAssertSimpleProduct1PageImageNotDefault" after="browseGrabSimpleProduct1PageImageSrc"/> + + <!-- View Simple Product 2 --> + <comment userInput="View simple product 2" stepKey="commentViewSimpleProduct2" after="browseAssertSimpleProduct1PageImageNotDefault"/> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="clickCategory1" after="commentViewSimpleProduct2"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct2.name$$)}}" stepKey="browseClickCategorySimpleProduct2View" after="clickCategory1"/> + <waitForLoadingMaskToDisappear stepKey="waitForSimpleProduct2ViewLoaded" after="browseClickCategorySimpleProduct2View"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="browseAssertProduct2Page" after="waitForSimpleProduct2ViewLoaded"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="browseGrabSimpleProduct2PageImageSrc" after="browseAssertProduct2Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$browseGrabSimpleProduct2PageImageSrc" stepKey="browseAssertSimpleProduct2PageImageNotDefault" after="browseGrabSimpleProduct2PageImageSrc"/> + <comment userInput="End of browsing catalog" stepKey="endOfBrowsingCatalog" after="browseAssertSimpleProduct2PageImageNotDefault"/> + + <!-- Step 4: User compares products --> + <comment userInput="Start of comparing products" stepKey="startOfComparingProducts" after="endOfBrowsingCatalog"/> + <!-- Add Simple Product 1 to comparison --> + <comment userInput="Add simple product 1 to comparison" stepKey="commentAddSimpleProduct1ToComparison" after="startOfComparingProducts"/> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="compareClickCategory" after="commentAddSimpleProduct1ToComparison"/> + <waitForLoadingMaskToDisappear stepKey="waitForCategoryloaded" after="compareClickCategory"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="compareAssertCategory" after="waitForCategoryloaded"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="compareAssertSimpleProduct1" after="compareAssertCategory"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="compareGrabSimpleProduct1ImageSrc" after="compareAssertSimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabSimpleProduct1ImageSrc" stepKey="compareAssertSimpleProduct1ImageNotDefault" after="compareGrabSimpleProduct1ImageSrc"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct1.name$$)}}" stepKey="compareClickSimpleProduct1" after="compareAssertSimpleProduct1ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForCompareSimpleProduct1loaded" after="compareClickSimpleProduct1"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="compareAssertProduct1Page" after="waitForCompareSimpleProduct1loaded"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="compareGrabSimpleProduct1PageImageSrc" after="compareAssertProduct1Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$compareGrabSimpleProduct1PageImageSrc" stepKey="compareAssertSimpleProduct2PageImageNotDefault" after="compareGrabSimpleProduct1PageImageSrc"/> + <actionGroup ref="StorefrontAddProductToCompareActionGroup" stepKey="compareAddSimpleProduct1ToCompare" after="compareAssertSimpleProduct2PageImageNotDefault"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + + <!-- Add Simple Product 2 to comparison --> + <comment userInput="Add simple product 2 to comparison" stepKey="commentAddSimpleProduct2ToComparison" after="compareAddSimpleProduct1ToCompare"/> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="compareClickCategory1" after="commentAddSimpleProduct2ToComparison"/> + <waitForLoadingMaskToDisappear stepKey="waitForCompareCategory1loaded" after="compareClickCategory1"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="compareAssertCategory1" after="waitForCompareCategory1loaded"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="compareAssertSimpleProduct2" after="compareAssertCategory1"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="compareGrabSimpleProduct2ImageSrc" after="compareAssertSimpleProduct2"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabSimpleProduct2ImageSrc" stepKey="compareAssertSimpleProduct2ImageNotDefault" after="compareGrabSimpleProduct2ImageSrc"/> + <actionGroup ref="StorefrontAddCategoryProductToCompareActionGroup" stepKey="compareAddSimpleProduct2ToCompare" after="compareAssertSimpleProduct2ImageNotDefault"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + + <!-- Check products in comparison sidebar --> + <!-- Check simple product 1 in comparison sidebar --> + <comment userInput="Check simple product 1 in comparison sidebar" stepKey="commentCheckSimpleProduct1InComparisonSidebar" after="compareAddSimpleProduct2ToCompare"/> + <actionGroup ref="StorefrontCheckCompareSidebarProductActionGroup" stepKey="compareSimpleProduct1InSidebar" after="commentCheckSimpleProduct1InComparisonSidebar"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- Check simple product2 in comparison sidebar --> + <actionGroup ref="StorefrontCheckCompareSidebarProductActionGroup" stepKey="compareSimpleProduct2InSidebar" after="compareSimpleProduct1InSidebar"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + + <!-- Check products on comparison page --> + <!-- Check simple product 1 on comparison page --> + <comment userInput="Check simple product 1 on comparison page" stepKey="commentCheckSimpleProduct1OnComparisonPage" after="compareSimpleProduct2InSidebar"/> + <actionGroup ref="StorefrontOpenAndCheckComparisionActionGroup" stepKey="compareOpenComparePage" after="commentCheckSimpleProduct1OnComparisonPage"/> + <actionGroup ref="StorefrontCheckCompareSimpleProductActionGroup" stepKey="compareAssertSimpleProduct1InComparison" after="compareOpenComparePage"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductCompareMainSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="compareGrabSimpleProduct1ImageSrcInComparison" after="compareAssertSimpleProduct1InComparison"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabSimpleProduct1ImageSrcInComparison" stepKey="compareAssertSimpleProduct1ImageNotDefaultInComparison" after="compareGrabSimpleProduct1ImageSrcInComparison"/> + <!-- Check simple product2 on comparison page --> + <actionGroup ref="StorefrontCheckCompareSimpleProductActionGroup" stepKey="compareAssertSimpleProduct2InComparison" after="compareAssertSimpleProduct1ImageNotDefaultInComparison"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductCompareMainSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="compareGrabSimpleProduct2ImageSrcInComparison" after="compareAssertSimpleProduct2InComparison"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabSimpleProduct2ImageSrcInComparison" stepKey="compareAssertSimpleProduct2ImageNotDefaultInComparison" after="compareGrabSimpleProduct2ImageSrcInComparison"/> + + <!-- Clear comparison sidebar --> + <comment userInput="Clear comparison sidebar" stepKey="commentClearComparisonSidebar" after="compareAssertSimpleProduct2ImageNotDefaultInComparison"/> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="compareClickCategoryBeforeClear" after="commentClearComparisonSidebar"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="compareAssertCategory2" after="compareClickCategoryBeforeClear"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontClearCompareActionGroup" stepKey="compareClearCompare" after="compareAssertCategory2"/> + <comment userInput="End of Comparing Products" stepKey="endOfComparingProducts" after="compareClearCompare"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/VerifyDefaultWYSIWYGToolbarOnProductCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/VerifyDefaultWYSIWYGToolbarOnProductCest.xml index 26852d17e6440..3c396aac369e7 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/VerifyDefaultWYSIWYGToolbarOnProductCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/Test/VerifyDefaultWYSIWYGToolbarOnProductCest.xml @@ -23,7 +23,7 @@ <actionGroup ref="EnabledWYSIWYG" stepKey="enableWYSIWYG"/> <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> </before> - <amOnPage url="{{AdminProductCreatePage(AddToDefaultSet.attributeSetId, 'simple')}}" stepKey="navigateToProduct"/> + <amOnPage url="{{AdminProductCreatePage.url(AddToDefaultSet.attributeSetId, 'simple')}}" stepKey="navigateToProduct"/> <waitForPageLoad stepKey="wait"/> <scrollTo selector="{{AdminProductFormSection.productQuantity}}" stepKey="scrollToQty" /> <click selector="{{AdminProductFormSection.contentTab}}" stepKey="clickContentTab" /> @@ -62,7 +62,7 @@ <actionGroup ref="EnabledWYSIWYG" stepKey="enableWYSIWYG"/> <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> </before> - <amOnPage url="{{AdminProductCreatePage(AddToDefaultSet.attributeSetId, 'simple')}}" stepKey="navigateToProduct"/> + <amOnPage url="{{AdminProductCreatePage.url(AddToDefaultSet.attributeSetId, 'simple')}}" stepKey="navigateToProduct"/> <waitForPageLoad stepKey="wait"/> <scrollTo selector="{{AdminProductFormSection.productQuantity}}" stepKey="scrollToQty" /> <click selector="{{AdminProductFormSection.contentTab}}" stepKey="clickContentTab" /> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/composer.json index 3b9967130fe18..a4c32f5a2436e 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Catalog/composer.json @@ -11,15 +11,19 @@ "sort-packages": true }, "require": { - "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-testing-framework": "~2.0.0", + "magento/magento2-functional-test-framework": "100.0.0-dev", + "magento/magento2-functional-test-module-backend": "100.0.0-dev", + "magento/magento2-functional-test-module-checkout": "100.0.0-dev", + "magento/magento2-functional-test-module-quote": "100.0.0-dev", + "magento/magento2-functional-test-module-theme": "100.0.0-dev", + "magento/magento2-functional-test-module-ui": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { - "magento/magento2-functional-test-module-backend": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-rule": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-url-rewrite": "100.0.0-dev", - "magento/magento2-functional-test-module-checkout": "100.0.0-dev", "magento/magento2-functional-test-module-cms": "100.0.0-dev", "magento/magento2-functional-test-module-config": "100.0.0-dev", "magento/magento2-functional-test-module-customer": "100.0.0-dev", @@ -30,11 +34,8 @@ "magento/magento2-functional-test-module-msrp": "100.0.0-dev", "magento/magento2-functional-test-module-page-cache": "100.0.0-dev", "magento/magento2-functional-test-module-product-alert": "100.0.0-dev", - "magento/magento2-functional-test-module-quote": "100.0.0-dev", "magento/magento2-functional-test-module-store": "100.0.0-dev", "magento/magento2-functional-test-module-tax": "100.0.0-dev", - "magento/magento2-functional-test-module-theme": "100.0.0-dev", - "magento/magento2-functional-test-module-ui": "100.0.0-dev", "magento/magento2-functional-test-module-url-rewrite": "100.0.0-dev", "magento/magento2-functional-test-module-widget": "100.0.0-dev", "magento/magento2-functional-test-module-wishlist": "100.0.0-dev" diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/ActionGroup/StorefrontCatalogSearchActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/ActionGroup/StorefrontCatalogSearchActionGroup.xml new file mode 100644 index 0000000000000..4fdd061640f9a --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/ActionGroup/StorefrontCatalogSearchActionGroup.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Quick search the phrase and check if the result page contains correct information --> + <actionGroup name="StorefrontCheckQuickSearchActionGroup"> + <arguments> + <argument name="phrase"/> + </arguments> + <fillField userInput="{{phrase}}" selector="{{StorefrontQuickSearchSection.searchPhrase}}" stepKey="fillQuickSearch"/> + <click selector="{{StorefrontQuickSearchSection.searchButton}}" stepKey="clickQuickSearchButton" /> + <seeInCurrentUrl url="{{StorefrontCatalogSearchPage.url}}" stepKey="checkUrl"/> + <seeInTitle userInput="Search results for: '{{phrase}}'" stepKey="assertQuickSearchTitle"/> + <see userInput="Search results for: '{{phrase}}'" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertQuickSearchName"/> + </actionGroup> + + <!-- Open advanced search page --> + <actionGroup name="StorefrontOpenAdvancedSearchActionGroup"> + <click selector="{{StorefrontFooterSection.AdvancedSearch}}" stepKey="clickAdvancedSearchLink" /> + <seeInCurrentUrl url="{{StorefrontCatalogSearchAdvancedFormPage.url}}" stepKey="checkUrl"/> + <seeInTitle userInput="Advanced Search" stepKey="assertAdvancedSearchTitle"/> + <see userInput="Advanced Search" selector="{{StorefrontCatalogSearchAdvancedFormSection.SearchTitle}}" stepKey="assertAdvancedSearchTitle"/> + </actionGroup> + + <!-- Check that Advanced Search result page contains correct information --> + <actionGroup name="StorefrontCheckAdvancedSearchResultActionGroup"> + <seeInCurrentUrl url="{{StorefrontCatalogSearchAdvancedResultPage.url}}" stepKey="checkUrl"/> + <seeInTitle userInput="Advanced Search Results" stepKey="assertAdvancedSearchTitle"/> + <see userInput="Catalog Advanced Search" selector="{{StorefrontCatalogSearchMainSection.SearchTitle}}" stepKey="assertAdvancedSearchName"/> + </actionGroup> + + <!-- Select the category in the filter --> + <actionGroup name="StorefrontSelectSearchFilterCategoryActionGroup"> + <arguments> + <argument name="category"/> + </arguments> + <click selector="{{StorefrontCategoryFilterSection.CategoryFilter}}" stepKey="clickCategoryFilterTitle" /> + <scrollTo selector="{{StorefrontCategoryFilterSection.CategoryByName(category.name)}}" stepKey="scrollToClickCategoryFilter"/> + <click selector="{{StorefrontCategoryFilterSection.CategoryByName(category.name)}}" stepKey="clickCategoryFilter" /> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Data/ConstData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Data/ConstData.xml new file mode 100644 index 0000000000000..fd28b0ddc5c6c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Data/ConstData.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <!-- @TODO: Get rid off this workaround and its usages after MQE-498 is implemented --> + <entity name="CONST" type="CONST"> + <data key="apiSimpleProduct">Api Simple Product</data> + <data key="nonexistentProductName">NonexistentProductName</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Page/StorefrontCatalogSearchAdvancedFormPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Page/StorefrontCatalogSearchAdvancedFormPage.xml new file mode 100644 index 0000000000000..0fa4333ca2088 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Page/StorefrontCatalogSearchAdvancedFormPage.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="StorefrontCatalogSearchAdvancedFormPage" url="/catalogsearch/advanced/" area="storefront" module="Magento_CatalogSearch"> + <section name="StorefrontCatalogSearchAdvancedFormSection" /> + <section name="StorefrontQuickSearchSection" /> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Page/StorefrontCatalogSearchAdvancedResultPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Page/StorefrontCatalogSearchAdvancedResultPage.xml new file mode 100644 index 0000000000000..4afdbea5f9263 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Page/StorefrontCatalogSearchAdvancedResultPage.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="StorefrontCatalogSearchAdvancedResultPage" url="/catalogsearch/advanced/result" area="storefront" module="Magento_CatalogSearch"> + <section name="StorefrontCatalogSearchAdvancedResultMainSection" /> + <section name="StorefrontQuickSearchSection" /> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Page/StorefrontCatalogSearchPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Page/StorefrontCatalogSearchPage.xml new file mode 100644 index 0000000000000..bbca39348ba26 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Page/StorefrontCatalogSearchPage.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="StorefrontCatalogSearchPage" url="/catalogsearch/result/" area="storefront" module="Magento_CatalogSearch"> + <section name="StorefrontCatalogSearchMainSection" /> + <section name="StorefrontQuickSearchSection" /> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchAdvancedFormSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchAdvancedFormSection.xml new file mode 100644 index 0000000000000..30cb16d684be6 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchAdvancedFormSection.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontCatalogSearchAdvancedFormSection"> + <element name="SearchTitle" type="text" selector=".page-title span"/> + <element name="ProductName" type="input" selector="#name"/> + <element name="SKU" type="input" selector="#sku"/> + <element name="Description" type="input" selector="#description"/> + <element name="ShortDescription" type="input" selector="#short_description"/> + <element name="PriceFrom" type="input" selector="#price"/> + <element name="PriceTo" type="input" selector="#price_to"/> + <element name="AttributeByCode" type="input" selector="#{{var1}}" parameterized="true"/> + <element name="SubmitButton" type="button" selector="//*[@id='form-validate']//button[@type='submit']"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchAdvancedResultMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchAdvancedResultMainSection.xml new file mode 100644 index 0000000000000..25671dc811285 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchAdvancedResultMainSection.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontCatalogSearchAdvancedResultMainSection"> + <element name="SearchTitle" type="text" selector=".page-title span"/> + <element name="ProductItemInfo" type="button" selector=".product-item-info"/> + <element name="AddToCartBtn" type="button" selector="button.action.tocart.primary"/> + <element name="SuccessMsg" type="button" selector="div.message-success"/> + <element name="productCount" type="text" selector="#toolbar-amount"/> + <element name="message" type="text" selector="div.message div"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchMainSection.xml new file mode 100644 index 0000000000000..440cd4fe8da0b --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontCatalogSearchMainSection.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontCatalogSearchMainSection"> + <element name="SearchTitle" type="text" selector=".page-title span"/> + <element name="ProductItemInfo" type="button" selector=".product-item-info"/> + <element name="AddToCartBtn" type="button" selector="button.action.tocart.primary"/> + <element name="SuccessMsg" type="button" selector="div.message-success"/> + <element name="productCount" type="text" selector="#toolbar-amount"/> + <element name="message" type="text" selector="div.message div"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontFooterSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontFooterSection.xml new file mode 100644 index 0000000000000..97f4c35537099 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Section/StorefrontFooterSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontFooterSection"> + <element name="AdvancedSearch" type="button" selector="//footer//ul//li//a[text()='Advanced Search']"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/EndToEndB2CGuestUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/EndToEndB2CGuestUserTest.xml new file mode 100644 index 0000000000000..a5b7e520a76e4 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/EndToEndB2CGuestUserTest.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CGuestUserTest"> + <!-- Step 2: User searches for product --> + <comment userInput="Start of searching products" stepKey="startOfSearchingProducts" after="endOfBrowsingCatalog"/> + <!-- Advanced Search with Product 1 Data --> + <comment userInput="Advanced search" stepKey="commentAdvancedSearch" after="startOfSearchingProducts"/> + <actionGroup ref="StorefrontOpenAdvancedSearchActionGroup" stepKey="searchOpenAdvancedSearchForm" after="commentAdvancedSearch"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <fillField userInput="$$createSimpleProduct1.name$$" selector="{{StorefrontCatalogSearchAdvancedFormSection.ProductName}}" stepKey="searchAdvancedFillProductName" after="searchOpenAdvancedSearchForm"/> + <fillField userInput="$$createSimpleProduct1.sku$$" selector="{{StorefrontCatalogSearchAdvancedFormSection.SKU}}" stepKey="searchAdvancedFillSKU" after="searchAdvancedFillProductName"/> + <fillField userInput="$$createSimpleProduct1.price$$" selector="{{StorefrontCatalogSearchAdvancedFormSection.PriceFrom}}" stepKey="searchAdvancedFillPriceFrom" after="searchAdvancedFillSKU"/> + <fillField userInput="$$createSimpleProduct1.price$$" selector="{{StorefrontCatalogSearchAdvancedFormSection.PriceTo}}" stepKey="searchAdvancedFillPriceTo" after="searchAdvancedFillPriceFrom"/> + <click selector="{{StorefrontCatalogSearchAdvancedFormSection.SubmitButton}}" stepKey="searchClickAdvancedSearchSubmitButton" after="searchAdvancedFillPriceTo"/> + <waitForLoadingMaskToDisappear stepKey="waitForSearchProductsloaded" after="searchClickAdvancedSearchSubmitButton"/> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="searchCheckAdvancedSearchResult" after="waitForSearchProductsloaded"/> + <see userInput="1" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productCount}} span" stepKey="searchAdvancedAssertProductCount" after="searchCheckAdvancedSearchResult"/> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="searchAssertSimpleProduct1" after="searchAdvancedAssertProductCount"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="searchAdvancedGrabSimpleProduct1ImageSrc" after="searchAssertSimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$searchAdvancedGrabSimpleProduct1ImageSrc" stepKey="searchAdvancedAssertSimpleProduct1ImageNotDefault" after="searchAdvancedGrabSimpleProduct1ImageSrc"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct1.name$$)}}" stepKey="searchClickSimpleProduct1View" after="searchAdvancedAssertSimpleProduct1ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForSearchSimpleProduct1Viewloaded" after="searchClickSimpleProduct1View"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="searchAssertSimpleProduct1Page" after="waitForSearchSimpleProduct1Viewloaded"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="searchAdvancedGrabSimpleProduct1PageImageSrc" after="searchAssertSimpleProduct1Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$searchAdvancedGrabSimpleProduct1PageImageSrc" stepKey="searchAdvancedAssertSimpleProduct1PageImageNotDefault" after="searchAdvancedGrabSimpleProduct1PageImageSrc"/> + + <!-- Quick Search with common part of product names --> + <comment userInput="Quick search" stepKey="commentQuickSearch" after="searchAdvancedAssertSimpleProduct1PageImageNotDefault"/> + <actionGroup ref="StorefrontCheckQuickSearchActionGroup" stepKey="searchQuickSearchCommonPart" after="commentQuickSearch"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="phrase" value="CONST.apiSimpleProduct"/> + </actionGroup> + <actionGroup ref="StorefrontSelectSearchFilterCategoryActionGroup" stepKey="searchSelectFilterCategoryCommonPart" after="searchQuickSearchCommonPart"> + <argument name="category" value="$$createCategory$$"/> + </actionGroup> + <see userInput="3" selector="{{StorefrontCategoryMainSection.productCount}} span" stepKey="searchAssertFilterCategoryProductCountCommonPart" after="searchSelectFilterCategoryCommonPart"/> + + <!-- Search simple product 1 --> + <comment userInput="Search simple product 1" stepKey="commentSearchSimpleProduct1" after="searchAssertFilterCategoryProductCountCommonPart"/> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="searchAssertFilterCategorySimpleProduct1" after="commentSearchSimpleProduct1"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="searchGrabSimpleProduct1ImageSrc" after="searchAssertFilterCategorySimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$searchGrabSimpleProduct1ImageSrc" stepKey="searchAssertSimpleProduct1ImageNotDefault" after="searchGrabSimpleProduct1ImageSrc"/> + <!-- Search simple product2 --> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="searchAssertFilterCategorySimpleProduct2" after="searchAssertSimpleProduct1ImageNotDefault"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="searchGrabSimpleProduct2ImageSrc" after="searchAssertFilterCategorySimpleProduct2"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$searchGrabSimpleProduct2ImageSrc" stepKey="searchAssertSimpleProduct2ImageNotDefault" after="searchGrabSimpleProduct2ImageSrc"/> + + <!-- Quick Search with non-existent product name --> + <comment userInput="Quick Search with non-existent product name" stepKey="commentQuickSearchWithNonExistentProductName" after="searchAssertSimpleProduct2ImageNotDefault" /> + <actionGroup ref="StorefrontCheckQuickSearchActionGroup" stepKey="searchFillQuickSearchNonExistent" after="commentQuickSearchWithNonExistentProductName"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="phrase" value="CONST.nonexistentProductName"/> + </actionGroup> + <see userInput="Your search returned no results." selector="{{StorefrontCatalogSearchMainSection.message}}" stepKey="searchAssertQuickSearchMessageNonExistent" after="searchFillQuickSearchNonExistent"/> + <comment userInput="End of searching products" stepKey="endOfSearchingProducts" after="searchAssertQuickSearchMessageNonExistent" /> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/EndToEndB2CLoggedInUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/EndToEndB2CLoggedInUserTest.xml new file mode 100644 index 0000000000000..cb84e46ebf54c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/Test/EndToEndB2CLoggedInUserTest.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CLoggedInUserTest"> + <!-- Step 2: User searches for product --> + <comment userInput="Start of searching products" stepKey="startOfSearchingProducts" after="endOfBrowsingCatalog"/> + <!-- Advanced Search with Product 1 Data --> + <comment userInput="Advanced search" stepKey="commentAdvancedSearch" after="startOfSearchingProducts"/> + <actionGroup ref="StorefrontOpenAdvancedSearchActionGroup" stepKey="searchOpenAdvancedSearchForm" after="commentAdvancedSearch"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <fillField userInput="$$createSimpleProduct1.name$$" selector="{{StorefrontCatalogSearchAdvancedFormSection.ProductName}}" stepKey="searchAdvancedFillProductName" after="searchOpenAdvancedSearchForm"/> + <fillField userInput="$$createSimpleProduct1.sku$$" selector="{{StorefrontCatalogSearchAdvancedFormSection.SKU}}" stepKey="searchAdvancedFillSKU" after="searchAdvancedFillProductName"/> + <fillField userInput="$$createSimpleProduct1.price$$" selector="{{StorefrontCatalogSearchAdvancedFormSection.PriceFrom}}" stepKey="searchAdvancedFillPriceFrom" after="searchAdvancedFillSKU"/> + <fillField userInput="$$createSimpleProduct1.price$$" selector="{{StorefrontCatalogSearchAdvancedFormSection.PriceTo}}" stepKey="searchAdvancedFillPriceTo" after="searchAdvancedFillPriceFrom"/> + <click selector="{{StorefrontCatalogSearchAdvancedFormSection.SubmitButton}}" stepKey="searchClickAdvancedSearchSubmitButton" after="searchAdvancedFillPriceTo"/> + <waitForLoadingMaskToDisappear stepKey="waitForSearchProductsloaded" after="searchClickAdvancedSearchSubmitButton"/> + <actionGroup ref="StorefrontCheckAdvancedSearchResultActionGroup" stepKey="searchCheckAdvancedSearchResult" after="waitForSearchProductsloaded"/> + <see userInput="1" selector="{{StorefrontCatalogSearchAdvancedResultMainSection.productCount}} span" stepKey="searchAdvancedAssertProductCount" after="searchCheckAdvancedSearchResult"/> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="searchAssertSimpleProduct1" after="searchAdvancedAssertProductCount"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="searchAdvancedGrabSimpleProduct1ImageSrc" after="searchAssertSimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$searchAdvancedGrabSimpleProduct1ImageSrc" stepKey="searchAdvancedAssertSimpleProduct1ImageNotDefault" after="searchAdvancedGrabSimpleProduct1ImageSrc"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct1.name$$)}}" stepKey="searchClickSimpleProduct1View" after="searchAdvancedAssertSimpleProduct1ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForSearchSimpleProduct1Viewloaded" after="searchClickSimpleProduct1View"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="searchAssertSimpleProduct1Page" after="waitForSearchSimpleProduct1Viewloaded"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="searchAdvancedGrabSimpleProduct1PageImageSrc" after="searchAssertSimpleProduct1Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$searchAdvancedGrabSimpleProduct1PageImageSrc" stepKey="searchAdvancedAssertSimpleProduct1PageImageNotDefault" after="searchAdvancedGrabSimpleProduct1PageImageSrc"/> + + <!-- Quick Search with common part of product names --> + <comment userInput="Quick search" stepKey="commentQuickSearch" after="searchAdvancedAssertSimpleProduct1PageImageNotDefault"/> + <actionGroup ref="StorefrontCheckQuickSearchActionGroup" stepKey="searchQuickSearchCommonPart" after="commentQuickSearch"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="phrase" value="CONST.apiSimpleProduct"/> + </actionGroup> + <actionGroup ref="StorefrontSelectSearchFilterCategoryActionGroup" stepKey="searchSelectFilterCategoryCommonPart" after="searchQuickSearchCommonPart"> + <argument name="category" value="$$createCategory$$"/> + </actionGroup> + <see userInput="3" selector="{{StorefrontCategoryMainSection.productCount}} span" stepKey="searchAssertFilterCategoryProductCountCommonPart" after="searchSelectFilterCategoryCommonPart"/> + + <!-- Search simple product 1 --> + <comment userInput="Search simple product 1" stepKey="commentSearchSimpleProduct1" after="searchAssertFilterCategoryProductCountCommonPart"/> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="searchAssertFilterCategorySimpleProduct1" after="commentSearchSimpleProduct1"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="searchGrabSimpleProduct1ImageSrc" after="searchAssertFilterCategorySimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$searchGrabSimpleProduct1ImageSrc" stepKey="searchAssertSimpleProduct1ImageNotDefault" after="searchGrabSimpleProduct1ImageSrc"/> + <!-- Search simple product2 --> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="searchAssertFilterCategorySimpleProduct2" after="searchAssertSimpleProduct1ImageNotDefault"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="searchGrabSimpleProduct2ImageSrc" after="searchAssertFilterCategorySimpleProduct2"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$searchGrabSimpleProduct2ImageSrc" stepKey="searchAssertSimpleProduct2ImageNotDefault" after="searchGrabSimpleProduct2ImageSrc"/> + + <!-- Quick Search with non-existent product name --> + <comment userInput="Quick Search with non-existent product name" stepKey="commentQuickSearchWithNonExistentProductName" after="searchAssertSimpleProduct2ImageNotDefault" /> + <actionGroup ref="StorefrontCheckQuickSearchActionGroup" stepKey="searchFillQuickSearchNonExistent" after="commentQuickSearchWithNonExistentProductName"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="phrase" value="CONST.nonexistentProductName"/> + </actionGroup> + <see userInput="Your search returned no results." selector="{{StorefrontCatalogSearchMainSection.message}}" stepKey="searchAssertQuickSearchMessageNonExistent" after="searchFillQuickSearchNonExistent"/> + <comment userInput="End of searching products" stepKey="endOfSearchingProducts" after="searchAssertQuickSearchMessageNonExistent" /> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/composer.json index 50e466e1185ca..132dbba8f8365 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/CatalogSearch/composer.json @@ -12,19 +12,19 @@ }, "require": { "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", + "magento/magento2-functional-test-module-search": "100.0.0-dev", + "magento/magento2-functional-test-module-theme": "100.0.0-dev", + "magento/magento2-functional-test-module-ui": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", "magento/magento2-functional-test-module-customer": "100.0.0-dev", "magento/magento2-functional-test-module-directory": "100.0.0-dev", "magento/magento2-functional-test-module-eav": "100.0.0-dev", - "magento/magento2-functional-test-module-search": "100.0.0-dev", - "magento/magento2-functional-test-module-store": "100.0.0-dev", - "magento/magento2-functional-test-module-theme": "100.0.0-dev", - "magento/magento2-functional-test-module-ui": "100.0.0-dev" + "magento/magento2-functional-test-module-store": "100.0.0-dev" }, "autoload": { "psr-4": { diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/ActionGroup/CheckoutActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/ActionGroup/CheckoutActionGroup.xml new file mode 100644 index 0000000000000..c5b4463003bc7 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/ActionGroup/CheckoutActionGroup.xml @@ -0,0 +1,147 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Go to checkout from minicart --> + <actionGroup name="GoToCheckoutFromMinicartActionGroup"> + <wait stepKey="wait" time="10" /> + <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickCart"/> + <click selector="{{StorefrontMinicartSection.goToCheckout}}" stepKey="goToCheckout"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + </actionGroup> + + <!-- Guest checkout filling shipping section --> + <actionGroup name="GuestCheckoutFillingShippingSectionActionGroup"> + <arguments> + <argument name="customerVar"/> + <argument name="customerAddressVar"/> + </arguments> + <fillField selector="{{CheckoutShippingSection.email}}" userInput="{{customerVar.email}}" stepKey="enterEmail"/> + <fillField selector="{{CheckoutShippingSection.firstName}}" userInput="{{customerVar.firstname}}" stepKey="enterFirstName"/> + <fillField selector="{{CheckoutShippingSection.lastName}}" userInput="{{customerVar.lastname}}" stepKey="enterLastName"/> + <fillField selector="{{CheckoutShippingSection.street}}" userInput="{{customerAddressVar.street[0]}}" stepKey="enterStreet"/> + <fillField selector="{{CheckoutShippingSection.city}}" userInput="{{customerAddressVar.city}}" stepKey="enterCity"/> + <selectOption selector="{{CheckoutShippingSection.region}}" userInput="{{customerAddressVar.state}}" stepKey="selectRegion"/> + <fillField selector="{{CheckoutShippingSection.postcode}}" userInput="{{customerAddressVar.postcode}}" stepKey="enterPostcode"/> + <fillField selector="{{CheckoutShippingSection.telephone}}" userInput="{{customerAddressVar.telephone}}" stepKey="enterTelephone"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> + <click selector="{{CheckoutShippingSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> + <waitForElement selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> + <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <seeInCurrentUrl url="{{CheckoutPage.url}}/#payment" stepKey="assertCheckoutPaymentUrl"/> + </actionGroup> + + <!-- Logged in user checkout filling shipping section --> + <actionGroup name="LoggedInUserCheckoutFillingShippingSectionActionGroup"> + <arguments> + <argument name="customerVar"/> + <argument name="customerAddressVar"/> + </arguments> + <fillField selector="{{CheckoutShippingSection.firstName}}" userInput="{{customerVar.firstname}}" stepKey="enterFirstName"/> + <fillField selector="{{CheckoutShippingSection.lastName}}" userInput="{{customerVar.lastname}}" stepKey="enterLastName"/> + <fillField selector="{{CheckoutShippingSection.street}}" userInput="{{customerAddressVar.street[0]}}" stepKey="enterStreet"/> + <fillField selector="{{CheckoutShippingSection.city}}" userInput="{{customerAddressVar.city}}" stepKey="enterCity"/> + <selectOption selector="{{CheckoutShippingSection.region}}" userInput="{{customerAddressVar.state}}" stepKey="selectRegion"/> + <fillField selector="{{CheckoutShippingSection.postcode}}" userInput="{{customerAddressVar.postcode}}" stepKey="enterPostcode"/> + <fillField selector="{{CheckoutShippingSection.telephone}}" userInput="{{customerAddressVar.telephone}}" stepKey="enterTelephone"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> + <click selector="{{CheckoutShippingSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> + <waitForElement selector="{{CheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> + <click selector="{{CheckoutShippingSection.next}}" stepKey="clickNext"/> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <seeInCurrentUrl url="{{CheckoutPage.url}}/#payment" stepKey="assertCheckoutPaymentUrl"/> + </actionGroup> + + <!-- Check product in checkout cart items --> + <actionGroup name="CheckProductInCheckoutCartItemsActionGroup"> + <arguments> + <argument name="productVar"/> + </arguments> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <conditionalClick selector="{{CheckoutPaymentSection.cartItemsArea}}" dependentSelector="{{CheckoutPaymentSection.cartItemsArea}}" visible="true" stepKey="exposeMiniCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskForCartItem"/> + <waitForElement selector="{{CheckoutPaymentSection.cartItemsAreaActive}}" time="30" stepKey="waitForCartItemsAreaActive"/> + <see selector="{{CheckoutPaymentSection.cartItems}}" userInput="{{productVar.name}}" stepKey="seeProductInCart"/> + </actionGroup> + + <!-- Check order summary in checkout --> + <actionGroup name="CheckOrderSummaryInCheckoutActionGroup"> + <arguments> + <argument name="subtotal"/> + <argument name="shippingTotal"/> + <argument name="shippingMethod"/> + <argument name="total"/> + </arguments> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <see userInput="${{subtotal}}" selector="{{CheckoutPaymentSection.orderSummarySubtotal}}" stepKey="assertSubtotal"/> + <see userInput="${{shippingTotal}}" selector="{{CheckoutPaymentSection.orderSummaryShippingTotal}}" stepKey="assertShipping"/> + <see userInput="{{shippingMethod}}" selector="{{CheckoutPaymentSection.orderSummaryShippingMethod}}" stepKey="assertShippingMethod"/> + <see userInput="${{total}}" selector="{{CheckoutPaymentSection.orderSummaryTotal}}" stepKey="assertTotal"/> + </actionGroup> + + <!-- Check ship to information in checkout --> + <actionGroup name="CheckShipToInformationInCheckoutActionGroup"> + <arguments> + <argument name="customerVar"/> + <argument name="customerAddressVar"/> + </arguments> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <see userInput="{{customerVar.firstname}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationFirstName"/> + <see userInput="{{customerVar.lastname}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationLastName"/> + <see userInput="{{customerAddressVar.street[0]}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationStreet"/> + <see userInput="{{customerAddressVar.city}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationCity"/> + <see userInput="{{customerAddressVar.state}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationState"/> + <see userInput="{{customerAddressVar.postcode}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationPostcode"/> + <see userInput="{{customerAddressVar.telephone}}" selector="{{CheckoutPaymentSection.shipToInfomation}}" stepKey="assertShipToInformationTelephone"/> + </actionGroup> + + <!-- Check shipping method in checkout --> + <actionGroup name="CheckShippingMethodInCheckoutActionGroup"> + <arguments> + <argument name="shippingMethod"/> + </arguments> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <see userInput="{{shippingMethod}}" selector="{{CheckoutPaymentSection.shippingMethodInfomation}}" stepKey="assertshippingMethodInfomation"/> + </actionGroup> + + <!-- Checkout select Check/Money Order payment --> + <actionGroup name="CheckoutSelectCheckMoneyOrderPaymentActionGroup"> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <conditionalClick selector="{{CheckoutPaymentSection.checkMoneyOrderPayment}}" dependentSelector="{{CheckoutPaymentSection.billingAddress}}" visible="false" stepKey="clickCheckMoneyOrderPayment" /> + </actionGroup> + + <!-- Check billing address in checkout --> + <actionGroup name="CheckBillingAddressInCheckoutActionGroup"> + <arguments> + <argument name="customerVar"/> + <argument name="customerAddressVar"/> + </arguments> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <see userInput="{{customerVar.firstName}}" selector="{{CheckoutPaymentSection.billingAddress}}" stepKey="assertBillingAddressFirstName"/> + <see userInput="{{customerVar.lastName}}" selector="{{CheckoutPaymentSection.billingAddress}}" stepKey="assertBillingAddressLastName"/> + <see userInput="{{customerAddressVar.street[0]}}" selector="{{CheckoutPaymentSection.billingAddress}}" stepKey="assertBillingAddressStreet"/> + <see userInput="{{customerAddressVar.city}}" selector="{{CheckoutPaymentSection.billingAddress}}" stepKey="assertBillingAddressCity"/> + <see userInput="{{customerAddressVar.state}}" selector="{{CheckoutPaymentSection.billingAddress}}" stepKey="assertBillingAddressState"/> + <see userInput="{{customerAddressVar.postcode}}" selector="{{CheckoutPaymentSection.billingAddress}}" stepKey="assertBillingAddressPostcode"/> + <see userInput="{{customerAddressVar.telephone}}" selector="{{CheckoutPaymentSection.billingAddress}}" stepKey="assertBillingAddressTelephone"/> + </actionGroup> + + <!-- Checkout place order --> + <actionGroup name="CheckoutPlaceOrderActionGroup"> + <arguments> + <argument name="orderNumberMessage"/> + <argument name="emailYouMessage"/> + </arguments> + <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> + <see selector="{{CheckoutSuccessMainSection.success}}" userInput="{{orderNumberMessage}}" stepKey="seeOrderNumber"/> + <see selector="{{CheckoutSuccessMainSection.success}}" userInput="{{emailYouMessage}}" stepKey="seeEmailYou"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/ActionGroup/StorefrontMiniCartActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/ActionGroup/StorefrontMiniCartActionGroup.xml new file mode 100644 index 0000000000000..9e7c0e082036f --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/ActionGroup/StorefrontMiniCartActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="clickViewAndEditCartFromMiniCart"> + <conditionalClick selector="{{StorefrontMinicartSection.showCart}}" dependentSelector="{{StorefrontMinicartSection.miniCartOpened}}" visible="false" stepKey="openMiniCart"/> + <waitForElementVisible selector="{{StorefrontMinicartSection.viewAndEditCart}}" stepKey="waitForViewAndEditCartVisible"/> + <click selector="{{StorefrontMinicartSection.viewAndEditCart}}" stepKey="viewAndEditCart"/> + <seeInCurrentUrl url="checkout/cart" stepKey="seeInCurrentUrl"/> + </actionGroup> + <actionGroup name="assertOneProductNameInMiniCart"> + <arguments> + <argument name="productName"/> + </arguments> + <conditionalClick selector="{{StorefrontMinicartSection.showCart}}" dependentSelector="{{StorefrontMinicartSection.miniCartOpened}}" visible="false" stepKey="openMiniCart"/> + <waitForElementVisible selector="{{StorefrontMinicartSection.viewAndEditCart}}" stepKey="waitForViewAndEditCartVisible"/> + <see selector="{{StorefrontMinicartSection.miniCartItemsText}}" userInput="{{productName}}" stepKey="seeInMiniCart"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/ActionGroup/StorefrontProductCartActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/ActionGroup/StorefrontProductCartActionGroup.xml new file mode 100644 index 0000000000000..945e70fa62417 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/ActionGroup/StorefrontProductCartActionGroup.xml @@ -0,0 +1,80 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Add Product to Cart from the category page and check message and product count in Minicart --> + <actionGroup name="StorefrontAddCategoryProductToCartActionGroup"> + <arguments> + <argument name="product"/> + <argument name="productCount"/> + </arguments> + <moveMouseOver selector="{{StorefrontCategoryProductSection.ProductInfoByName(product.name)}}" stepKey="moveMouseOverProduct" /> + <click selector="{{StorefrontCategoryProductSection.ProductAddToCartByName(product.name)}}" stepKey="clickAddToCart" /> + <!-- @TODO: Use general message selector after MQE-694 is fixed --> + <waitForElement selector="{{StorefrontMessagesSection.messageProductAddedToCart(product.name)}}" time="30" stepKey="assertMessage"/> + <waitForText userInput="{{productCount}}" selector="{{StorefrontMinicartSection.productCount}}" time="30" stepKey="assertProductCount"/> + </actionGroup> + + <!-- Add Product to Cart from the product page and check message and product count in Minicart --> + <actionGroup name="StorefrontAddProductToCartActionGroup"> + <arguments> + <argument name="product"/> + <argument name="productCount"/> + </arguments> + <click selector="{{StorefrontProductInfoMainSection.AddToCart}}" stepKey="clickAddToCart" /> + <!-- @TODO: Use general message selector after MQE-694 is fixed --> + <waitForElement selector="{{StorefrontMessagesSection.messageProductAddedToCart(product.name)}}" time="30" stepKey="assertMessage"/> + <waitForText userInput="{{productCount}}" selector="{{StorefrontMinicartSection.productCount}}" time="30" stepKey="assertProductCount"/> + </actionGroup> + + <!-- Open the Minicart and check Simple Product --> + <actionGroup name="StorefrontOpenMinicartAndCheckSimpleProductActionGroup"> + <arguments> + <argument name="product"/> + </arguments> + <waitForElement selector="{{StorefrontMinicartSection.productLinkByName(product.name)}}" stepKey="waitForMinicartProduct" /> + <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickShowMinicart" /> + <see userInput="${{product.price}}.00" selector="{{StorefrontMinicartSection.productPriceByName(product.name)}}" stepKey="assertProductPrice"/> + </actionGroup> + + <!-- Check Simple Product in the Cart --> + <actionGroup name="StorefrontCheckCartSimpleProductActionGroup"> + <arguments> + <argument name="product"/> + <argument name="productQuantity"/> + </arguments> + <seeElement selector="{{CheckoutCartProductSection.ProductLinkByName(product.name)}}" stepKey="assertProductName"/> + <see userInput="${{product.price}}.00" selector="{{CheckoutCartProductSection.ProductPriceByName(product.name)}}" stepKey="assertProductPrice"/> + <seeInField userInput="{{productQuantity}}" selector="{{CheckoutCartProductSection.ProductQuantityByName(product.name)}}" stepKey="assertProductQuantity"/> + </actionGroup> + + <!-- Check the Cart --> + <actionGroup name="StorefrontCheckCartActionGroup"> + <arguments> + <argument name="subtotal"/> + <argument name="shipping"/> + <argument name="shippingMethod"/> + <argument name="total"/> + </arguments> + <seeInCurrentUrl url="{{CheckoutCartPage.url}}" stepKey="assertUrl"/> + <waitForText userInput="${{total}}" selector="{{CheckoutCartSummarySection.total}}" time="30" stepKey="waitForTotal"/> + <see userInput="${{subtotal}}" selector="{{CheckoutCartSummarySection.subtotal}}" stepKey="assertSubtotal"/> + <see userInput="${{shipping}}" selector="{{CheckoutCartSummarySection.shipping}}" stepKey="assertShipping"/> + <see userInput="({{shippingMethod}})" selector="{{CheckoutCartSummarySection.shippingMethod}}" stepKey="assertShippingMethod"/> + <see userInput="${{total}}" selector="{{CheckoutCartSummarySection.total}}" stepKey="assertTotal"/> + </actionGroup> + + <!-- Open the Cart from Minicart--> + <actionGroup name="StorefrontOpenCartFromMinicartActionGroup"> + <waitForElement selector="{{StorefrontMinicartSection.showCart}}" stepKey="waitForShowMinicart" /> + <waitForElement selector="{{StorefrontMinicartSection.viewAndEditCart}}" stepKey="waitForCartLink" /> + <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickShowMinicart" /> + <click selector="{{StorefrontMinicartSection.viewAndEditCart}}" stepKey="clickCart" /> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Data/ConstData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Data/ConstData.xml new file mode 100644 index 0000000000000..10bc4fd90e7f9 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Data/ConstData.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <!-- @TODO: Get rid off this workaround and its usages after MQE-498 is implemented --> + <entity name="CONST" type="CONST"> + <data key="successGuestCheckoutOrderNumberMessage">Your order # is:</data> + <data key="successCheckoutOrderNumberMessage">Your order number is:</data> + <data key="successCheckoutEmailYouMessage">We'll email you an order confirmation with details and tracking info.</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Data/CouponData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Data/CouponData.xml deleted file mode 100644 index 2acdc14e51cc1..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Data/CouponData.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="_defaultCoupon" type="coupon"> - <data key="rule_id">4</data> - <data key="code">FREESHIPPING123</data> - <data key="times_used">0</data> - <data key="is_primary">false</data> - </entity> -</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Data/QuoteData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Data/QuoteData.xml new file mode 100644 index 0000000000000..d3c7507390973 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Data/QuoteData.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <!-- @TODO: Get rid off this workaround and its usages after MQE-498 is implemented --> + <entity name="E2EB2CQuote" type="Quote"> + <data key="subtotal">480.00</data> + <data key="shipping">15.00</data> + <data key="total">495.00</data> + <data key="shippingMethod">Flat Rate - Fixed</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Metadata/coupon-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Metadata/coupon-meta.xml deleted file mode 100644 index 458be017a8fcc..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Metadata/coupon-meta.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> - <operation name="CreateCoupon" dataType="coupon" type="create" auth="adminOauth" url="/rest/V1/coupons" method="POST"> - <contentType>application/json</contentType> - <object key="coupon" dataType="coupon"> - <field key="rule_id" required="true">integer</field> - <field key="times_used" required="true">integer</field> - <field key="is_primary" required="true">boolean</field> - <field key="code">string</field> - <field key="usage_limit">integer</field> - <field key="usage_per_customer">integer</field> - <field key="expiration_date">string</field> - <field key="created_at">string</field> - <field key="type">integer</field> - <field key="extension_attributes">empty_extension_attribute</field> - </object> - </operation> - - <operation name="DeleteCoupon" dataType="coupon" type="delete" auth="adminOauth" url="/rest/V1/coupons/{coupon_id}" method="DELETE"> - <contentType>application/json</contentType> - </operation> -</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Page/CheckoutCartPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Page/CheckoutCartPage.xml new file mode 100644 index 0000000000000..0979c6470399b --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Page/CheckoutCartPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="CheckoutCartPage" url="/checkout/cart" module="Checkout" area="storefront"> + <section name="CheckoutCartProductSection"/> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Page/CheckoutPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Page/CheckoutPage.xml index 63c669c76af29..69bb6bf57833c 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Page/CheckoutPage.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Page/CheckoutPage.xml @@ -14,6 +14,5 @@ <section name="CheckoutOrderSummarySection"/> <section name="CheckoutSuccessMainSection"/> <section name="CheckoutPaymentSection"/> - <section name="CheckoutGuestShippingInfoSection"/> </page> </pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Page/GuestCheckoutPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Page/GuestCheckoutPage.xml deleted file mode 100644 index 2e1cc6ce6e79e..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Page/GuestCheckoutPage.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="GuestCheckoutPage" url="/checkout" area="storefront" module="Checkout"> - <section name="GuestCheckoutShippingSection"/> - <section name="GuestCheckoutPaymentSection"/> - </page> -</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutCartProductSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutCartProductSection.xml new file mode 100644 index 0000000000000..6e4f52f689eb4 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutCartProductSection.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="CheckoutCartProductSection"> + <element name="ProductLinkByName" type="button" + selector="//main//table[@id='shopping-cart-table']//tbody//tr//strong[contains(@class, 'product-item-name')]//a[contains(text(), '{{var1}}')]" + parameterized="true"/> + <element name="ProductPriceByName" type="text" + selector="//main//table[@id='shopping-cart-table']//tbody//tr[..//strong[contains(@class, 'product-item-name')]//a/text()='{{var1}}'][1]//td[contains(@class, 'price')]//span[@class='price']" + parameterized="true"/> + <element name="ProductImageByName" type="text" + selector="//main//table[@id='shopping-cart-table']//tbody//tr//img[contains(@class, 'product-image-photo') and @alt='{{var1}}']" + parameterized="true"/> + <element name="ProductQuantityByName" type="input" + selector="//main//table[@id='shopping-cart-table']//tbody//tr[..//strong[contains(@class, 'product-item-name')]//a/text()='{{var1}}'][1]//td[contains(@class, 'qty')]//input[contains(@class, 'qty')]" + parameterized="true"/> + <element name="ProductOptionByNameAndAttribute" type="input" + selector="//main//table[@id='shopping-cart-table']//tbody//tr[.//strong[contains(@class, 'product-item-name')]//a[contains(text(), '{{var1}}')]]//dl[@class='item-options']//dt[.='{{var2}}']/following-sibling::dd[1]" + parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutCartSummarySection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutCartSummarySection.xml new file mode 100644 index 0000000000000..b309736564523 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutCartSummarySection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="CheckoutCartSummarySection"> + <element name="subtotal" type="text" selector="//*[@id='cart-totals']//tr[@class='totals sub']//td//span[@class='price']"/> + <element name="shippingMethod" type="text" selector="//*[@id='cart-totals']//tr[@class='totals shipping excl']//th//span[@class='value']"/> + <element name="shipping" type="text" selector="//*[@id='cart-totals']//tr[@class='totals shipping excl']//td//span[@class='price']"/> + <element name="total" type="text" selector="//*[@id='cart-totals']//tr[@class='grand totals']//td//span[@class='price']"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutPaymentSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutPaymentSection.xml index f9a582b2f8ff4..b0e3af6b0244c 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutPaymentSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutPaymentSection.xml @@ -9,8 +9,21 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="CheckoutPaymentSection"> - <element name="cartItems" type="text" selector=".minicart-items"/> <element name="billingAddress" type="text" selector="div.billing-address-details"/> + <element name="cartItems" type="text" selector="ol.minicart-items"/> + <element name="cartItemsArea" type="button" selector="div.block.items-in-cart"/> + <element name="cartItemsAreaActive" type="textarea" selector="div.block.items-in-cart.active"/> + <element name="checkMoneyOrderPayment" type="radio" selector="input#checkmo.radio" timeout="30"/> <element name="placeOrder" type="button" selector="button.action.primary.checkout" timeout="30"/> + <element name="paymentSectionTitle" type="text" selector="//*[@id='checkout-payment-method-load']//div[text()='Payment Method']" /> + <element name="orderSummarySubtotal" type="text" selector="//tr[@class='totals sub']//span[@class='price']" /> + <element name="orderSummaryShippingTotal" type="text" selector="//tr[@class='totals shipping excl']//span[@class='price']" /> + <element name="orderSummaryShippingMethod" type="text" selector="//tr[@class='totals shipping excl']//span[@class='value']" /> + <element name="orderSummaryTotal" type="text" selector="//tr[@class='grand totals']//span[@class='price']" /> + <element name="ProductItemByName" type="text" selector="//div[@class='product-item-details']//strong[@class='product-item-name'][text()='{{var1}}']" parameterized="true" /> + <element name="ProductOptionsByProductItemName" type="text" selector="//div[@class='product-item-details']//strong[@class='product-item-name'][text()='{{var1}}']//ancestor::div[@class='product-item-details']//div[@class='product options']" parameterized="true" /> + <element name="ProductOptionsActiveByProductItemName" type="text" selector="//div[@class='product-item-details']//strong[@class='product-item-name'][text()='{{var1}}']//ancestor::div[@class='product-item-details']//div[@class='product options active']" parameterized="true" /> + <element name="shipToInfomation" type="text" selector="//div[@class='ship-to']//div[@class='shipping-information-content']" /> + <element name="shippingMethodInfomation" type="text" selector="//div[@class='ship-via']//div[@class='shipping-information-content']" /> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutShippingMethodsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutShippingMethodsSection.xml index 3a95a18023375..c6023a05937e7 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutShippingMethodsSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutShippingMethodsSection.xml @@ -10,6 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="CheckoutShippingMethodsSection"> <element name="next" type="button" selector="button.button.action.continue.primary"/> - <element name="firstShippingMethod" type="radio" selector=".row:nth-of-type(1) .col-method .radio"/> + <element name="firstShippingMethod" type="radio" selector="//*[@id='checkout-shipping-method-load']//input[@class='radio']"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutShippingSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutShippingSection.xml index 14a633ec4020d..780353a8a17c7 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutShippingSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/CheckoutShippingSection.xml @@ -11,5 +11,15 @@ <section name="CheckoutShippingSection"> <element name="selectedShippingAddress" type="text" selector=".shipping-address-item.selected-item"/> <element name="newAddressButton" type="button" selector="#checkout-step-shipping button"/> + <element name="email" type="input" selector="#customer-email"/> + <element name="firstName" type="input" selector="input[name=firstname]"/> + <element name="lastName" type="input" selector="input[name=lastname]"/> + <element name="street" type="input" selector="input[name='street[0]']"/> + <element name="city" type="input" selector="input[name=city]"/> + <element name="region" type="select" selector="select[name=region_id]"/> + <element name="postcode" type="input" selector="input[name=postcode]"/> + <element name="telephone" type="input" selector="input[name=telephone]"/> + <element name="next" type="button" selector="button.button.action.continue.primary"/> + <element name="firstShippingMethod" type="radio" selector="//*[@id='checkout-shipping-method-load']//input[@class='radio']"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/GuestCheckoutPaymentSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/GuestCheckoutPaymentSection.xml deleted file mode 100644 index 04693458c3751..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/GuestCheckoutPaymentSection.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="GuestCheckoutPaymentSection"> - <element name="cartItemsArea" type="textarea" selector=".items-in-cart"/> - <element name="cartItemsAreaActive" type="textarea" selector="div.block.items-in-cart.active"/> - <element name="cartItems" type="text" selector=".minicart-items"/> - <element name="billingAddress" type="text" selector="div.billing-address-details"/> - <element name="placeOrder" type="button" selector="button.action.primary.checkout" timeout="30"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/GuestCheckoutShippingSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/GuestCheckoutShippingSection.xml deleted file mode 100644 index 0af05846f4b54..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/GuestCheckoutShippingSection.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="GuestCheckoutShippingSection"> - <element name="email" type="input" selector="#customer-email"/> - <element name="firstName" type="input" selector="input[name=firstname]"/> - <element name="lastName" type="input" selector="input[name=lastname]"/> - <element name="street" type="input" selector="input[name='street[0]']"/> - <element name="city" type="input" selector="input[name=city]"/> - <element name="region" type="select" selector="select[name=region_id]"/> - <element name="postcode" type="input" selector="input[name=postcode]"/> - <element name="telephone" type="input" selector="input[name=telephone]"/> - <element name="next" type="button" selector="button.button.action.continue.primary"/> - <element name="firstShippingMethod" type="radio" selector=".row:nth-of-type(1) .col-method .radio"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontCategoryProductSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontCategoryProductSection.xml new file mode 100644 index 0000000000000..a23caf141fc07 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontCategoryProductSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontCategoryProductSection"> + <element name="ProductAddToCartByNumber" type="button" selector="//main//li[{{var1}}]//button[contains(@class, 'tocart')]" parameterized="true"/> + <element name="ProductAddToCartByName" type="button" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//button[contains(@class, 'tocart')]" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontMessagesSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontMessagesSection.xml new file mode 100644 index 0000000000000..d6f260ecaaac3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontMessagesSection.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontMessagesSection"> + <!-- @TODO: Use general message selector after MQE-694 is fixed --> + <element name="messageProductAddedToCart" type="text" + selector="//main//div[contains(@class, 'messages')]//div[contains(@class, 'message')]/div[contains(text(), 'You added {{var1}} to your shopping cart.')]" + parameterized="true" + /> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontMiniCartSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontMiniCartSection.xml new file mode 100644 index 0000000000000..8f21770491f58 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontMiniCartSection.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontMinicartSection"> + <element name="productCount" type="text" selector="//header//div[contains(@class, 'minicart-wrapper')]//a[contains(@class, 'showcart')]//span[@class='counter-number']"/> + <element name="viewAndEditCart" type="button" selector="//header//div[contains(@class, 'minicart-wrapper')]//a[contains(@class, 'viewcart')]"/> + <element name="productLinkByName" type="button" selector="//header//ol[@id='mini-cart']//div[@class='product-item-details']//a[contains(text(), '{{var1}}')]" parameterized="true"/> + <element name="productPriceByName" type="text" selector="//header//ol[@id='mini-cart']//div[@class='product-item-details'][.//a[contains(text(), '{{var1}}')]]//span[@class='price']" parameterized="true"/> + <element name="productImageByName" type="text" selector="//header//ol[@id='mini-cart']//span[@class='product-image-container']//img[@alt='{{var1}}']" parameterized="true"/> + <element name="productOptionsDetailsByName" type="button" selector="//header//ol[@id='mini-cart']//div[@class='product-item-details'][.//a[contains(text(), '{{var1}}')]]//span[.='See Details']" parameterized="true"/> + <element name="productOptionByNameAndAttribute" type="text" selector="//header//ol[@id='mini-cart']//div[@class='product-item-details'][.//a[contains(text(), '{{var1}}')]]//dt[@class='label' and .='{{var2}}']/following-sibling::dd[@class='values']//span" parameterized="true"/> + <element name="showCart" type="button" selector="a.showcart"/> + <element name="quantity" type="button" selector="span.counter-number"/> + <element name="miniCartOpened" type="button" selector="a.showcart.active"/> + <element name="goToCheckout" type="button" selector="#top-cart-btn-checkout" timeout="30"/> + <element name="viewAndEditCart" type="button" selector=".action.viewcart" timeout="30"/> + <element name="miniCartItemsText" type="text" selector=".minicart-items"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontProductCompareMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontProductCompareMainSection.xml new file mode 100644 index 0000000000000..ba706aca8fe4a --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontProductCompareMainSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontProductCompareMainSection"> + <element name="ProductAddToCartByName" type="button" selector="//*[@id='product-comparison']//td[.//strong[@class='product-item-name']/a[contains(text(), '{{var1}}')]]//button[contains(@class, 'tocart')]" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontProductInfoMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontProductInfoMainSection.xml new file mode 100644 index 0000000000000..798bbdf115d66 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Section/StorefrontProductInfoMainSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontProductInfoMainSection"> + <element name="AddToCart" type="button" selector="#product-addtocart-button"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/EndToEndB2CGuestUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/EndToEndB2CGuestUserTest.xml new file mode 100644 index 0000000000000..d512aebb2c243 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/EndToEndB2CGuestUserTest.xml @@ -0,0 +1,210 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CGuestUserTest"> + <!-- Step 3: User adds products to cart --> + <comment userInput="Start of adding products to cart" stepKey="startOfAddingProductsToCart" after="endOfBrowsingCatalog"/> + <!-- Add Simple Product 1 to cart --> + <comment userInput="Add Simple Product 1 to cart" stepKey="commentAddSimpleProduct1ToCart" after="startOfAddingProductsToCart" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="cartClickCategory" after="commentAddSimpleProduct1ToCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartCategoryloaded" after="cartClickCategory"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="cartAssertCategory" after="waitForCartCategoryloaded"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="cartAssertSimpleProduct1" after="cartAssertCategory"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="cartGrabSimpleProduct1ImageSrc" after="cartAssertSimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartGrabSimpleProduct1ImageSrc" stepKey="cartAssertSimpleProduct1ImageNotDefault" after="cartGrabSimpleProduct1ImageSrc"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct1.name$$)}}" stepKey="cartClickSimpleProduct1" after="cartAssertSimpleProduct1ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartSimpleProduct1loaded" after="cartClickSimpleProduct1"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="cartAssertProduct1Page" after="waitForCartSimpleProduct1loaded"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartGrabSimpleProduct1PageImageSrc" after="cartAssertProduct1Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartGrabSimpleProduct1PageImageSrc" stepKey="cartAssertSimpleProduct1PageImageNotDefault" after="cartGrabSimpleProduct1PageImageSrc"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="cartAddProduct1ToCart" after="cartAssertSimpleProduct1PageImageNotDefault"> + <argument name="product" value="$$createSimpleProduct1$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.one"/> + </actionGroup> + + <!-- Add Simple Product 2 to cart --> + <comment userInput="Add Simple Product 2 to cart" stepKey="commentAddSimpleProduct2ToCart" after="cartAddProduct1ToCart" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="cartClickCategory1" after="commentAddSimpleProduct2ToCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartCategory1loaded" after="cartClickCategory1"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="cartAssertCategory1ForSimpleProduct2" after="waitForCartCategory1loaded"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="cartAssertSimpleProduct2" after="cartAssertCategory1ForSimpleProduct2"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="cartGrabSimpleProduct2ImageSrc" after="cartAssertSimpleProduct2"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartGrabSimpleProduct2ImageSrc" stepKey="cartAssertSimpleProduct2ImageNotDefault" after="cartGrabSimpleProduct2ImageSrc"/> + <actionGroup ref="StorefrontAddCategoryProductToCartActionGroup" stepKey="cartAddProduct2ToCart" after="cartAssertSimpleProduct2ImageNotDefault"> + <argument name="product" value="$$createSimpleProduct2$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.two"/> + </actionGroup> + + <!-- Check products in minicart --> + <!-- Check simple product 1 in minicart --> + <comment userInput="Check simple product 1 in minicart" stepKey="commentCheckSimpleProduct1InMinicart" after="cartAddProduct2ToCart"/> + <actionGroup ref="StorefrontOpenMinicartAndCheckSimpleProductActionGroup" stepKey="cartOpenMinicartAndCheckSimpleProduct1" after="commentCheckSimpleProduct1InMinicart"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontMinicartSection.productImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="cartMinicartGrabSimpleProduct1ImageSrc" after="cartOpenMinicartAndCheckSimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/thumbnail\.jpg/'" actual="$cartMinicartGrabSimpleProduct1ImageSrc" stepKey="cartMinicartAssertSimpleProduct1ImageNotDefault" after="cartMinicartGrabSimpleProduct1ImageSrc"/> + <click selector="{{StorefrontMinicartSection.productLinkByName($$createSimpleProduct1.name$$)}}" stepKey="cartMinicartClickSimpleProduct1" after="cartMinicartAssertSimpleProduct1ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForMinicartSimpleProduct1loaded" after="cartMinicartClickSimpleProduct1"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="cartAssertMinicartProduct1Page" after="waitForMinicartSimpleProduct1loaded"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartMinicartGrabSimpleProduct1PageImageSrc" after="cartAssertMinicartProduct1Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartMinicartGrabSimpleProduct1PageImageSrc" stepKey="cartMinicartAssertSimpleProduct1PageImageNotDefault" after="cartMinicartGrabSimpleProduct1PageImageSrc"/> + <actionGroup ref="StorefrontOpenMinicartAndCheckSimpleProductActionGroup" stepKey="cartOpenMinicartAndCheckSimpleProduct2" after="cartMinicartAssertSimpleProduct1PageImageNotDefault"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- Check simple product2 in minicart --> + <comment userInput="Check simple product 2 in minicart" stepKey="commentCheckSimpleProduct2InMinicart" after="cartOpenMinicartAndCheckSimpleProduct2"/> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontMinicartSection.productImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="cartMinicartGrabSimpleProduct2ImageSrc" after="commentCheckSimpleProduct2InMinicart"/> + <assertNotRegExp expected="'/placeholder\/thumbnail\.jpg/'" actual="$cartMinicartGrabSimpleProduct2ImageSrc" stepKey="cartMinicartAssertSimpleProduct2ImageNotDefault" after="cartMinicartGrabSimpleProduct2ImageSrc"/> + <click selector="{{StorefrontMinicartSection.productLinkByName($$createSimpleProduct2.name$$)}}" stepKey="cartMinicartClickSimpleProduct2" after="cartMinicartAssertSimpleProduct2ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForMinicartSimpleProduct2loaded" after="cartMinicartClickSimpleProduct2"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="cartAssertMinicartProduct2Page" after="waitForMinicartSimpleProduct2loaded"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartMinicartGrabSimpleProduct2PageImageSrc" after="cartAssertMinicartProduct2Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartMinicartGrabSimpleProduct2PageImageSrc" stepKey="cartMinicartAssertSimpleProduct2PageImageNotDefault" after="cartMinicartGrabSimpleProduct2PageImageSrc"/> + + <!-- Check products in cart --> + <comment userInput="Check cart information" stepKey="commentCheckCartInformation" after="cartMinicartAssertSimpleProduct2PageImageNotDefault" /> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="cartOpenCart" after="commentCheckCartInformation"/> + <actionGroup ref="StorefrontCheckCartActionGroup" stepKey="cartAssertCart" after="cartOpenCart"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="subtotal" value="E2EB2CQuote.subtotal"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shipping" value="E2EB2CQuote.shipping"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shippingMethod" value="E2EB2CQuote.shippingMethod"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="total" value="E2EB2CQuote.total"/> + </actionGroup> + + <!-- Check simple product 1 in cart --> + <comment userInput="Check simple product 1 in cart" stepKey="commentCheckSimpleProduct1InCart" after="cartAssertCart"/> + <actionGroup ref="StorefrontCheckCartSimpleProductActionGroup" stepKey="cartAssertCartSimpleProduct1" after="commentCheckSimpleProduct1InCart"> + <argument name="product" value="$$createSimpleProduct1$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productQuantity" value="CONST.one"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{CheckoutCartProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="cartCartGrabSimpleProduct1ImageSrc" after="cartAssertCartSimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartCartGrabSimpleProduct1ImageSrc" stepKey="cartCartAssertSimpleProduct1ImageNotDefault" after="cartCartGrabSimpleProduct1ImageSrc"/> + <click selector="{{CheckoutCartProductSection.ProductLinkByName($$createSimpleProduct1.name$$)}}" stepKey="cartClickCartSimpleProduct1" after="cartCartAssertSimpleProduct1ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartSimpleProduct1loadedAgain" after="cartClickCartSimpleProduct1"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="cartAssertCartProduct1Page" after="waitForCartSimpleProduct1loadedAgain"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartCartGrabSimpleProduct2PageImageSrc1" after="cartAssertCartProduct1Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartCartGrabSimpleProduct2PageImageSrc1" stepKey="cartCartAssertSimpleProduct2PageImageNotDefault1" after="cartCartGrabSimpleProduct2PageImageSrc1"/> + + <!-- Check simple product 2 in cart --> + <comment userInput="Check simple product 2 in cart" stepKey="commentCheckSimpleProduct2InCart" after="cartCartAssertSimpleProduct2PageImageNotDefault1"/> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="cartOpenCart1" after="commentCheckSimpleProduct2InCart"/> + <actionGroup ref="StorefrontCheckCartSimpleProductActionGroup" stepKey="cartAssertCartSimpleProduct2" after="cartOpenCart1"> + <argument name="product" value="$$createSimpleProduct2$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productQuantity" value="CONST.one"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{CheckoutCartProductSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="cartCartGrabSimpleProduct2ImageSrc" after="cartAssertCartSimpleProduct2"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartCartGrabSimpleProduct2ImageSrc" stepKey="cartCartAssertSimpleProduct2ImageNotDefault" after="cartCartGrabSimpleProduct2ImageSrc"/> + <click selector="{{CheckoutCartProductSection.ProductLinkByName($$createSimpleProduct2.name$$)}}" stepKey="cartClickCartSimpleProduct2" after="cartCartAssertSimpleProduct2ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartSimpleProduct2loaded" after="cartClickCartSimpleProduct2"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="cartAssertCartProduct2Page" after="waitForCartSimpleProduct2loaded"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartCartGrabSimpleProduct2PageImageSrc2" after="cartAssertCartProduct2Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartCartGrabSimpleProduct2PageImageSrc2" stepKey="cartCartAssertSimpleProduct2PageImageNotDefault2" after="cartCartGrabSimpleProduct2PageImageSrc2"/> + <comment userInput="End of adding products to cart" stepKey="endOfAddingProductsToCart" after="cartCartAssertSimpleProduct2PageImageNotDefault2" /> + + <!-- Step 6: Check out --> + <comment userInput="Start of checking out" stepKey="startOfCheckingOut" after="endOfUsingCouponCode" /> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="guestGoToCheckoutFromMinicart" after="startOfCheckingOut"/> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShippingSection" after="guestGoToCheckoutFromMinicart"> + <argument name="customerVar" value="CustomerEntityOne" /> + <argument name="customerAddressVar" value="CustomerAddressSimple" /> + </actionGroup> + + <!-- Check order summary in checkout --> + <comment userInput="Check order summary in checkout" stepKey="commentCheckOrderSummaryInCheckout" after="guestCheckoutFillingShippingSection" /> + <actionGroup ref="CheckOrderSummaryInCheckoutActionGroup" stepKey="guestCheckoutCheckOrderSummary" after="commentCheckOrderSummaryInCheckout"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="subtotal" value="E2EB2CQuote.subtotal"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shippingTotal" value="E2EB2CQuote.shipping"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shippingMethod" value="E2EB2CQuote.shippingMethod"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="total" value="E2EB2CQuote.total"/> + </actionGroup> + + <!-- Check ship to information in checkout --> + <comment userInput="Check ship to information in checkout" stepKey="commentCheckShipToInformationInCheckout" after="guestCheckoutCheckOrderSummary" /> + <actionGroup ref="CheckShipToInformationInCheckoutActionGroup" stepKey="guestCheckoutCheckShipToInformation" after="commentCheckShipToInformationInCheckout"> + <argument name="customerVar" value="CustomerEntityOne" /> + <argument name="customerAddressVar" value="CustomerAddressSimple" /> + </actionGroup> + + <!-- Check shipping method in checkout --> + <comment userInput="Check shipping method in checkout" stepKey="commentCheckShippingMethodInCheckout" after="guestCheckoutCheckShipToInformation" /> + <actionGroup ref="CheckShippingMethodInCheckoutActionGroup" stepKey="guestCheckoutCheckShippingMethod" after="commentCheckShippingMethodInCheckout"> + <argument name="shippingMethod" value="E2EB2CQuote.shippingMethod" /> + </actionGroup> + + <!-- Verify Simple Product 1 is in checkout cart items --> + <comment userInput="Verify Simple Product 1 is in checkout cart items" stepKey="commentVerifySimpleProduct1IsInCheckoutCartItems" after="guestCheckoutCheckShippingMethod" /> + <actionGroup ref="CheckProductInCheckoutCartItemsActionGroup" stepKey="guestCheckoutCheckSimpleProduct1InCartItems" after="commentVerifySimpleProduct1IsInCheckoutCartItems"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + + <!-- Verify Simple Product 2 is in checkout cart items --> + <comment userInput="Verify Simple Product 2 is in checkout cart items" stepKey="commentVerifySimpleProduct2IsInCheckoutCartItems" after="guestCheckoutCheckSimpleProduct1InCartItems" /> + <actionGroup ref="CheckProductInCheckoutCartItemsActionGroup" stepKey="guestCheckoutCheckSimpleProduct2InCartItems" after="commentVerifySimpleProduct2IsInCheckoutCartItems"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + + <comment userInput="Place order with check money order payment" stepKey="commentPlaceOrderWithCheckMoneyOrderPayment" after="guestCheckoutCheckSimpleProduct2InCartItems" /> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="guestSelectCheckMoneyOrderPayment" after="commentPlaceOrderWithCheckMoneyOrderPayment"/> + <actionGroup ref="CheckBillingAddressInCheckoutActionGroup" stepKey="guestSeeBillingAddress" after="guestSelectCheckMoneyOrderPayment"> + <argument name="customerVar" value="CustomerEntityOne" /> + <argument name="customerAddressVar" value="CustomerAddressSimple" /> + </actionGroup> + <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="guestPlaceorder" after="guestSeeBillingAddress"> + <argument name="orderNumberMessage" value="CONST.successGuestCheckoutOrderNumberMessage" /> + <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage" /> + </actionGroup> + <comment userInput="End of checking out" stepKey="endOfCheckingOut" after="guestPlaceorder" /> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/EndToEndB2CLoggedInUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/EndToEndB2CLoggedInUserTest.xml new file mode 100644 index 0000000000000..1cd30954d7f51 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/EndToEndB2CLoggedInUserTest.xml @@ -0,0 +1,210 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CLoggedInUserTest"> + <!-- Step 3: User adds products to cart --> + <comment userInput="Start of adding products to cart" stepKey="startOfAddingProductsToCart" after="endOfBrowsingCatalog"/> + <!-- Add Simple Product 1 to cart --> + <comment userInput="Add Simple Product 1 to cart" stepKey="commentAddSimpleProduct1ToCart" after="startOfAddingProductsToCart" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="cartClickCategory" after="commentAddSimpleProduct1ToCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartCategoryloaded" after="cartClickCategory"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="cartAssertCategory" after="waitForCartCategoryloaded"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="cartAssertSimpleProduct1" after="cartAssertCategory"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="cartGrabSimpleProduct1ImageSrc" after="cartAssertSimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartGrabSimpleProduct1ImageSrc" stepKey="cartAssertSimpleProduct1ImageNotDefault" after="cartGrabSimpleProduct1ImageSrc"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct1.name$$)}}" stepKey="cartClickSimpleProduct1" after="cartAssertSimpleProduct1ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartSimpleProduct1loaded" after="cartClickSimpleProduct1"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="cartAssertProduct1Page" after="waitForCartSimpleProduct1loaded"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartGrabSimpleProduct1PageImageSrc" after="cartAssertProduct1Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartGrabSimpleProduct1PageImageSrc" stepKey="cartAssertSimpleProduct1PageImageNotDefault" after="cartGrabSimpleProduct1PageImageSrc"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="cartAddProduct1ToCart" after="cartAssertSimpleProduct1PageImageNotDefault"> + <argument name="product" value="$$createSimpleProduct1$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.one"/> + </actionGroup> + + <!-- Add Simple Product 2 to cart --> + <comment userInput="Add Simple Product 2 to cart" stepKey="commentAddSimpleProduct2ToCart" after="cartAddProduct1ToCart" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="cartClickCategory1" after="commentAddSimpleProduct2ToCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartCategory1loaded" after="cartClickCategory1"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="cartAssertCategory1ForSimpleProduct2" after="waitForCartCategory1loaded"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCategorySimpleProduct" stepKey="cartAssertSimpleProduct2" after="cartAssertCategory1ForSimpleProduct2"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="cartGrabSimpleProduct2ImageSrc" after="cartAssertSimpleProduct2"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartGrabSimpleProduct2ImageSrc" stepKey="cartAssertSimpleProduct2ImageNotDefault" after="cartGrabSimpleProduct2ImageSrc"/> + <actionGroup ref="StorefrontAddCategoryProductToCartActionGroup" stepKey="cartAddProduct2ToCart" after="cartAssertSimpleProduct2ImageNotDefault"> + <argument name="product" value="$$createSimpleProduct2$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.two"/> + </actionGroup> + + <!-- Check products in minicart --> + <!-- Check simple product 1 in minicart --> + <comment userInput="Check simple product 1 in minicart" stepKey="commentCheckSimpleProduct1InMinicart" after="cartAddProduct2ToCart"/> + <actionGroup ref="StorefrontOpenMinicartAndCheckSimpleProductActionGroup" stepKey="cartOpenMinicartAndCheckSimpleProduct1" after="commentCheckSimpleProduct1InMinicart"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontMinicartSection.productImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="cartMinicartGrabSimpleProduct1ImageSrc" after="cartOpenMinicartAndCheckSimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/thumbnail\.jpg/'" actual="$cartMinicartGrabSimpleProduct1ImageSrc" stepKey="cartMinicartAssertSimpleProduct1ImageNotDefault" after="cartMinicartGrabSimpleProduct1ImageSrc"/> + <click selector="{{StorefrontMinicartSection.productLinkByName($$createSimpleProduct1.name$$)}}" stepKey="cartMinicartClickSimpleProduct1" after="cartMinicartAssertSimpleProduct1ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForMinicartSimpleProduct1loaded" after="cartMinicartClickSimpleProduct1"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="cartAssertMinicartProduct1Page" after="waitForMinicartSimpleProduct1loaded"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartMinicartGrabSimpleProduct1PageImageSrc" after="cartAssertMinicartProduct1Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartMinicartGrabSimpleProduct1PageImageSrc" stepKey="cartMinicartAssertSimpleProduct1PageImageNotDefault" after="cartMinicartGrabSimpleProduct1PageImageSrc"/> + <actionGroup ref="StorefrontOpenMinicartAndCheckSimpleProductActionGroup" stepKey="cartOpenMinicartAndCheckSimpleProduct2" after="cartMinicartAssertSimpleProduct1PageImageNotDefault"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- Check simple product2 in minicart --> + <comment userInput="Check simple product 2 in minicart" stepKey="commentCheckSimpleProduct2InMinicart" after="cartOpenMinicartAndCheckSimpleProduct2"/> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontMinicartSection.productImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="cartMinicartGrabSimpleProduct2ImageSrc" after="commentCheckSimpleProduct2InMinicart"/> + <assertNotRegExp expected="'/placeholder\/thumbnail\.jpg/'" actual="$cartMinicartGrabSimpleProduct2ImageSrc" stepKey="cartMinicartAssertSimpleProduct2ImageNotDefault" after="cartMinicartGrabSimpleProduct2ImageSrc"/> + <click selector="{{StorefrontMinicartSection.productLinkByName($$createSimpleProduct2.name$$)}}" stepKey="cartMinicartClickSimpleProduct2" after="cartMinicartAssertSimpleProduct2ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForMinicartSimpleProduct2loaded" after="cartMinicartClickSimpleProduct2"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="cartAssertMinicartProduct2Page" after="waitForMinicartSimpleProduct2loaded"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartMinicartGrabSimpleProduct2PageImageSrc" after="cartAssertMinicartProduct2Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartMinicartGrabSimpleProduct2PageImageSrc" stepKey="cartMinicartAssertSimpleProduct2PageImageNotDefault" after="cartMinicartGrabSimpleProduct2PageImageSrc"/> + + <!-- Check products in cart --> + <comment userInput="Check cart information" stepKey="commentCheckCartInformation" after="cartMinicartAssertSimpleProduct2PageImageNotDefault" /> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="cartOpenCart" after="commentCheckCartInformation"/> + <actionGroup ref="StorefrontCheckCartActionGroup" stepKey="cartAssertCart" after="cartOpenCart"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="subtotal" value="E2EB2CQuote.subtotal"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shipping" value="E2EB2CQuote.shipping"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shippingMethod" value="E2EB2CQuote.shippingMethod"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="total" value="E2EB2CQuote.total"/> + </actionGroup> + + <!-- Check simple product 1 in cart --> + <comment userInput="Check simple product 1 in cart" stepKey="commentCheckSimpleProduct1InCart" after="cartAssertCart"/> + <actionGroup ref="StorefrontCheckCartSimpleProductActionGroup" stepKey="cartAssertCartSimpleProduct1" after="commentCheckSimpleProduct1InCart"> + <argument name="product" value="$$createSimpleProduct1$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productQuantity" value="CONST.one"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{CheckoutCartProductSection.ProductImageByName($$createSimpleProduct1.name$$)}}" userInput="src" stepKey="cartCartGrabSimpleProduct1ImageSrc" after="cartAssertCartSimpleProduct1"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartCartGrabSimpleProduct1ImageSrc" stepKey="cartCartAssertSimpleProduct1ImageNotDefault" after="cartCartGrabSimpleProduct1ImageSrc"/> + <click selector="{{CheckoutCartProductSection.ProductLinkByName($$createSimpleProduct1.name$$)}}" stepKey="cartClickCartSimpleProduct1" after="cartCartAssertSimpleProduct1ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartSimpleProduct1loadedAgain" after="cartClickCartSimpleProduct1"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="cartAssertCartProduct1Page" after="waitForCartSimpleProduct1loadedAgain"> + <argument name="product" value="$$createSimpleProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartCartGrabSimpleProduct2PageImageSrc1" after="cartAssertCartProduct1Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartCartGrabSimpleProduct2PageImageSrc1" stepKey="cartCartAssertSimpleProduct2PageImageNotDefault1" after="cartCartGrabSimpleProduct2PageImageSrc1"/> + + <!-- Check simple product 2 in cart --> + <comment userInput="Check simple product 2 in cart" stepKey="commentCheckSimpleProduct2InCart" after="cartCartAssertSimpleProduct2PageImageNotDefault1"/> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="cartOpenCart1" after="commentCheckSimpleProduct2InCart"/> + <actionGroup ref="StorefrontCheckCartSimpleProductActionGroup" stepKey="cartAssertCartSimpleProduct2" after="cartOpenCart1"> + <argument name="product" value="$$createSimpleProduct2$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productQuantity" value="CONST.one"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{CheckoutCartProductSection.ProductImageByName($$createSimpleProduct2.name$$)}}" userInput="src" stepKey="cartCartGrabSimpleProduct2ImageSrc" after="cartAssertCartSimpleProduct2"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartCartGrabSimpleProduct2ImageSrc" stepKey="cartCartAssertSimpleProduct2ImageNotDefault" after="cartCartGrabSimpleProduct2ImageSrc"/> + <click selector="{{CheckoutCartProductSection.ProductLinkByName($$createSimpleProduct2.name$$)}}" stepKey="cartClickCartSimpleProduct2" after="cartCartAssertSimpleProduct2ImageNotDefault"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartSimpleProduct2loaded" after="cartClickCartSimpleProduct2"/> + <actionGroup ref="StorefrontCheckSimpleProduct" stepKey="cartAssertCartProduct2Page" after="waitForCartSimpleProduct2loaded"> + <argument name="product" value="$$createSimpleProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartCartGrabSimpleProduct2PageImageSrc2" after="cartAssertCartProduct2Page"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartCartGrabSimpleProduct2PageImageSrc2" stepKey="cartCartAssertSimpleProduct2PageImageNotDefault2" after="cartCartGrabSimpleProduct2PageImageSrc2"/> + <comment userInput="End of adding products to cart" stepKey="endOfAddingProductsToCart" after="cartCartAssertSimpleProduct2PageImageNotDefault2" /> + + <!-- Step 7: Check out --> + <comment userInput="Start of checking out" stepKey="startOfCheckingOut" after="endOfUsingCouponCode" /> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart" after="startOfCheckingOut"/> + <actionGroup ref="LoggedInUserCheckoutFillingShippingSectionActionGroup" stepKey="checkoutFillingShippingSection" after="goToCheckoutFromMinicart"> + <argument name="customerVar" value="CustomerEntityOne" /> + <argument name="customerAddressVar" value="CustomerAddressSimple" /> + </actionGroup> + + <!-- Check order summary in checkout --> + <comment userInput="Check order summary in checkout" stepKey="commentCheckOrderSummaryInCheckout" after="checkoutFillingShippingSection" /> + <actionGroup ref="CheckOrderSummaryInCheckoutActionGroup" stepKey="checkoutCheckOrderSummary" after="commentCheckOrderSummaryInCheckout"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="subtotal" value="E2EB2CQuote.subtotal"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shippingTotal" value="E2EB2CQuote.shipping"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shippingMethod" value="E2EB2CQuote.shippingMethod"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="total" value="E2EB2CQuote.total"/> + </actionGroup> + + <!-- Check ship to information in checkout --> + <comment userInput="Check ship to information in checkout" stepKey="commentCheckShipToInformationInCheckout" after="checkoutCheckOrderSummary" /> + <actionGroup ref="CheckShipToInformationInCheckoutActionGroup" stepKey="checkoutCheckShipToInformation" after="commentCheckShipToInformationInCheckout"> + <argument name="customerVar" value="CustomerEntityOne" /> + <argument name="customerAddressVar" value="CustomerAddressSimple" /> + </actionGroup> + + <!-- Check shipping method in checkout --> + <comment userInput="Check shipping method in checkout" stepKey="commentCheckShippingMethodInCheckout" after="checkoutCheckShipToInformation" /> + <actionGroup ref="CheckShippingMethodInCheckoutActionGroup" stepKey="checkoutCheckShippingMethod" after="commentCheckShippingMethodInCheckout"> + <argument name="shippingMethod" value="E2EB2CQuote.shippingMethod" /> + </actionGroup> + + <!-- Verify Simple Product 1 is in checkout cart items --> + <comment userInput="Verify Simple Product 1 is in checkout cart items" stepKey="commentVerifySimpleProduct1IsInCheckoutCartItems" after="checkoutCheckShippingMethod" /> + <actionGroup ref="CheckProductInCheckoutCartItemsActionGroup" stepKey="checkoutCheckSimpleProduct1InCartItems" after="commentVerifySimpleProduct1IsInCheckoutCartItems"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + + <!-- Verify Simple Product 2 is in checkout cart items --> + <comment userInput="Verify Simple Product 2 is in checkout cart items" stepKey="commentVerifySimpleProduct2IsInCheckoutCartItems" after="checkoutCheckSimpleProduct1InCartItems" /> + <actionGroup ref="CheckProductInCheckoutCartItemsActionGroup" stepKey="checkoutCheckSimpleProduct2InCartItems" after="commentVerifySimpleProduct2IsInCheckoutCartItems"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + + <comment userInput="Place order with check money order payment" stepKey="commentPlaceOrderWithCheckMoneyOrderPayment" after="checkoutCheckSimpleProduct2InCartItems" /> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="selectCheckMoneyOrderPayment" after="commentPlaceOrderWithCheckMoneyOrderPayment"/> + <actionGroup ref="CheckBillingAddressInCheckoutActionGroup" stepKey="seeBillingAddress" after="selectCheckMoneyOrderPayment"> + <argument name="customerVar" value="CustomerEntityOne" /> + <argument name="customerAddressVar" value="CustomerAddressSimple" /> + </actionGroup> + <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="placeorder" after="seeBillingAddress"> + <argument name="orderNumberMessage" value="CONST.successCheckoutOrderNumberMessage" /> + <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage" /> + </actionGroup> + <comment userInput="End of checking out" stepKey="endOfCheckingOut" after="placeorder" /> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/StorefrontCustomerCheckoutTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/StorefrontCustomerCheckoutTest.xml index e5de7083dc824..5acc46be18d7c 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/StorefrontCustomerCheckoutTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/StorefrontCustomerCheckoutTest.xml @@ -32,22 +32,19 @@ <deleteData createDataKey="simpleuscustomer" stepKey="deleteCustomer"/> </after> - <amOnPage stepKey="s1" url="customer/account/login/"/> - <fillField stepKey="s3" userInput="$$simpleuscustomer.email$$" selector="{{StorefrontCustomerSignInFormSection.emailField}}"/> - <fillField stepKey="s5" userInput="$$simpleuscustomer.password$$" selector="{{StorefrontCustomerSignInFormSection.passwordField}}"/> - <click stepKey="s7" selector="{{StorefrontCustomerSignInFormSection.signInAccountButton}}"/> - <waitForPageLoad stepKey="s9"/> + <actionGroup ref="LoginToStorefrontActionGroup" stepKey="customerLogin"> + <argument name="Customer" value="$$simpleuscustomer$$" /> + </actionGroup> + + <amOnPage url="{{StorefrontCategoryPage.url($$simplecategory.name$$)}}" stepKey="onCategoryPage"/> + <waitForPageLoad stepKey="waitForCatalogPageLoad"/> + <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <click selector="{{StorefrontCategoryMainSection.AddToCartBtn}}" stepKey="addToCart"/> + <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> + <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$simpleproduct1.name$$ to your shopping cart." stepKey="seeAddedToCartMessage"/> + <see selector="{{StorefrontMinicartSection.quantity}}" userInput="1" stepKey="seeCartQuantity"/> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="goToCheckoutFromMinicart" /> - <amOnPage stepKey="s11" url="/$$simplecategory.name$$.html" /> - <moveMouseOver stepKey="s15" selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" /> - <click stepKey="s17" selector="{{StorefrontCategoryMainSection.AddToCartBtn}}" /> - <waitForElementVisible stepKey="s21" selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" /> - <see stepKey="s23" selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$simpleproduct1.name$$ to your shopping cart."/> - <see stepKey="s25" selector="{{StorefrontMiniCartSection.quantity}}" userInput="1" /> - <click stepKey="s27" selector="{{StorefrontMiniCartSection.show}}" /> - <click stepKey="s31" selector="{{StorefrontMiniCartSection.goToCheckout}}" /> - <waitForPageLoad stepKey="s33"/> - <waitForLoadingMaskToDisappear stepKey="s34"/> <click stepKey="s35" selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}"/> <waitForElement stepKey="s36" selector="{{CheckoutShippingMethodsSection.next}}" time="30"/> <click stepKey="s37" selector="{{CheckoutShippingMethodsSection.next}}" /> @@ -61,19 +58,19 @@ <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> - <amOnPage stepKey="s67" url="{{OrdersPage.url}}"/> + <amOnPage stepKey="s67" url="{{AdminOrdersPage.url}}"/> <waitForPageLoad stepKey="s75"/> - <fillField stepKey="s77" selector="{{OrdersGridSection.search}}" userInput="{$s53}" /> + <fillField stepKey="s77" selector="{{AdminOrdersGridSection.search}}" userInput="{$s53}" /> <waitForPageLoad stepKey="s78"/> - <click stepKey="s81" selector="{{OrdersGridSection.submitSearch22}}" /> + <click stepKey="s81" selector="{{AdminOrdersGridSection.submitSearch22}}" /> <waitForPageLoad stepKey="s831"/> - <click stepKey="s84" selector="{{OrdersGridSection.firstRow}}" /> - <see stepKey="s85" selector="{{OrderDetailsInformationSection.orderStatus}}" userInput="Pending" /> - <see stepKey="s87" selector="{{OrderDetailsInformationSection.accountInformation}}" userInput="Customer" /> - <see stepKey="s89" selector="{{OrderDetailsInformationSection.accountInformation}}" userInput="$$simpleuscustomer.email$$" /> - <see stepKey="s91" selector="{{OrderDetailsInformationSection.billingAddress}}" userInput="{{US_Address_TX.street[0]}}" /> - <see stepKey="s93" selector="{{OrderDetailsInformationSection.shippingAddress}}" userInput="{{US_Address_TX.street[0]}}" /> - <see stepKey="s95" selector="{{OrderDetailsInformationSection.itemsOrdered}}" userInput="$$simpleproduct1.name$$" /> + <click stepKey="s84" selector="{{AdminOrdersGridSection.firstRow}}" /> + <see stepKey="s85" selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Pending" /> + <see stepKey="s87" selector="{{AdminOrderDetailsInformationSection.accountInformation}}" userInput="Customer" /> + <see stepKey="s89" selector="{{AdminOrderDetailsInformationSection.accountInformation}}" userInput="$$simpleuscustomer.email$$" /> + <see stepKey="s91" selector="{{AdminOrderDetailsInformationSection.billingAddress}}" userInput="{{US_Address_TX.street[0]}}" /> + <see stepKey="s93" selector="{{AdminOrderDetailsInformationSection.shippingAddress}}" userInput="{{US_Address_TX.street[0]}}" /> + <see stepKey="s95" selector="{{AdminOrderDetailsInformationSection.itemsOrdered}}" userInput="$$simpleproduct1.name$$" /> </test> </tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/StorefrontGuestCheckoutTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/StorefrontGuestCheckoutTest.xml index e98657b66c4d9..02ce7ae57cf3e 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/StorefrontGuestCheckoutTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/Test/StorefrontGuestCheckoutTest.xml @@ -20,7 +20,7 @@ </annotations> <before> <createData entity="_defaultCategory" stepKey="createCategory"/> - <createData entity="_defaultProduct" stepKey="createProduct"> + <createData entity="ApiSimpleProduct" stepKey="createProduct"> <requiredEntity createDataKey="createCategory"/> </createData> </before> @@ -36,44 +36,36 @@ <click selector="{{StorefrontCategoryMainSection.AddToCartBtn}}" stepKey="addToCart"/> <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> <see selector="{{StorefrontCategoryMainSection.SuccessMsg}}" userInput="You added $$createProduct.name$$ to your shopping cart." stepKey="seeAddedToCartMessage"/> - <see selector="{{StorefrontMiniCartSection.quantity}}" userInput="1" stepKey="seeCartQuantity"/> - <click selector="{{StorefrontMiniCartSection.show}}" stepKey="clickCart"/> - <click selector="{{StorefrontMiniCartSection.goToCheckout}}" stepKey="goToCheckout"/> - <waitForPageLoad stepKey="waitForPageLoad2"/> - <fillField selector="{{GuestCheckoutShippingSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="enterEmail"/> - <fillField selector="{{GuestCheckoutShippingSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="enterFirstName"/> - <fillField selector="{{GuestCheckoutShippingSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="enterLastName"/> - <fillField selector="{{GuestCheckoutShippingSection.street}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="enterStreet"/> - <fillField selector="{{GuestCheckoutShippingSection.city}}" userInput="{{CustomerAddressSimple.city}}" stepKey="enterCity"/> - <selectOption selector="{{GuestCheckoutShippingSection.region}}" userInput="{{CustomerAddressSimple.state}}" stepKey="selectRegion"/> - <fillField selector="{{GuestCheckoutShippingSection.postcode}}" userInput="{{CustomerAddressSimple.postcode}}" stepKey="enterPostcode"/> - <fillField selector="{{GuestCheckoutShippingSection.telephone}}" userInput="{{CustomerAddressSimple.telephone}}" stepKey="enterTelephone"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> - <click selector="{{GuestCheckoutShippingSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> - <waitForElement selector="{{GuestCheckoutShippingSection.next}}" time="30" stepKey="waitForNextButton"/> - <click selector="{{GuestCheckoutShippingSection.next}}" stepKey="clickNext"/> - <waitForElement selector="{{GuestCheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> - <conditionalClick selector="{{GuestCheckoutPaymentSection.cartItemsArea}}" dependentSelector="{{GuestCheckoutPaymentSection.cartItemsAreaActive}}" visible="false" stepKey="exposeMiniCart"/> - <see selector="{{GuestCheckoutPaymentSection.cartItems}}" userInput="{{_defaultProduct.name}}" stepKey="seeProductInCart"/> - <see selector="{{GuestCheckoutPaymentSection.billingAddress}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="seeAddress"/> - <click selector="{{GuestCheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> + <see selector="{{StorefrontMinicartSection.quantity}}" userInput="1" stepKey="seeCartQuantity"/> + <actionGroup ref="GoToCheckoutFromMinicartActionGroup" stepKey="guestGoToCheckoutFromMinicart" /> + <actionGroup ref="GuestCheckoutFillingShippingSectionActionGroup" stepKey="guestCheckoutFillingShippingSection"> + <argument name="customerVar" value="CustomerEntityOne" /> + <argument name="customerAddressVar" value="CustomerAddressSimple" /> + </actionGroup> + <actionGroup ref="CheckoutSelectCheckMoneyOrderPaymentActionGroup" stepKey="guestSelectCheckMoneyOrderPayment" /> + <actionGroup ref="CheckBillingAddressInCheckoutActionGroup" stepKey="guestSeeAddress"> + <argument name="customerVar" value="CustomerEntityOne" /> + <argument name="customerAddressVar" value="CustomerAddressSimple" /> + </actionGroup> + <actionGroup ref="CheckoutPlaceOrderActionGroup" stepKey="guestPlaceorder"> + <argument name="orderNumberMessage" value="CONST.successGuestCheckoutOrderNumberMessage" /> + <argument name="emailYouMessage" value="CONST.successCheckoutEmailYouMessage" /> + </actionGroup> <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> - <see selector="{{CheckoutSuccessMainSection.success}}" userInput="Your order # is:" stepKey="seeOrderNumber"/> - <see selector="{{CheckoutSuccessMainSection.success}}" userInput="We'll email you an order confirmation with details and tracking info." stepKey="seeEmailYou"/> <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> - <amOnPage url="{{OrdersPage.url}}" stepKey="onOrdersPage"/> + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnOrdersPage"/> - <fillField selector="{{OrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="fillOrderNum"/> - <click selector="{{OrdersGridSection.submitSearch}}" stepKey="submitSearchOrderNum"/> + <fillField selector="{{AdminOrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="fillOrderNum"/> + <click selector="{{AdminOrdersGridSection.submitSearch}}" stepKey="submitSearchOrderNum"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskToDisappearOnSearch"/> - <click selector="{{OrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> - <see selector="{{OrderDetailsInformationSection.orderStatus}}" userInput="Pending" stepKey="seeAdminOrderStatus"/> - <see selector="{{OrderDetailsInformationSection.accountInformation}}" userInput="Guest" stepKey="seeAdminOrderGuest"/> - <see selector="{{OrderDetailsInformationSection.accountInformation}}" userInput="{{CustomerEntityOne.email}}" stepKey="seeAdminOrderEmail"/> - <see selector="{{OrderDetailsInformationSection.billingAddress}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="seeAdminOrderBillingAddress"/> - <see selector="{{OrderDetailsInformationSection.shippingAddress}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="seeAdminOrderShippingAddress"/> - <see selector="{{OrderDetailsInformationSection.itemsOrdered}}" userInput="{{_defaultProduct.name}}" stepKey="seeAdminOrderProduct"/> + <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Pending" stepKey="seeAdminOrderStatus"/> + <see selector="{{AdminOrderDetailsInformationSection.accountInformation}}" userInput="Guest" stepKey="seeAdminOrderGuest"/> + <see selector="{{AdminOrderDetailsInformationSection.accountInformation}}" userInput="{{CustomerEntityOne.email}}" stepKey="seeAdminOrderEmail"/> + <see selector="{{AdminOrderDetailsInformationSection.billingAddress}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="seeAdminOrderBillingAddress"/> + <see selector="{{AdminOrderDetailsInformationSection.shippingAddress}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="seeAdminOrderShippingAddress"/> + <see selector="{{AdminOrderDetailsInformationSection.itemsOrdered}}" userInput="$$createProduct.name$$" stepKey="seeAdminOrderProduct"/> </test> </tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/composer.json index 2a19649ad5202..cec9325d2eb60 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Checkout/composer.json @@ -11,28 +11,28 @@ "sort-packages": true }, "require": { - "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-testing-framework": "~2.0.0", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", + "magento/magento2-functional-test-module-customer": "100.0.0-dev", + "magento/magento2-functional-test-module-payment": "100.0.0-dev", + "magento/magento2-functional-test-module-quote": "100.0.0-dev", + "magento/magento2-functional-test-module-sales": "100.0.0-dev", + "magento/magento2-functional-test-module-sales-rule": "100.0.0-dev", + "magento/magento2-functional-test-module-shipping": "100.0.0-dev", + "magento/magento2-functional-test-module-theme": "100.0.0-dev", + "magento/magento2-functional-test-module-ui": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", "magento/magento2-functional-test-module-config": "100.0.0-dev", - "magento/magento2-functional-test-module-customer": "100.0.0-dev", "magento/magento2-functional-test-module-directory": "100.0.0-dev", "magento/magento2-functional-test-module-eav": "100.0.0-dev", "magento/magento2-functional-test-module-msrp": "100.0.0-dev", "magento/magento2-functional-test-module-page-cache": "100.0.0-dev", - "magento/magento2-functional-test-module-payment": "100.0.0-dev", - "magento/magento2-functional-test-module-quote": "100.0.0-dev", - "magento/magento2-functional-test-module-sales": "100.0.0-dev", - "magento/magento2-functional-test-module-sales-rule": "100.0.0-dev", - "magento/magento2-functional-test-module-shipping": "100.0.0-dev", "magento/magento2-functional-test-module-store": "100.0.0-dev", - "magento/magento2-functional-test-module-tax": "100.0.0-dev", - "magento/magento2-functional-test-module-theme": "100.0.0-dev", - "magento/magento2-functional-test-module-ui": "100.0.0-dev" + "magento/magento2-functional-test-module-tax": "100.0.0-dev" }, "autoload": { "psr-4": { diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssignBlockToCMSPageActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssignBlockToCMSPageActionGroup.xml new file mode 100644 index 0000000000000..5c787549ab9d0 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/AssignBlockToCMSPageActionGroup.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AssignBlockToCMSPage"> + <arguments> + <argument name="Block" defaultValue=""/> + <argument name="CmsPage" defaultValue=""/> + </arguments> + <amOnPage url="{{CmsPagesPage.url}}" stepKey="amOnEditPage"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <conditionalClick selector="{{CmsPagesPageActionsSection.clearAll}}" dependentSelector="{{CmsPagesPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> + <waitForPageLoad stepKey="waitForGridReload"/> + <conditionalClick selector="//div[contains(@data-role, 'grid-wrapper')]/table/thead/tr/th/span[contains(text(), 'ID')]" dependentSelector="//span[contains(text(), 'ID')]/parent::th[not(contains(@class, '_descend'))]/parent::tr/parent::thead/parent::table/parent::div[contains(@data-role, 'grid-wrapper')]" stepKey="clickToAttemptSortByIdDescending1" visible="true"/> + <waitForLoadingMaskToDisappear stepKey="waitForFirstIdSortDescendingToFinish1" /> + <!-- Conditional Click again in case it goes from default state to ascending on first click --> + <conditionalClick selector="//div[contains(@data-role, 'grid-wrapper')]/table/thead/tr/th/span[contains(text(), 'ID')]" dependentSelector="//span[contains(text(), 'ID')]/parent::th[not(contains(@class, '_descend'))]/parent::tr/parent::thead/parent::table/parent::div[contains(@data-role, 'grid-wrapper')]" stepKey="secondClickToAttemptSortByIdDescending2" visible="true"/> + <waitForLoadingMaskToDisappear stepKey="waitForSecondIdSortDescendingToFinish1" /> + <waitForElementVisible selector="{{CmsPagesPageActionsSection.select(CmsPage.identifier)}}" stepKey="waitForCMSPageGrid" /> + <click selector="{{CmsPagesPageActionsSection.select(CmsPage.identifier)}}" stepKey="clickSelect" /> + <waitForElementVisible selector="{{CmsPagesPageActionsSection.edit(CmsPage.identifier)}}" stepKey="waitForEditLink" /> + <click selector="{{CmsPagesPageActionsSection.edit(CmsPage.identifier)}}" stepKey="clickEdit" /> + <waitForPageLoad stepKey="waitForPageLoad2" /> + <click selector="{{CmsNewPagePageContentSection.header}}" stepKey="clickContentTab" /> + <waitForElementVisible selector="{{TinyMCESection.TinyMCE4}}" stepKey="waitForTinyMCE4"/> + <seeElement selector="{{TinyMCESection.InsertWidgetIcon}}" stepKey="seeWidgetIcon" /> + <click selector="{{TinyMCESection.InsertWidgetIcon}}" stepKey="clickInsertWidgetIcon" /> + <waitForPageLoad stepKey="waitForPageLoad3" /> + <selectOption selector="{{WidgetSection.WidgetType}}" userInput="CMS Static Block" stepKey="selectCMSStaticBlock" /> + <waitForLoadingMaskToDisappear stepKey="waitForLoading1" /> + <selectOption selector="{{WidgetSection.WidgetTemplate}}" userInput="CMS Static Block Default Template" stepKey="selectTemplate" /> + <click selector="{{WidgetSection.BtnChooser}}" stepKey="clickSelectPageBtn" /> + <waitForLoadingMaskToDisappear stepKey="waitForLoading2" /> + <fillField selector="//input[@name='chooser_identifier']" userInput="{{Block.identifier}}" stepKey="fillBlockIdentifier"/> + <click selector="//div[@class='modal-inner-wrap']//button[@title='Search']" stepKey="clickSearchBtn" /> + <waitForLoadingMaskToDisappear stepKey="waitForSecondIdSortDescendingToFinish2" /> + <waitForElementVisible selector="{{WidgetSection.BlockPage(Block.identifier)}}" stepKey="waitForBlockTitle" /> + <click selector="{{WidgetSection.BlockPage(Block.identifier)}}" stepKey="selectPreCreateBlock" /> + <wait time="3" stepKey="wait1" /> + <click selector="{{WidgetSection.InsertWidget}}" stepKey="clickInsertWidgetBtn" /> + <waitForLoadingMaskToDisappear stepKey="waitForLoading3" /> + <waitForPageLoad stepKey="waitForPageLoad4" /> + <click selector="{{CmsNewPagePageActionsSection.savePage}}" stepKey="clickSavePage"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/CMSActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/CMSActionGroup.xml index 0c3706b9a633b..40d0833e34b67 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/CMSActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/CMSActionGroup.xml @@ -13,7 +13,7 @@ </arguments> <amOnPage url="{{CmsPagesPage.url}}" stepKey="navigateToCMSPagesGrid"/> <waitForPageLoad stepKey="waitForPageLoad1"/> - <conditionalClick selector="{{BlockPageActionsSection.clearAll}}" dependentSelector="{{BlockPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> + <conditionalClick selector="{{CmsPagesPageActionsSection.clearAll}}" dependentSelector="{{CmsPagesPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> <waitForPageLoad stepKey="waitForPageLoad2"/> <conditionalClick selector="//div[contains(@data-role, 'grid-wrapper')]/table/thead/tr/th/span[contains(text(), 'ID')]" dependentSelector="//span[contains(text(), 'ID')]/parent::th[not(contains(@class, '_descend'))]/parent::tr/parent::thead/parent::table/parent::div[contains(@data-role, 'grid-wrapper')]" stepKey="clickToAttemptSortByIdDescending" visible="true"/> <waitForLoadingMaskToDisappear stepKey="waitForFirstIdSortDescendingToFinish" /> @@ -32,6 +32,8 @@ </arguments> <amOnPage url="{{CmsBlocksPage.url}}" stepKey="navigateToCMSBlocksGrid"/> <waitForPageLoad stepKey="waitForPageLoad1"/> + <conditionalClick selector="{{CmsPagesPageActionsSection.clearAll}}" dependentSelector="{{CmsPagesPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> <conditionalClick selector="{{BlockPageActionsSection.idColumn}}" dependentSelector="//span[contains(text(), 'ID')]/parent::th[not(contains(@class, '_descend'))]/parent::tr/parent::thead/parent::table/parent::div[contains(@data-role, 'grid-wrapper')]" stepKey="clickToAttemptSortByIdDescending" visible="true"/> <waitForLoadingMaskToDisappear stepKey="waitForFirstIdSortDescendingToFinish" /> <!-- Conditional Click again in case it goes from default state to ascending on first click --> @@ -39,7 +41,7 @@ <waitForLoadingMaskToDisappear stepKey="waitForSecondIdSortDescendingToFinish" /> <click selector="{{BlockPageActionsSection.select(CMSBlockPage.identifier)}}" stepKey="clickSelectCreatedCMSBlock" /> <click selector="{{BlockPageActionsSection.edit(CMSBlockPage.identifier)}}" stepKey="navigateToCreatedCMSBlock" /> - <waitForPageLoad stepKey="waitForPageLoad2"/> + <waitForPageLoad stepKey="waitForPageLoad3"/> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskOfStagingSection" /> </actionGroup> </actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/SearchBlockOnGridPageActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/SearchBlockOnGridPageActionGroup.xml new file mode 100644 index 0000000000000..cee15a652d9f2 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/SearchBlockOnGridPageActionGroup.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="searchBlockOnGridPage"> + <arguments> + <argument name="Block" defaultValue=""/> + </arguments> + <fillField selector="//input[@name='chooser_identifier']" userInput="{{Block.identifier}}" stepKey="fillEntityIdentifier"/> + <click selector="//div[@class='modal-inner-wrap']//button[@title='Search']" stepKey="clickSearchBtn" /> + <waitForLoadingMaskToDisappear stepKey="waitForSecondIdSortDescendingToFinish2" /> + <waitForElementVisible selector="{{WidgetSection.BlockPage(Block.identifier)}}" stepKey="waitForBlockTitle" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/SelectImageFromMediaStorageActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/SelectImageFromMediaStorageActionGroup.xml new file mode 100644 index 0000000000000..3fcc2ae8337d0 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/ActionGroup/SelectImageFromMediaStorageActionGroup.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="clickBrowseBtnOnUploadPopup"> + <click selector="{{MediaGallerySection.Browse}}" stepKey="clickBrowse" /> + <waitForPageLoad stepKey="waitForPageLoad1" /> + </actionGroup> + <actionGroup name="VerifyMediaGalleryStorageActions"> + <waitForPageLoad stepKey="waitForPageLoad1" /> + <waitForLoadingMaskToDisappear stepKey="waitForLoading1" /> + <waitForLoadingMaskToDisappear stepKey="waitForLoading2" /> + <see selector="{{MediaGallerySection.CancelBtn}}" userInput="Cancel" stepKey="seeCancelBtn" /> + <see selector="{{MediaGallerySection.CreateFolder}}" userInput="Create Folder" stepKey="seeCreateFolderBtn" /> + <see selector="{{MediaGallerySection.InsertFile}}" userInput="Add Selected" stepKey="seeAddSelectedBtn" /> + </actionGroup> + <actionGroup name="CreateImageFolder"> + <arguments> + <argument name="ImageFolder" defaultValue="ImageFolder"/> + </arguments> + <click selector="{{MediaGallerySection.CreateFolder}}" stepKey="createFolder"/> + <waitForElementVisible selector="{{MediaGallerySection.FolderName}}" stepKey="waitForPopUp" /> + <fillField selector="{{MediaGallerySection.FolderName}}" userInput="{{ImageFolder.name}}" stepKey="fillFolderName" /> + <click selector="{{MediaGallerySection.AcceptFolderName}}" stepKey="acceptFolderName" /> + <waitForLoadingMaskToDisappear stepKey="waitForLoading3" /> + <conditionalClick selector="{{MediaGallerySection.StorageRootArrow}}" dependentSelector="{{MediaGallerySection.checkIfArrowExpand}}" stepKey="clickArrowIfCloses" visible="true"/> + <waitForText userInput="{{ImageFolder.name}}" stepKey="waitForNewFolder" /> + <click userInput="{{ImageFolder.name}}" stepKey="clickOnCreatedFolder" /> + <waitForLoadingMaskToDisappear stepKey="waitForLoading5" /> + </actionGroup> + <actionGroup name="attachImage"> + <arguments> + <argument name="Image" defaultValue=""/> + </arguments> + <attachFile selector="{{MediaGallerySection.BrowseUploadImage}}" userInput="{{Image.value}}" stepKey="uploadImage1"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoading6" /> + <waitForElementVisible selector="{{MediaGallerySection.image(Image.value)}}" stepKey="waitForUploadImage1" /> + <seeElement selector="{{MediaGallerySection.imageSelected(Image.value)}}" stepKey="seeImageSelected" /> + </actionGroup> + <actionGroup name="deleteImage"> + <see selector="{{MediaGallerySection.DeleteSelectedBtn}}" userInput="Delete Selected" stepKey="seeDeleteBtn"/> + <click selector="{{MediaGallerySection.DeleteSelectedBtn}}" stepKey="clickDeleteSelected" /> + <waitForText userInput="OK" stepKey="waitForConfirm" /> + <click selector="{{MediaGallerySection.confirmDelete}}" stepKey="confirmDelete" /> + <waitForElementNotVisible selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="waitForImageDeleted" /> + <dontSeeElement selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="dontSeeImage" /> + </actionGroup> + <actionGroup name="saveImage"> + <click selector="{{MediaGallerySection.InsertFile}}" stepKey="clickInsertBtn" /> + <waitForPageLoad stepKey="waitForPageLoad2"/> + </actionGroup> + <actionGroup name="fillOutUploadImagePopup"> + <waitForElementVisible selector="{{MediaGallerySection.OkBtn}}" stepKey="waitForOkBtn" /> + <fillField selector="{{MediaGallerySection.ImageDescription}}" userInput="{{ImageUpload.content}}" stepKey="fillImageDescription" /> + <fillField selector="{{MediaGallerySection.Height}}" userInput="{{ImageUpload.height}}" stepKey="fillImageHeight" /> + <click selector="{{MediaGallerySection.OkBtn}}" stepKey="clickOkBtn" /> + <waitForPageLoad stepKey="wait3"/> + </actionGroup> + <actionGroup name="verifyOversizeValidationMsg"> + <see userInput="this is oversize" stepKey="seeValidationMsg"/> + <click selector="#OK" stepKey="clickOKBtn"/> + </actionGroup> + <actionGroup name="verifyWrongExtensionValidationMsg"> + <see userInput="this is wrong extension" stepKey="seeValidationMsg"/> + <click selector="#OK" stepKey="clickOKBtn"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Data/CmsPageData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Data/CmsPageData.xml index a2619ec290708..49a96bdc27ed2 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Data/CmsPageData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Data/CmsPageData.xml @@ -7,7 +7,7 @@ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> <entity name="_defaultCmsPage" type="cms_page"> <data key="title">Test CMS Page</data> <data key="content_heading">Test Content Heading</data> @@ -25,7 +25,18 @@ <data key="price">1.00</data> <data key="file_type">Upload File</data> <data key="shareable">Yes</data> - <data key="file">magento.jpg</data> + <data key="value">magento.jpg</data> + <data key="fileName">magento</data> + <data key="content">Image content. Yeah.</data> + <data key="height">1000</data> + </entity> + <entity name="ImageUpload_1" type="uploadImage"> + <data key="title" unique="suffix">Image1</data> + <data key="price">1.00</data> + <data key="file_type">Upload File</data> + <data key="shareable">Yes</data> + <data key="file">magento-again.jpg</data> + <data key="value">magento-again.jpg</data> <data key="content">Image content. Yeah.</data> <data key="height">1000</data> </entity> @@ -34,7 +45,20 @@ <data key="price">1.00</data> <data key="file_type">Upload File</data> <data key="shareable">Yes</data> - <data key="file">magento2.jpg</data> + <data key="value">magento2.jpg</data> + <data key="fileName">magento2</data> + <data key="extension">jpg</data> + <data key="content">Image content. Yeah.</data> + <data key="height">1000</data> + </entity> + <entity name="ImageUpload3" type="uploadImage"> + <data key="title" unique="suffix">Image1</data> + <data key="price">1.00</data> + <data key="file_type">Upload File</data> + <data key="shareable">Yes</data> + <data key="value">magento3.jpg</data> + <data key="fileName">magento3</data> + <data key="extension">jpg</data> <data key="content">Image content. Yeah.</data> <data key="height">1000</data> </entity> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Page/CmsBlocksPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Page/CmsBlocksPage.xml index e3ce452abbf01..e2db4ced8c4d0 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Page/CmsBlocksPage.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Page/CmsBlocksPage.xml @@ -7,8 +7,8 @@ --> <pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="CmsBlocksPage" url="cms/block" area="admin" module="Magento_Block"> + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="CmsBlocksPage" url="/cms/block/" area="admin" module="Magento_Cms"> <section name="BlockPageActionsSection"/> </page> </pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Page/StorefrontHomePage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Page/StorefrontHomePage.xml new file mode 100644 index 0000000000000..a6cdd6d333984 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Page/StorefrontHomePage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="StorefrontHomePage" url="/" module="Magento_Cms" area="storefront"> + <section name="StorefrontHeaderSection"/> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageActionsSection.xml index 7dce25478979f..b196bee7981c5 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageActionsSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockNewPageActionsSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="BlockNewPagePageActionsSection"> <element name="saveBlock" type="button" selector="#save" timeout="30"/> + <element name="saveAndContinueEdit" type="button" selector="#save_and_continue"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockPageActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockPageActionsSection.xml index 4d69570e5994e..e5609f55daec7 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockPageActionsSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/BlockPageActionsSection.xml @@ -15,5 +15,8 @@ <element name="idColumn" type="button" selector="//div[contains(@data-role, 'grid-wrapper')]/table/thead/tr/th/span[contains(text(), 'ID')]"/> <element name="clearAll" type="button" selector="//div[@class='admin__data-grid-header']//button[contains(text(), 'Clear all')]"/> <element name="activeFilters" type="button" selector="//div[@class='admin__data-grid-header']//span[contains(text(), 'Active filters:')]" /> + <element name="FilterBtn" type="input" selector="//button[text()='Filters']"/> + <element name="URLKey" type="input" selector="//div[@class='admin__form-field-control']/input[@name='identifier']"/> + <element name="ApplyFiltersBtn" type="button" selector="//span[text()='Apply Filters']"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsPagesPageActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsPagesPageActionsSection.xml index 5e6ca7a193613..c302a029792e9 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsPagesPageActionsSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/CmsPagesPageActionsSection.xml @@ -18,5 +18,7 @@ <element name="select" type="button" selector="//div[text()='{{var1}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//button[text()='Select']" parameterized="true"/> <element name="edit" type="button" selector="//div[text()='{{var1}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//a[text()='Edit']" parameterized="true"/> <element name="preview" type="button" selector="//div[text()='{{var1}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//a[text()='Preview']" parameterized="true"/> + <element name="clearAll" type="button" selector="//div[@class='admin__data-grid-header']//button[contains(text(), 'Clear all')]"/> + <element name="activeFilters" type="button" selector="//div[@class='admin__data-grid-header']//span[contains(text(), 'Active filters:')]" /> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontBlockSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontBlockSection.xml index 1f242f4b5deeb..69d07ba32b9a2 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontBlockSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontBlockSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontBlockSection"> <element name="mediaDescription" type="text" selector=".widget.block.block-static-block>p>img"/> + <element name="ImageSource" type="text" selector="//img[contains(@src,'{{var1}}') and not(contains(@src,'{{var2}}/'))]" parameterized="true"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontCMSPageSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontCMSPageSection.xml index 7c617d0707072..8f70dc8f1f98d 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontCMSPageSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontCMSPageSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontCMSPageSection"> <element name="mediaDescription" type="text" selector=".column.main>p>img"/> + <element name="ImageSource" type="text" selector="//img[contains(@src,'{{var1}}') and not(contains(@src,'{{var2}}/'))]" parameterized="true"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontHeaderSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontHeaderSection.xml new file mode 100644 index 0000000000000..0a2fb1179ebbd --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Section/StorefrontHeaderSection.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontHeaderSection"> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGBlockCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGBlockCest.xml index aff3a399f4753..00673747c7c99 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGBlockCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGBlockCest.xml @@ -16,6 +16,8 @@ <description value="Admin should be able to add image to WYSIWYG content of Block"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-84376"/> + <!--Skip because of issue MAGETWO-88266--> + <group value="skip"/> </annotations> <before> <createData entity="_defaultCmsPage" stepKey="createCMSPage" /> @@ -31,48 +33,25 @@ <waitForElementVisible selector="{{TinyMCESection.TinyMCE4}}" stepKey="waitForTinyMCE" /> <click selector="{{TinyMCESection.InsertImageIcon}}" stepKey="clickInsertImageIcon" /> <waitForPageLoad stepKey="waitForPageLoad2" /> - <click selector="{{MediaGallerySection.Browse}}" stepKey="clickBrowse" /> - <waitForPageLoad stepKey="waitForPageLoad3" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading1" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading2" /> - <waitForElement selector="{{MediaGallerySection.CancelBtn}}" stepKey="waitForContent" /> - <see selector="{{MediaGallerySection.CancelBtn}}" userInput="Cancel" stepKey="seeCancelBtn" /> - <see selector="{{MediaGallerySection.CreateFolder}}" userInput="Create Folder" stepKey="seeCreateFolderBtn" /> - <see selector="{{MediaGallerySection.InsertFile}}" userInput="Add Selected" stepKey="seeAddSelectedBtn" /> - <click selector="{{MediaGallerySection.CreateFolder}}" stepKey="createFolder"/> - <waitForElementVisible selector="{{MediaGallerySection.FolderName}}" stepKey="waitForPopUp" /> - <fillField selector="{{MediaGallerySection.FolderName}}" userInput="{{ImageFolder.name}}" stepKey="fillFolderName" /> - <waitForElement selector="{{MediaGallerySection.AcceptFolderName}}" stepKey="waitForAcceptBtn" /> - <wait time="3" stepKey="wait"/> - <click selector="{{MediaGallerySection.AcceptFolderName}}" stepKey="acceptFolderName" /> - <waitForPageLoad stepKey="waitForPageLoad4" /> - <conditionalClick selector="{{MediaGallerySection.StorageRootArrow}}" dependentSelector="{{MediaGallerySection.checkIfArrowExpand}}" stepKey="clickArrowIfCloses" visible="true"/> - <waitForText userInput="{{ImageFolder.name}}" stepKey="waitForNewFolder" /> - <click userInput="{{ImageFolder.name}}" stepKey="clickOnCreatedFolder" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading3" /> - <attachFile selector="{{MediaGallerySection.BrowseUploadImage}}" userInput="{{ImageUpload.file}}" stepKey="uploadImage1"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading4" /> - <waitForElementVisible selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="waitForUploadImage1" /> - <seeElement selector="{{MediaGallerySection.imageSelected(ImageUpload.file)}}" stepKey="seeImageSelected" /> - <see selector="{{MediaGallerySection.DeleteSelectedBtn}}" userInput="Delete Selected" stepKey="seeDeleteBtn"/> - <click selector="{{MediaGallerySection.DeleteSelectedBtn}}" stepKey="clickDeleteSelected" /> - <waitForText userInput="OK" stepKey="waitForConfirm" /> - <click selector="{{MediaGallerySection.confirmDelete}}" stepKey="confirmDelete" /> - <waitForElementNotVisible selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="waitForImageDeleted" /> - <dontSeeElement selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="dontSeeImage" /> - <attachFile selector="{{MediaGallerySection.BrowseUploadImage}}" userInput="{{ImageUpload.file}}" stepKey="uploadImage2"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading5" /> - <waitForElementVisible selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="waitForUploadImage2" /> - <click selector="{{MediaGallerySection.InsertFile}}" stepKey="clickInsertBtn" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading6" /> - <waitForElementVisible selector="{{MediaGallerySection.OkBtn}}" stepKey="waitForOkBtn" /> - <fillField selector="{{MediaGallerySection.ImageDescription}}" userInput="{{ImageUpload.content}}" stepKey="fillImageDescription" /> - <fillField selector="{{MediaGallerySection.Height}}" userInput="{{ImageUpload.height}}" stepKey="fillImageHeight" /> - <click selector="{{MediaGallerySection.OkBtn}}" stepKey="clickOkBtn" /> - <waitForPageLoad stepKey="waitForPageLoad5"/> + <actionGroup ref="clickBrowseBtnOnUploadPopup" stepKey="clickBrowserBtn"/> + <actionGroup ref="VerifyMediaGalleryStorageActions" stepKey="VerifyMediaGalleryStorageBtn"/> + <actionGroup ref="CreateImageFolder" stepKey="CreateImageFolder"> + <argument name="ImageFolder" value="ImageFolder"/> + </actionGroup> + <actionGroup ref="attachImage" stepKey="attachImage1"> + <argument name="Image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="deleteImage" stepKey="deleteImage"/> + <actionGroup ref="attachImage" stepKey="attachImage2"> + <argument name="Image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="saveImage" stepKey="insertImage"/> + <actionGroup ref="fillOutUploadImagePopup" stepKey="fillOutUploadImagePopup" /> <click selector="{{BlockNewPagePageActionsSection.saveBlock}}" stepKey="clickSaveBlock"/> <amOnPage url="{{CmsPagesPage.url}}" stepKey="amOnEditPage"/> <waitForPageLoad stepKey="waitForPageLoad6"/> + <conditionalClick selector="{{CmsPagesPageActionsSection.clearAll}}" dependentSelector="{{CmsPagesPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> + <waitForPageLoad stepKey="waitForGridReload"/> <click selector="{{CmsPagesPageActionsSection.FilterBtn}}" stepKey="clickFiltersBtn" /> <fillField selector="{{CmsPagesPageActionsSection.URLKey}}" userInput="$$createCMSPage.identifier$$" stepKey="fillOutURLKey" /> <click selector="{{CmsPagesPageActionsSection.ApplyFiltersBtn}}" stepKey="clickApplyBtn" /> @@ -107,7 +86,12 @@ <waitForPageLoad stepKey="waitForPageLoad11" /> <!--see image on Storefront--> <seeElement selector="{{StorefrontBlockSection.mediaDescription}}" stepKey="assertMediaDescription"/> + <seeElementInDOM selector="{{StorefrontBlockSection.ImageSource(ImageUpload3.fileName,ImageUpload3.extension)}}" stepKey="assertMediaSource"/> <after> + <amOnPage url="{{CmsPagesPage.url}}" stepKey="amOnEditPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <conditionalClick selector="{{CmsPagesPageActionsSection.clearAll}}" dependentSelector="{{CmsPagesPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> + <waitForPageLoad stepKey="waitForGridReload"/> <deleteData createDataKey="createCMSPage" stepKey="deletePreReqCMSPage" /> <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> <actionGroup ref="logout" stepKey="logout"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGCMSCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGCMSCest.xml index f490a221b311b..b82d1836aa603 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGCMSCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddImageToWYSIWYGCMSCest.xml @@ -16,6 +16,8 @@ <description value="Admin should be able to add image to WYSIWYG content of CMS Page"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-85825"/> + <!--Skip because of issue MAGETWO-88266--> + <group value="skip"/> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="login"/> @@ -29,42 +31,21 @@ <waitForElementVisible selector="{{TinyMCESection.TinyMCE4}}" stepKey="waitForTinyMCE4" /> <click selector="{{TinyMCESection.InsertImageIcon}}" stepKey="clickInsertImageIcon" /> <waitForPageLoad stepKey="waitForPageLoad" /> - <click selector="{{MediaGallerySection.Browse}}" stepKey="clickBrowse" /> - <waitForPageLoad stepKey="waitForPageLoad1" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading1" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading2" /> - <see selector="{{MediaGallerySection.CancelBtn}}" userInput="Cancel" stepKey="seeCancelBtn" /> - <see selector="{{MediaGallerySection.CreateFolder}}" userInput="Create Folder" stepKey="seeCreateFolderBtn" /> - <see selector="{{MediaGallerySection.InsertFile}}" userInput="Add Selected" stepKey="seeAddSelectedBtn" /> - <click selector="{{MediaGallerySection.CreateFolder}}" stepKey="createFolder"/> - <waitForElementVisible selector="{{MediaGallerySection.FolderName}}" stepKey="waitForPopUp" /> - <fillField selector="{{MediaGallerySection.FolderName}}" userInput="{{ImageFolder.name}}" stepKey="fillFolderName" /> - <click selector="{{MediaGallerySection.AcceptFolderName}}" stepKey="acceptFolderName" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading3" /> - <conditionalClick selector="{{MediaGallerySection.StorageRootArrow}}" dependentSelector="{{MediaGallerySection.checkIfArrowExpand}}" stepKey="clickArrowIfCloses" visible="true"/> - <waitForText userInput="{{ImageFolder.name}}" stepKey="waitForNewFolder" /> - <click userInput="{{ImageFolder.name}}" stepKey="clickOnCreatedFolder" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading5" /> - <attachFile selector="{{MediaGallerySection.BrowseUploadImage}}" userInput="{{ImageUpload.file}}" stepKey="uploadImage1"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading6" /> - <waitForElementVisible selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="waitForUploadImage1" /> - <seeElement selector="{{MediaGallerySection.imageSelected(ImageUpload.file)}}" stepKey="seeImageSelected" /> - <see selector="{{MediaGallerySection.DeleteSelectedBtn}}" userInput="Delete Selected" stepKey="seeDeleteBtn"/> - <click selector="{{MediaGallerySection.DeleteSelectedBtn}}" stepKey="clickDeleteSelected" /> - <waitForText userInput="OK" stepKey="waitForConfirm" /> - <click selector="{{MediaGallerySection.confirmDelete}}" stepKey="confirmDelete" /> - <waitForElementNotVisible selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="waitForImageDeleted" /> - <dontSeeElement selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="dontSeeImage" /> - <attachFile selector="{{MediaGallerySection.BrowseUploadImage}}" userInput="{{ImageUpload.file}}" stepKey="uploadImage2"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading9" /> - <waitForElementVisible selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="waitForUploadImage2" /> - <click selector="{{MediaGallerySection.InsertFile}}" stepKey="clickInsertBtn" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading7" /> - <waitForElementVisible selector="{{MediaGallerySection.OkBtn}}" stepKey="waitForOkBtn" /> - <fillField selector="{{MediaGallerySection.ImageDescription}}" userInput="{{ImageUpload.content}}" stepKey="fillImageDescription" /> - <fillField selector="{{MediaGallerySection.Height}}" userInput="{{ImageUpload.height}}" stepKey="fillImageHeight" /> - <click selector="{{MediaGallerySection.OkBtn}}" stepKey="clickOkBtn" /> - <waitForPageLoad stepKey="wait3"/> + <actionGroup ref="clickBrowseBtnOnUploadPopup" stepKey="clickBrowserBtn"/> + <actionGroup ref="VerifyMediaGalleryStorageActions" stepKey="VerifyMediaGalleryStorageBtn"/> + <actionGroup ref="CreateImageFolder" stepKey="CreateImageFolder"> + <argument name="ImageFolder" value="ImageFolder"/> + </actionGroup> + <actionGroup ref="attachImage" stepKey="attachImage1"> + <argument name="Image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="deleteImage" stepKey="deleteImage"/> + + <actionGroup ref="attachImage" stepKey="attachImage2"> + <argument name="Image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="saveImage" stepKey="insertImage"/> + <actionGroup ref="fillOutUploadImagePopup" stepKey="fillOutUploadImagePopup" /> <click selector="{{CmsNewPagePageSeoSection.header}}" stepKey="clickExpandSearchEngineOptimisation"/> <fillField selector="{{CmsNewPagePageSeoSection.urlKey}}" userInput="{{_defaultCmsPage.identifier}}" stepKey="fillFieldUrlKey"/> <click selector="{{CmsNewPagePageActionsSection.savePage}}" stepKey="clickSavePage"/> @@ -72,6 +53,7 @@ <amOnPage url="{{_defaultCmsPage.identifier}}" stepKey="amOnPageTestPage"/> <waitForPageLoad stepKey="wait4"/> <seeElement selector="{{StorefrontCMSPageSection.mediaDescription}}" stepKey="assertMediaDescription"/> + <seeElementInDOM selector="{{StorefrontCMSPageSection.ImageSource(ImageUpload3.fileName,ImageUpload3.extension)}}" stepKey="assertMediaSource"/> <after> <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> <actionGroup ref="logout" stepKey="logout"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGBlockCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGBlockCest.xml index cdabb43bd4658..464a708e0f70b 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGBlockCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGBlockCest.xml @@ -12,6 +12,8 @@ <features value="MAGETWO-36659-[CMS] WYSIWYG update"/> <stories value="MAGETWO-42158-Variable with WYSIWYG"/> <group value="Cms"/> + <group value="skip"/> + <!-- Skipped; see MAGETWO-88218 --> <title value="Admin should be able to add variable to WYSIWYG content of Block"/> <description value="You should be able to add variable to WYSIWYG content Block"/> <testCaseId value="MAGETWO-84378"/> @@ -72,13 +74,13 @@ <waitForPageLoad stepKey="waitForPageLoad6"/> <click selector="{{VariableSection.InsertVariableBtnEnabled}}" stepKey="save2" /> <waitForElementNotVisible selector="{{VariableSection.VariableTitle}}" stepKey="waitForSlideOutClose" /> - <click selector="{{BlockWYSIWYGSection.ShowHideBtn}}" stepKey="clickShow/HideBtn"/> + <click selector="{{BlockWYSIWYGSection.ShowHideBtn}}" stepKey="clickShowHideBtn"/> <waitForElementVisible selector="{{TinyMCESection.InsertVariableBtn}}" stepKey="waitForInsertVariableBtn" /> <seeElement selector="{{TinyMCESection.InsertVariableBtn}}" stepKey="InsertVariableBtn" /> <click selector="{{BlockNewPagePageActionsSection.saveBlock}}" stepKey="clickSaveBlock"/> <amOnPage url="{{CmsPagesPage.url}}" stepKey="amOnEditPage"/> <waitForPageLoad stepKey="waitForPageLoad7"/> - <conditionalClick selector="{{BlockPageActionsSection.clearAll}}" dependentSelector="{{BlockPageActionsSection.activeFilters}}" stepKey="clickToResetFilter1" visible="true"/> + <conditionalClick selector="{{CmsPagesPageActionsSection.clearAll}}" dependentSelector="{{CmsPagesPageActionsSection.activeFilters}}" stepKey="clickToResetFilter1" visible="true"/> <waitForPageLoad stepKey="waitForFilterReload"/> <click selector="{{CmsPagesPageActionsSection.FilterBtn}}" stepKey="clickFiltersBtn" /> <fillField selector="{{CmsPagesPageActionsSection.URLKey}}" userInput="$$createCMSPage.identifier$$" stepKey="fillOutURLKey" /> @@ -128,6 +130,10 @@ <!--see custom variable blank--> <dontSee userInput="{{customVariable.html}}" stepKey="dontSeeCustomVariableName" /> <after> + <amOnPage url="{{CmsPagesPage.url}}" stepKey="amOnEditPage"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <conditionalClick selector="{{CmsPagesPageActionsSection.clearAll}}" dependentSelector="{{CmsPagesPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> + <waitForPageLoad stepKey="waitForGridReload"/> <deleteData createDataKey="createCMSPage" stepKey="deletePreReqCMSPage" /> <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> <actionGroup ref="logout" stepKey="logout"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGCMSCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGCMSCest.xml index 36f997cfd3849..33115159e2f71 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGCMSCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddVariableToWYSIWYGCMSCest.xml @@ -11,7 +11,7 @@ <annotations> <features value="MAGETWO-36659-[CMS] WYSIWYG update"/> <stories value="MAGETWO-42158-Variable with WYSIWYG "/> - <group value="Cms"/> + <group value="skip"/> <title value="Insert default Magento variable into content of WYSIWYG on CMS Pages"/> <description value="Insert default Magento variable into content of WYSIWYG on CMS Pages"/> <severity value="CRITICAL"/> @@ -71,7 +71,7 @@ <waitForPageLoad stepKey="waitForPageLoad6"/> <click selector="{{VariableSection.InsertVariableBtnEnabled}}" stepKey="save2" /> <waitForElementNotVisible selector="{{VariableSection.VariableTitle}}" stepKey="waitForSlideOutClose" /> - <click selector="{{CmsWYSIWYGSection.ShowHideBtn}}" stepKey="clickShow/HideBtn"/> + <click selector="{{CmsWYSIWYGSection.ShowHideBtn}}" stepKey="clickShowHideBtn"/> <waitForElementVisible selector="{{CmsWYSIWYGSection.InsertVariableBtn}}" stepKey="waitForInsertVariableBtn" /> <seeElement selector="{{CmsWYSIWYGSection.InsertVariableBtn}}" stepKey="InsertVariableBtn" /> <scrollTo selector="{{CmsNewPagePageSeoSection.header}}" stepKey="scrollToSearchEngineTab" /> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGBlockCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGBlockCest.xml index 22d7661b2b952..c3c76271597ff 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGBlockCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGBlockCest.xml @@ -16,18 +16,17 @@ <description value="Admin should be able to add widget to WYSIWYG content Block"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-84654"/> - <group value="skip" /> </annotations> <before> <createData entity="_defaultCmsPage" stepKey="createCMSPage" /> + <createData entity="_defaultBlock" stepKey="createPreReqBlock" /> <actionGroup ref="LoginActionGroup" stepKey="login"/> <actionGroup ref="EnabledWYSIWYG" stepKey="enableWYSIWYG"/> <actionGroup ref="SwitchToVersion4ActionGroup" stepKey="switchToTinyMCE4" /> </before> - <amOnPage url="{{CmsNewBlock.url}}" stepKey="amOnNewBlockPage"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> - <fillField selector="{{BlockNewPageBasicFieldsSection.blockTitle}}" userInput="{{_defaultBlock.title}}" stepKey="fillFieldTitle"/> - <fillField selector="{{BlockNewPageBasicFieldsSection.identifier}}" userInput="{{_defaultBlock.identifier}}" stepKey="fillFieldIdentifier"/> + <actionGroup ref="navigateToCreatedCMSBlockPage" stepKey="navigateToCreatedCMSBlockPage"> + <argument name="CMSBlockPage" value="$$createPreReqBlock$$"/> + </actionGroup> <selectOption selector="{{BlockNewPageBasicFieldsSection.storeView}}" userInput="All Store View" stepKey="selectAllStoreView" /> <waitForElementVisible selector="{{TinyMCESection.TinyMCE4}}" stepKey="waitForTinyMCE" /> <click selector="{{TinyMCESection.InsertWidgetIcon}}" stepKey="clickInsertWidgetIcon1" /> @@ -45,19 +44,9 @@ <waitForLoadingMaskToDisappear stepKey="waitForLoading" /> <waitForElementNotVisible selector="{{WidgetSection.InsertWidgetTitle}}" stepKey="waitForSlideOutCloses1" /> <click selector="{{BlockNewPagePageActionsSection.saveBlock}}" stepKey="clickSaveBlock"/> - <amOnPage url="{{CmsPagesPage.url}}" stepKey="amOnEditPage"/> - <waitForPageLoad stepKey="waitForPageLoad3"/> - <click selector="{{CmsPagesPageActionsSection.FilterBtn}}" stepKey="clickFiltersBtn" /> - <fillField selector="{{CmsPagesPageActionsSection.URLKey}}" userInput="$$createCMSPage.identifier$$" stepKey="fillOutURLKey" /> - <click selector="{{CmsPagesPageActionsSection.ApplyFiltersBtn}}" stepKey="clickApplyBtn" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading1" /> - <actionGroup ref="SortByIdDescendingActionGroup" stepKey="sortByIdDescending" /> - <waitForElementVisible selector="{{CmsPagesPageActionsSection.select('$$createCMSPage.identifier$$')}}" stepKey="waitForCMSPageGrid" /> - <click selector="{{CmsPagesPageActionsSection.select('$$createCMSPage.identifier$$')}}" stepKey="clickSelect" /> - <waitForElementVisible selector="{{CmsPagesPageActionsSection.edit('$$createCMSPage.identifier$$')}}" stepKey="waitForEditLink" /> - <click selector="{{CmsPagesPageActionsSection.edit('$$createCMSPage.identifier$$')}}" stepKey="clickEdit" /> - <waitForPageLoad stepKey="waitForPageLoad4" /> - <click selector="{{CmsNewPagePageContentSection.header}}" stepKey="clickContentTab" /> + <actionGroup ref="navigateToCreatedCMSPage" stepKey="navigateToCreatedCMSPage"> + <argument name="CMSPage" value="$$createCMSPage$$"/> + </actionGroup> <waitForElementVisible selector="{{TinyMCESection.TinyMCE4}}" stepKey="waitForTinyMCE4"/> <seeElement selector="{{TinyMCESection.InsertWidgetIcon}}" stepKey="seeWidgetIcon" /> <click selector="{{TinyMCESection.InsertWidgetIcon}}" stepKey="clickInsertWidgetIcon2" /> @@ -67,8 +56,9 @@ <selectOption selector="{{WidgetSection.WidgetTemplate}}" userInput="CMS Static Block Default Template" stepKey="selectTemplate2" /> <click selector="{{WidgetSection.BtnChooser}}" stepKey="clickSelectPageBtn2" /> <waitForLoadingMaskToDisappear stepKey="waitForWidgetChooserLoadingMaskToDisappear"/> - <actionGroup ref="SortByIdDescendingActionGroup" stepKey="sortByIdDescending2" /> - <waitForElementVisible selector="{{WidgetSection.BlockPage(_defaultBlock.identifier)}}" stepKey="waitForBlockTitle" /> + <actionGroup ref="searchBlockOnGridPage" stepKey="searchBlockOnGridPage"> + <argument name="Block" value="_defaultBlock"/> + </actionGroup> <click selector="{{WidgetSection.BlockPage(_defaultBlock.identifier)}}" stepKey="selectPreCreateBlock" /> <wait time="3" stepKey="wait1" /> <click selector="{{WidgetSection.InsertWidget}}" stepKey="clickInsertWidgetBtn" /> @@ -76,11 +66,17 @@ <waitForPageLoad stepKey="waitForPageLoad6" /> <click selector="{{CmsNewPagePageActionsSection.savePage}}" stepKey="clickSavePage"/> <see userInput="You saved the page." stepKey="seeSuccessMessage"/> + <actionGroup ref="ClearCacheActionGroup" stepKey="clearCache" /> <amOnPage url="$$createCMSPage.identifier$$" stepKey="amOnPageTestPage1"/> <waitForPageLoad stepKey="waitForPageLoad7" /> <see userInput="Home page" stepKey="seeHomePageCMSPage"/> <after> + <amOnPage url="{{CmsPagesPage.url}}" stepKey="amOnEditPage"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <conditionalClick selector="{{CmsPagesPageActionsSection.clearAll}}" dependentSelector="{{CmsPagesPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> + <waitForPageLoad stepKey="waitForGridReload"/> <deleteData createDataKey="createCMSPage" stepKey="deletePreReqCMSPage" /> + <deleteData createDataKey="createPreReqBlock" stepKey="deletePreReqBlock" /> <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> <actionGroup ref="logout" stepKey="logout"/> </after> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeCest.xml index bbcca1571db54..3317b4143033c 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCMSPageLinkTypeCest.xml @@ -44,13 +44,14 @@ <see selector="{{WidgetSection.InsertWidgetBtnEnabled}}" userInput="Insert Widget" stepKey="seeInsertWidgetEnabled" /> <selectOption selector="{{WidgetSection.WidgetTemplate}}" userInput="CMS Page Link Block Template" stepKey="selectTemplate" /> <click selector="{{WidgetSection.BtnChooser}}" stepKey="clickSelectPageBtn" /> - <!--<waitForLoadingMaskToDisappear stepKey="wait3"/>--> <waitForElementVisible selector="{{WidgetSection.CMSPage}}" stepKey="waitForPageVisible" /> <scrollTo selector="{{WidgetSection.CMSPage}}" stepKey="scrollToCMSName" /> <click selector="{{WidgetSection.CMSPage}}" stepKey="selectPreCreateCMS" /> <waitForElementNotVisible selector="{{WidgetSection.SelectPageTitle}}" stepKey="waitForSlideOutCloses" /> + <wait time="3" stepKey="waitForInsertWidgetClickable"/> <click selector="{{WidgetSection.InsertWidget}}" stepKey="clickInsertWidget" /> <waitForLoadingMaskToDisappear stepKey="waitForLoading" /> + <waitForElementNotVisible selector="{{WidgetSection.InsertWidgetTitle}}" stepKey="waitForSlideoutCloses" /> <scrollTo selector="{{CmsNewPagePageSeoSection.header}}" stepKey="scrollToSearchEngineTab" /> <click selector="{{CmsNewPagePageSeoSection.header}}" stepKey="clickExpandSearchEngineOptimisation"/> <wait stepKey="waitForPageLoad5" time="10" /> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeCest.xml index e21a77b25e6e0..52dccc139c48f 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithCatalogProductListTypeCest.xml @@ -54,7 +54,7 @@ <waitForElementVisible selector="{{WidgetSection.ConditionsDropdown}}" stepKey="waitForDropdownVisible"/> <selectOption selector="{{WidgetSection.ConditionsDropdown}}" userInput="Category" stepKey="selectCategoryCondition" /> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskDisappear2" /> - <click selector="{{WidgetSection.RuleParam}}" stepKey="click ..." /> + <click selector="{{WidgetSection.RuleParam}}" stepKey="clickRuleParam" /> <waitForElementVisible selector="{{WidgetSection.Chooser}}" stepKey="waitForElement" /> <click selector="{{WidgetSection.Chooser}}" stepKey="clickChooser" /> <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskDisappear3" /> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeCest.xml index 102de9727adb6..367d166fe502e 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/AdminAddWidgetToWYSIWYGWithRecentlyComparedProductsTypeCest.xml @@ -68,7 +68,7 @@ <waitForPageLoad stepKey="waitForPage2" /> <waitForElementVisible selector="{{WidgetSection.ClearCompare}}" stepKey="waitForClearBtn" /> <click selector="{{WidgetSection.ClearCompare}}" stepKey="clickClearCompareBtn" /> - <waitForElementVisible selector="{{WidgetSection.AcceptClear}}" stepKey=""/> + <waitForElementVisible selector="{{WidgetSection.AcceptClear}}" stepKey="waitForAcceptBtn"/> <click selector="{{WidgetSection.AcceptClear}}" stepKey="acceptClearCompare" /> <waitForPageLoad stepKey="waitForPage3" /> <amOnPage url="{{_defaultCmsPage.identifier}}" stepKey="amOnPageTestPage"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockCest.xml index 7e9685814348f..adcc522cbf8ba 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Cms/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnBlockCest.xml @@ -41,7 +41,7 @@ <click selector="{{BlockNewPagePageActionsSection.saveBlock}}" stepKey="clickSaveBlock"/> <amOnPage url="{{CmsPagesPage.url}}" stepKey="amOnEditPage"/> <waitForPageLoad stepKey="waitForPageLoad2"/> - <conditionalClick selector="{{BlockPageActionsSection.clearAll}}" dependentSelector="{{BlockPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> + <conditionalClick selector="{{CmsPagesPageActionsSection.clearAll}}" dependentSelector="{{CmsPagesPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> <waitForPageLoad stepKey="waitForGridReload"/> <click selector="{{CmsPagesPageActionsSection.FilterBtn}}" stepKey="clickFiltersBtn" /> <fillField selector="{{CmsPagesPageActionsSection.URLKey}}" userInput="$$createPreReqCMSPage.identifier$$" stepKey="fillOutURLKey" /> @@ -82,6 +82,10 @@ <!--see content of Block on Storefront--> <see userInput="Hello Block Page!" stepKey="seeContent"/> <after> + <amOnPage url="{{CmsPagesPage.url}}" stepKey="amOnEditPage"/> + <waitForPageLoad stepKey="waitForPageLoad"/> + <conditionalClick selector="{{CmsPagesPageActionsSection.clearAll}}" dependentSelector="{{CmsPagesPageActionsSection.activeFilters}}" stepKey="clickToResetFilter" visible="true"/> + <waitForPageLoad stepKey="waitForGridReload"/> <deleteData createDataKey="createPreReqCMSPage" stepKey="deletePreReqCMSPage" /> <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> <actionGroup ref="logout" stepKey="logout"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/ConfigWYSIWYGActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/ConfigWYSIWYGActionGroup.xml index d9f8bb2170c55..11d7acc61d75e 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/ConfigWYSIWYGActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/ConfigWYSIWYGActionGroup.xml @@ -13,6 +13,7 @@ <waitForPageLoad stepKey="wait1"/> <conditionalClick stepKey="expandWYSIWYGOptions" selector="{{ContentManagementSection.WYSIWYGOptions}}" dependentSelector="{{ContentManagementSection.CheckIfTabExpand}}" visible="true" /> <waitForElementVisible selector="{{ContentManagementSection.EnableWYSIWYG}}" stepKey="waitForEnableWYSIWYGDropdown1" /> + <waitForElementVisible selector="{{ContentManagementSection.EnableSystemValue}}" stepKey="waitForUseSystemValueVisible"/> <uncheckOption selector="{{ContentManagementSection.EnableSystemValue}}" stepKey="uncheckUseSystemValue"/> <selectOption selector="{{ContentManagementSection.EnableWYSIWYG}}" userInput="Enabled by Default" stepKey="selectOption1"/> <click selector="{{ContentManagementSection.WYSIWYGOptions}}" stepKey="collapseWYSIWYGOptions" /> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/SwitcherActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/SwitcherActionGroup.xml index 7e2c4db153236..f127b14931c98 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/SwitcherActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Config/ActionGroup/SwitcherActionGroup.xml @@ -10,6 +10,7 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> <actionGroup name="SwitchToVersion4ActionGroup"> <amOnPage url="{{ConfigurationStoresPage.url}}" stepKey="navigateToWYSIWYGConfigPage1"/> + <waitForPageLoad stepKey="waitForConfigPageToLoad"/> <conditionalClick stepKey="expandWYSIWYGOptions" selector="{{ContentManagementSection.WYSIWYGOptions}}" dependentSelector="{{ContentManagementSection.CheckIfTabExpand}}" visible="true" /> <waitForElementVisible selector="{{ContentManagementSection.SwitcherSystemValue}}" stepKey="waitForCheckbox" /> <uncheckOption selector="{{ContentManagementSection.SwitcherSystemValue}}" stepKey="uncheckUseSystemValue"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/ConfigurableProductCheckoutActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/ConfigurableProductCheckoutActionGroup.xml new file mode 100644 index 0000000000000..78a7e8e09ad03 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/ConfigurableProductCheckoutActionGroup.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Check configurable product in checkout cart items --> + <actionGroup name="CheckConfigurableProductInCheckoutCartItemsActionGroup"> + <arguments> + <argument name="productVar" /> + <argument name="optionLabel" /> + <argument name="optionValue" /> + </arguments> + <waitForElement selector="{{CheckoutPaymentSection.paymentSectionTitle}}" time="30" stepKey="waitForPaymentSectionLoaded"/> + <conditionalClick selector="{{CheckoutPaymentSection.cartItemsArea}}" dependentSelector="{{CheckoutPaymentSection.cartItemsArea}}" visible="true" stepKey="exposeMiniCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMaskForCartItem"/> + <waitForElement selector="{{CheckoutPaymentSection.cartItemsAreaActive}}" time="30" stepKey="waitForCartItemsAreaActive"/> + <see selector="{{CheckoutPaymentSection.cartItems}}" userInput="{{productVar.name}}" stepKey="seeProductInCart"/> + <conditionalClick selector="{{CheckoutPaymentSection.ProductOptionsByProductItemName(productVar.name)}}" dependentSelector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName(productVar.name)}}" visible="false" stepKey="exposeProductOptions"/> + <see selector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName(productVar.name)}}" userInput="{{optionLabel}}" stepKey="seeProductOptionLabel" /> + <see selector="{{CheckoutPaymentSection.ProductOptionsActiveByProductItemName(productVar.name)}}" userInput="{{optionValue}}" stepKey="seeProductOptionValue" /> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontCategoryActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontCategoryActionGroup.xml new file mode 100644 index 0000000000000..6baf48fa6de04 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontCategoryActionGroup.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Check configurable product on the category page --> + <actionGroup name="StorefrontCheckCategoryConfigurableProduct"> + <arguments> + <argument name="product"/> + <argument name="optionProduct"/> + </arguments> + <seeElement selector="{{StorefrontCategoryProductSection.ProductTitleByName(product.name)}}" stepKey="assertProductName"/> + <see userInput="${{optionProduct.price}}.00" selector="{{StorefrontCategoryProductSection.ProductPriceByName(product.name)}}" stepKey="AssertProductPrice"/> + <!-- @TODO: MAGETWO-80272 Move to Magento_Checkout --> + <moveMouseOver selector="{{StorefrontCategoryProductSection.ProductInfoByName(product.name)}}" stepKey="moveMouseOverProduct" /> + <!-- @TODO: MAGETWO-80272 Move to Magento_Checkout --> + <seeElement selector="{{StorefrontCategoryProductSection.ProductAddToCartByName(product.name)}}" stepKey="AssertAddToCart" /> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontCompareActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontCompareActionGroup.xml new file mode 100644 index 0000000000000..f11f9cc6801ba --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontCompareActionGroup.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Check the configurable product in comparison page --> + <actionGroup name="StorefrontCheckCompareConfigurableProductActionGroup"> + <arguments> + <argument name="product"/> + <argument name="optionProduct"/> + </arguments> + <seeElement selector="{{StorefrontProductCompareMainSection.ProductLinkByName(product.name)}}" stepKey="assertProductName"/> + <see userInput="${{optionProduct.price}}.00" selector="{{StorefrontProductCompareMainSection.ProductPriceByName(product.name)}}" stepKey="assertProductPrice"/> + <see userInput="{{product.sku}}" selector="{{StorefrontProductCompareMainSection.ProductAttributeByCodeAndProductName('SKU', product.name)}}" stepKey="assertProductPrice"/> + <!-- @TODO: MAGETWO-80272 Move to Magento_Checkout --> + <seeElement selector="{{StorefrontProductCompareMainSection.ProductAddToCartByName(product.name)}}" stepKey="assertProductAddToCart"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontProductActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontProductActionGroup.xml new file mode 100644 index 0000000000000..9358faeca4625 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontProductActionGroup.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Check the configurable product on the product page --> + <actionGroup name="StorefrontCheckConfigurableProduct"> + <arguments> + <argument name="product"/> + <argument name="optionProduct"/> + </arguments> + <seeInCurrentUrl url="/{{product.custom_attributes[url_key]}}.html" stepKey="checkUrl"/> + <seeInTitle userInput="{{product.name}}" stepKey="AssertProductNameInTitle"/> + <see userInput="{{product.name}}" selector="{{StorefrontProductInfoMainSection.productName}}" stepKey="assertProductName"/> + <see userInput="{{product.sku}}" selector="{{StorefrontProductInfoMainSection.productSku}}" stepKey="assertProductSku"/> + <see userInput="${{optionProduct.price}}.00" selector="{{StorefrontProductInfoMainSection.productPrice}}" stepKey="assertProductPrice"/> + <see userInput="IN STOCK" selector="{{StorefrontProductInfoMainSection.productStockStatus}}" stepKey="assertInStock"/> + <seeElement selector="{{StorefrontProductInfoMainSection.AddToCart}}" stepKey="assertAddToCart" /> + <see userInput="{{product.custom_attributes[description]}}" selector="{{StorefrontProductInfoMainSection.productDescription}}" stepKey="assertProductDescription"/> + <see userInput="{{product.custom_attributes[short_description]}}" selector="{{StorefrontProductInfoMainSection.productShortDescription}}" stepKey="assertProductShortDescription"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontProductCartActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontProductCartActionGroup.xml new file mode 100644 index 0000000000000..3d813d4a06e43 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/ActionGroup/StorefrontProductCartActionGroup.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Check Configurable Product in the Cart --> + <actionGroup name="StorefrontCheckCartConfigurableProductActionGroup"> + <arguments> + <argument name="product"/> + <argument name="optionProduct"/> + <argument name="productQuantity"/> + </arguments> + <seeElement selector="{{CheckoutCartProductSection.ProductLinkByName(product.name)}}" stepKey="assertProductName"/> + <see userInput="${{optionProduct.price}}.00" selector="{{CheckoutCartProductSection.ProductPriceByName(product.name)}}" stepKey="assertProductPrice"/> + <seeInField userInput="{{productQuantity}}" selector="{{CheckoutCartProductSection.ProductQuantityByName(product.name)}}" stepKey="assertProductQuantity"/> + </actionGroup> + + <!-- Open the Minicart and check Configurable Product --> + <actionGroup name="StorefrontOpenMinicartAndCheckConfigurableProductActionGroup"> + <arguments> + <argument name="product"/> + <argument name="optionProduct"/> + </arguments> + <waitForElement selector="{{StorefrontMinicartSection.productLinkByName(product.name)}}" stepKey="waitForMinicartProduct" /> + <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickShowMinicart" /> + <see userInput="${{optionProduct.price}}.00" selector="{{StorefrontMinicartSection.productPriceByName(product.name)}}" stepKey="assertProductPrice"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ConfigurableProductData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ConfigurableProductData.xml index b5f538394380a..0a2429fa8f9e5 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ConfigurableProductData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ConfigurableProductData.xml @@ -22,6 +22,18 @@ <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> </entity> + <entity name="ApiConfigurableProduct" type="product"> + <data key="sku" unique="suffix">api-configurable-product</data> + <data key="type_id">configurable</data> + <data key="attribute_set_id">4</data> + <data key="visibility">4</data> + <data key="name" unique="suffix">API Configurable Product</data> + <data key="urlKey" unique="suffix">api-configurable-product</data> + <data key="status">1</data> + <data key="quantity">100</data> + <requiredEntity type="product_extension_attribute">EavStockItem</requiredEntity> + <requiredEntity type="custom_attribute_array">CustomAttributeCategoryIds</requiredEntity> + </entity> <entity name="ConfigurableProductAddChild" type="ConfigurableProductAddChild"> <var key="sku" entityKey="sku" entityType="product" /> <var key="childSku" entityKey="sku" entityType="product2"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ConstData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ConstData.xml new file mode 100644 index 0000000000000..457f59f214f9e --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Data/ConstData.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <!-- @TODO: Get rid off this workaround and its usages after MQE-498 is implemented --> + <entity name="CONST" type="CONST"> + <data key="three">3</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/AdminNewAttributePanelSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/AdminNewAttributePanelSection.xml index 81a9c58c6e820..469afa426bc1f 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/AdminNewAttributePanelSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/AdminNewAttributePanelSection.xml @@ -13,7 +13,7 @@ <element name="saveAttribute" type="button" selector="#save"/> <element name="newAttributeIFrame" type="iframe" selector="create_new_attribute_container"/> <element name="defaultLabel" type="input" selector="input[name='frontend_label[0]']"/> - <element name="inputType" type="select" selector="select[name='frontend_input']" timeout="10"/> + <element name="inputType" type="select" selector="select[name='frontend_input']" timeout="30"/> <element name="addOption" type="button" selector="#add_new_option_button"/> <element name="isDefault" type="radio" selector="[data-role='options-container'] tr:nth-of-type({{row}}) input[name='default[]']" parameterized="true"/> <element name="optionAdminValue" type="input" selector="[data-role='options-container'] input[name='option[value][option_{{row}}][0]']" parameterized="true"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/StorefrontProductInfoMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/StorefrontProductInfoMainSection.xml new file mode 100644 index 0000000000000..c5da83d9ac6ed --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Section/StorefrontProductInfoMainSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontProductInfoMainSection"> + <element name="optionByAttributeId" type="input" selector="#attribute{{var1}}" parameterized="true"/> + <element name="productAttributeTitle1" type="text" selector="#product-options-wrapper div[tabindex='0'] label"/> + <element name="productAttributeOptions1" type="select" selector="#product-options-wrapper div[tabindex='0'] option"/> + <element name="productAttributeOptionsSelectButton" type="select" selector="#product-options-wrapper .super-attribute-select"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminRelatedProductsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminRelatedProductsTest.xml new file mode 100644 index 0000000000000..00d53d7dbadb4 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/AdminRelatedProductsTest.xml @@ -0,0 +1,205 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminRelatedProductsTest"> + <annotations> + <features value="Promote Products as Related"/> + <stories value="Promote Products as Related"/> + <title value="Promote Products as Related"/> + <description value="You should be able to promote products as related via the admin."/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-12392"/> + <useCaseId value="USECASE-114"/> + <group value="configurable"/> + <group value="product"/> + </annotations> + <before> + <createData entity="SimpleSubCategory" stepKey="categoryHandle"/> + + <createData entity="SimpleProduct" stepKey="simple1Handle"> + <requiredEntity createDataKey="categoryHandle"/> + </createData> + + <createData entity="SimpleProduct" stepKey="simple2Handle"> + <requiredEntity createDataKey="categoryHandle"/> + </createData> + + <!-- TODO: Move configurable product creation to an actionGroup when MQE-697 is fixed --> + <createData entity="BaseConfigurableProduct" stepKey="baseConfigProductHandle"> + <requiredEntity createDataKey="categoryHandle"/> + </createData> + <createData entity="productDropDownAttribute" stepKey="productAttributeHandle"/> + + <createData entity="productAttributeOption1" stepKey="productAttributeOption1Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + <createData entity="productAttributeOption2" stepKey="productAttributeOption2Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + + <createData entity="AddToDefaultSet" stepKey="addToAttributeSetHandle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </createData> + + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getAttributeOption1Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getAttributeOption2Handle"> + <requiredEntity createDataKey="productAttributeHandle"/> + </getData> + + <createData entity="SimpleOne" stepKey="childProductHandle1"> + <requiredEntity createDataKey="productAttributeHandle"/> + <requiredEntity createDataKey="getAttributeOption1Handle"/> + </createData> + <createData entity="SimpleOne" stepKey="childProductHandle2"> + <requiredEntity createDataKey="productAttributeHandle"/> + <requiredEntity createDataKey="getAttributeOption2Handle"/> + </createData> + + <createData entity="ConfigurableProductTwoOptions" stepKey="configProductOptionHandle"> + <requiredEntity createDataKey="baseConfigProductHandle"/> + <requiredEntity createDataKey="productAttributeHandle"/> + <requiredEntity createDataKey="getAttributeOption1Handle"/> + <requiredEntity createDataKey="getAttributeOption2Handle"/> + </createData> + + <createData entity="ConfigurableProductAddChild" stepKey="configProductHandle1"> + <requiredEntity createDataKey="childProductHandle1"/> + <requiredEntity createDataKey="baseConfigProductHandle"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="configProductHandle2"> + <requiredEntity createDataKey="childProductHandle2"/> + <requiredEntity createDataKey="baseConfigProductHandle"/> + </createData> + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + </before> + <after> + <amOnPage url="admin/admin/auth/logout/" stepKey="logout"/> + <deleteData createDataKey="simple1Handle" stepKey="deleteSimple1"/> + <deleteData createDataKey="simple2Handle" stepKey="deleteSimple2"/> + <deleteData createDataKey="childProductHandle1" stepKey="deleteChild1"/> + <deleteData createDataKey="childProductHandle2" stepKey="deleteChild2"/> + <deleteData createDataKey="baseConfigProductHandle" stepKey="deleteConfig"/> + <deleteData createDataKey="categoryHandle" stepKey="deleteCategory"/> + <deleteData createDataKey="productAttributeHandle" stepKey="deleteProductAttribute"/> + </after> + + <comment userInput="Filter and edit simple product 1" stepKey="filterAndEditComment1"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="productIndexPage"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad1"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridSimple"> + <argument name="product" value="$$simple1Handle$$"/> + </actionGroup> + <click selector="{{AdminProductGridSection.productGridXRowYColumnButton('1', '2')}}" stepKey="openProductForEdit"/> + <conditionalClick selector="{{AdminProductFormSection.productFormTab('Related Products')}}" dependentSelector="{{AdminProductFormSection.productFormTabState('Related Products', 'closed')}}" visible="true" stepKey="openRelatedProductTab"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad3"/> + + <!-- TODO: move adding related product to a action group when nested action group is allowed (ref#: MQE-539)--> + <comment userInput="Add related simple product to simple product" stepKey="addSimpleToSimpleComment"/> + <click selector="{{AdminProductFormRelatedUpSellCrossSellSection.AddRelatedProductsButton}}" stepKey="clickAddRelatedProductButton"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridSimple1"> + <argument name="product" value="$$simple2Handle$$"/> + </actionGroup> + <click selector="{{AdminProductModalSlideGridSection.productGridXRowYColumnButton('1', '1')}}" stepKey="selectSimpleTwo"/> + <click selector="{{AdminProductGridFilterSection.clearFilters}}" stepKey="selectClearAll1"/> + <click selector="{{AdminAddRelatedProductsModalSection.AddSelectedProductsButton}}" stepKey="addRelatedProductSelected1"/> + + <comment userInput="Add related config product to simple product" stepKey="addConfigToSimpleComment"/> + <click selector="{{AdminProductFormRelatedUpSellCrossSellSection.AddRelatedProductsButton}}" stepKey="clickAddRelatedProductButton2"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridSimpleForRelatedConfig1"> + <argument name="product" value="$$baseConfigProductHandle$$"/> + </actionGroup> + <click selector="{{AdminProductModalSlideGridSection.productGridXRowYColumnButton('1', '1')}}" stepKey="selectConfigProduct"/> + <click selector="{{AdminProductGridFilterSection.clearFilters}}" stepKey="selectClearAll2"/> + <click selector="{{AdminAddRelatedProductsModalSection.AddSelectedProductsButton}}" stepKey="addRelatedProductSelected2"/> + + <comment userInput="Save simple product" stepKey="saveSimpleProductComment"/> + <actionGroup ref="saveProductForm" stepKey="saveRelatedProduct1"/> + + <comment userInput="Assert related simple products for simple product in Admin Product Form" stepKey="assertRelated1Comment"/> + <actionGroup ref="AssertTextInAdminProductRelatedUpSellCrossSellSection" stepKey="assertRelated1"> + <argument name="element" value="AdminProductFormRelatedUpSellCrossSellSection.relatedProductSectionText"/> + <argument name="expectedText" value="$$simple2Handle.name$$"/> + </actionGroup> + + <comment userInput="Assert related config products for simple product in Admin Product Form" stepKey="assertRelated2Comment"/> + <actionGroup ref="AssertTextInAdminProductRelatedUpSellCrossSellSection" stepKey="assertRelated2"> + <argument name="element" value="AdminProductFormRelatedUpSellCrossSellSection.relatedProductSectionText"/> + <argument name="expectedText" value="$$baseConfigProductHandle.name$$"/> + </actionGroup> + + <comment userInput="Filter and edit config product" stepKey="filterAndEditComment2"/> + <amOnPage url="{{AdminProductIndexPage.url}}" stepKey="productIndexPage2"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad5"/> + <actionGroup ref="resetProductGridToDefaultView" stepKey="resetProductGridColumnsInitial2"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridConfig"> + <argument name="product" value="$$baseConfigProductHandle$$"/> + </actionGroup> + <click selector="{{AdminProductGridSection.productGridXRowYColumnButton('1', '2')}}" stepKey="openProductForEdit2"/> + <conditionalClick selector="{{AdminProductFormSection.productFormTab('Related Products')}}" dependentSelector="{{AdminProductFormSection.productFormTabState('Related Products', 'closed')}}" visible="true" stepKey="openRelatedProductTab2"/> + <waitForPageLoad time="30" stepKey="waitForPageLoad7"/> + + <comment userInput="Add related simple product to config product" stepKey="addSimpleToConfigComment"/> + <click selector="{{AdminProductFormRelatedUpSellCrossSellSection.AddRelatedProductsButton}}" stepKey="clickAddRelatedProductButton3"/> + <actionGroup ref="filterProductGridBySku" stepKey="filterProductGridForConfig3"> + <argument name="product" value="$$simple2Handle$$"/> + </actionGroup> + <click selector="{{AdminProductModalSlideGridSection.productGridXRowYColumnButton('1', '1')}}" stepKey="selectSimpleTwo2"/> + <click selector="{{AdminProductGridFilterSection.clearFilters}}" stepKey="selectClearAll3"/> + <click selector="{{AdminAddRelatedProductsModalSection.AddSelectedProductsButton}}" stepKey="addRelatedProductSelected3"/> + + <comment userInput="Save config product" stepKey="saveConfigProductComment"/> + <actionGroup ref="saveProductForm" stepKey="saveRelatedProduct2"/> + + <comment userInput="Assert related simple product for config product in Admin Product Form" stepKey="assertRelated3Comment"/> + <actionGroup ref="AssertTextInAdminProductRelatedUpSellCrossSellSection" stepKey="assertRelated3"> + <argument name="element" value="AdminProductFormRelatedUpSellCrossSellSection.relatedProductSectionText"/> + <argument name="expectedText" value="$$simple2Handle.name$$"/> + </actionGroup> + + <comment userInput="Check storefront related products on simple product page" stepKey="navigateToSimpleProduct1PageComment"/> + <amOnPage url="$$simple1Handle.custom_attributes[url_key]$$.html" stepKey="navigateToSimpleProduct1Page"/> + <waitForPageLoad stepKey="waitForPageLoad9"/> + <see selector="{{StorefrontProductRelatedProductsSection.relatedProductsActionsHeaderText}}" userInput="Check items to add to the cart" stepKey="assertRelatedProductHeaderInStorefront1"/> + <see selector="{{StorefrontProductRelatedProductsSection.relatedProductsActionsHeaderText}}" userInput="select all" stepKey="assertRelatedProductHeaderInStorefront2"/> + <see selector="{{StorefrontProductRelatedProductsSection.relatedProductsListSectionText}}" userInput="$$simple2Handle.name$$" stepKey="assertRelatedSimpleProductNameInStorefront"/> + <see selector="{{StorefrontProductRelatedProductsSection.relatedProductsListSectionText}}" userInput="$$baseConfigProductHandle.name$$" stepKey="assertRelatedConfigProductNameInStorefront"/> + + <comment userInput="Navigate to product page from related product link" stepKey="navigateToConfigProductFromRelatedSectionComment"/> + <click selector="{{StorefrontProductRelatedProductsSection.relatedProductName('$$baseConfigProductHandle.custom_attributes[url_key]$$')}}" stepKey="clickRelatedProductByName"/> + <waitForPageLoad stepKey="waitForPageLoad11"/> + <seeInCurrentUrl url="$$baseConfigProductHandle.custom_attributes[url_key]$$" stepKey="seeInCurrentUrl"/> + + <comment userInput="Select option for configurable product" stepKey="selectOptionConfigProduct"/> + <selectOption selector="{{StorefrontProductInfoMainSection.productAttributeOptionsSelectButton}}" userInput="$$productAttributeOption1Handle.option[store_labels][0][label]$$" stepKey="configSelectOption"/> + + <comment userInput="Check storefront related products on config product page" stepKey="navigateToConfigProductPageComment"/> + <see selector="{{StorefrontProductRelatedProductsSection.relatedProductsListSectionText}}" userInput="$$simple2Handle.name$$" stepKey="assertRelatedSimpleProductNameInStorefront2"/> + + <comment userInput="Check related product in product page" stepKey="checkRelatedProductInProductPageComment"/> + <click selector="{{StorefrontProductRelatedProductsSection.relatedProductCheckBoxButton('$$simple2Handle.name$$')}}" stepKey="checkRelatedProcut"/> + + <actionGroup ref="addToCartFromStorefrontProductPage" stepKey="addToCartFromStorefrontProductPage"> + <argument name="productName" value="$$baseConfigProductHandle.name$$"/> + </actionGroup> + + <see selector="{{StorefrontMinicartSection.quantity}}" userInput="2" stepKey="seeItemCounterInMiniCart"/> + + <actionGroup ref="assertOneProductNameInMiniCart" stepKey="assertOneProductNameInMiniCart"> + <argument name="productName" value="$$baseConfigProductHandle.name$$"/> + </actionGroup> + + <actionGroup ref="assertOneProductNameInMiniCart" stepKey="assertOneProductNameInMiniCart2"> + <argument name="productName" value="$$simple2Handle.name$$"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/EndToEndB2CAdminTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/EndToEndB2CAdminTest.xml index 1169bb074c579..fcd6f4fd465a7 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/EndToEndB2CAdminTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/EndToEndB2CAdminTest.xml @@ -20,28 +20,28 @@ </actionGroup> <!--Create product configurations--> <click selector="{{AdminProductFormConfigurationsSection.createConfigurations}}" stepKey="clickCreateConfigurations" after="fillConfigurableProductMain"/> - <waitForElementVisible selector="{{AdminCreateProductConfigurationsPanel.createNewAttribute}}" stepKey="waitForConfigurationModalOpen" after="clickCreateConfigurations"/> + <waitForElementVisible selector="{{AdminCreateProductConfigurationsPanel.createNewAttribute}}" time="30" stepKey="waitForConfigurationModalOpen" after="clickCreateConfigurations"/> <!--Create new attribute--> <click selector="{{AdminCreateProductConfigurationsPanel.createNewAttribute}}" stepKey="clickCreateNewAttribute" after="waitForConfigurationModalOpen"/> <switchToIFrame selector="{{AdminNewAttributePanel.newAttributeIFrame}}" stepKey="enterAttributePanelIFrame" after="clickCreateNewAttribute"/> <wait time="2" stepKey="waitForModalIframeReady" after="enterAttributePanelIFrame"/> - <waitForElementVisible selector="{{AdminNewAttributePanel.defaultLabel}}" stepKey="waitForIframeLoad" after="waitForModalIframeReady"/> + <waitForElementVisible selector="{{AdminNewAttributePanel.defaultLabel}}" time="30" stepKey="waitForIframeLoad" after="waitForModalIframeReady"/> <fillField selector="{{AdminNewAttributePanel.defaultLabel}}" userInput="{{colorProductAttribute.default_label}}" stepKey="fillDefaultLabel" after="waitForIframeLoad"/> <selectOption selector="{{AdminNewAttributePanel.inputType}}" userInput="{{colorProductAttribute.input_type}}" stepKey="selectAttributeInputType" after="fillDefaultLabel"/> <!--Add option 1 to attribute--> <click selector="{{AdminNewAttributePanel.addOption}}" stepKey="clickAddOption1" after="selectAttributeInputType"/> - <waitForElementVisible selector="{{AdminNewAttributePanel.isDefault('1')}}" stepKey="waitForOptionRow1" after="clickAddOption1"/> + <waitForElementVisible selector="{{AdminNewAttributePanel.isDefault('1')}}" time="30" stepKey="waitForOptionRow1" after="clickAddOption1"/> <fillField selector="{{AdminNewAttributePanel.optionAdminValue('0')}}" userInput="{{colorProductAttribute1.name}}" stepKey="fillAdminLabel1" after="waitForOptionRow1"/> <fillField selector="{{AdminNewAttributePanel.optionDefaultStoreValue('0')}}" userInput="{{colorProductAttribute1.name}}" stepKey="fillDefaultLabel1" after="fillAdminLabel1"/> <!--Add option 2 to attribute--> <click selector="{{AdminNewAttributePanel.addOption}}" stepKey="clickAddOption2" after="fillDefaultLabel1"/> - <waitForElementVisible selector="{{AdminNewAttributePanel.isDefault('2')}}" stepKey="waitForOptionRow2" after="clickAddOption2"/> + <waitForElementVisible selector="{{AdminNewAttributePanel.isDefault('2')}}" time="30" stepKey="waitForOptionRow2" after="clickAddOption2"/> <fillField selector="{{AdminNewAttributePanel.optionAdminValue('1')}}" userInput="{{colorProductAttribute2.name}}" stepKey="fillAdminLabel2" after="waitForOptionRow2"/> <fillField selector="{{AdminNewAttributePanel.optionDefaultStoreValue('1')}}" userInput="{{colorProductAttribute2.name}}" stepKey="fillDefaultLabel2" after="fillAdminLabel2"/> <!--Save new attribute--> <click selector="{{AdminNewAttributePanel.saveAttribute}}" stepKey="clickSaveAttribute" after="fillDefaultLabel2"/> <switchToIFrame stepKey="switchToParentPage" after="clickSaveAttribute"/> - <waitForElementNotVisible selector="{{AdminNewAttributePanel.container}}" stepKey="waitForNewAttributePanelClose" after="switchToParentPage"/> + <waitForElementNotVisible selector="{{AdminNewAttributePanel.container}}" time="30" stepKey="waitForNewAttributePanelClose" after="switchToParentPage"/> <waitForLoadingMaskToDisappear stepKey="waitForSaveAttributeLoadingMask" after="waitForNewAttributePanelClose"/> <!--Find new attribute in grid and select--> <click selector="{{AdminCreateProductConfigurationsPanel.filters}}" stepKey="openFilterPanel" after="waitForSaveAttributeLoadingMask"/> @@ -60,15 +60,16 @@ <click selector="{{AdminCreateProductConfigurationsPanel.next}}" stepKey="clickGenerateProducts" after="clickNext3"/> <!--Save configurable product--> <click selector="{{AdminProductFormActionSection.saveButton}}" stepKey="clickSaveConfigurableProduct" after="clickGenerateProducts"/> - <waitForElementVisible selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" stepKey="waitForAttributeSetConfirmation" after="clickSaveConfigurableProduct"/> + <waitForElementVisible selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" time="30" stepKey="waitForAttributeSetConfirmation" after="clickSaveConfigurableProduct"/> <click selector="{{AdminChooseAffectedAttributeSetPopup.confirm}}" stepKey="clickConfirmAttributeSet" after="waitForAttributeSetConfirmation"/> <see selector="You saved the product" stepKey="seeConfigurableSaveConfirmation" after="clickConfirmAttributeSet"/> <actionGroup ref="viewConfigurableProductInAdminGrid" stepKey="viewConfigurableProductInGrid" after="seeConfigurableSaveConfirmation"> <argument name="product" value="BaseConfigurableProduct"/> </actionGroup> - <!--TODO - Move to 'after' block when MQE-732 is fixed--> - <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteConfigurableProduct"> + <!--@TODO Move cleanup to "after" when MQE-830 is resolved--> + <comment userInput="Clean up configurable product" stepKey="cleanUpConfigurableProduct" after="deleteSimpleProduct"/> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteConfigurableProduct" after="cleanUpConfigurableProduct"> <argument name="product" value="BaseConfigurableProduct"/> </actionGroup> </test> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/EndToEndB2CGuestUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/EndToEndB2CGuestUserTest.xml new file mode 100644 index 0000000000000..d3791f4d52657 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/EndToEndB2CGuestUserTest.xml @@ -0,0 +1,222 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CGuestUserTest"> + <before> + <createData entity="ApiConfigurableProduct" stepKey="createConfigProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="productAttributeWithTwoOptions" stepKey="createConfigProductAttribute"/> + <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOption1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOption2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getConfigAttributeOption2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <createData entity="ApiSimpleOne" stepKey="createConfigChildProduct1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryTestImage" stepKey="createConfigChildProduct1Image"> + <requiredEntity createDataKey="createConfigChildProduct1"/> + </createData> + <createData entity="ApiSimpleTwo" stepKey="createConfigChildProduct2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption2"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryMagentoLogo" stepKey="createConfigChildProduct2Image"> + <requiredEntity createDataKey="createConfigChildProduct2"/> + </createData> + <createData entity="ConfigurableProductTwoOptions" stepKey="createConfigProductOption"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + <requiredEntity createDataKey="getConfigAttributeOption2"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild1"> + <requiredEntity createDataKey="createConfigChildProduct1"/> + <requiredEntity createDataKey="createConfigProduct"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild2"> + <requiredEntity createDataKey="createConfigChildProduct2"/> + <requiredEntity createDataKey="createConfigProduct"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryTestImage" stepKey="createConfigProductImage"> + <requiredEntity createDataKey="createConfigProduct"/> + </createData> + <updateData entity="ApiSimpleProductUpdateDescription" stepKey="updateConfigProduct" createDataKey="createConfigProduct"/> + </before> + <after> + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createConfigChildProduct1Image" stepKey="deleteConfigChildProduct1Image"/>--> + <deleteData createDataKey="createConfigChildProduct1" stepKey="deleteConfigChildProduct1"/> + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createConfigChildProduct2Image" stepKey="deleteConfigChildProduct2Image"/>--> + <deleteData createDataKey="createConfigChildProduct2" stepKey="deleteConfigChildProduct2"/> + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createConfigProductImage" stepKey="deleteConfigProductImage"/>--> + <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> + <deleteData createDataKey="createConfigProductAttribute" stepKey="deleteConfigProductAttribute"/> + </after> + + <!-- Verify Configurable Product in checkout cart items --> + <comment userInput="Verify Configurable Product in checkout cart items" stepKey="commentVerifyConfigurableProductInCheckoutCartItems" after="guestCheckoutCheckSimpleProduct2InCartItems" /> + <actionGroup ref="CheckConfigurableProductInCheckoutCartItemsActionGroup" stepKey="guestCheckoutCheckConfigurableProductInCartItems" after="commentVerifyConfigurableProductInCheckoutCartItems"> + <argument name="productVar" value="$$createConfigProduct$$"/> + <argument name="optionLabel" value="$$createConfigProductAttribute.attribute[frontend_labels][0][label]$$" /> + <argument name="optionValue" value="$$createConfigProductAttributeOption2.option[store_labels][1][label]$$" /> + </actionGroup> + + <!-- Check configurable product in category --> + <comment userInput="Verify Configurable Product in category" stepKey="commentVerifyConfigurableProductInCategory" after="browseAssertSimpleProduct2ImageNotDefault" /> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="browseAssertCategoryConfigProduct" after="commentVerifyConfigurableProductInCategory"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="browseGrabConfigProductImageSrc" after="browseAssertCategoryConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$browseGrabConfigProductImageSrc" stepKey="browseAssertConfigProductImageNotDefault" after="browseGrabConfigProductImageSrc"/> + + <!-- View Configurable Product --> + <comment userInput="View Configurable Product" stepKey="commentViewConfigurableProduct" after="browseAssertSimpleProduct2PageImageNotDefault" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="clickCategory2" after="commentViewConfigurableProduct"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createConfigProduct.name$$)}}" stepKey="browseClickCategoryConfigProductView" after="clickCategory2"/> + <waitForLoadingMaskToDisappear stepKey="waitForConfigurableProductViewloaded" after="browseClickCategoryConfigProductView"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="browseAssertConfigProductPage" after="waitForConfigurableProductViewloaded"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="browseGrabConfigProductPageImageSrc" after="browseAssertConfigProductPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$browseGrabConfigProductPageImageSrc" stepKey="browseAssertConfigProductPageImageNotDefault" after="browseGrabConfigProductPageImageSrc"/> + + <!-- Add Configurable Product to cart --> + <comment userInput="Add Configurable Product to cart" stepKey="commentAddConfigurableProductToCart" after="cartAddProduct2ToCart" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="cartClickCategory2" after="commentAddConfigurableProductToCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartCategory2loaded" after="cartClickCategory2"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="cartAssertCategory1ForConfigurableProduct" after="waitForCartCategory2loaded"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="cartAssertConfigProduct" after="cartAssertCategory1ForConfigurableProduct"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="cartGrabConfigProductImageSrc" after="cartAssertConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartGrabConfigProductImageSrc" stepKey="cartAssertConfigProductImageNotDefault" after="cartGrabConfigProductImageSrc"/> + <click selector="{{StorefrontCategoryProductSection.ProductAddToCartByName($$createConfigProduct.name$$)}}" stepKey="cartClickCategoryConfigProductAddToCart" after="cartAssertConfigProductImageNotDefault"/> + <waitForElement selector="{{StorefrontMessagesSection.message('You need to choose options for your item.')}}" time="30" stepKey="cartWaitForConfigProductPageLoad" after="cartClickCategoryConfigProductAddToCart"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="cartAssertConfigProductPage" after="cartWaitForConfigProductPageLoad"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartGrabConfigProductPageImageSrc1" after="cartAssertConfigProductPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartGrabConfigProductPageImageSrc1" stepKey="cartAssertConfigProductPageImageNotDefault1" after="cartGrabConfigProductPageImageSrc1"/> + <selectOption userInput="$$createConfigProductAttributeOption2.option[store_labels][1][label]$$" selector="{{StorefrontProductInfoMainSection.optionByAttributeId($$createConfigProductAttribute.attribute_id$$)}}" stepKey="cartConfigProductFillOption" after="cartAssertConfigProductPageImageNotDefault1"/> + <waitForLoadingMaskToDisappear stepKey="waitForConfigurableProductOptionloaded" after="cartConfigProductFillOption"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="cartAssertConfigProductWithOptionPage" after="waitForConfigurableProductOptionloaded"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartGrabConfigProductPageImageSrc2" after="cartAssertConfigProductWithOptionPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartGrabConfigProductPageImageSrc2" stepKey="cartAssertConfigProductPageImageNotDefault2" after="cartGrabConfigProductPageImageSrc2"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="cartAddConfigProductToCart" after="cartAssertConfigProductPageImageNotDefault2"> + <argument name="product" value="$$createConfigProduct$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + + <!-- Check configurable product in minicart --> + <comment userInput="Check configurable product in minicart" stepKey="commentCheckConfigurableProductInMinicart" after="cartMinicartAssertSimpleProduct2PageImageNotDefault" /> + <actionGroup ref="StorefrontOpenMinicartAndCheckConfigurableProductActionGroup" stepKey="cartOpenMinicartAndCheckConfigProduct" after="commentCheckConfigurableProductInMinicart"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontMinicartSection.productImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="cartMinicartGrabConfigProductImageSrc" after="cartOpenMinicartAndCheckConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/thumbnail\.jpg/'" actual="$cartMinicartGrabConfigProductImageSrc" stepKey="cartMinicartAssertConfigProductImageNotDefault" after="cartMinicartGrabConfigProductImageSrc"/> + <click selector="{{StorefrontMinicartSection.productOptionsDetailsByName($$createConfigProduct.name$$)}}" stepKey="cartMinicartClickConfigProductDetails" after="cartMinicartAssertConfigProductImageNotDefault"/> + <see userInput="$$createConfigProductAttributeOption2.option[store_labels][1][label]$$" selector="{{StorefrontMinicartSection.productOptionByNameAndAttribute($$createConfigProduct.name$$, $$createConfigProductAttribute.attribute[frontend_labels][0][label]$$)}}" stepKey="cartMinicartCheckConfigProductOption" after="cartMinicartClickConfigProductDetails"/> + <click selector="{{StorefrontMinicartSection.productLinkByName($$createConfigProduct.name$$)}}" stepKey="cartMinicartClickConfigProduct" after="cartMinicartCheckConfigProductOption"/> + <waitForLoadingMaskToDisappear stepKey="waitForMinicartConfigProductloaded" after="cartMinicartClickConfigProduct"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="cartAssertMinicartConfigProductPage" after="waitForMinicartConfigProductloaded"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartMinicartGrabConfigProductPageImageSrc" after="cartAssertMinicartConfigProductPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartMinicartGrabConfigProductPageImageSrc" stepKey="cartMinicartAssertConfigProductPageImageNotDefault" after="cartMinicartGrabConfigProductPageImageSrc"/> + + <!-- Check configurable product in cart --> + <comment userInput="Check configurable product in cart" stepKey="commentCheckConfigurableProductInCart" after="cartCartAssertSimpleProduct2PageImageNotDefault2" /> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="cartOpenCart2" after="commentCheckConfigurableProductInCart"/> + <actionGroup ref="StorefrontCheckCartConfigurableProductActionGroup" stepKey="cartAssertCartConfigProduct" after="cartOpenCart2"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct2$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productQuantity" value="CONST.one"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{CheckoutCartProductSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="cartCartGrabConfigProduct2ImageSrc" after="cartAssertCartConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartCartGrabConfigProduct2ImageSrc" stepKey="cartCartAssertConfigProduct2ImageNotDefault" after="cartCartGrabConfigProduct2ImageSrc"/> + <see userInput="$$createConfigProductAttributeOption2.option[store_labels][1][label]$$" selector="{{CheckoutCartProductSection.ProductOptionByNameAndAttribute($$createConfigProduct.name$$, $$createConfigProductAttribute.attribute[frontend_labels][0][label]$$)}}" stepKey="cartCheckConfigProductOption" after="cartCartAssertConfigProduct2ImageNotDefault"/> + <click selector="{{CheckoutCartProductSection.ProductLinkByName($$createConfigProduct.name$$)}}" stepKey="cartClickCartConfigProduct" after="cartCheckConfigProductOption"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartConfigProductloaded" after="cartClickCartConfigProduct"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="cartAssertCartConfigProductPage" after="waitForCartConfigProductloaded"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartCartGrabConfigProductPageImageSrc" after="cartAssertCartConfigProductPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartCartGrabConfigProductPageImageSrc" stepKey="cartCartAssertConfigProductPageImageNotDefault" after="cartCartGrabConfigProductPageImageSrc"/> + + <!-- Add Configurable Product to comparison --> + <comment userInput="Add Configurable Product to comparison" stepKey="commentAddConfigurableProductToComparison" after="compareAddSimpleProduct2ToCompare" /> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="compareAssertConfigProduct" after="commentAddConfigurableProductToComparison"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="compareGrabConfigProductImageSrc" after="compareAssertConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabConfigProductImageSrc" stepKey="compareAssertConfigProductImageNotDefault" after="compareGrabConfigProductImageSrc"/> + <actionGroup ref="StorefrontAddCategoryProductToCompareActionGroup" stepKey="compareAddConfigProductToCompare" after="compareAssertConfigProductImageNotDefault"> + <argument name="productVar" value="$$createConfigProduct$$"/> + </actionGroup> + + <!-- Check configurable product in comparison sidebar --> + <comment userInput="Add Configurable Product in comparison sidebar" stepKey="commentAddConfigurableProductInComparisonSidebar" after="compareSimpleProduct2InSidebar" /> + <actionGroup ref="StorefrontCheckCompareSidebarProductActionGroup" stepKey="compareConfigProductInSidebar" after="commentAddConfigurableProductInComparisonSidebar"> + <argument name="productVar" value="$$createConfigProduct$$"/> + </actionGroup> + + <!-- Check configurable product on comparison page --> + <comment userInput="Add Configurable Product on comparison page" stepKey="commentAddConfigurableProductOnComparisonPage" after="compareAssertSimpleProduct2ImageNotDefaultInComparison" /> + <actionGroup ref="StorefrontCheckCompareConfigurableProductActionGroup" stepKey="compareAssertConfigProductInComparison" after="commentAddConfigurableProductOnComparisonPage"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductCompareMainSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="compareGrabConfigProductImageSrcInComparison" after="compareAssertConfigProductInComparison"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabConfigProductImageSrcInComparison" stepKey="compareAssertConfigProductImageNotDefaultInComparison" after="compareGrabConfigProductImageSrcInComparison"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/EndToEndB2CLoggedInUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/EndToEndB2CLoggedInUserTest.xml new file mode 100644 index 0000000000000..b1b73d40da144 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/Test/EndToEndB2CLoggedInUserTest.xml @@ -0,0 +1,222 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CLoggedInUserTest"> + <before> + <createData entity="ApiConfigurableProduct" stepKey="createConfigProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="productAttributeWithTwoOptions" stepKey="createConfigProductAttribute"/> + <createData entity="productAttributeOption1" stepKey="createConfigProductAttributeOption1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="productAttributeOption2" stepKey="createConfigProductAttributeOption2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <createData entity="AddToDefaultSet" stepKey="createConfigAddToAttributeSet"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </createData> + <getData entity="ProductAttributeOptionGetter" index="1" stepKey="getConfigAttributeOption1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <getData entity="ProductAttributeOptionGetter" index="2" stepKey="getConfigAttributeOption2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + </getData> + <createData entity="ApiSimpleOne" stepKey="createConfigChildProduct1"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryTestImage" stepKey="createConfigChildProduct1Image"> + <requiredEntity createDataKey="createConfigChildProduct1"/> + </createData> + <createData entity="ApiSimpleTwo" stepKey="createConfigChildProduct2"> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption2"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryMagentoLogo" stepKey="createConfigChildProduct2Image"> + <requiredEntity createDataKey="createConfigChildProduct2"/> + </createData> + <createData entity="ConfigurableProductTwoOptions" stepKey="createConfigProductOption"> + <requiredEntity createDataKey="createConfigProduct"/> + <requiredEntity createDataKey="createConfigProductAttribute"/> + <requiredEntity createDataKey="getConfigAttributeOption1"/> + <requiredEntity createDataKey="getConfigAttributeOption2"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild1"> + <requiredEntity createDataKey="createConfigChildProduct1"/> + <requiredEntity createDataKey="createConfigProduct"/> + </createData> + <createData entity="ConfigurableProductAddChild" stepKey="createConfigProductAddChild2"> + <requiredEntity createDataKey="createConfigChildProduct2"/> + <requiredEntity createDataKey="createConfigProduct"/> + </createData> + <createData entity="ApiProductAttributeMediaGalleryEntryTestImage" stepKey="createConfigProductImage"> + <requiredEntity createDataKey="createConfigProduct"/> + </createData> + <updateData entity="ApiSimpleProductUpdateDescription" stepKey="updateConfigProduct" createDataKey="createConfigProduct"/> + </before> + <after> + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createConfigChildProduct1Image" stepKey="deleteConfigChildProduct1Image"/>--> + <deleteData createDataKey="createConfigChildProduct1" stepKey="deleteConfigChildProduct1"/> + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createConfigChildProduct2Image" stepKey="deleteConfigChildProduct2Image"/>--> + <deleteData createDataKey="createConfigChildProduct2" stepKey="deleteConfigChildProduct2"/> + <!-- @TODO: Uncomment once MQE-679 is fixed --> + <!--<deleteData createDataKey="createConfigProductImage" stepKey="deleteConfigProductImage"/>--> + <deleteData createDataKey="createConfigProduct" stepKey="deleteConfigProduct"/> + <deleteData createDataKey="createConfigProductAttribute" stepKey="deleteConfigProductAttribute"/> + </after> + + <!-- Verify Configurable Product in checkout cart items --> + <comment userInput="Verify Configurable Product in checkout cart items" stepKey="commentVerifyConfigurableProductInCheckoutCartItems" after="checkoutCheckSimpleProduct2InCartItems" /> + <actionGroup ref="CheckConfigurableProductInCheckoutCartItemsActionGroup" stepKey="checkoutCheckConfigurableProductInCartItems" after="commentVerifyConfigurableProductInCheckoutCartItems"> + <argument name="productVar" value="$$createConfigProduct$$"/> + <argument name="optionLabel" value="$$createConfigProductAttribute.attribute[frontend_labels][0][label]$$" /> + <argument name="optionValue" value="$$createConfigProductAttributeOption2.option[store_labels][1][label]$$" /> + </actionGroup> + + <!-- Check configurable product in category --> + <comment userInput="Verify Configurable Product in category" stepKey="commentVerifyConfigurableProductInCategory" after="browseAssertSimpleProduct2ImageNotDefault" /> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="browseAssertCategoryConfigProduct" after="commentVerifyConfigurableProductInCategory"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="browseGrabConfigProductImageSrc" after="browseAssertCategoryConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$browseGrabConfigProductImageSrc" stepKey="browseAssertConfigProductImageNotDefault" after="browseGrabConfigProductImageSrc"/> + + <!-- View Configurable Product --> + <comment userInput="View Configurable Product" stepKey="commentViewConfigurableProduct" after="browseAssertSimpleProduct2PageImageNotDefault" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="clickCategory2" after="commentViewConfigurableProduct"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createConfigProduct.name$$)}}" stepKey="browseClickCategoryConfigProductView" after="clickCategory2"/> + <waitForLoadingMaskToDisappear stepKey="waitForConfigurableProductViewloaded" after="browseClickCategoryConfigProductView"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="browseAssertConfigProductPage" after="waitForConfigurableProductViewloaded"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="browseGrabConfigProductPageImageSrc" after="browseAssertConfigProductPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$browseGrabConfigProductPageImageSrc" stepKey="browseAssertConfigProductPageImageNotDefault" after="browseGrabConfigProductPageImageSrc"/> + + <!-- Add Configurable Product to cart --> + <comment userInput="Add Configurable Product to cart" stepKey="commentAddConfigurableProductToCart" after="cartAddProduct2ToCart" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" stepKey="cartClickCategory2" after="commentAddConfigurableProductToCart"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartCategory2loaded" after="cartClickCategory2"/> + <actionGroup ref="StorefrontCheckCategoryActionGroup" stepKey="cartAssertCategory1ForConfigurableProduct" after="waitForCartCategory2loaded"> + <argument name="category" value="$$createCategory$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="cartAssertConfigProduct" after="cartAssertCategory1ForConfigurableProduct"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="cartGrabConfigProductImageSrc" after="cartAssertConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartGrabConfigProductImageSrc" stepKey="cartAssertConfigProductImageNotDefault" after="cartGrabConfigProductImageSrc"/> + <click selector="{{StorefrontCategoryProductSection.ProductAddToCartByName($$createConfigProduct.name$$)}}" stepKey="cartClickCategoryConfigProductAddToCart" after="cartAssertConfigProductImageNotDefault"/> + <waitForElement selector="{{StorefrontMessagesSection.message('You need to choose options for your item.')}}" time="30" stepKey="cartWaitForConfigProductPageLoad" after="cartClickCategoryConfigProductAddToCart"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="cartAssertConfigProductPage" after="cartWaitForConfigProductPageLoad"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartGrabConfigProductPageImageSrc1" after="cartAssertConfigProductPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartGrabConfigProductPageImageSrc1" stepKey="cartAssertConfigProductPageImageNotDefault1" after="cartGrabConfigProductPageImageSrc1"/> + <selectOption userInput="$$createConfigProductAttributeOption2.option[store_labels][1][label]$$" selector="{{StorefrontProductInfoMainSection.optionByAttributeId($$createConfigProductAttribute.attribute_id$$)}}" stepKey="cartConfigProductFillOption" after="cartAssertConfigProductPageImageNotDefault1"/> + <waitForLoadingMaskToDisappear stepKey="waitForConfigurableProductOptionloaded" after="cartConfigProductFillOption"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="cartAssertConfigProductWithOptionPage" after="waitForConfigurableProductOptionloaded"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartGrabConfigProductPageImageSrc2" after="cartAssertConfigProductWithOptionPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartGrabConfigProductPageImageSrc2" stepKey="cartAssertConfigProductPageImageNotDefault2" after="cartGrabConfigProductPageImageSrc2"/> + <actionGroup ref="StorefrontAddProductToCartActionGroup" stepKey="cartAddConfigProductToCart" after="cartAssertConfigProductPageImageNotDefault2"> + <argument name="product" value="$$createConfigProduct$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productCount" value="CONST.three"/> + </actionGroup> + + <!-- Check configurable product in minicart --> + <comment userInput="Check configurable product in minicart" stepKey="commentCheckConfigurableProductInMinicart" after="cartMinicartAssertSimpleProduct2PageImageNotDefault" /> + <actionGroup ref="StorefrontOpenMinicartAndCheckConfigurableProductActionGroup" stepKey="cartOpenMinicartAndCheckConfigProduct" after="commentCheckConfigurableProductInMinicart"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct2$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontMinicartSection.productImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="cartMinicartGrabConfigProductImageSrc" after="cartOpenMinicartAndCheckConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/thumbnail\.jpg/'" actual="$cartMinicartGrabConfigProductImageSrc" stepKey="cartMinicartAssertConfigProductImageNotDefault" after="cartMinicartGrabConfigProductImageSrc"/> + <click selector="{{StorefrontMinicartSection.productOptionsDetailsByName($$createConfigProduct.name$$)}}" stepKey="cartMinicartClickConfigProductDetails" after="cartMinicartAssertConfigProductImageNotDefault"/> + <see userInput="$$createConfigProductAttributeOption2.option[store_labels][1][label]$$" selector="{{StorefrontMinicartSection.productOptionByNameAndAttribute($$createConfigProduct.name$$, $$createConfigProductAttribute.attribute[frontend_labels][0][label]$$)}}" stepKey="cartMinicartCheckConfigProductOption" after="cartMinicartClickConfigProductDetails"/> + <click selector="{{StorefrontMinicartSection.productLinkByName($$createConfigProduct.name$$)}}" stepKey="cartMinicartClickConfigProduct" after="cartMinicartCheckConfigProductOption"/> + <waitForLoadingMaskToDisappear stepKey="waitForMinicartConfigProductloaded" after="cartMinicartClickConfigProduct"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="cartAssertMinicartConfigProductPage" after="waitForMinicartConfigProductloaded"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartMinicartGrabConfigProductPageImageSrc" after="cartAssertMinicartConfigProductPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartMinicartGrabConfigProductPageImageSrc" stepKey="cartMinicartAssertConfigProductPageImageNotDefault" after="cartMinicartGrabConfigProductPageImageSrc"/> + + <!-- Check configurable product in cart --> + <comment userInput="Check configurable product in cart" stepKey="commentCheckConfigurableProductInCart" after="cartCartAssertSimpleProduct2PageImageNotDefault2" /> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="cartOpenCart2" after="commentCheckConfigurableProductInCart"/> + <actionGroup ref="StorefrontCheckCartConfigurableProductActionGroup" stepKey="cartAssertCartConfigProduct" after="cartOpenCart2"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct2$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="productQuantity" value="CONST.one"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{CheckoutCartProductSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="cartCartGrabConfigProduct2ImageSrc" after="cartAssertCartConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$cartCartGrabConfigProduct2ImageSrc" stepKey="cartCartAssertConfigProduct2ImageNotDefault" after="cartCartGrabConfigProduct2ImageSrc"/> + <see userInput="$$createConfigProductAttributeOption2.option[store_labels][1][label]$$" selector="{{CheckoutCartProductSection.ProductOptionByNameAndAttribute($$createConfigProduct.name$$, $$createConfigProductAttribute.attribute[frontend_labels][0][label]$$)}}" stepKey="cartCheckConfigProductOption" after="cartCartAssertConfigProduct2ImageNotDefault"/> + <click selector="{{CheckoutCartProductSection.ProductLinkByName($$createConfigProduct.name$$)}}" stepKey="cartClickCartConfigProduct" after="cartCheckConfigProductOption"/> + <waitForLoadingMaskToDisappear stepKey="waitForCartConfigProductloaded" after="cartClickCartConfigProduct"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="cartAssertCartConfigProductPage" after="waitForCartConfigProductloaded"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="cartCartGrabConfigProductPageImageSrc" after="cartAssertCartConfigProductPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$cartCartGrabConfigProductPageImageSrc" stepKey="cartCartAssertConfigProductPageImageNotDefault" after="cartCartGrabConfigProductPageImageSrc"/> + + <!-- Add Configurable Product to comparison --> + <comment userInput="Add Configurable Product to comparison" stepKey="commentAddConfigurableProductToComparison" after="compareAddSimpleProduct2ToCompare" /> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="compareAssertConfigProduct" after="commentAddConfigurableProductToComparison"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="compareGrabConfigProductImageSrc" after="compareAssertConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabConfigProductImageSrc" stepKey="compareAssertConfigProductImageNotDefault" after="compareGrabConfigProductImageSrc"/> + <actionGroup ref="StorefrontAddCategoryProductToCompareActionGroup" stepKey="compareAddConfigProductToCompare" after="compareAssertConfigProductImageNotDefault"> + <argument name="productVar" value="$$createConfigProduct$$"/> + </actionGroup> + + <!-- Check configurable product in comparison sidebar --> + <comment userInput="Add Configurable Product in comparison sidebar" stepKey="commentAddConfigurableProductInComparisonSidebar" after="compareSimpleProduct2InSidebar" /> + <actionGroup ref="StorefrontCheckCompareSidebarProductActionGroup" stepKey="compareConfigProductInSidebar" after="commentAddConfigurableProductInComparisonSidebar"> + <argument name="productVar" value="$$createConfigProduct$$"/> + </actionGroup> + + <!-- Check configurable product on comparison page --> + <comment userInput="Add Configurable Product on comparison page" stepKey="commentAddConfigurableProductOnComparisonPage" after="compareAssertSimpleProduct2ImageNotDefaultInComparison" /> + <actionGroup ref="StorefrontCheckCompareConfigurableProductActionGroup" stepKey="compareAssertConfigProductInComparison" after="commentAddConfigurableProductOnComparisonPage"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductCompareMainSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="compareGrabConfigProductImageSrcInComparison" after="compareAssertConfigProductInComparison"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$compareGrabConfigProductImageSrcInComparison" stepKey="compareAssertConfigProductImageNotDefaultInComparison" after="compareGrabConfigProductImageSrcInComparison"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/composer.json index 93144b56d2fd9..60dc9a490fd85 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProduct/composer.json @@ -12,20 +12,20 @@ }, "require": { "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", + "magento/magento2-functional-test-module-checkout": "100.0.0-dev", + "magento/magento2-functional-test-module-quote": "100.0.0-dev", + "magento/magento2-functional-test-module-ui": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/magento2-functional-test-module-checkout": "100.0.0-dev", "magento/magento2-functional-test-module-customer": "100.0.0-dev", "magento/magento2-functional-test-module-eav": "100.0.0-dev", "magento/magento2-functional-test-module-media-storage": "100.0.0-dev", "magento/magento2-functional-test-module-msrp": "100.0.0-dev", - "magento/magento2-functional-test-module-quote": "100.0.0-dev", - "magento/magento2-functional-test-module-store": "100.0.0-dev", - "magento/magento2-functional-test-module-ui": "100.0.0-dev" + "magento/magento2-functional-test-module-store": "100.0.0-dev" }, "autoload": { "psr-4": { diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/LICENSE.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/LICENSE_AFL.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/README.md b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/README.md new file mode 100644 index 0000000000000..bacebfd269160 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/README.md @@ -0,0 +1,3 @@ +# Magento 2 Functional Tests + +The Functional Tests Module for **Magento_ConfigurableProductCatalogSearch** Module. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/Test/EndToEndB2CGuestUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/Test/EndToEndB2CGuestUserTest.xml new file mode 100644 index 0000000000000..f5cd41bda74d7 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/Test/EndToEndB2CGuestUserTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CGuestUserTest"> + <!-- Search configurable product --> + <comment userInput="Search configurable product" stepKey="commentSearchConfigurableProduct" after="searchAssertSimpleProduct2ImageNotDefault" /> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="searchAssertFilterCategoryConfigProduct" after="commentSearchConfigurableProduct"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="searchGrabConfigProductImageSrc" after="searchAssertFilterCategoryConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$searchGrabConfigProductImageSrc" stepKey="searchAssertConfigProductImageNotDefault" after="searchGrabConfigProductImageSrc"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createConfigProduct.name$$)}}" stepKey="searchClickConfigProductView" after="searchAssertConfigProductImageNotDefault"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="searchAssertConfigProductPage" after="searchClickConfigProductView"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="searchGrabConfigProductPageImageSrc" after="searchAssertConfigProductPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$searchGrabConfigProductPageImageSrc" stepKey="searchAssertConfigProductPageImageNotDefault" after="searchGrabConfigProductPageImageSrc"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/Test/EndToEndB2CLoggedInUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/Test/EndToEndB2CLoggedInUserTest.xml new file mode 100644 index 0000000000000..3e386a034eecc --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/Test/EndToEndB2CLoggedInUserTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CLoggedInUserTest"> + <!-- Search configurable product --> + <comment userInput="Search configurable product" stepKey="commentSearchConfigurableProduct" after="searchAssertSimpleProduct2ImageNotDefault" /> + <actionGroup ref="StorefrontCheckCategoryConfigurableProduct" stepKey="searchAssertFilterCategoryConfigProduct" after="commentSearchConfigurableProduct"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontCategoryProductSection.ProductImageByName($$createConfigProduct.name$$)}}" userInput="src" stepKey="searchGrabConfigProductImageSrc" after="searchAssertFilterCategoryConfigProduct"/> + <assertNotRegExp expected="'/placeholder\/small_image\.jpg/'" actual="$searchGrabConfigProductImageSrc" stepKey="searchAssertConfigProductImageNotDefault" after="searchGrabConfigProductImageSrc"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createConfigProduct.name$$)}}" stepKey="searchClickConfigProductView" after="searchAssertConfigProductImageNotDefault"/> + <actionGroup ref="StorefrontCheckConfigurableProduct" stepKey="searchAssertConfigProductPage" after="searchClickConfigProductView"> + <argument name="product" value="$$createConfigProduct$$"/> + <argument name="optionProduct" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <!-- @TODO: Move Image check to action group after MQE-697 is fixed --> + <grabAttributeFrom selector="{{StorefrontProductInfoMainSection.productImage}}" userInput="src" stepKey="searchGrabConfigProductPageImageSrc" after="searchAssertConfigProductPage"/> + <assertNotRegExp expected="'/placeholder\/image\.jpg/'" actual="$searchGrabConfigProductPageImageSrc" stepKey="searchAssertConfigProductPageImageNotDefault" after="searchGrabConfigProductPageImageSrc"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/composer.json new file mode 100644 index 0000000000000..cbe5f173a3827 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch/composer.json @@ -0,0 +1,33 @@ +{ + "name": "magento/magento2-functional-test-module-configurable-product-catalog-search", + "description": "Magento 2 Functional Test Module Configurable Product Catalog Search", + "type": "magento2-test-module", + "version": "100.0.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "config": { + "sort-packages": true + }, + "require": { + "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", + "magento/magento2-functional-test-module-catalog-search": "100.0.0-dev", + "magento/magento2-functional-test-module-configurable-product": "100.0.0-dev", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "autoload": { + "psr-4": { + "Magento\\FunctionalTest\\ConfigurableProductCatalogSearch\\": "" + } + }, + "extra": { + "map": [ + [ + "*", + "tests/functional/Magento/FunctionalTest/ConfigurableProductCatalogSearch" + ] + ] + } +} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/ActionGroup/StorefrontCustomerWishlistActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/ActionGroup/StorefrontCustomerWishlistActionGroup.xml new file mode 100644 index 0000000000000..48b5bd2308310 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/ActionGroup/StorefrontCustomerWishlistActionGroup.xml @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Check configurable product in wishlist --> + <actionGroup name="StorefrontCustomerCheckConfigurableProductInWishlist"> + <arguments> + <argument name="productVar"/> + <argument name="optionProductVar" /> + </arguments> + <waitForElement selector="{{StorefrontCustomerWishlistProductSection.ProductTitleByName(productVar.name)}}" time="30" stepKey="assertWishlistProductName"/> + <see userInput="${{optionProductVar.price}}.00" selector="{{StorefrontCustomerWishlistProductSection.ProductPriceByName(productVar.name)}}" stepKey="AssertWishlistProductPrice"/> + <moveMouseOver selector="{{StorefrontCustomerWishlistProductSection.ProductInfoByName(productVar.name)}}" stepKey="wishlistMoveMouseOverProduct" /> + <seeElement selector="{{StorefrontCustomerWishlistProductSection.ProductAddToCartByName(productVar.name)}}" stepKey="AssertWishlistAddToCart" /> + <seeElement selector="{{StorefrontCustomerWishlistProductSection.ProductImageByName(productVar.name)}}" stepKey="AssertWishlistProductImage" /> + </actionGroup> + + <!-- Check configurable product in wishlist sidebar --> + <actionGroup name="StorefrontCustomerCheckConfigurableProductInWishlistSidebar"> + <arguments> + <argument name="productVar"/> + <argument name="optionProductVar" /> + </arguments> + <waitForElement selector="{{StorefrontCustomerWishlistSidebarSection.ProductTitleByName(productVar.name)}}" time="30" stepKey="assertWishlistSidebarProductName"/> + <see userInput="${{optionProductVar.price}}.00" selector="{{StorefrontCustomerWishlistSidebarSection.ProductPriceByName(productVar.name)}}" stepKey="AssertWishlistSidebarProductPrice"/> + <seeElement selector="{{StorefrontCustomerWishlistSidebarSection.ProductAddToCartByName(productVar.name)}}" stepKey="AssertWishlistSidebarAddToCart" /> + <seeElement selector="{{StorefrontCustomerWishlistSidebarSection.ProductImageByName(productVar.name)}}" stepKey="AssertWishlistSidebarProductImage" /> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/LICENSE.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/LICENSE_AFL.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/README.md b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/README.md new file mode 100644 index 0000000000000..96b277513a414 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/README.md @@ -0,0 +1,3 @@ +# Magento 2 Functional Tests + +The Functional Tests Module for **Magento_ConfigurableProduct** and **Magento_Wishlist** Modules. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/Test/EndToEndB2CLoggedInUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/Test/EndToEndB2CLoggedInUserTest.xml new file mode 100644 index 0000000000000..d3b009eecf877 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/Test/EndToEndB2CLoggedInUserTest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CLoggedInUserTest"> + <!-- Step 5: Add products to wishlist --> + <!-- Add Configurable Product to wishlist --> + <comment userInput="Add Configurable Product to wishlist" stepKey="commentAddConfigurableProductToWishlist" before="endOfAddingProductsToWishlist" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" after="commentAddConfigurableProductToWishlist" stepKey="wishlistGotoCategory3"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createConfigProduct.name$$)}}" after="wishlistGotoCategory3" stepKey="wishlistClickConfigurableProduct"/> + <actionGroup ref="StorefrontCustomerAddProductToWishlistActionGroup" after="wishlistClickConfigurableProduct" stepKey="wishlistAddConfigurableProductToWishlist"> + <argument name="productVar" value="$$createConfigProduct$$"/> + </actionGroup> + <actionGroup ref="StorefrontCustomerCheckConfigurableProductInWishlist" after="wishlistAddConfigurableProductToWishlist" stepKey="wishlistCheckConfigurableProductInWishlist"> + <argument name="productVar" value="$$createConfigProduct$$"/> + <argument name="optionProductVar" value="$$createConfigChildProduct1$$"/> + </actionGroup> + <actionGroup ref="StorefrontCustomerCheckConfigurableProductInWishlistSidebar" after="wishlistCheckConfigurableProductInWishlist" stepKey="wishlistCheckConfigurableProductInWishlistSidebar"> + <argument name="productVar" value="$$createConfigProduct$$"/> + <argument name="optionProductVar" value="$$createConfigChildProduct1$$"/> + </actionGroup> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/composer.json new file mode 100644 index 0000000000000..5da136f954255 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist/composer.json @@ -0,0 +1,33 @@ +{ + "name": "magento/magento2-functional-test-module-configurable-product-wishlist", + "description": "Magento 2 Functional Test Module Configurable Product Wishlist", + "type": "magento2-test-module", + "version": "100.0.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "config": { + "sort-packages": true + }, + "require": { + "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", + "magento/magento2-functional-test-module-configurable-product": "100.0.0-dev", + "magento/magento2-functional-test-module-wishlist": "100.0.0-dev", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "autoload": { + "psr-4": { + "Magento\\FunctionalTest\\ConfigurableProductWishlist\\": "" + } + }, + "extra": { + "map": [ + [ + "*", + "tests/functional/Magento/FunctionalTest/ConfigurableProductWishlist" + ] + ] + } +} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml new file mode 100644 index 0000000000000..ef00e2d72f100 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/ActionGroup/SignUpNewUserFromStorefrontActionGroup.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="SignUpNewUserFromStorefrontActionGroup"> + <arguments> + <argument name="Customer"/> + </arguments> + <amOnPage stepKey="amOnStorefrontPage" url="/"/> + <click stepKey="clickOnCreateAccountLink" selector="{{StorefrontPanelHeaderSection.createAnAccountLink}}"/> + <fillField stepKey="fillFirstName" userInput="{{Customer.firstname}}" selector="{{StorefrontCustomerCreateFormSection.firstnameField}}"/> + <fillField stepKey="fillLastName" userInput="{{Customer.lastname}}" selector="{{StorefrontCustomerCreateFormSection.lastnameField}}"/> + <fillField stepKey="fillEmail" userInput="{{Customer.email}}" selector="{{StorefrontCustomerCreateFormSection.emailField}}"/> + <fillField stepKey="fillPassword" userInput="{{Customer.password}}" selector="{{StorefrontCustomerCreateFormSection.passwordField}}"/> + <fillField stepKey="fillConfirmPassword" userInput="{{Customer.password}}" selector="{{StorefrontCustomerCreateFormSection.confirmPasswordField}}"/> + <click stepKey="clickCreateAccountButton" selector="{{StorefrontCustomerCreateFormSection.createAccountButton}}"/> + <see stepKey="seeThankYouMessage" userInput="Thank you for registering with Main Website Store."/> + <see stepKey="seeFirstName" userInput="{{Customer.firstname}}" selector="{{StorefrontCustomerDashboardAccountInformationSection.ContactInformation}}" /> + <see stepKey="seeLastName" userInput="{{Customer.lastname}}" selector="{{StorefrontCustomerDashboardAccountInformationSection.ContactInformation}}" /> + <see stepKey="seeEmail" userInput="{{Customer.email}}" selector="{{StorefrontCustomerDashboardAccountInformationSection.ContactInformation}}" /> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/AddressData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/AddressData.xml index 04f42d9a6f451..5f89a3ce9aaa7 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/AddressData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/AddressData.xml @@ -41,6 +41,7 @@ <item>7700 West Parmer Lane</item> </array> <data key="city">Austin</data> + <data key="state">Texas</data> <data key="country_id">US</data> <data key="postcode">78729</data> <data key="telephone">512-345-6789</data> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/CustomerData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/CustomerData.xml index fad2748a120db..9dee9a1c245f5 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/CustomerData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/CustomerData.xml @@ -39,6 +39,7 @@ <data key="email" unique="prefix">John.Doe@example.com</data> <data key="firstname">John</data> <data key="lastname">Doe</data> + <data key="fullname">John Doe</data> <data key="password">pwdTest123!</data> <data key="store_id">0</data> <data key="website_id">0</data> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/CustomerGroupData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/CustomerGroupData.xml new file mode 100644 index 0000000000000..61e0c05ea82a6 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Data/CustomerGroupData.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="GeneralCustomerGroup" type="customerGroup"> + <data key="code">General</data> + <data key="tax_class_id">3</data> + <data key="tax_class_name">Retail Customer</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Section/StorefrontPanelHeaderSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Section/StorefrontPanelHeaderSection.xml index 9d1477f1c6ed2..f3efca32c3243 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Section/StorefrontPanelHeaderSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Section/StorefrontPanelHeaderSection.xml @@ -9,6 +9,7 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontPanelHeaderSection"> + <element name="WelcomeMessage" type="text" selector=".greet.welcome span"/> <element name="createAnAccountLink" type="select" selector=".panel.header li:nth-child(3)"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/EndToEndB2CLoggedInUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/EndToEndB2CLoggedInUserTest.xml new file mode 100644 index 0000000000000..cc1fc78ca691a --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/EndToEndB2CLoggedInUserTest.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CLoggedInUserTest"> + <annotations> + <features value="End to End scenarios"/> + <stories value="B2C logged in user - MAGETWO-72524"/> + <group value="e2e"/> + <title value="You should be able to pass End to End B2C Logged In User scenario"/> + <description value="New user signup and browses catalog, searches for product, adds product to cart, adds product to wishlist, compares products, uses coupon code and checks out."/> + <severity value="CRITICAL"/> + <testCaseId value="MAGETWO-87653"/> + </annotations> + <before> + <resetCookie userInput="PHPSESSID" stepKey="resetCookieForCart"/> + </before> + <after> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + </after> + <!-- Step 0: User signs up an account --> + <comment userInput="Start of signing up user account" stepKey="startOfSigningUpUserAccount" /> + <actionGroup ref="SignUpNewUserFromStorefrontActionGroup" stepKey="SignUpNewUser"> + <argument name="Customer" value="CustomerEntityOne"/> + </actionGroup> + <comment userInput="End of signing up user account" stepKey="endOfSigningUpUserAccount" /> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/StorefrontCreateCustomerTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/StorefrontCreateCustomerTest.xml index c5c5ff201d2d8..6c155f8c1dbfe 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/StorefrontCreateCustomerTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Customer/Test/StorefrontCreateCustomerTest.xml @@ -23,17 +23,8 @@ <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> </after> - <amOnPage stepKey="amOnStorefrontPage" url="/"/> - <click stepKey="clickOnCreateAccountLink" selector="{{StorefrontPanelHeaderSection.createAnAccountLink}}"/> - <fillField stepKey="fillFirstName" userInput="{{CustomerEntityOne.firstname}}" selector="{{StorefrontCustomerCreateFormSection.firstnameField}}"/> - <fillField stepKey="fillLastName" userInput="{{CustomerEntityOne.lastname}}" selector="{{StorefrontCustomerCreateFormSection.lastnameField}}"/> - <fillField stepKey="fillEmail" userInput="{{CustomerEntityOne.email}}" selector="{{StorefrontCustomerCreateFormSection.emailField}}"/> - <fillField stepKey="fillPassword" userInput="{{CustomerEntityOne.password}}" selector="{{StorefrontCustomerCreateFormSection.passwordField}}"/> - <fillField stepKey="fillConfirmPassword" userInput="{{CustomerEntityOne.password}}" selector="{{StorefrontCustomerCreateFormSection.confirmPasswordField}}"/> - <click stepKey="clickCreateAccountButton" selector="{{StorefrontCustomerCreateFormSection.createAccountButton}}"/> - <see stepKey="seeThankYouMessage" userInput="Thank you for registering with Main Website Store."/> - <see stepKey="seeFirstName" userInput="{{CustomerEntityOne.firstname}}" selector="{{StorefrontCustomerDashboardAccountInformationSection.ContactInformation}}" /> - <see stepKey="seeLastName" userInput="{{CustomerEntityOne.lastname}}" selector="{{StorefrontCustomerDashboardAccountInformationSection.ContactInformation}}" /> - <see stepKey="seeEmail" userInput="{{CustomerEntityOne.email}}" selector="{{StorefrontCustomerDashboardAccountInformationSection.ContactInformation}}" /> + <actionGroup ref="SignUpNewUserFromStorefrontActionGroup" stepKey="SignUpNewUser"> + <argument name="Customer" value="CustomerEntityOne"/> + </actionGroup> </test> </tests> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/EndToEndB2CAdminTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/EndToEndB2CAdminTest.xml index 4dd2a5aca7562..1dab233132e32 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/EndToEndB2CAdminTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/Test/EndToEndB2CAdminTest.xml @@ -9,7 +9,7 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> <test name="EndToEndB2CAdminTest"> <!--Create Downloadable Product--> - <amOnPage url="{{AdminProductIndexPage}}" stepKey="visitProductPageDownloadable" after="viewBundleProductInGrid"/> + <amOnPage url="{{AdminProductIndexPage}}" stepKey="visitProductPageDownloadable" after="seeSimpleProductInGrid"/> <waitForPageLoad stepKey="waitForProductPageLoadDownloadable" after="visitProductPageDownloadable"/> <actionGroup ref="goToCreateProductPage" stepKey="goToCreateDownloadableProduct" after="waitForProductPageLoadDownloadable"> <argument name="product" value="DownloadableProduct"/> @@ -50,8 +50,9 @@ <argument name="product" value="DownloadableProduct"/> </actionGroup> - <!--TODO - Move to 'after' block when MQE-732 is fixed--> - <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteDownloadableProduct"> + <!--@TODO Move cleanup to "after" when MQE-830 is resolved--> + <comment userInput="Clean up downloadable product" stepKey="cleanUpDownloadableProduct" after="deleteSimpleProduct"/> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteDownloadableProduct" after="cleanUpDownloadableProduct"> <argument name="product" value="DownloadableProduct"/> </actionGroup> </test> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/composer.json index 400738980fd06..cb97370b3d73f 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Downloadable/composer.json @@ -12,11 +12,11 @@ }, "require": { "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", "magento/magento2-functional-test-module-checkout": "100.0.0-dev", "magento/magento2-functional-test-module-config": "100.0.0-dev", diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE_AFL.txt b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under <insert your license name here>" or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/Metadata/image_content-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/Metadata/image_content-meta.xml new file mode 100644 index 0000000000000..8b12a2fbbbc5d --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/Metadata/image_content-meta.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateImageContent" dataType="ImageContent" type="create"> + <field key="base64_encoded_data" required="true">string</field> + <field key="type" required="true">string</field> + <field key="name" required="true">string</field> + </operation> + <operation name="UpdateImageContent" dataType="ImageContent" type="update"> + <field key="base64_encoded_data" required="true">string</field> + <field key="type" required="true">string</field> + <field key="name" required="true">string</field> + </operation> +</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/README.md b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/README.md new file mode 100644 index 0000000000000..7fbe454f709c2 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/README.md @@ -0,0 +1,3 @@ +# Magento 2 Functional Tests + +The Functional Tests Module for **Magento_Framework**. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/composer.json new file mode 100644 index 0000000000000..e5a2f7fbe9e0f --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework/composer.json @@ -0,0 +1,30 @@ +{ + "name": "magento/magento2-functional-test-framework", + "description": "Magento 2 Functional Test Framework", + "type": "magento2-test-module", + "version": "100.0.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "config": { + "sort-packages": true + }, + "require": { + "magento/magento2-functional-testing-framework": "~2.0.0", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "autoload": { + "psr-4": { + "Magento\\FunctionalTest\\Framework\\": "" + } + }, + "extra": { + "map": [ + [ + "*", + "dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Framework" + ] + ] + } +} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/EndToEndB2CAdminTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/EndToEndB2CAdminTest.xml index 40aee930c8baf..dc88f99af5da4 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/EndToEndB2CAdminTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/Test/EndToEndB2CAdminTest.xml @@ -9,7 +9,7 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> <test name="EndToEndB2CAdminTest"> <!--Create Grouped Product--> - <amOnPage url="{{AdminProductIndexPage}}" stepKey="visitAdminProductPageGrouped" after="viewConfigurableProductInGrid"/> + <amOnPage url="{{AdminProductIndexPage}}" stepKey="visitAdminProductPageGrouped" after="seeSimpleProductInGrid"/> <waitForPageLoad stepKey="waitForProductPageLoadGrouped" after="visitAdminProductPageGrouped"/> <actionGroup ref="goToCreateProductPage" stepKey="goToCreateGroupedProduct" after="waitForProductPageLoadGrouped"> <argument name="product" value="GroupedProduct"/> @@ -33,8 +33,9 @@ <argument name="product" value="GroupedProduct"/> </actionGroup> - <!--TODO - Move to 'after' block when MQE-732 is fixed--> - <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteGroupedProduct"> + <!--@TODO Move cleanup to "after" when MQE-830 is resolved--> + <comment userInput="Clean up grouped product" stepKey="cleanUpGroupedProduct" after="deleteSimpleProduct"/> + <actionGroup ref="deleteProductUsingProductGrid" stepKey="deleteGroupedProduct" after="cleanUpGroupedProduct"> <argument name="product" value="GroupedProduct"/> </actionGroup> </test> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/composer.json index 4f4638a6e31cb..1e484a6d48433 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/GroupedProduct/composer.json @@ -12,11 +12,11 @@ }, "require": { "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", "magento/magento2-functional-test-module-checkout": "100.0.0-dev", "magento/magento2-functional-test-module-customer": "100.0.0-dev", diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MessageQueue/README.md b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MessageQueue/README.md new file mode 100644 index 0000000000000..900e136684513 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MessageQueue/README.md @@ -0,0 +1,3 @@ +# Magento 2 Functional Tests + +The Functional Tests Module for **Magento_MessageQueue** Module. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MessageQueue/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MessageQueue/composer.json new file mode 100644 index 0000000000000..6b9d8196a58d8 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MessageQueue/composer.json @@ -0,0 +1,29 @@ +{ + "name": "magento/magento2-functional-test-module-message-queue", + "description": "Magento 2 Functional Test Module Message Queue", + "type": "magento2-test-module", + "version": "100.0.0-dev", + "license": [ + "proprietary" + ], + "config": { + "sort-packages": true + }, + "require": { + "magento/magento2-functional-testing-framework": "1.0.0", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "autoload": { + "psr-4": { + "Magento\\FunctionalTest\\MessageQueue\\": "" + } + }, + "extra": { + "map": [ + [ + "*", + "dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MessageQueue" + ] + ] + } +} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MysqlMq/README.md b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MysqlMq/README.md new file mode 100644 index 0000000000000..a20eb0010356d --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MysqlMq/README.md @@ -0,0 +1,3 @@ +# Magento 2 Functional Tests + +The Functional Tests Module for **Magento_MysqlMq** Module. diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MysqlMq/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MysqlMq/composer.json new file mode 100644 index 0000000000000..0b741f776abdc --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MysqlMq/composer.json @@ -0,0 +1,32 @@ +{ + "name": "magento/magento2-functional-test-module-mysql-mq", + "description": "Magento 2 Functional Test Module Mysql Mq", + "type": "magento2-test-module", + "version": "100.0.0-dev", + "license": [ + "proprietary" + ], + "config": { + "sort-packages": true + }, + "require": { + "magento/magento2-functional-testing-framework": "1.0.0", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "suggest": { + "magento/magento2-functional-test-module-store": "100.0.0-dev" + }, + "autoload": { + "psr-4": { + "Magento\\FunctionalTest\\MysqlMq\\": "" + } + }, + "extra": { + "map": [ + [ + "*", + "dev/tests/acceptance/tests/functional/Magento/FunctionalTest/MysqlMq" + ] + ] + } +} diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Section/StorefrontNewsletterSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Section/StorefrontNewsletterSection.xml index d9bd1b55b8431..f8cff8986a848 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Section/StorefrontNewsletterSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Section/StorefrontNewsletterSection.xml @@ -10,5 +10,6 @@ xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontNewsletterSection"> <element name="mediaDescription" type="text" selector="body>p>img" /> + <element name="ImageSource" type="text" selector="//img[contains(@src,'{{var1}}') and not(contains(@src,'{{var2}}/'))]" parameterized="true"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddImageToWYSIWYGNewsletterCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddImageToWYSIWYGNewsletterCest.xml index a8e08bccec8c4..dcc9c798dc4c1 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddImageToWYSIWYGNewsletterCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddImageToWYSIWYGNewsletterCest.xml @@ -16,6 +16,8 @@ <description value="Admin should be able to add image to WYSIWYG content Newsletter"/> <severity value="CRITICAL"/> <testCaseId value="MAGETWO-84377"/> + <!--Skip because of issue MAGETWO-88266--> + <group value="skip"/> </annotations> <before> <actionGroup ref="LoginActionGroup" stepKey="login"/> @@ -28,47 +30,25 @@ <fillField selector="{{BasicFieldNewsletterSection.templateSubject}}" userInput="{{_defaultNewsletter.subject}}" stepKey="fillTemplateSubject" /> <fillField selector="{{BasicFieldNewsletterSection.senderName}}" userInput="{{_defaultNewsletter.senderName}}" stepKey="fillSenderName" /> <fillField selector="{{BasicFieldNewsletterSection.senderEmail}}" userInput="{{_defaultNewsletter.senderEmail}}" stepKey="fillSenderEmail" /> + <conditionalClick selector="{{NewsletterWYSIWYGSection.ShowHideBtn}}" dependentSelector="{{NewsletterWYSIWYGSection.TinyMCE4}}" visible="false" stepKey="toggleEditorIfHidden"/> <waitForElementVisible selector="{{NewsletterWYSIWYGSection.TinyMCE4}}" stepKey="waitForTinyMCE4"/> <click selector="{{TinyMCESection.InsertImageIcon}}" stepKey="clickInsertImageIcon" /> <waitForPageLoad stepKey="waitForPageLoad" /> - <click selector="{{MediaGallerySection.Browse}}" stepKey="clickBrowse" /> - <waitForElement selector="{{MediaGallerySection.CancelBtn}}" stepKey="waitForCancelBtn" /> - <waitForPageLoad stepKey="waitForPageLoad2" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading1" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading2" /> - <waitForElement selector="{{MediaGallerySection.StorageRootArrow}}" stepKey="waitForStorageFoot" /> - <see selector="{{MediaGallerySection.CancelBtn}}" userInput="Cancel" stepKey="seeCancelBtn" /> - <see selector="{{MediaGallerySection.CreateFolder}}" userInput="Create Folder" stepKey="seeCreateFolderBtn" /> - <see selector="{{MediaGallerySection.InsertFile}}" userInput="Add Selected" stepKey="seeAddSelectedBtn" /> - <click selector="{{MediaGallerySection.CreateFolder}}" stepKey="createFolder"/> - <waitForElementVisible selector="{{MediaGallerySection.FolderName}}" stepKey="waitForPopUp" /> - <fillField selector="{{MediaGallerySection.FolderName}}" userInput="{{ImageFolder.name}}" stepKey="fillFolderName" /> - <click selector="{{MediaGallerySection.AcceptFolderName}}" stepKey="acceptFolderName" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading3" /> - <conditionalClick selector="{{MediaGallerySection.StorageRootArrow}}" dependentSelector="{{MediaGallerySection.checkIfArrowExpand}}" stepKey="clickArrowIfCloses" visible="true"/> - <waitForText userInput="{{ImageFolder.name}}" stepKey="waitForNewFolder" /> - <click userInput="{{ImageFolder.name}}" stepKey="clickOnCreatedFolder" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading5" /> - <attachFile selector="{{MediaGallerySection.BrowseUploadImage}}" userInput="{{ImageUpload.file}}" stepKey="uploadImage1"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading6" /> - <waitForElementVisible selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="waitForUploadImage1" /> - <seeElement selector="{{MediaGallerySection.imageSelected(ImageUpload.file)}}" stepKey="seeImageSelected" /> - <see selector="{{MediaGallerySection.DeleteSelectedBtn}}" userInput="Delete Selected" stepKey="seeDeleteBtn"/> - <click selector="{{MediaGallerySection.DeleteSelectedBtn}}" stepKey="clickDeleteSelected" /> - <waitForText userInput="OK" stepKey="waitForConfirm" /> - <click selector="{{MediaGallerySection.confirmDelete}}" stepKey="confirmDelete" /> - <waitForElementNotVisible selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="waitForImageDeleted" /> - <dontSeeElement selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="dontSeeImage" /> - <attachFile selector="{{MediaGallerySection.BrowseUploadImage}}" userInput="{{ImageUpload.file}}" stepKey="uploadImage2"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoading9" /> - <waitForElementVisible selector="{{MediaGallerySection.image(ImageUpload.file)}}" stepKey="waitForUploadImage2" /> - <click selector="{{MediaGallerySection.InsertFile}}" stepKey="clickInsertBtn" /> - <waitForLoadingMaskToDisappear stepKey="waitForLoading7" /> - <waitForElementVisible selector="{{MediaGallerySection.OkBtn}}" stepKey="waitForOkBtn" /> - <fillField selector="{{MediaGallerySection.ImageDescription}}" userInput="{{ImageUpload.content}}" stepKey="fillImageDescription" /> - <fillField selector="{{MediaGallerySection.Height}}" userInput="{{ImageUpload.height}}" stepKey="fillImageHeight" /> - <click selector="{{MediaGallerySection.OkBtn}}" stepKey="clickOkBtn" /> - <waitForPageLoad stepKey="waitForPageLoad8"/> + <actionGroup ref="clickBrowseBtnOnUploadPopup" stepKey="clickBrowserBtn"/> + <actionGroup ref="VerifyMediaGalleryStorageActions" stepKey="VerifyMediaGalleryStorageBtn"/> + <actionGroup ref="CreateImageFolder" stepKey="CreateImageFolder"> + <argument name="ImageFolder" value="ImageFolder"/> + </actionGroup> + <actionGroup ref="attachImage" stepKey="attachImage1"> + <argument name="Image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="deleteImage" stepKey="deleteImage"/> + + <actionGroup ref="attachImage" stepKey="attachImage2"> + <argument name="Image" value="ImageUpload3"/> + </actionGroup> + <actionGroup ref="saveImage" stepKey="insertImage"/> + <actionGroup ref="fillOutUploadImagePopup" stepKey="fillOutUploadImagePopup" /> <!--Go to Storefront--> <click selector="{{BasicFieldNewsletterSection.save}}" stepKey="clickSaveTemplate"/> <waitForPageLoad stepKey="waitForPageLoad10" /> @@ -77,8 +57,10 @@ <switchToIFrame userInput="preview_iframe" stepKey="switchToIframe" /> <waitForPageLoad stepKey="waitForPageLoad9"/> <seeElement selector="{{StorefrontNewsletterSection.mediaDescription}}" stepKey="assertMediaDescription"/> + <seeElementInDOM selector="{{StorefrontNewsletterSection.ImageSource(ImageUpload3.fileName,ImageUpload3.extension)}}" stepKey="assertMediaSource"/> <closeTab stepKey="closeTab"/> <after> + <closeTab stepKey="closeTab"/> <actionGroup ref="DisabledWYSIWYG" stepKey="disableWYSIWYG"/> <actionGroup ref="logout" stepKey="logout"/> </after> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddVariableToWYSIWYGNewsletterCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddVariableToWYSIWYGNewsletterCest.xml index ae2f33f92bace..fe0f067039209 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddVariableToWYSIWYGNewsletterCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddVariableToWYSIWYGNewsletterCest.xml @@ -10,8 +10,9 @@ <test name="AddVariableToNewsletter"> <annotations> <features value="MAGETWO-36659-[CMS] WYSIWYG update"/> - <stories value="MAGETWO-42158-Variables with WYSIWYG"/> + <stories value="MAGETWO-42158-Variable with WYSIWYG"/> <group value="Newsletter"/> + <group value="skip"/> <title value="Admin should be able to add variable to WYSIWYG Editor of Newsletter"/> <description value="Admin should be able to add variable to WYSIWYG Editor Newsletter"/> <testCaseId value="MAGETWO-84379"/> @@ -37,6 +38,9 @@ <fillField selector="{{BasicFieldNewsletterSection.templateSubject}}" userInput="{{_defaultNewsletter.subject}}" stepKey="fillTemplateSubject" /> <fillField selector="{{BasicFieldNewsletterSection.senderName}}" userInput="{{_defaultNewsletter.senderName}}" stepKey="fillSenderName" /> <fillField selector="{{BasicFieldNewsletterSection.senderEmail}}" userInput="{{_defaultNewsletter.senderEmail}}" stepKey="fillSenderEmail" /> + <conditionalClick selector="{{NewsletterWYSIWYGSection.ShowHideBtn}}" dependentSelector="{{NewsletterWYSIWYGSection.TinyMCE4}}" visible="false" stepKey="toggleEditorIfHidden"/> + <waitForPageLoad time="10" stepKey="waitForPageLoad21"/> + <conditionalClick selector="#toggletext" dependentSelector=".mce-tinymce" visible="false" stepKey="clickBtnIfTinyMCEHidden"/> <waitForElementVisible selector="{{NewsletterWYSIWYGSection.TinyMCE4}}" stepKey="waitForTinyMCE4"/> <executeJS function="tinyMCE.get('text').setContent('Hello World From Newsletter Template!');" stepKey="executeJSFillContent"/> <seeElement selector="{{NewsletterWYSIWYGSection.InsertVariableIcon}}" stepKey="seeInsertVariableIcon" /> @@ -72,7 +76,7 @@ <waitForPageLoad stepKey="waitForPageLoad6"/> <click selector="{{VariableSection.InsertVariableBtnEnabled}}" stepKey="save2" /> <waitForElementNotVisible selector="{{VariableSection.VariableTitle}}" stepKey="waitForSlideOutClose" /> - <click selector="{{NewsletterWYSIWYGSection.ShowHideBtn}}" stepKey="clickShow/HideBtn"/> + <click selector="{{NewsletterWYSIWYGSection.ShowHideBtn}}" stepKey="clickShowHideBtn"/> <waitForElementVisible selector="{{NewsletterWYSIWYGSection.InsertVariableBtn}}" stepKey="waitForInsertVariableBtn" /> <seeElement selector="{{NewsletterWYSIWYGSection.InsertVariableBtn}}" stepKey="InsertVariableBtn" /> <click selector="{{BasicFieldNewsletterSection.save}}" stepKey="clickSaveTemplate"/> @@ -92,7 +96,7 @@ <click selector="{{NewsletterWYSIWYGSection.Preview(_defaultNewsletter.name)}}" stepKey="clickPreview2" /> <switchToWindow userInput="action_window" stepKey="switchToWindow2"/> <switchToIFrame userInput="preview_iframe" stepKey="switchToIframe2" /> - <waitForPageLoad stepKey="waitForPageLoad8"/> + <wait time="10" stepKey="waitForPageLoad8"/> <!--see custom variable blank--> <dontSee userInput="{{customVariable.html}}" stepKey="dontSeeCustomVariableName" /> <closeTab stepKey="closeTab"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddWidgetToWYSIWYGNewsletterCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddWidgetToWYSIWYGNewsletterCest.xml index 85ba7e6fcc9c3..4df702f478cdc 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddWidgetToWYSIWYGNewsletterCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/AdminAddWidgetToWYSIWYGNewsletterCest.xml @@ -28,6 +28,7 @@ <fillField selector="{{BasicFieldNewsletterSection.templateSubject}}" userInput="{{_defaultNewsletter.subject}}" stepKey="fillTemplateSubject" /> <fillField selector="{{BasicFieldNewsletterSection.senderName}}" userInput="{{_defaultNewsletter.senderName}}" stepKey="fillSenderName" /> <fillField selector="{{BasicFieldNewsletterSection.senderEmail}}" userInput="{{_defaultNewsletter.senderEmail}}" stepKey="fillSenderEmail" /> + <conditionalClick selector="{{NewsletterWYSIWYGSection.ShowHideBtn}}" dependentSelector="{{NewsletterWYSIWYGSection.TinyMCE4}}" visible="false" stepKey="toggleEditorIfHidden"/> <waitForElementVisible selector="{{TinyMCESection.TinyMCE4}}" stepKey="waitForTinyMCE" /> <click selector="{{NewsletterWYSIWYGSection.InsertWidgetIcon}}" stepKey="clickInsertWidgetIcon" /> <wait time="10" stepKey="waitForPageLoad" /> @@ -48,7 +49,7 @@ <click selector="{{NewsletterWYSIWYGSection.Preview(_defaultNewsletter.name)}}" stepKey="clickPreview" /> <switchToWindow stepKey="switchToWindow" userInput="action_window"/> <switchToIFrame userInput="preview_iframe" stepKey="switchToIframe" /> - <waitForPageLoad stepKey="waitForPageLoad9"/> + <waitForText userInput="Home page" stepKey="waitForPageLoad9"/> <see userInput="Home page" stepKey="seeHomePageCMSPage"/> <closeTab stepKey="closeTab"/> <after> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnNewsletterCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnNewsletterCest.xml index f9571a6e7477e..d60f19d2f8def 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnNewsletterCest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Newsletter/Test/VerifyTinyMCEv4IsNativeWYSIWYGOnNewsletterCest.xml @@ -43,7 +43,7 @@ <click selector="{{NewsletterWYSIWYGSection.Preview(_defaultNewsletter.name)}}" stepKey="clickPreview" /> <switchToWindow stepKey="switchToWindow" userInput="action_window"/> <switchToIFrame userInput="preview_iframe" stepKey="switchToIframe" /> - <waitForPageLoad stepKey="waitForPageLoad2"/> + <waitForText userInput="Hello World From Newsletter Template!" stepKey="waitForPageLoad2"/> <see userInput="Hello World From Newsletter Template!" stepKey="seeContent" /> <closeTab stepKey="closeTab"/> <after> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Payment/Data/PaymentMethodData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Payment/Data/PaymentMethodData.xml new file mode 100644 index 0000000000000..5b14d8b5e3f58 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Payment/Data/PaymentMethodData.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="PaymentMethodCheckMoneyOrder" type="payment_method"> + <data key="method">checkmo</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Payment/Metadata/payment_method-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Payment/Metadata/payment_method-meta.xml new file mode 100644 index 0000000000000..a091800bac070 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Payment/Metadata/payment_method-meta.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreatePaymentMethod" dataType="payment_method" type="create"> + <field key="method">string</field> + </operation> +</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Data/CartItemData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Data/CartItemData.xml new file mode 100644 index 0000000000000..c1ffe00468abe --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Data/CartItemData.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="SimpleCartItem" type="CartItem"> + <data key="qty">1</data> + <var key="quote_id" entityKey="return" entityType="GuestCart"/> + <var key="sku" entityKey="sku" entityType="product"/> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Data/GuestCartData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Data/GuestCartData.xml index 197fad0fab291..bb65c1ade2e3f 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Data/GuestCartData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Data/GuestCartData.xml @@ -9,6 +9,20 @@ <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="guestCart" type="guestCart"> + + <entity name="GuestCart" type="GuestCart"> + </entity> + + <entity name="GuestAddressInformation" type="AddressInformation"> + <var key="quote_id" entityKey="return" entityType="GuestCart"/> + <requiredEntity type="shipping_address">ShippingAddressTX</requiredEntity> + <requiredEntity type="billing_address">BillingAddressTX</requiredEntity> + <data key="shipping_method_code">flatrate</data> + <data key="shipping_carrier_code">flatrate</data> + </entity> + + <entity name="GuestOrderPaymentMethod" type="PaymentInformation"> + <requiredEntity type="payment_method">PaymentMethodCheckMoneyOrder</requiredEntity> + <requiredEntity type="billing_address">BillingAddressTX</requiredEntity> </entity> </entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/billing_address-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/billing_address-meta.xml new file mode 100644 index 0000000000000..488f8ba49e28e --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/billing_address-meta.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateBillingAddress" dataType="billing_address" type="create"> + <field key="city">string</field> + <field key="region">string</field> + <field key="region_code">string</field> + <field key="region_id">int</field> + <field key="country_id">string</field> + <array key="street"> + <value>string</value> + </array> + <field key="postcode">string</field> + <field key="firstname">string</field> + <field key="lastname">string</field> + <field key="email">string</field> + <field key="telephone">string</field> + </operation> +</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/guest-cart-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/guest-cart-meta.xml deleted file mode 100644 index c4a290e43156f..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/guest-cart-meta.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> - <operation name="CreateGuestCart" dataType="guestCart" type="create" auth="anonymous" url="/V1/guest-carts" method="POST"> - <contentType>application/json</contentType> - </operation> -</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/guest_cart-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/guest_cart-meta.xml new file mode 100644 index 0000000000000..29d6266342fee --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/guest_cart-meta.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateGuestCart" dataType="GuestCart" type="create" auth="anonymous" url="/V1/guest-carts" method="POST"> + <contentType>application/json</contentType> + </operation> + + <operation name="AddProductToGuestCart" dataType="CartItem" type="create" auth="anonymous" url="V1/guest-carts/{return}/items" method="POST"> + <contentType>application/json</contentType> + <object key="cartItem" dataType="CartItem"> + <field key="quote_id">string</field> + <field key="sku" type="string">string</field> + <field key="qty">integer</field> + </object> + </operation> + + <operation name="AddAddressInfoToGuestCart" dataType="AddressInformation" type="create" auth="anonymous" url="/V1/guest-carts/{return}/shipping-information" method="POST"> + <contentType>application/json</contentType> + <object key="addressInformation" dataType="AddressInformation"> + <object key="shipping_address" dataType="shipping_address"> + <field key="city">string</field> + <field key="region">string</field> + <field key="region_code">string</field> + <field key="region_id">integer</field> + <field key="country_id">string</field> + <array key="street"> + <value>string</value> + </array> + <field key="postcode">string</field> + <field key="firstname">string</field> + <field key="lastname">string</field> + <field key="email">string</field> + <field key="telephone">string</field> + </object> + <object key="billing_address" dataType="billing_address"> + <field key="city">string</field> + <field key="region">string</field> + <field key="region_code">string</field> + <field key="region_id">integer</field> + <field key="country_id">string</field> + <array key="street"> + <value>string</value> + </array> + <field key="postcode">string</field> + <field key="firstname">string</field> + <field key="lastname">string</field> + <field key="email">string</field> + <field key="telephone">string</field> + </object> + <field key="shipping_method_code">string</field> + <field key="shipping_carrier_code">string</field> + </object> + </operation> + + <operation name="SendGuestPaymentInformation" dataType="PaymentInformation" type="update" auth="anonymous" url="/V1/guest-carts/{return}/order" method="PUT"> + <contentType>application/json</contentType> + <object key="paymentMethod" dataType="payment_method"> + <field key="method">string</field> + </object> + </operation> +</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/shipping_address-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/shipping_address-meta.xml new file mode 100644 index 0000000000000..e75f49537dad5 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Quote/Metadata/shipping_address-meta.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateShippingAddress" dataType="shipping_address" type="create"> + <field key="city">string</field> + <field key="region">string</field> + <field key="region_code">string</field> + <field key="region_id">int</field> + <field key="country_id">string</field> + <array key="street"> + <value>string</value> + </array> + <field key="postcode">string</field> + <field key="firstname">string</field> + <field key="lastname">string</field> + <field key="email">string</field> + <field key="telephone">string</field> + </operation> +</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminCreditMemoActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminCreditMemoActionGroup.xml new file mode 100644 index 0000000000000..e83f061f56268 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminCreditMemoActionGroup.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!--Check customer information is correct in credit memo--> + <actionGroup name="verifyBasicCreditMemoInformation"> + <arguments> + <argument name="customer" defaultValue=""/> + <argument name="shippingAddress" defaultValue=""/> + <argument name="billingAddress" defaultValue=""/> + <argument name="customerGroup" defaultValue="GeneralCustomerGroup"/> + </arguments> + <see selector="{{AdminCreditMemoOrderInformationSection.customerName}}" userInput="{{customer.firstname}}" stepKey="seeCustomerName"/> + <see selector="{{AdminCreditMemoOrderInformationSection.customerEmail}}" userInput="{{customer.email}}" stepKey="seeCustomerEmail"/> + <see selector="{{AdminCreditMemoOrderInformationSection.customerGroup}}" userInput="{{customerGroup.code}}" stepKey="seeCustomerGroup"/> + + <see selector="{{AdminCreditMemoAddressInformationSection.billingAddress}}" userInput="{{billingAddress.street[0]}}" stepKey="seeBillingAddressStreet"/> + <see selector="{{AdminCreditMemoAddressInformationSection.billingAddress}}" userInput="{{billingAddress.city}}" stepKey="seeBillingAddressCity"/> + <see selector="{{AdminCreditMemoAddressInformationSection.billingAddress}}" userInput="{{billingAddress.country_id}}" stepKey="seeBillingAddressCountry"/> + <see selector="{{AdminCreditMemoAddressInformationSection.billingAddress}}" userInput="{{billingAddress.postcode}}" stepKey="seeBillingAddressPostcode"/> + + <see selector="{{AdminCreditMemoAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.street[0]}}" stepKey="seeShippingAddressStreet"/> + <see selector="{{AdminCreditMemoAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.city}}" stepKey="seeShippingAddressCity"/> + <see selector="{{AdminCreditMemoAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.country_id}}" stepKey="seeShippingAddressCountry"/> + <see selector="{{AdminCreditMemoAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.postcode}}" stepKey="seeShippingAddressPostcode"/> + </actionGroup> + + <actionGroup name="seeProductInItemsRefunded"> + <arguments> + <argument name="product"/> + </arguments> + <see selector="{{AdminCreditMemoItemsSection.skuColumn}}" userInput="{{product.sku}}" stepKey="seeProductSkuInGrid"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminInvoiceActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminInvoiceActionGroup.xml new file mode 100644 index 0000000000000..29d7a2773aad6 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminInvoiceActionGroup.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!--Check customer information is correct in invoice--> + <actionGroup name="verifyBasicInvoiceInformation"> + <arguments> + <argument name="customer"/> + <argument name="shippingAddress"/> + <argument name="billingAddress"/> + <argument name="customerGroup" defaultValue="GeneralCustomerGroup"/> + </arguments> + <see selector="{{AdminInvoiceOrderInformationSection.customerName}}" userInput="{{customer.firstname}}" stepKey="seeCustomerName"/> + <see selector="{{AdminInvoiceOrderInformationSection.customerEmail}}" userInput="{{customer.email}}" stepKey="seeCustomerEmail"/> + <see selector="{{AdminInvoiceOrderInformationSection.customerGroup}}" userInput="{{customerGroup.code}}" stepKey="seeCustomerGroup"/> + + <see selector="{{AdminInvoiceAddressInformationSection.billingAddress}}" userInput="{{billingAddress.street[0]}}" stepKey="seeBillingAddressStreet"/> + <see selector="{{AdminInvoiceAddressInformationSection.billingAddress}}" userInput="{{billingAddress.city}}" stepKey="seeBillingAddressCity"/> + <see selector="{{AdminInvoiceAddressInformationSection.billingAddress}}" userInput="{{billingAddress.country_id}}" stepKey="seeBillingAddressCountry"/> + <see selector="{{AdminInvoiceAddressInformationSection.billingAddress}}" userInput="{{billingAddress.postcode}}" stepKey="seeBillingAddressPostcode"/> + + <see selector="{{AdminInvoiceAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.street[0]}}" stepKey="seeShippingAddressStreet"/> + <see selector="{{AdminInvoiceAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.city}}" stepKey="seeShippingAddressCity"/> + <see selector="{{AdminInvoiceAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.country_id}}" stepKey="seeShippingAddressCountry"/> + <see selector="{{AdminInvoiceAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.postcode}}" stepKey="seeShippingAddressPostcode"/> + </actionGroup> + + <!--Check that product is in invoice items--> + <actionGroup name="seeProductInInvoiceItems"> + <arguments> + <argument name="product"/> + </arguments> + <see selector="{{AdminInvoiceItemsSection.skuColumn}}" userInput="{{product.sku}}" stepKey="seeProductSkuInGrid"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminOrderActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminOrderActionGroup.xml new file mode 100644 index 0000000000000..e975a1c2cb9b7 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminOrderActionGroup.xml @@ -0,0 +1,137 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!--Navigate to create order page (New Order -> Create New Customer)--> + <actionGroup name="navigateToNewOrderPageNewCustomer"> + <arguments> + <argument name="storeView" defaultValue="_defaultStore"/> + </arguments> + <amOnPage url="{{AdminOrdersPage}}" stepKey="navigateToOrderIndexPage"/> + <waitForPageLoad stepKey="waitForIndexPageLoad"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="Orders" stepKey="seeIndexPageTitle"/> + <click selector="{{AdminOrdersGridSection.createNewOrder}}" stepKey="clickCreateNewOrder"/> + <click selector="{{AdminOrderFormActionSection.CreateNewCustomer}}" stepKey="clickCreateCustomer"/> + <click selector="{{AdminOrderStoreScopeTreeSection.storeOption(storeView.name)}}" stepKey="selectDefaultStoreView"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="Create New Order" stepKey="seeNewOrderPageTitle"/> + </actionGroup> + + <!--Check the required fields are actually required--> + <actionGroup name="checkRequiredFieldsNewOrderForm"> + <seeElement selector="{{AdminOrderFormAccountSection.requiredGroup}}" stepKey="seeCustomerGroupRequired"/> + <clearField selector="{{AdminOrderFormBillingAddressSection.FirstName}}" stepKey="clearFirstNameField"/> + <clearField selector="{{AdminOrderFormBillingAddressSection.LastName}}" stepKey="clearLastNameField"/> + <clearField selector="{{AdminOrderFormBillingAddressSection.StreetLine1}}" stepKey="clearStreetField"/> + <clearField selector="{{AdminOrderFormBillingAddressSection.City}}" stepKey="clearCityField"/> + <selectOption selector="{{AdminOrderFormBillingAddressSection.Country}}" userInput="United States" stepKey="selectUSCountry"/> + <selectOption selector="{{AdminOrderFormBillingAddressSection.State}}" userInput="Please select" stepKey="selectNoState"/> + <clearField selector="{{AdminOrderFormBillingAddressSection.PostalCode}}" stepKey="clearPostalCodeField"/> + <clearField selector="{{AdminOrderFormBillingAddressSection.Phone}}" stepKey="clearPhoneField"/> + <seeElement selector="{{AdminOrderFormPaymentSection.getShippingMethods}}" stepKey="seeShippingMethodNotSelected"/> + <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="trySubmitOrder"/> + <see selector="{{AdminOrderFormBillingAddressSection.firstNameError}}" userInput="This is a required field." stepKey="seeFirstNameRequired"/> + <see selector="{{AdminOrderFormBillingAddressSection.lastNameError}}" userInput="This is a required field." stepKey="seeLastNameRequired"/> + <see selector="{{AdminOrderFormBillingAddressSection.streetAddressError}}" userInput="This is a required field." stepKey="seeStreetRequired"/> + <see selector="{{AdminOrderFormBillingAddressSection.cityError}}" userInput="This is a required field." stepKey="seeCityRequired"/> + <see selector="{{AdminOrderFormBillingAddressSection.stateError}}" userInput="This is a required field." stepKey="seeStateRequired"/> + <see selector="{{AdminOrderFormBillingAddressSection.postalCodeError}}" userInput="This is a required field." stepKey="seePostalCodeRequired"/> + <see selector="{{AdminOrderFormBillingAddressSection.phoneError}}" userInput="This is a required field." stepKey="seePhoneRequired"/> + <see selector="{{AdminOrderFormPaymentSection.shippingError}}" userInput="This is a required field." stepKey="seeShippingMethodRequired"/> + </actionGroup> + + <!--Add a simple product to order--> + <actionGroup name="addSimpleProductToOrder"> + <arguments> + <argument name="product" defaultValue="_defaultProduct"/> + </arguments> + <click selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="clickAddProducts"/> + <fillField selector="{{AdminOrderFormItemsSection.skuFilter}}" userInput="{{product.sku}}" stepKey="fillSkuFilter"/> + <click selector="{{AdminOrderFormItemsSection.search}}" stepKey="clickSearch"/> + <scrollTo selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" x="0" y="-100" stepKey="scrollToCheckColumn"/> + <checkOption selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="selectProduct"/> + <fillField selector="{{AdminOrderFormItemsSection.rowQty('1')}}" userInput="1" stepKey="fillProductQty"/> + <scrollTo selector="{{AdminOrderFormItemsSection.addSelected}}" x="0" y="-100" stepKey="scrollToAddSelectedButton"/> + <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> + </actionGroup> + + <!--Add configurable product to order --> + <actionGroup name="addConfigurableProductToOrder"> + <arguments> + <argument name="product"/> + <argument name="attribute"/> + <argument name="option"/> + </arguments> + <click selector="{{AdminOrderFormItemsSection.addProducts}}" stepKey="clickAddProducts"/> + <fillField selector="{{AdminOrderFormItemsSection.skuFilter}}" userInput="{{product.sku}}" stepKey="fillSkuFilterConfigurable"/> + <click selector="{{AdminOrderFormItemsSection.search}}" stepKey="clickSearchConfigurable"/> + <scrollTo selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" x="0" y="-100" stepKey="scrollToCheckColumn"/> + <checkOption selector="{{AdminOrderFormItemsSection.rowCheck('1')}}" stepKey="selectConfigurableProduct"/> + <waitForElementVisible selector="{{AdminOrderFormConfigureProductSection.optionSelect(attribute.default_label)}}" stepKey="waitForConfigurablePopover"/> + <wait time="2" stepKey="waitForOptionsToLoad"/> + <selectOption selector="{{AdminOrderFormConfigureProductSection.optionSelect(attribute.default_label)}}" + userInput="{{option.name}}" stepKey="selectionConfigurableOption"/> + <click selector="{{AdminOrderFormConfigureProductSection.ok}}" stepKey="clickOkConfigurablePopover"/> + <scrollTo selector="{{AdminOrderFormItemsSection.addSelected}}" x="0" y="-100" stepKey="scrollToAddSelectedButton"/> + <click selector="{{AdminOrderFormItemsSection.addSelected}}" stepKey="clickAddSelectedProducts"/> + </actionGroup> + + <!--Fill customer billing address--> + <actionGroup name="fillOrderCustomerInformation"> + <arguments> + <argument name="customer"/> + <argument name="address"/> + </arguments> + <fillField selector="{{AdminOrderFormBillingAddressSection.FirstName}}" userInput="{{customer.firstname}}" stepKey="fillFirstName"/> + <fillField selector="{{AdminOrderFormBillingAddressSection.LastName}}" userInput="{{customer.lastname}}" stepKey="fillLastName"/> + <fillField selector="{{AdminOrderFormBillingAddressSection.StreetLine1}}" userInput="{{address.street[0]}}" stepKey="fillStreetLine1"/> + <fillField selector="{{AdminOrderFormBillingAddressSection.City}}" userInput="{{address.city}}" stepKey="fillCity"/> + <selectOption selector="{{AdminOrderFormBillingAddressSection.Country}}" userInput="{{address.country_id}}" stepKey="fillCountry"/> + <selectOption selector="{{AdminOrderFormBillingAddressSection.State}}" userInput="{{address.state}}" stepKey="fillState"/> + <fillField selector="{{AdminOrderFormBillingAddressSection.PostalCode}}" userInput="{{address.postcode}}" stepKey="fillPostalCode"/> + <fillField selector="{{AdminOrderFormBillingAddressSection.Phone}}" userInput="{{address.telephone}}" stepKey="fillPhone"/> + </actionGroup> + + <!--Select flat rate shipping method--> + <actionGroup name="orderSelectFlatRateShipping"> + <click selector="{{AdminOrderFormPaymentSection.header}}" stepKey="unfocus"/> + <waitForPageLoad stepKey="waitForJavascriptToFinish"/> + <click selector="{{AdminOrderFormPaymentSection.getShippingMethods}}" stepKey="clickShippingMethods"/> + <waitForElementVisible selector="{{AdminOrderFormPaymentSection.flatRateOption}}" stepKey="waitForShippingOptions"/> + <selectOption selector="{{AdminOrderFormPaymentSection.flatRateOption}}" userInput="flatrate_flatrate" stepKey="checkFlatRate"/> + </actionGroup> + + <!--Check that customer information is correct in order--> + <actionGroup name="verifyBasicOrderInformation"> + <arguments> + <argument name="customer"/> + <argument name="shippingAddress"/> + <argument name="billingAddress"/> + <argument name="customerGroup" defaultValue="GeneralCustomerGroup"/> + </arguments> + <see selector="{{AdminOrderDetailsInformationSection.customerName}}" userInput="{{customer.firstname}}" stepKey="seeCustomerName"/> + <see selector="{{AdminOrderDetailsInformationSection.customerEmail}}" userInput="{{customer.email}}" stepKey="seeCustomerEmail"/> + <see selector="{{AdminOrderDetailsInformationSection.customerGroup}}" userInput="{{customerGroup.code}}" stepKey="seeCustomerGroup"/> + <see selector="{{AdminOrderAddressInformationSection.billingAddress}}" userInput="{{billingAddress.street[0]}}" stepKey="seeBillingAddressStreet"/> + <see selector="{{AdminOrderAddressInformationSection.billingAddress}}" userInput="{{billingAddress.city}}" stepKey="seeBillingAddressCity"/> + <see selector="{{AdminOrderAddressInformationSection.billingAddress}}" userInput="{{billingAddress.country_id}}" stepKey="seeBillingAddressCountry"/> + <see selector="{{AdminOrderAddressInformationSection.billingAddress}}" userInput="{{billingAddress.postcode}}" stepKey="seeBillingAddressPostcode"/> + <see selector="{{AdminOrderAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.street[0]}}" stepKey="seeShippingAddressStreet"/> + <see selector="{{AdminOrderAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.city}}" stepKey="seeShippingAddressCity"/> + <see selector="{{AdminOrderAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.country_id}}" stepKey="seeShippingAddressCountry"/> + <see selector="{{AdminOrderAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.postcode}}" stepKey="seeShippingAddressPostcode"/> + </actionGroup> + + <!--Check for product in order items list--> + <actionGroup name="seeProductInItemsOrdered"> + <arguments> + <argument name="product"/> + </arguments> + <see selector="{{AdminOrderItemsOrderedSection.productSkuColumn}}" userInput="{{product.sku}}" stepKey="seeSkuInItemsOrdered"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminOrderGridActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminOrderGridActionGroup.xml new file mode 100644 index 0000000000000..b65d32670bb48 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/ActionGroup/AdminOrderGridActionGroup.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!--Filter order grid by order id field--> + <actionGroup name="filterOrderGridById"> + <amOnPage url="{{AdminOrdersPage}}" stepKey="navigateToOrderGridPage"/> + <waitForPageLoad stepKey="waitForOrderGridLoad"/> + <conditionalClick selector="{{AdminOrdersGridSection.clearFilters}}" dependentSelector="{{AdminOrdersGridSection.clearFilters}}" visible="true" stepKey="clearExistingOrderFilters"/> + <click selector="{{AdminOrdersGridSection.filters}}" stepKey="openOrderGridFilters"/> + <fillField selector="{{AdminOrdersGridSection.idFilter}}" userInput="$getOrderId" stepKey="fillOrderIdFilter"/> + <click selector="{{AdminOrdersGridSection.applyFilters}}" stepKey="clickOrderApplyFilters"/> + </actionGroup> + + <!--Filter order grid by the billing name field--> + <actionGroup name="filterOrderGridByBillingName"> + <arguments> + <argument name="customer"/> + </arguments> + <amOnPage url="{{AdminOrdersPage}}" stepKey="navigateToOrderGridPage"/> + <waitForPageLoad stepKey="waitForOrderGridLoad"/> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clearExistingOrderFilters"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openOrderGridFilters"/> + <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('billing_name')}}" userInput="{{customer.fullname}}" stepKey="fillBillToNameFilter"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickOrderApplyFilters"/> + </actionGroup> + + <!--Filter order grid by order total range--> + <actionGroup name="filterOrderGridByBaseTotalRange"> + <arguments> + <argument name="from"/> + <argument name="to"/> + </arguments> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clearExistingOrderFilters"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openOrderGridFilters"/> + <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('base_grand_total[from]')}}" userInput="{{from}}" stepKey="fillOrderTotalFrom"/> + <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('base_grand_total[to]')}}" userInput="{{to}}" stepKey="fillOrderTotalTo"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFilters"/> + </actionGroup> + + <actionGroup name="filterOrderGridByPurchaseDate"> + <arguments> + <argument name="from"/> + <argument name="to"/> + </arguments> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clearExistingOrderFilters"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openOrderGridFilters"/> + <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('created_at[from]')}}" userInput="{{from}}" stepKey="fillOrderPurchaseDateFrom"/> + <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('created_at[to]')}}" userInput="{{to}}" stepKey="fillOrderPurchaseDateTo"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFilters"/> + </actionGroup> + + <actionGroup name="filterOrderGridByStatus"> + <arguments> + <argument name="status"/> + </arguments> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clearExistingOrderFilters"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openOrderGridFilters"/> + <selectOption selector="{{AdminDataGridHeaderSection.filterFieldSelect('status')}}" userInput="{{status}}" stepKey="fillOrderStatusFilter"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="clickApplyFilters"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/AddressData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/AddressData.xml new file mode 100644 index 0000000000000..4c3bd6d7f7ed8 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/AddressData.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="ShippingAddressTX" type="shipping_address"> + <data key="firstname">Joe</data> + <data key="lastname">Buyer</data> + <data key="fullname">Joe Buyer</data> + <array key="street"> + <item>11501 Domain Dr</item> + <item>#150</item> + </array> + <data key="city">Austin</data> + <data key="region">Texas</data> + <data key="region_code">TX</data> + <data key="region_id">1</data> + <data key="country_id">US</data> + <data key="postcode">78758</data> + <data key="email" unique="prefix">joe.buyer@email.com</data> + <data key="telephone">512-345-6789</data> + </entity> + <entity name="BillingAddressTX" type="billing_address"> + <data key="firstname">Joe</data> + <data key="lastname">Buyer</data> + <data key="fullname">Joe Buyer</data> + <array key="street"> + <item>11501 Domain Dr</item> + <item>#150</item> + </array> + <data key="city">Austin</data> + <data key="region">Texas</data> + <data key="region_code">TX</data> + <data key="region_id">1</data> + <data key="country_id">US</data> + <data key="postcode">78758</data> + <data key="email" unique="prefix">joe.buyer@email.com</data> + <data key="telephone">512-345-6789</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/ConstData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/ConstData.xml new file mode 100644 index 0000000000000..a91f31a88c235 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/ConstData.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="Const" type="constant"> + <data key="one">1</data> + <data key="two">2</data> + <data key="fifty">50</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/OrderData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/OrderData.xml new file mode 100644 index 0000000000000..39772e4c5da10 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/OrderData.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <!--Data for order created through UI with simple and configurable order--> + <entity name="AdminOrderSimpleConfigurableProduct" type="order"> + <data key="subtotal">246.00</data> + <data key="shipping">10.00</data> + <data key="grandTotal">256.00</data> + </entity> + <entity name="AdminOrderSimpleProduct" type="order"> + <data key="subtotal">123.00</data> + <data key="shipping">5.00</data> + <data key="grandTotal">128.00</data> + </entity> + <entity name="OrderGrandTotalFilterRange" type="filter"> + <data key="from">200</data> + <data key="to">400</data> + </entity> + + <entity name="OrderStatus" type="status"> + <data key="canceled">Canceled</data> + <data key="closed">Closed</data> + <data key="complete">Complete</data> + <data key="suspected">Suspected</data> + <data key="onHold">On Hold</data> + <data key="paymentReview">Payment Review</data> + <data key="pending">Pending</data> + <data key="pendingPayment">Pending Payment</data> + <data key="processing">Processing</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/SalesData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/SalesData.xml deleted file mode 100644 index 429fc331c6519..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Data/SalesData.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> - <entity name="salesRecordOne" type="sales"> - <data key="salesId">data</data> - </entity> -</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminCreditMemoNewPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminCreditMemoNewPage.xml new file mode 100644 index 0000000000000..79312e75a6416 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminCreditMemoNewPage.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminCreditMemoNewPage" url="sales/order_creditmemo/new/order_id/" area="admin" module="Magento_Sales"> + <section name="AdminCreditMemoOrderInformationSection"/> + <section name="AdminCreditMemoAddressInformationSection"/> + <section name="AdminCreditMemoPaymentShippingSection"/> + <section name="AdminCreditMemoItemsSection"/> + <section name="AdminCreditMemoTotalSection"/> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminInvoiceDetailsPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminInvoiceDetailsPage.xml new file mode 100644 index 0000000000000..9322a5779d232 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminInvoiceDetailsPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminInvoiceDetailsPage" url="sales/invoice/view/invoice_id/" area="admin" module="Magento_Sales"> + <section name="AdminInvoiceDetailsInformationSection"/> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminInvoiceNewPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminInvoiceNewPage.xml new file mode 100644 index 0000000000000..6c603f582738e --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminInvoiceNewPage.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminInvoiceNewPage" url="sales/order_invoice/new/order_id/" area="admin" module="Magento_Sales"> + <section name="AdminInvoiceMainActionsSection"/> + <section name="AdminInvoiceOrderInformationSection"/> + <section name="AdminInvoiceAddressInformationSection"/> + <section name="AdminInvoicePaymentShippingSection"/> + <section name="AdminInvoiceItemsSection"/> + <section name="AdminInvoiceTotalSection"/> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminInvoicesPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminInvoicesPage.xml new file mode 100644 index 0000000000000..d29844da5a8c1 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminInvoicesPage.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminInvoicesPage" url="sales/invoice/" area="admin" module="Magento_Sales"> + <section name="AdminInvoicesGridSection"/> + <section name="AdminInvoicesFiltersSection"/> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminOrderCreatePage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminOrderCreatePage.xml new file mode 100644 index 0000000000000..4eba7f02302fd --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminOrderCreatePage.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminOrderCreatePage" url="sales/order_create/index" area="admin" module="Magento_Sales"> + <section name="AdminOrderFormActionSection"/> + <section name="AdminOrderFormItemsSection"/> + <section name="AdminOrderFormConfigureProductSection"/> + <section name="AdminOrderFormAccountSection"/> + <section name="AdminOrderFormBillingAddressSection"/> + <section name="AdminOrderFormShippingAddressSection"/> + <section name="AdminOrderFormPaymentSection"/> + <section name="AdminOrderFormTotalSection"/> + </page> +</pages> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminOrderDetailsPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminOrderDetailsPage.xml new file mode 100644 index 0000000000000..4755c074a0352 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminOrderDetailsPage.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminOrderDetailsPage" url="sales/order/view/order_id/" area="admin" module="Magento_Sales"> + <section name="AdminOrderDetailsMainActionsSection"/> + <section name="AdminOrderDetailsOrderViewSection"/> + <section name="AdminOrderDetailsInformationSection"/> + <section name="AdminOrderAddressInformationSection"/> + <section name="AdminOrderPaymentInformationSection"/> + <section name="AdminOrderShippingInformationSection"/> + <section name="AdminOrderItemsOrderedSection"/> + <section name="AdminOrderDetailsMessagesSection"/> + <section name="AdminOrderInvoicesTabSection"/> + <section name="AdminOrderCreditMemosTabSection"/> + <section name="AdminOrderShipmentsTabSection"/> + <section name="AdminOrderCommentsTabSection"/> + </page> +</pages> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminOrdersPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminOrdersPage.xml new file mode 100644 index 0000000000000..b3620c1935a32 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/AdminOrdersPage.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminOrdersPage" url="sales/order/" area="admin" module="Magento_Sales"> + <section name="AdminOrdersGridSection"/> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/InvoiceDetailsPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/InvoiceDetailsPage.xml deleted file mode 100644 index 4b827bd345934..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/InvoiceDetailsPage.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="InvoiceDetailsPage" url="/sales/invoice/view/invoice_id/" area="admin" module="Sales"> - <section name="InvoiceDetailsInformationSection"/> - </page> -</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/InvoiceNewPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/InvoiceNewPage.xml deleted file mode 100644 index 9df50cc8f285d..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/InvoiceNewPage.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="InvoiceNewPage" url="/sales/order_invoice/new/order_id/" area="admin" module="Sales"> - <section name="InvoiceNewSection"/> - </page> -</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/InvoicesPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/InvoicesPage.xml deleted file mode 100644 index c3bcdb3eb1240..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/InvoicesPage.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="InvoicesPage" url="/sales/invoice/" area="admin" module="Sales"> - <section name="InvoicesGridSection"/> - <section name="InvoicesFiltersSection"/> - </page> -</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/OrderDetailsPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/OrderDetailsPage.xml deleted file mode 100644 index 285a0e2f61cde..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/OrderDetailsPage.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="OrderDetailsPage" url="/sales/order/view/order_id/" area="admin" module="Sales"> - <section name="OrderDetailsMainActionsSection"/> - <section name="OrderDetailsInformationSection"/> - <section name="OrderDetailsMessagesSection"/> - </page> -</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/OrdersPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/OrdersPage.xml deleted file mode 100644 index e2d6146886993..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Page/OrdersPage.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> - <page name="OrdersPage" url="/sales/order/" area="admin" module="Sales"> - <section name="OrdersGridSection"/> - </page> -</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoAddressInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoAddressInformationSection.xml new file mode 100644 index 0000000000000..68baf82796fe3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoAddressInformationSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCreditMemoAddressInformationSection"> + <element name="billingAddress" type="text" selector=".order-billing-address address"/> + <element name="billingAddressEdit" type="button" selector=".order-billing-address .actions a"/> + <element name="shippingAddress" type="text" selector=".order-shipping-address address"/> + <element name="shippingAddressEdit" type="button" selector=".order-shipping-address .actions a"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoItemsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoItemsSection.xml new file mode 100644 index 0000000000000..024a2c55bef1c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoItemsSection.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCreditMemoItemsSection"> + <element name="header" type="text" selector="#creditmemo_item_container span.title"/> + <element name="itemName" type="text" selector=".order-creditmemo-tables tbody:nth-of-type({{row}}) .col-product .product-title" parameterized="true"/> + <element name="itemSku" type="text" selector=".order-creditmemo-tables tbody:nth-of-type({{row}}) .col-product .product-sku-block" parameterized="true"/> + <element name="itemPrice" type="text" selector=".order-creditmemo-tables tbody:nth-of-type({{row}}) .col-price .price" parameterized="true"/> + <element name="itemQty" type="text" selector=".order-creditmemo-tables tbody:nth-of-type({{row}}) .col-ordered-qty .qty-table" parameterized="true"/> + <element name="itemReturnToStock" type="checkbox" selector=".order-creditmemo-tables tbody:nth-of-type({{row}}) .col-return-to-stock input" parameterized="true"/> + <element name="itemQtyToRefund" type="input" selector=".order-creditmemo-tables tbody:nth-of-type({{row}}) .col-refund .qty-input" parameterized="true"/> + <element name="itemSubtotal" type="text" selector=".order-creditmemo-tables tbody:nth-of-type({{row}}) .col-subtotal .price" parameterized="true"/> + <element name="itemTaxAmount" type="text" selector=".order-creditmemo-tables tbody:nth-of-type({{row}}) .col-tax-amount .price" parameterized="true"/> + <element name="itemDiscountAmount" type="text" selector=".order-creditmemo-tables tbody:nth-of-type({{row}}) .col-discont .price" parameterized="true"/> + <element name="itemTotal" type="text" selector=".order-creditmemo-tables tbody:nth-of-type({{row}}) .col-total .price" parameterized="true"/> + <element name="updateQty" type="button" selector=".order-creditmemo-tables tfoot button[data-ui-id='order-items-update-button']" timeout="30"/> + <element name="nameColumn" type="text" selector=".order-creditmemo-tables .product-title"/> + <element name="skuColumn" type="text" selector=".order-creditmemo-tables .product-sku-block"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoOrderInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoOrderInformationSection.xml new file mode 100644 index 0000000000000..6ffaa51c2d4d3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoOrderInformationSection.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCreditMemoOrderInformationSection"> + <element name="orderId" type="text" selector="div.order-information span.title > a" timeout="60"/> + <element name="orderDate" type="text" selector=".order-information table.order-information-table tr:first-of-type > td"/> + <element name="orderStatus" type="text" selector=".order-information table.order-information-table #order_status"/> + <element name="purchasedFrom" type="text" selector=".order-information table.order-information-table tr:last-of-type > td"/> + <element name="customerName" type="text" selector=".order-account-information table tr:first-of-type > td span"/> + <element name="customerEmail" type="text" selector=".order-account-information table tr:nth-of-type(2) > td a"/> + <element name="customerGroup" type="text" selector=".order-account-information table tr:nth-of-type(3) > td"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoPaymentShippingSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoPaymentShippingSection.xml new file mode 100644 index 0000000000000..1411ee23970a1 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoPaymentShippingSection.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCreditMemoPaymentShippingSection"> + <element name="PaymentMethod" type="text" selector=".order-payment-method .order-payment-method-title"/> + <element name="CurrencyInformation" type="text" selector=".order-payment-method .order-payment-currency"/> + <element name="PaymentAdditional" type="text" selector=".order-payment-method .order-payment-additional"/> + <element name="ShippingMethod" type="text" selector=".order-shipping-address .shipping-description-title"/> + <element name="ShippingPrice" type="text" selector=".order-shipping-address .shipping-description-content .price"/> + <element name="CreateShipment" type="checkbox" selector=".order-shipping-address input[name='invoice[do_shipment]']"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoTotalSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoTotalSection.xml new file mode 100644 index 0000000000000..529d86dc203a1 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminCreditMemoTotalSection.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminCreditMemoTotalSection"> + <element name="subtotalRow" type="text" selector=".order-subtotal-table tbody > tr:nth-of-type({{row}}) td span.price" parameterized="true"/> + <element name="total" type="text" selector="//table[contains(@class,'order-subtotal-table')]/tbody/tr/td[contains(text(), '{{total}}')]/following-sibling::td/span/span[contains(@class, 'price')]" parameterized="true"/> + <element name="refundShipping" type="input" selector=".order-subtotal-table tbody input[name='creditmemo[shipping_amount]']"/> + <element name="adjustmentRefund" type="input" selector=".order-subtotal-table tbody input[name='creditmemo[adjustment_positive]'"/> + <element name="adjustmentFee" type="input" selector=".order-subtotal-table tbody input[name='creditmemo[adjustment_negative]']"/> + <element name="grandTotal" type="text" selector=".order-subtotal-table tfoot tr.col-0>td span.price"/> + <element name="appendComments" type="checkbox" selector=".order-totals-actions #notify_customer"/> + <element name="emailCopy" type="checkbox" selector=".order-totals-actions #send_email"/> + <element name="refundStoreCredit" type="checkbox" selector=".order-totals-actions .field-refund-store-credit input[type='checkbox']"/> + <element name="submitRefundOffline" type="button" selector=".order-totals-actions button[data-ui-id='order-items-submit-button']" timeout="30"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceAddressInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceAddressInformationSection.xml new file mode 100644 index 0000000000000..f8b0e3dd284a4 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceAddressInformationSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminInvoiceAddressInformationSection"> + <element name="billingAddress" type="text" selector=".order-billing-address address"/> + <element name="billingAddressEdit" type="button" selector=".order-billing-address .actions a"/> + <element name="shippingAddress" type="text" selector=".order-shipping-address address"/> + <element name="shippingAddressEdit" type="button" selector=".order-shipping-address .actions a"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceDetailsInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceDetailsInformationSection.xml new file mode 100644 index 0000000000000..d45a0245c00b9 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceDetailsInformationSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminInvoiceDetailsInformationSection"> + <element name="orderStatus" type="text" selector="#order_status"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceItemsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceItemsSection.xml new file mode 100644 index 0000000000000..da2a7e10ae1f8 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceItemsSection.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminInvoiceItemsSection"> + <element name="itemName" type="text" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .product-title" parameterized="true"/> + <element name="itemSku" type="text" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .product-sku-block" parameterized="true"/> + <element name="itemPrice" type="text" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .col-price .price" parameterized="true"/> + <element name="itemQty" type="text" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .col-qty .qty-table" parameterized="true"/> + <element name="itemQtyToInvoice" type="input" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .col-qty-invoice .qty-input" parameterized="true"/> + <element name="itemSubtotal" type="text" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .col-subtotal .price" parameterized="true"/> + <element name="itemTaxAmount" type="text" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .col-tax .price" parameterized="true"/> + <element name="itemDiscountAmount" type="text" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .col-discount .price" parameterized="true"/> + <element name="itemTotal" type="text" selector=".order-invoice-tables tbody:nth-of-type({{row}}) .col-total .price" parameterized="true"/> + <element name="nameColumn" type="text" selector=".order-invoice-tables .product-title"/> + <element name="skuColumn" type="text" selector=".order-invoice-tables .product-sku-block"/> + <element name="priceColumn" type="text" selector=".order-invoice-tables .col-price .price"/> + <element name="qtyColumn" type="text" selector=".order-invoice-tables .col-qty .qty-table"/> + <element name="qtyToInvoiceColumn" type="input" selector=".order-invoice-tables .col-qty-invoice .qty-input"/> + <element name="subtotalColumn" type="text" selector=".order-invoice-tables .col-subtotal .price"/> + <element name="taxAmountColumn" type="text" selector=".order-invoice-tables .col-tax .price"/> + <element name="discountAmountColumn" type="text" selector=".order-invoice-tables .col-discount .price"/> + <element name="totalColumn" type="text" selector=".order-invoice-tables .col-total .price"/> + <element name="updateQty" type="button" selector=".order-invoice-tables tfoot button[data-ui-id='order-items-update-button']"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceMainActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceMainActionsSection.xml new file mode 100644 index 0000000000000..dff6a0d84cafc --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceMainActionsSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminInvoiceMainActionsSection"> + <element name="submitInvoice" type="button" selector=".action-default.scalable.save.submit-button.primary"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceOrderInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceOrderInformationSection.xml new file mode 100644 index 0000000000000..ad1d3052158a5 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceOrderInformationSection.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminInvoiceOrderInformationSection"> + <element name="orderId" type="text" selector="div.order-information span.title > a" timeout="30"/> + <element name="orderDate" type="text" selector=".order-information table.order-information-table tr:first-of-type > td"/> + <element name="orderStatus" type="text" selector=".order-information table.order-information-table #order_status"/> + <element name="purchasedFrom" type="text" selector=".order-information table.order-information-table tr:last-of-type > td"/> + <element name="customerName" type="text" selector=".order-account-information table tr:first-of-type > td span"/> + <element name="customerEmail" type="text" selector=".order-account-information table tr:nth-of-type(2) > td a"/> + <element name="customerGroup" type="text" selector=".order-account-information table tr:nth-of-type(3) > td"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoicePaymentShippingSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoicePaymentShippingSection.xml new file mode 100644 index 0000000000000..d3ca09c1811cb --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoicePaymentShippingSection.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminInvoicePaymentShippingSection"> + <element name="PaymentMethod" type="text" selector=".order-payment-method .order-payment-method-title"/> + <element name="CurrencyInformation" type="text" selector=".order-payment-method .order-payment-currency"/> + <element name="PaymentAdditional" type="text" selector=".order-payment-method .order-payment-additional"/> + <element name="ShippingMethod" type="text" selector=".order-shipping-address .shipping-description-title"/> + <element name="ShippingPrice" type="text" selector=".order-shipping-address .shipping-description-content .price"/> + <element name="CreateShipment" type="checkbox" selector=".order-shipping-address input[name='invoice[do_shipment]']"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceTotalSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceTotalSection.xml new file mode 100644 index 0000000000000..49b734320a7ea --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoiceTotalSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminInvoiceTotalSection"> + <element name="subtotalRow" type="text" selector=".order-subtotal-table tbody > tr:nth-of-type({{row}}) td span.price" parameterized="true"/> + <element name="total" type="text" selector="//table[contains(@class,'order-subtotal-table')]/tbody/tr/td[contains(text(), '{{total}}')]/following-sibling::td/span/span[contains(@class, 'price')]" parameterized="true"/> + <element name="grandTotal" type="text" selector=".order-subtotal-table tfoot tr.col-0>td span.price"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoicesFiltersSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoicesFiltersSection.xml new file mode 100644 index 0000000000000..1fad379d23176 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoicesFiltersSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminInvoicesFiltersSection"> + <element name="orderNum" type="input" selector="input[name='order_increment_id']"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoicesGridSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoicesGridSection.xml new file mode 100644 index 0000000000000..3b7bbd6fd14e4 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminInvoicesGridSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminInvoicesGridSection"> + <element name="spinner" type="button" selector=".spinner"/> + <element name="filter" type="button" selector="#container > div > div.admin__data-grid-header > div:nth-child(1) > div.data-grid-filters-actions-wrap > div > button"/> + <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderAddressInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderAddressInformationSection.xml new file mode 100644 index 0000000000000..90887c13f526c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderAddressInformationSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderAddressInformationSection"> + <element name="billingAddress" type="text" selector=".order-billing-address address"/> + <element name="shippingAddress" type="text" selector=".order-shipping-address address"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderCommentsTabSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderCommentsTabSection.xml new file mode 100644 index 0000000000000..18f10f5c8ba31 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderCommentsTabSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderCommentsTabSection"> + <element name="orderNotesList" type="text" selector="#Order_History .edit-order-comments .note-list"/> + <element name="orderComments" type="text" selector="#Order_History .edit-order-comments-block"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderCreditMemosTabSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderCreditMemosTabSection.xml new file mode 100644 index 0000000000000..98b34bda914a0 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderCreditMemosTabSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderCreditMemosTabSection"> + <element name="spinner" type="text" selector="[data-role='spinner'][data-component*='sales_order_view_creditmemo']"/> + <element name="gridRow" type="text" selector="#sales_order_view_tabs_order_creditmemos_content .data-grid tbody > tr:nth-of-type({{row}})" parameterized="true"/> + <element name="viewGridRow" type="button" selector="#sales_order_view_tabs_order_creditmemos_content .data-grid tbody > tr:nth-of-type({{row}}) a[href*='order_creditmemo/view']" parameterized="true"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsInformationSection.xml new file mode 100644 index 0000000000000..2ba11746694ad --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsInformationSection.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderDetailsInformationSection"> + <element name="orderDate" type="text" selector=".order-information table.order-information-table tr:first-of-type > td"/> + <element name="orderStatus" type="text" selector=".order-information table.order-information-table #order_status"/> + <element name="purchasedFrom" type="text" selector=".order-information table.order-information-table tr:last-of-type > td"/> + <element name="accountInformation" type="text" selector=".order-account-information-table"/> + <element name="customerName" type="text" selector=".order-account-information table tr:first-of-type > td span"/> + <element name="customerEmail" type="text" selector=".order-account-information table tr:nth-of-type(2) > td a"/> + <element name="customerGroup" type="text" selector=".order-account-information table tr:nth-of-type(3) > td"/> + <element name="billingAddress" type="text" selector=".order-billing-address"/> + <element name="shippingAddress" type="text" selector=".order-shipping-address"/> + <element name="itemsOrdered" type="text" selector=".edit-order-table"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsInvoicesSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsInvoicesSection.xml new file mode 100644 index 0000000000000..5831e07f41e6d --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsInvoicesSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderDetailsInvoicesSection"> + <element name="spinner" type="button" selector=".spinner"/> + <element name="content" type="text" selector="#sales_order_view_tabs_order_invoices_content"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsMainActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsMainActionsSection.xml new file mode 100644 index 0000000000000..4c08980bf7dde --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsMainActionsSection.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderDetailsMainActionsSection"> + <element name="back" type="button" selector="#back" timeout="30"/> + <element name="cancel" type="button" selector="#order-view-cancel-button" timeout="30"/> + <element name="sendEmail" type="button" selector="#send_notification" timeout="30"/> + <element name="creditMemo" type="button" selector="#order_creditmemo" timeout="30"/> + <element name="hold" type="button" selector="#order-view-hold-button" timeout="30"/> + <element name="invoice" type="button" selector="#order_invoice" timeout="30"/> + <element name="ship" type="button" selector="#order_ship" timeout="30"/> + <element name="reorder" type="button" selector="#order_reorder" timeout="30"/> + <element name="edit" type="button" selector="#order_edit" timeout="30"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsMessagesSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsMessagesSection.xml new file mode 100644 index 0000000000000..0311d5cf75c6d --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsMessagesSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderDetailsMessagesSection"> + <element name="successMessage" type="text" selector="div.message-success"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsOrderViewSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsOrderViewSection.xml new file mode 100644 index 0000000000000..1a83aa0eb6234 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderDetailsOrderViewSection.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderDetailsOrderViewSection"> + <element name="information" type="button" selector="#sales_order_view_tabs_order_info"/> + <element name="invoices" type="button" selector="#sales_order_view_tabs_order_invoices"/> + <element name="creditMemos" type="button" selector="#sales_order_view_tabs_order_creditmemos"/> + <element name="shipments" type="button" selector="#sales_order_view_tabs_order_shipments"/> + <element name="commentsHistory" type="button" selector="#sales_order_view_tabs_order_history"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormAccountSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormAccountSection.xml new file mode 100644 index 0000000000000..df3efc481a48f --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormAccountSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderFormAccountSection"> + <element name="group" type="select" selector="#group_id"/> + <element name="email" type="input" selector="#email"/> + <element name="requiredGroup" type="text" selector=".admin__field.required[data-ui-id='billing-address-fieldset-element-form-field-group-id']"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormActionSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormActionSection.xml new file mode 100644 index 0000000000000..302e0badb4543 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormActionSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderFormActionSection"> + <element name="SubmitOrder" type="button" selector="#submit_order_top_button" timeout="30"/> + <element name="Cancel" type="button" selector="#reset_order_top_button" timeout="30"/> + <element name="CreateNewCustomer" type="button" selector="#order-customer-selector .actions button.primary" timeout="30"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormBillingAddressSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormBillingAddressSection.xml new file mode 100644 index 0000000000000..f1000476d50fe --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormBillingAddressSection.xml @@ -0,0 +1,40 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderFormBillingAddressSection"> + <element name="NamePrefix" type="input" selector="#order-billing_address_prefix" timeout="30"/> + <element name="FirstName" type="input" selector="#order-billing_address_firstname" timeout="30"/> + <element name="MiddleName" type="input" selector="#order-billing_address_middlename" timeout="30"/> + <element name="LastName" type="input" selector="#order-billing_address_lastname" timeout="30"/> + <element name="NameSuffix" type="input" selector="#order-billing_address_suffix" timeout="30"/> + <element name="Company" type="input" selector="#order-billing_address_company" timeout="30"/> + <element name="StreetLine1" type="input" selector="#order-billing_address_street0" timeout="30"/> + <element name="StreetLine2" type="input" selector="#order-billing_address_street1" timeout="30"/> + <element name="City" type="input" selector="#order-billing_address_city" timeout="30"/> + <element name="Country" type="select" selector="#order-billing_address_country_id" timeout="30"/> + <element name="State" type="select" selector="#order-billing_address_region_id" timeout="30"/> + <element name="Province" type="input" selector="#order-billing_address_region" timeout="30"/> + <element name="PostalCode" type="input" selector="#order-billing_address_postcode" timeout="30"/> + <element name="Phone" type="input" selector="#order-billing_address_telephone" timeout="30"/> + <element name="Fax" type="input" selector="#order-billing_address_fax" timeout="30"/> + <element name="VatNumber" type="input" selector="#order-billing_address_vat_id" timeout="30"/> + <element name="ValidateVatNumber" type="button" selector="#order-billing_address_vat_id + .actions>button.action-default" timeout="30"/> + <element name="SaveAddress" type="checkbox" selector="#order-billing_address_save_in_address_book"/> + + <element name="firstNameError" type="text" selector="#order-billing_address_firstname-error"/> + <element name="lastNameError" type="text" selector="#order-billing_address_lastname-error"/> + <element name="streetAddressError" type="text" selector="#order-billing_address_street0-error"/> + <element name="cityError" type="text" selector="#order-billing_address_city-error"/> + <element name="countryError" type="text" selector="#order-billing_address_country_id-error"/> + <element name="stateError" type="text" selector="#order-billing_address_region_id-error"/> + <element name="postalCodeError" type="text" selector="#order-billing_address_postcode-error"/> + <element name="phoneError" type="text" selector="#order-billing_address_telephone-error"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormConfigureProductSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormConfigureProductSection.xml new file mode 100644 index 0000000000000..1d1ff664eb7a3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormConfigureProductSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderFormConfigureProductSection"> + <element name="optionSelect" type="select" selector="//div[@class='product-options']/div/div/select[../../label[text() = '{{option}}']]" parameterized="true"/> + <element name="quantity" type="input" selector="#product_composite_configure_input_qty"/> + <element name="ok" type="button" selector=".modal-header .page-actions button[data-role='action']" timeout="30"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormItemsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormItemsSection.xml new file mode 100644 index 0000000000000..c3486e1af5a1c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormItemsSection.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderFormItemsSection"> + <element name="skuNumber" type="input" selector="#sku_{{row}}" parameterized="true"/> + <element name="qty" type="input" selector="#sku_qty_{{row}}" parameterized="true"/> + <element name="addAnother" type="button" selector="#sku_container .col-actions > button.add"/> + <element name="deleteRow" type="button" selector="#sku_container tr:nth_of_type({{row}}) .col-actions button.action-delete" parameterized="true"/> + <element name="addToOrder" type="button" selector="#order-additional_area .admin__page-section-title .actions button.action-add"/> + <element name="addProducts" type="button" selector="//section[@id='order-items']/div/div/button/span[text() = 'Add Products']" timeout="30"/> + <element name="search" type="button" selector="#sales_order_create_search_grid [data-action='grid-filter-apply']" timeout="30"/> + <element name="resetFilter" type="button" selector="#sales_order_create_search_grid [data-action='grid-filter-reset']" timeout="30"/> + <element name="idFilter" type="input" selector="#sales_order_create_search_grid_filter_entity_id"/> + <element name="nameFilter" type="input" selector="#sales_order_create_search_grid_filter_name"/> + <element name="skuFilter" type="input" selector="#sales_order_create_search_grid_filter_sku"/> + <element name="priceFromFilter" type="input" selector="#sales_order_create_search_grid_filter_price_from"/> + <element name="priceToFilter" type="input" selector="#sales_order_create_search_grid_filter_price_to"/> + <element name="selectedFilter" type="select" selector="#sales_order_create_search_grid_filter_in_products"/> + <element name="row" type="text" selector="#sales_order_create_search_grid_table > tbody tr:nth-of-type({{row}})" parameterized="true"/> + <element name="rowCheck" type="checkbox" selector="#sales_order_create_search_grid_table > tbody tr:nth-of-type({{row}}) td.col-select [type=checkbox]" parameterized="true"/> + <element name="rowQty" type="input" selector="#sales_order_create_search_grid_table > tbody tr:nth-of-type({{row}}) td.col-qty [name='qty']" parameterized="true"/> + <element name="addSelected" type="button" selector="#order-search .admin__page-section-title .actions button.action-add" timeout="30"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormPaymentSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormPaymentSection.xml new file mode 100644 index 0000000000000..ff0d91a2b0d08 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormPaymentSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderFormPaymentSection"> + <element name="header" type="text" selector="#order-methods span.title"/> + <element name="getShippingMethods" type="text" selector="#order-shipping_method a.action-default" timeout="30"/> + <element name="flatRateOption" type="radio" selector="#s_method_flatrate_flatrate" timeout="30"/> + <element name="shippingError" type="text" selector="#order[has_shipping]-error"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormShippingAddressSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormShippingAddressSection.xml new file mode 100644 index 0000000000000..c7fc616eac6f1 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormShippingAddressSection.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderFormShippingAddressSection"> + <element name="SameAsBilling" type="checkbox" selector="#order-shipping_same_as_billing"/> + <element name="NamePrefix" type="input" selector="#order-shipping_address_prefix"/> + <element name="FirstName" type="input" selector="#order-shipping_address_firstname"/> + <element name="MiddleName" type="input" selector="#order-shipping_address_middlename"/> + <element name="LastName" type="input" selector="#order-shipping_address_lastname"/> + <element name="NameSuffix" type="input" selector="#order-shipping_address_suffix"/> + <element name="Company" type="input" selector="#order-shipping_address_company"/> + <element name="StreetLine1" type="input" selector="#order-shipping_address_street0"/> + <element name="StreetLine2" type="input" selector="#order-shipping_address_street1"/> + <element name="City" type="input" selector="#order-shipping_address_city"/> + <element name="Country" type="select" selector="#order-shipping_address_country_id"/> + <element name="State" type="select" selector="#order-shipping_address_region_id"/> + <element name="Province" type="input" selector="#order-shipping_address_region"/> + <element name="PostalCode" type="input" selector="#order-shipping_address_postcode"/> + <element name="Phone" type="input" selector="#order-shipping_address_telephone"/> + <element name="Fax" type="input" selector="#order-shipping_address_fax"/> + <element name="VatNumber" type="input" selector="#order-shipping_address_vat_id"/> + <element name="ValidateVatNumber" type="button" selector="#order-shipping_address_vat_id + .actions>button.action-default"/> + <element name="SaveAddress" type="checkbox" selector="#order-shipping_address_save_in_address_book"/> + + <element name="firstNameError" type="text" selector="#order-shipping_address_firstname-error"/> + <element name="lastNameError" type="text" selector="#order-shipping_address_lastname-error"/> + <element name="streetAddressError" type="text" selector="#order-shipping_address_street0-error"/> + <element name="cityError" type="text" selector="#order-shipping_address_city-error"/> + <element name="countryError" type="text" selector="#order-shipping_address_country_id-error"/> + <element name="stateError" type="text" selector="#order-shipping_address_region_id-error"/> + <element name="postalCodeError" type="text" selector="#order-shipping_address_postcode-error"/> + <element name="phoneError" type="text" selector="#order-shipping_address_telephone-error"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormTotalSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormTotalSection.xml new file mode 100644 index 0000000000000..d558ecb3dfb92 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderFormTotalSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderFormTotalSection"> + <element name="subtotalRow" type="text" selector="#order-totals>table tr.row-totals:nth-of-type({{row}}) span.price" parameterized="true"/> + <element name="total" type="text" selector="//tr[contains(@class,'row-totals')]/td[contains(text(), '{{total}}')]/following-sibling::td/span[contains(@class, 'price')]" parameterized="true"/> + <element name="grandTotal" type="text" selector="#order-totals>table tr.row-totals:nth-of-type(3) span.price"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderInvoicesTabSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderInvoicesTabSection.xml new file mode 100644 index 0000000000000..985c070933b48 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderInvoicesTabSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderInvoicesTabSection"> + <element name="spinner" type="text" selector="[data-role='spinner'][data-component*='sales_order_view_invoice']"/> + <element name="gridRow" type="text" selector="#sales_order_view_tabs_order_invoices_content .data-grid tbody > tr:nth-of-type({{row}})" parameterized="true"/> + <element name="viewGridRow" type="button" selector="#sales_order_view_tabs_order_invoices_content .data-grid tbody > tr:nth-of-type({{row}}) a[href*='order_invoice/view']" parameterized="true"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderItemsOrderedSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderItemsOrderedSection.xml new file mode 100644 index 0000000000000..5f7c9ea73e04d --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderItemsOrderedSection.xml @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderItemsOrderedSection"> + <element name="itemProductName" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-product .product-title" parameterized="true"/> + <element name="itemProductSku" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-product .product-sku-block" parameterized="true"/> + <element name="itemStatus" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-status" parameterized="true"/> + <element name="itemOriginalPrice" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-original-price .price" parameterized="true"/> + <element name="itemPrice" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-price .price" parameterized="true"/> + <element name="itemQty" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-ordered-qty .qty-table" parameterized="true"/> + <element name="itemSubtotal" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-subtotal .price" parameterized="true"/> + <element name="itemTaxAmount" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-tax-amount .price" parameterized="true"/> + <element name="itemTaxPercent" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-tax-percent" parameterized="true"/> + <element name="itemDiscountAmount" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-discont .price" parameterized="true"/> + <element name="itemTotal" type="text" selector=".edit-order-table tr:nth-of-type({{row}}) .col-total .price" parameterized="true"/> + + <element name="productNameColumn" type="text" selector=".edit-order-table .col-product .product-title"/> + <element name="productSkuColumn" type="text" selector=".edit-order-table .col-product .product-sku-block"/> + <element name="statusColumn" type="text" selector=".edit-order-table .col-status"/> + <element name="originalPriceColumn" type="text" selector=".edit-order-table .col-original-price .price"/> + <element name="priceColumn" type="text" selector=".edit-order-table .col-price .price"/> + <element name="qtyColumn" type="text" selector=".edit-order-table .col-ordered-qty .qty-table"/> + <element name="subtotalColumn" type="text" selector=".edit-order-table .col-subtotal .price"/> + <element name="taxAmountColumn" type="text" selector=".edit-order-table .col-tax-amount .price"/> + <element name="taxPercentColumn" type="text" selector=".edit-order-table .col-tax-percent"/> + <element name="discountAmountColumn" type="text" selector=".edit-order-table .col-discont .price"/> + <element name="totalColumn" type="text" selector=".edit-order-table .col-total .price"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderPaymentInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderPaymentInformationSection.xml new file mode 100644 index 0000000000000..a750f2fa062d7 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderPaymentInformationSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderPaymentInformationSection"> + <element name="paymentMethod" type="text" selector=".order-payment-method .order-payment-method-title"/> + <element name="paymentCurrency" type="text" selector=".order-payment-method .order-payment-currency"/> + <element name="paymentAdditional" type="text" selector=".order-payment-method .order-payment-additional"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderShipmentsTabSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderShipmentsTabSection.xml new file mode 100644 index 0000000000000..9ed9d852b4bea --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderShipmentsTabSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderShipmentsTabSection"> + <element name="spinner" type="text" selector="[data-role='spinner'][data-component*='sales_order_view_shipment']"/> + <element name="gridRow" type="text" selector="#sales_order_view_tabs_order_shipments_content .data-grid tbody > tr:nth-of-type({{row}})" parameterized="true"/> + <element name="viewGridRow" type="button" selector="#sales_order_view_tabs_order_shipments_content .data-grid tbody > tr:nth-of-type({{row}}) a[href*='order_shipment/view']" parameterized="true"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderShippingInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderShippingInformationSection.xml new file mode 100644 index 0000000000000..0c1bd47595931 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderShippingInformationSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderShippingInformationSection"> + <element name="shippingMethod" type="text" selector=".order-shipping-method .admin__page-section-item-content"/> + <element name="shippingPrice" type="text" selector=".order-shipping-method .admin__page-section-item-content .price"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderStoreScopeTreeSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderStoreScopeTreeSection.xml new file mode 100644 index 0000000000000..31617e2ff9dde --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrderStoreScopeTreeSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrderStoreScopeTreeSection"> + <element name="storeTree" type="text" selector="div.tree-store-scope"/> + <element name="storeOption" type="radio" selector="//div[contains(@class, 'tree-store-scope')]//label[contains(text(), '{{name}}')]/preceding-sibling::input" parameterized="true" timeout="30"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrdersGridSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrdersGridSection.xml new file mode 100644 index 0000000000000..ccf477b1e523c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/AdminOrdersGridSection.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminOrdersGridSection"> + <element name="spinner" type="button" selector=".spinner"/> + <element name="gridLoadingMask" type="button" selector=".admin__data-grid-loading-mask"/> + <element name="search" type="input" selector="#fulltext"/> + <element name="submitSearch" type="button" selector=".//*[@id='container']/div/div[2]/div[1]/div[2]/button"/> + <element name="submitSearch22" type="button" selector=".//*[@class="admin__data-grid-filters-wrap"]/parent::*/div[@class="data-grid-search-control-wrap"]/button"/> + <element name="filters" type="button" selector="button[data-action='grid-filter-expand']" timeout="30"/> + <element name="idFilter" type="input" selector=".admin__data-grid-filters input[name='increment_id']"/> + <element name="billToNameFilter" type="input" selector=".admin__data-grid-filters input[name='billing_name']"/> + <element name="clearFilters" type="button" selector=".admin__data-grid-header [data-action='grid-filter-reset']" timeout="30"/> + <element name="applyFilters" type="button" selector="button[data-action='grid-filter-apply']" timeout="30"/> + <element name="rowViewAction" type="button" selector=".data-grid tbody > tr:nth-of-type({{row}}) .action-menu-item" parameterized="true" timeout="30"/> + <element name="createNewOrder" type="button" selector=".page-actions-buttons button#add" timeout="30"/> + <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)"/> + <element name="columnHeader" type="button" selector="//div[@data-role='grid-wrapper']//table[contains(@class, 'data-grid')]/thead/tr/th[contains(@class, 'data-grid-th')]/span[text() = '{{label}}']" parameterized="true" timeout="30"/> + <element name="gridCell" type="text" selector="//tr[{{row}}]//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{column}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> + <element name="viewBookmarkDropdown" type="button" selector="div.admin__data-grid-action-bookmarks button" timeout="30"/> + <element name="viewBookmark" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/> + <element name="columnsDropdown" type="button" selector="div.admin__data-grid-action-columns button" timeout="30"/> + <element name="viewColumnCheckbox" type="checkbox" selector="//div[contains(@class,'admin__data-grid-action-columns')]//div[contains(@class, 'admin__field-option')]//label[text() = '{{column}}']/preceding-sibling::input" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoiceDetailsInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoiceDetailsInformationSection.xml deleted file mode 100644 index b8a7f6bd1ecdd..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoiceDetailsInformationSection.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="InvoiceDetailsInformationSection"> - <element name="orderStatus" type="text" selector="#order_status"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoiceNewSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoiceNewSection.xml deleted file mode 100644 index 6dbcdbe2810cb..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoiceNewSection.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="InvoiceNewSection"> - <element name="submitInvoice" type="button" selector=".action-default.scalable.save.submit-button.primary"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoicesFiltersSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoicesFiltersSection.xml deleted file mode 100644 index 774dbda9bb5e9..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoicesFiltersSection.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="InvoicesFiltersSection"> - <element name="orderNum" type="input" selector="input[name='order_increment_id']"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoicesGridSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoicesGridSection.xml deleted file mode 100644 index 6f2bcc3638780..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/InvoicesGridSection.xml +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="InvoicesGridSection"> - <element name="spinner" type="button" selector=".spinner"/> - <element name="filter" type="button" selector="#container > div > div.admin__data-grid-header > div:nth-child(1) > div.data-grid-filters-actions-wrap > div > button"/> - <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsInformationSection.xml deleted file mode 100644 index 1f5f678e239ab..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsInformationSection.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="OrderDetailsInformationSection"> - <element name="orderStatus" type="text" selector="#order_status"/> - <element name="accountInformation" type="text" selector=".order-account-information-table"/> - <element name="billingAddress" type="text" selector=".order-billing-address"/> - <element name="shippingAddress" type="text" selector=".order-shipping-address"/> - <element name="itemsOrdered" type="text" selector=".edit-order-table"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsInvoicesSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsInvoicesSection.xml deleted file mode 100644 index c7b4a64f96cb7..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsInvoicesSection.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="OrderDetailsInvoicesSection"> - <element name="spinner" type="button" selector=".spinner"/> - <element name="content" type="text" selector="#sales_order_view_tabs_order_invoices_content"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsMainActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsMainActionsSection.xml deleted file mode 100644 index 61ed91d366217..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsMainActionsSection.xml +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="OrderDetailsMainActionsSection"> - <element name="back" type="button" selector="#back"/> - <element name="cancel" type="button" selector="#order-view-cancel-button"/> - <element name="sendEmail" type="button" selector="#send_notification"/> - <element name="hold" type="button" selector="#order-view-hold-button"/> - <element name="invoice" type="button" selector="#order_invoice"/> - <element name="ship" type="button" selector="#order_ship"/> - <element name="reorder" type="button" selector="#order_reorder"/> - <element name="edit" type="button" selector="#order_edit"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsMessagesSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsMessagesSection.xml deleted file mode 100644 index 399a4e438601c..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsMessagesSection.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="OrderDetailsMessagesSection"> - <element name="successMessage" type="text" selector="div.message-success"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsOrderViewSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsOrderViewSection.xml deleted file mode 100644 index e79434e1b0802..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrderDetailsOrderViewSection.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> - <section name="OrderDetailsOrderViewSection"> - <element name="information" type="button" selector="#sales_order_view_tabs_order_info"/> - <element name="invoices" type="button" selector="#sales_order_view_tabs_order_invoices"/> - </section> -</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrdersGridSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrdersGridSection.xml index c926e4044d7e8..763f1e20a8d0e 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrdersGridSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Section/OrdersGridSection.xml @@ -14,7 +14,7 @@ <element name="search" type="input" selector="#fulltext"/> <element name="submitSearch" type="button" selector=".//*[@id='container']/div/div[2]/div[1]/div[2]/button"/> <element name="submitSearch22" type="button" selector=".//*[@class="admin__data-grid-filters-wrap"]/parent::*/div[@class="data-grid-search-control-wrap"]/button"/> - <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)"/> + <element name="firstRow" type="button" selector="//*[@id='container']//tr[@class='data-row']//a[@class='action-menu-item']"/> <element name="createNewOrder" type="button" selector="button[title='Create New Order'"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminCreateInvoiceCest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminCreateInvoiceCest.xml deleted file mode 100644 index fca6318429188..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminCreateInvoiceCest.xml +++ /dev/null @@ -1,85 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> - <test name="AdminCreateInvoiceTest"> - <annotations> - <features value="Invoice Creation"/> - <stories value="Create an Invoice via the Admin"/> - <title value="Create Invoice"/> - <description value="Should be able to create an invoice via the admin."/> - <severity value="NORMAL"/> - <testCaseId value="MAGETWO-72096"/> - <group value="sales"/> - </annotations> - <before> - <createData entity="_defaultCategory" stepKey="createCategory"/> - <createData entity="_defaultProduct" stepKey="createProduct"> - <requiredEntity createDataKey="createCategory"/> - </createData> - </before> - <after> - <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> - <deleteData createDataKey="createCategory" stepKey="deleteProduct1"/> - <deleteData createDataKey="createProduct" stepKey="deleteCategory1"/> - </after> - - <!-- todo: Create an order via the api instead of driving the browser --> - <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> - <waitForPageLoad stepKey="waitForPageLoad1"/> - <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> - <click selector="{{StorefrontCategoryMainSection.AddToCartBtn}}" stepKey="addToCart"/> - <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> - <click selector="{{StorefrontMiniCartSection.show}}" stepKey="clickCart"/> - <click selector="{{StorefrontMiniCartSection.goToCheckout}}" stepKey="goToCheckout"/> - <waitForPageLoad stepKey="waitForPageLoad2"/> - <fillField selector="{{CheckoutShippingGuestInfoSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="enterEmail"/> - <fillField selector="{{CheckoutShippingGuestInfoSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="enterFirstName"/> - <fillField selector="{{CheckoutShippingGuestInfoSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="enterLastName"/> - <fillField selector="{{CheckoutShippingGuestInfoSection.street}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="enterStreet"/> - <fillField selector="{{CheckoutShippingGuestInfoSection.city}}" userInput="{{CustomerAddressSimple.city}}" stepKey="enterCity"/> - <selectOption selector="{{CheckoutShippingGuestInfoSection.region}}" userInput="{{CustomerAddressSimple.state}}" stepKey="selectRegion"/> - <fillField selector="{{CheckoutShippingGuestInfoSection.postcode}}" userInput="{{CustomerAddressSimple.postcode}}" stepKey="enterPostcode"/> - <fillField selector="{{CheckoutShippingGuestInfoSection.telephone}}" userInput="{{CustomerAddressSimple.telephone}}" stepKey="enterTelephone"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> - <click selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask2"/> - <waitForElement selector="{{CheckoutShippingMethodsSection.next}}" time="30" stepKey="waitForNextButton"/> - <click selector="{{CheckoutShippingMethodsSection.next}}" stepKey="clickNext"/> - <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> - <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> - <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> - <!-- end todo --> - - <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> - - <amOnPage url="{{OrdersPage.url}}" stepKey="onOrdersPage"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask3"/> - <fillField selector="{{OrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="searchOrderNum"/> - <click selector="{{OrdersGridSection.submitSearch}}" stepKey="submitSearch"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask4"/> - - <click selector="{{OrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> - <click selector="{{OrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoice"/> - <click selector="{{InvoiceNewSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> - <see selector="{{OrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeSuccessMessage"/> - <click selector="{{OrderDetailsOrderViewSection.invoices}}" stepKey="clickInvoices"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask5" /> - <see selector="{{OrderDetailsInvoicesSection.content}}" userInput="{$grabOrderNumber}" stepKey="seeInvoice1"/> - <see selector="{{OrderDetailsInvoicesSection.content}}" userInput="John Doe" stepKey="seeInvoice2"/> - <click selector="{{OrderDetailsOrderViewSection.information}}" stepKey="clickInformation"/> - <see selector="{{OrderDetailsInformationSection.orderStatus}}" userInput="Processing" stepKey="seeOrderStatus"/> - <amOnPage url="{{InvoicesPage.url}}" stepKey="goToInvoices"/> - <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask6" /> - <click selector="{{InvoicesGridSection.filter}}" stepKey="clickFilters"/> - <fillField selector="{{InvoicesFiltersSection.orderNum}}" userInput="{$grabOrderNumber}" stepKey="searchOrderNum2"/> - <click selector="{{InvoicesGridSection.firstRow}}" stepKey="clickInvoice2"/> - <see selector="{{InvoiceDetailsInformationSection.orderStatus}}" userInput="Processing" stepKey="seeOrderStatus2"/> - </test> -</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminCreateInvoiceTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminCreateInvoiceTest.xml new file mode 100644 index 0000000000000..2e7af33aa25c4 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/AdminCreateInvoiceTest.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="AdminCreateInvoiceTest"> + <annotations> + <features value="Invoice Creation"/> + <stories value="Create an Invoice via the Admin"/> + <title value="Create Invoice"/> + <description value="Should be able to create an invoice via the admin."/> + <severity value="MAJOR"/> + <testCaseId value="MAGETWO-72096"/> + <group value="sales"/> + </annotations> + <before> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createProduct"> + <requiredEntity createDataKey="createCategory"/> + </createData> + </before> + <after> + <amOnPage url="admin/admin/auth/logout/" stepKey="amOnLogoutPage"/> + <deleteData createDataKey="createCategory" stepKey="deleteProduct1"/> + <deleteData createDataKey="createProduct" stepKey="deleteCategory1"/> + </after> + + <!-- todo: Create an order via the api instead of driving the browser --> + <amOnPage url="{{StorefrontCategoryPage.url($$createCategory.name$$)}}" stepKey="onCategoryPage"/> + <waitForPageLoad stepKey="waitForPageLoad1"/> + <moveMouseOver selector="{{StorefrontCategoryMainSection.ProductItemInfo}}" stepKey="hoverProduct"/> + <click selector="{{StorefrontCategoryMainSection.AddToCartBtn}}" stepKey="addToCart"/> + <waitForElementVisible selector="{{StorefrontCategoryMainSection.SuccessMsg}}" time="30" stepKey="waitForProductAdded"/> + <click selector="{{StorefrontMinicartSection.showCart}}" stepKey="clickCart"/> + <click selector="{{StorefrontMinicartSection.goToCheckout}}" stepKey="goToCheckout"/> + <waitForPageLoad stepKey="waitForPageLoad2"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.email}}" userInput="{{CustomerEntityOne.email}}" stepKey="enterEmail"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.firstName}}" userInput="{{CustomerEntityOne.firstname}}" stepKey="enterFirstName"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.lastName}}" userInput="{{CustomerEntityOne.lastname}}" stepKey="enterLastName"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.street}}" userInput="{{CustomerAddressSimple.street[0]}}" stepKey="enterStreet"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.city}}" userInput="{{CustomerAddressSimple.city}}" stepKey="enterCity"/> + <selectOption selector="{{CheckoutShippingGuestInfoSection.region}}" userInput="{{CustomerAddressSimple.state}}" stepKey="selectRegion"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.postcode}}" userInput="{{CustomerAddressSimple.postcode}}" stepKey="enterPostcode"/> + <fillField selector="{{CheckoutShippingGuestInfoSection.telephone}}" userInput="{{CustomerAddressSimple.telephone}}" stepKey="enterTelephone"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask"/> + <click selector="{{CheckoutShippingMethodsSection.firstShippingMethod}}" stepKey="selectFirstShippingMethod"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask2"/> + <waitForElement selector="{{CheckoutShippingMethodsSection.next}}" time="30" stepKey="waitForNextButton"/> + <click selector="{{CheckoutShippingMethodsSection.next}}" stepKey="clickNext"/> + <waitForElement selector="{{CheckoutPaymentSection.placeOrder}}" time="30" stepKey="waitForPlaceOrderButton"/> + <click selector="{{CheckoutPaymentSection.placeOrder}}" stepKey="clickPlaceOrder"/> + <grabTextFrom selector="{{CheckoutSuccessMainSection.orderNumber}}" stepKey="grabOrderNumber"/> + <!-- end todo --> + + <actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin1"/> + + <amOnPage url="{{AdminOrdersPage.url}}" stepKey="onOrdersPage"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask3"/> + <fillField selector="{{AdminOrdersGridSection.search}}" userInput="{$grabOrderNumber}" stepKey="searchOrderNum"/> + <click selector="{{AdminOrdersGridSection.submitSearch}}" stepKey="submitSearch"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask4"/> + + <click selector="{{AdminOrdersGridSection.firstRow}}" stepKey="clickOrderRow"/> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoice"/> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeSuccessMessage"/> + <click selector="{{AdminOrderDetailsOrderViewSection.invoices}}" stepKey="clickInvoices"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask5" /> + <see selector="{{AdminOrderDetailsInvoicesSection.content}}" userInput="{$grabOrderNumber}" stepKey="seeInvoice1"/> + <see selector="{{AdminOrderDetailsInvoicesSection.content}}" userInput="John Doe" stepKey="seeInvoice2"/> + <click selector="{{AdminOrderDetailsOrderViewSection.information}}" stepKey="clickInformation"/> + <waitForLoadingMaskToDisappear stepKey="waitForOrderInformationTabLoadingMask"/> + <see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Processing" stepKey="seeOrderStatus"/> + <amOnPage url="{{AdminInvoicesPage.url}}" stepKey="goToInvoices"/> + <waitForLoadingMaskToDisappear stepKey="waitForLoadingMask6" /> + <click selector="{{AdminInvoicesGridSection.filter}}" stepKey="clickFilters"/> + <fillField selector="{{AdminInvoicesFiltersSection.orderNum}}" userInput="{$grabOrderNumber}" stepKey="searchOrderNum2"/> + <click selector="{{AdminInvoicesGridSection.firstRow}}" stepKey="clickInvoice2"/> + <see selector="{{AdminInvoiceDetailsInformationSection.orderStatus}}" userInput="Processing" stepKey="seeOrderStatus2"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/EndToEndB2CAdminTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/EndToEndB2CAdminTest.xml new file mode 100644 index 0000000000000..4aa8e12ece827 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/Test/EndToEndB2CAdminTest.xml @@ -0,0 +1,281 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CAdminTest"> + <before> + <!--Create order via API--> + <createData entity="_defaultCategory" stepKey="createCategory"/> + <createData entity="_defaultProduct" stepKey="createSimpleProductApi"> + <requiredEntity createDataKey="createCategory"/> + </createData> + <createData entity="GuestCart" stepKey="createGuestCart"/> + <createData entity="SimpleCartItem" stepKey="addCartItem"> + <requiredEntity createDataKey="createGuestCart"/> + <requiredEntity createDataKey="createSimpleProductApi"/> + </createData> + <createData entity="GuestAddressInformation" stepKey="addGuestOrderAddress"> + <requiredEntity createDataKey="createGuestCart"/> + </createData> + <updateData createDataKey="createGuestCart" entity="GuestOrderPaymentMethod" stepKey="sendGuestPaymentInformation"> + <requiredEntity createDataKey="createGuestCart"/> + </updateData> + <!--END Create order via API--> + </before> + + <!--Prerequisites--> + <!--Create store view to ensure multiple store views--> + <comment userInput="Create prerequisite store view" stepKey="createStoreViewComment" before="createStoreView"/> + <actionGroup ref="AdminCreateStoreViewActionGroup" stepKey="createStoreView" before="navigateToNewOrderPage"/> + + <!--Admin creates order--> + <comment userInput="Admin creates order" stepKey="adminCreateOrderComment" before="navigateToNewOrderPage"/> + <actionGroup ref="navigateToNewOrderPageNewCustomer" stepKey="navigateToNewOrderPage" after="deleteCategory"/> + + <actionGroup ref="checkRequiredFieldsNewOrderForm" stepKey="checkRequiredFieldsNewOrder" after="navigateToNewOrderPage"/> + <scrollToTopOfPage stepKey="scrollToTopOfOrderFormPage" after="checkRequiredFieldsNewOrder"/> + <actionGroup ref="addSimpleProductToOrder" stepKey="addSimpleProductToOrder" after="scrollToTopOfOrderFormPage"> + <argument name="product" value="SimpleProduct"/> + </actionGroup> + <actionGroup ref="addConfigurableProductToOrder" stepKey="addConfigurableProductToOrder" after="addSimpleProductToOrder"> + <argument name="product" value="BaseConfigurableProduct"/> + <argument name="attribute" value="colorProductAttribute"/> + <argument name="option" value="colorProductAttribute1"/> + </actionGroup> + + <!--Fill customer group information--> + <selectOption selector="{{AdminOrderFormAccountSection.group}}" userInput="{{GeneralCustomerGroup.code}}" stepKey="selectGroup" after="addConfigurableProductToOrder"/> + <fillField selector="{{AdminOrderFormAccountSection.email}}" userInput="{{Simple_US_Customer.email}}" stepKey="fillEmail" after="selectGroup"/> + + <!--Fill customer address information--> + <actionGroup ref="fillOrderCustomerInformation" stepKey="fillCustomerAddress" after="fillEmail"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="address" value="US_Address_TX"/> + </actionGroup> + + <actionGroup ref="orderSelectFlatRateShipping" stepKey="selectFlatRateShipping" after="fillCustomerAddress"/> + + <!--Verify totals on Order page--> + <see selector="{{AdminOrderFormTotalSection.total('Subtotal')}}" userInput="${{AdminOrderSimpleConfigurableProduct.subtotal}}" stepKey="seeOrderSubTotal" after="selectFlatRateShipping"/> + <see selector="{{AdminOrderFormTotalSection.total('Shipping')}}" userInput="${{AdminOrderSimpleConfigurableProduct.shipping}}" stepKey="seeOrderShipping" after="seeOrderSubTotal"/> + <see selector="{{AdminOrderFormTotalSection.grandTotal}}" userInput="${{AdminOrderSimpleConfigurableProduct.grandTotal}}" stepKey="seeCorrectGrandTotal" after="seeOrderShipping"/> + + <!--Submit Order and verify information--> + <click selector="{{AdminOrderFormActionSection.SubmitOrder}}" stepKey="clickSubmitOrder" after="seeCorrectGrandTotal"/> + <seeInCurrentUrl url="{{AdminOrderDetailsPage}}" stepKey="seeViewOrderPage" after="clickSubmitOrder"/> + + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the order." stepKey="seeSuccessMessage" after="seeViewOrderPage"/> + <see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Pending" stepKey="seeOrderPendingStatus" after="seeSuccessMessage"/> + <grabTextFrom selector="|Order # (\d+)|" stepKey="getOrderId" after="seeOrderPendingStatus"/> + <assertNotEmpty actual="$getOrderId" stepKey="assertOrderIdIsNotEmpty" after="getOrderId"/> + <actionGroup ref="verifyBasicOrderInformation" stepKey="verifyOrderInformation" after="assertOrderIdIsNotEmpty"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="shippingAddress" value="US_Address_TX"/> + <argument name="billingAddress" value="US_Address_TX"/> + </actionGroup> + <actionGroup ref="seeProductInItemsOrdered" stepKey="seeSimpleProductInItemsOrdered" after="verifyOrderInformation"> + <argument name="product" value="SimpleProduct"/> + </actionGroup> + <actionGroup ref="seeProductInItemsOrdered" stepKey="seeConfigurableProductInItemsOrdered" after="seeSimpleProductInItemsOrdered"> + <argument name="product" value="BaseConfigurableProduct"/> + </actionGroup> + + <!--Create order invoice--> + <comment userInput="Admin creates invoice for order" stepKey="adminCreateInvoiceComment" before="closeAdminNotificationInvoice"/> + <closeAdminNotification stepKey="closeAdminNotificationInvoice" after="seeConfigurableProductInItemsOrdered"/> + <click selector="{{AdminOrderDetailsMainActionsSection.invoice}}" stepKey="clickInvoiceAction" after="closeAdminNotificationInvoice"/> + <seeInCurrentUrl url="{{AdminInvoiceNewPage}}" stepKey="seeOrderInvoiceUrl" after="clickInvoiceAction"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Invoice" stepKey="seePageNameNewInvoicePage" after="seeOrderInvoiceUrl"/> + + <!--Check Invoice Data--> + <see selector="{{AdminInvoiceOrderInformationSection.orderStatus}}" userInput="Pending" stepKey="seeOrderPendingInvoice" after="seePageNameNewInvoicePage"/> + <actionGroup ref="verifyBasicInvoiceInformation" stepKey="verifyOrderInvoiceInformation" after="seeOrderPendingInvoice"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="shippingAddress" value="US_Address_TX"/> + <argument name="billingAddress" value="US_Address_TX"/> + </actionGroup> + <see selector="{{AdminInvoicePaymentShippingSection.ShippingMethod}}" userInput="{{DefaultFlatRateMethod.title}}" stepKey="seeShippingMethod" after="verifyOrderInvoiceInformation"/> + <see selector="{{AdminInvoicePaymentShippingSection.ShippingPrice}}" userInput="${{AdminOrderSimpleConfigurableProduct.shipping}}" stepKey="seeShippingCost" after="seeShippingMethod"/> + <!--Submit Invoice--> + <click selector="{{AdminInvoiceMainActionsSection.submitInvoice}}" stepKey="clickSubmitInvoice" after="seeShippingCost"/> + <!--Invoice created successfully--> + <seeInCurrentUrl url="{{AdminOrderDetailsPage}}" stepKey="seeViewOrderPageInvoice" after="clickSubmitInvoice"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The invoice has been created." stepKey="seeInvoiceCreateSuccess" after="seeViewOrderPageInvoice"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="$getOrderId" stepKey="seePageNameMatchesOrderIdAfterInvoice" after="seeInvoiceCreateSuccess"/> + + <click selector="{{AdminOrderDetailsOrderViewSection.invoices}}" stepKey="clickOrderInvoicesTab" after="seePageNameMatchesOrderIdAfterInvoice"/> + <waitForLoadingMaskToDisappear stepKey="waitForInvoiceGridLoadingMask" after="clickOrderInvoicesTab"/> + <see selector="{{AdminOrderInvoicesTabSection.gridRow('1')}}" userInput="{{Simple_US_Customer.firstname}}" stepKey="seeOrderInvoiceInTabGrid" after="waitForInvoiceGridLoadingMask"/> + <click selector="{{AdminOrderInvoicesTabSection.viewGridRow('1')}}" stepKey="clickToViewInvoiceRow" after="seeOrderInvoiceInTabGrid"/> + <see selector="{{AdminInvoiceOrderInformationSection.orderId}}" userInput="$getOrderId" stepKey="seeOrderIdOnInvoice" after="clickToViewInvoiceRow"/> + <actionGroup ref="verifyBasicInvoiceInformation" stepKey="verifyBasicInvoiceInformation" after="seeOrderIdOnInvoice"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="shippingAddress" value="US_Address_TX"/> + <argument name="billingAddress" value="US_Address_TX"/> + </actionGroup> + <actionGroup ref="seeProductInInvoiceItems" stepKey="seeSimpleProductInInvoice" after="verifyBasicInvoiceInformation"> + <argument name="product" value="SimpleProduct"/> + </actionGroup> + <actionGroup ref="seeProductInInvoiceItems" stepKey="seeConfigurableProductInInvoice" after="seeSimpleProductInInvoice"> + <argument name="product" value="BaseConfigurableProduct"/> + </actionGroup> + <click selector="{{AdminInvoiceOrderInformationSection.orderId}}" stepKey="clickOrderIdLinkOnInvoice" after="seeConfigurableProductInInvoice"/> + + <!--Create Credit Memo--> + <comment userInput="Admin creates credit memo" stepKey="createCreditMemoComment" after="clickOrderIdOnShipment"/> + <click selector="{{AdminOrderDetailsMainActionsSection.creditMemo}}" stepKey="clickCreateCreditMemo" after="createCreditMemoComment"/> + <seeInCurrentUrl url="{{AdminCreditMemoNewPage}}" stepKey="seeNewCreditMemoPage" after="clickCreateCreditMemo"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="New Memo" stepKey="seeNewMemoInPageTitle" after="seeNewCreditMemoPage"/> + <!--Check Credit Memo Order Data--> + <actionGroup ref="verifyBasicCreditMemoInformation" stepKey="verifyOrderCreditMemoInformation" after="seeNewMemoInPageTitle"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="shippingAddress" value="US_Address_TX"/> + <argument name="billingAddress" value="US_Address_TX"/> + </actionGroup> + <!--Submit credit memo--> + <click selector="{{AdminCreditMemoTotalSection.submitRefundOffline}}" stepKey="clickRefundOffline" after="verifyOrderCreditMemoInformation"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="You created the credit memo." stepKey="seeCreditMemoSuccess" after="clickRefundOffline"/> + <click selector="{{AdminOrderDetailsOrderViewSection.creditMemos}}" stepKey="clickOrderCreditMemosTab" after="seeCreditMemoSuccess"/> + <waitForLoadingMaskToDisappear stepKey="waitForCreditMemoTabLoadingMask" after="clickOrderCreditMemosTab"/> + <see selector="{{AdminOrderCreditMemosTabSection.gridRow('1')}}" userInput="{{Simple_US_Customer.firstname}}" stepKey="seeOrderCreditMemoInTabGrid" after="waitForCreditMemoTabLoadingMask"/> + <click selector="{{AdminOrderCreditMemosTabSection.viewGridRow('1')}}" stepKey="clickToViewCreditMemoRow" after="seeOrderCreditMemoInTabGrid"/> + <waitForPageLoad stepKey="waitForCreditMemoPageLoad" after="clickToViewCreditMemoRow"/> + <see selector="{{AdminCreditMemoOrderInformationSection.orderId}}" userInput="$getOrderId" stepKey="seeOrderIdOnCreditMemo" after="waitForCreditMemoPageLoad"/> + <actionGroup ref="verifyBasicCreditMemoInformation" stepKey="verifyBasicCreditMemoInformation" after="seeOrderIdOnCreditMemo"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="shippingAddress" value="US_Address_TX"/> + <argument name="billingAddress" value="US_Address_TX"/> + </actionGroup> + <actionGroup ref="seeProductInItemsRefunded" stepKey="seeSimpleProductInItemsRefunded" after="verifyBasicCreditMemoInformation"> + <argument name="product" value="SimpleProduct"/> + </actionGroup> + <actionGroup ref="seeProductInItemsRefunded" stepKey="seeConfigurableProductInItemsRefunded" after="seeSimpleProductInItemsRefunded"> + <argument name="product" value="BaseConfigurableProduct"/> + </actionGroup> + <scrollToTopOfPage stepKey="scrollToTopOfCreditMemo" after="seeConfigurableProductInItemsRefunded"/> + <click selector="{{AdminCreditMemoOrderInformationSection.orderId}}" stepKey="clickOrderIdLinkOnCreditMemo" after="scrollToTopOfCreditMemo"/> + + <!--Admin uses order grid--> + <comment userInput="Admin uses order grid" stepKey="adminUseOrderGridComment" before="navigateToOrderGridPage"/> + <amOnPage url="{{AdminOrdersPage}}" stepKey="navigateToOrderGridPage" after="clickOrderIdLinkOnCreditMemo"/> + <waitForPageLoad time="60" stepKey="waitForLoadUseOrderGrid" after="navigateToOrderGridPage"/> + <waitForLoadingMaskToDisappear stepKey="waitForOrderGridPageLoad" after="waitForLoadUseOrderGrid"/> + + <!--Search order grid by name--> + <comment userInput="Admin searches order grid by name" stepKey="searchOrderGridComment" after="waitForOrderGridPageLoad"/> + <actionGroup ref="resetAdminDataGridToDefaultView" stepKey="setOrderGridToDefaultViewForSearch" after="searchOrderGridComment"/> + <!--@TODO use "Ship-to Name" when MQE-794 is fixed--> + <see selector="{{AdminDataGridTableSection.column('Ship')}}" userInput="{{Simple_US_Customer.fullname}}" stepKey="seeNonFilterNameInShipNameColumn" after="setOrderGridToDefaultViewForSearch"/> + <actionGroup ref="searchAdminDataGridByKeyword" stepKey="searchOrderGridByNameKeyword" after="seeNonFilterNameInShipNameColumn"> + <argument name="keyword" value="BillingAddressTX.fullname"/> + </actionGroup> + <dontSee selector="{{AdminDataGridTableSection.column('Ship')}}" userInput="{{Simple_US_Customer.fullname}}" stepKey="dontSeeNonFilterNameInShipNameColumn" after="searchOrderGridByNameKeyword"/> + <see selector="{{AdminDataGridTableSection.column('Ship')}}" userInput="{{BillingAddressTX.fullname}}" stepKey="seeFilterNameInShipNameColumn" after="dontSeeNonFilterNameInShipNameColumn"/> + + <!--Filter order grid--> + <comment userInput="Admin filters order grid by 'Bill-to Name'" stepKey="filterOrderGridByNameComment" after="seeFilterNameInShipNameColumn"/> + <!--Filter order grid by "Bill-to Name"--> + <actionGroup ref="resetAdminDataGridToDefaultView" stepKey="resetOrderGridForNameFilter" after="filterOrderGridByNameComment"/> + <!--@TODO use "Bill-to Name" when MQE-794 is fixed--> + <see selector="{{AdminDataGridTableSection.column('Bill')}}" userInput="{{BillingAddressTX.fullname}}" stepKey="seeNonFilterNameInColumn" after="resetOrderGridForNameFilter"/> + <actionGroup ref="filterOrderGridByBillingName" stepKey="filterOrderGridByBillingName" after="seeNonFilterNameInColumn"> + <argument name="customer" value="Simple_US_Customer"/> + </actionGroup> + <dontSee selector="{{AdminDataGridTableSection.column('Bill')}}" userInput="{{BillingAddressTX.fullname}}" stepKey="dontSeeNonFilterNameInColumn" after="filterOrderGridByBillingName"/> + <see selector="{{AdminDataGridTableSection.column('Bill')}}" userInput="{{Simple_US_Customer.fullname}}" stepKey="seeFilterNameInColumn" after="dontSeeNonFilterNameInColumn"/> + <!--Filter order grid by Grand Total (Base)--> + <comment userInput="Admin filters order grid by 'Grand Total'" stepKey="filterOrderGridByTotalComment" after="seeFilterNameInColumn"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearFilterBeforeTotalFilter" after="filterOrderGridByTotalComment"/> + <see selector="{{AdminDataGridTableSection.column('Grand Total')}}" userInput="{{AdminOrderSimpleProduct.grandTotal}}" stepKey="seeLowerTotalInGrid" after="clearFilterBeforeTotalFilter"/> + <actionGroup ref="filterOrderGridByBaseTotalRange" stepKey="filterOrderGridByTotal" after="seeLowerTotalInGrid"> + <argument name="from" value="OrderGrandTotalFilterRange.from"/> + <argument name="to" value="OrderGrandTotalFilterRange.to"/> + </actionGroup> + <dontSee selector="{{AdminDataGridTableSection.column('Grand Total')}}" userInput="{{AdminOrderSimpleProduct.grandTotal}}" stepKey="dontSeeLowerTotalInGrid" after="filterOrderGridByTotal"/> + <see selector="{{AdminDataGridTableSection.column('Grand Total')}}" userInput="{{AdminOrderSimpleConfigurableProduct.grandTotal}}" stepKey="seeExpectedTotalInGrid" after="dontSeeLowerTotalInGrid"/> + <!--Filter order grid by purchase date--> + <comment userInput="Admin filters order grid by 'Purchase Date'" stepKey="filterOrderGridByDateComment" after="seeExpectedTotalInGrid"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearFilterBeforeOrderDateFilter" after="filterOrderGridByDateComment"/> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openOrderFilterForOrderDateFrom" after="clearFilterBeforeOrderDateFilter"/> + <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('created_at[from]')}}" userInput="01/01/2018" stepKey="fillOrderDateFromFilter" after="openOrderFilterForOrderDateFrom"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="applyFilterOrderDateFrom" after="fillOrderDateFromFilter"/> + <!--Both of our orders should be in grid--> + <see selector="{{AdminDataGridTableSection.column('Bill')}}" userInput="{{Simple_US_Customer.fullname}}" stepKey="seeFirstOrderInGrid" after="applyFilterOrderDateFrom"/> + <see selector="{{AdminDataGridTableSection.column('Bill')}}" userInput="{{BillingAddressTX.fullname}}" stepKey="seeSecondOrderInGrid" after="seeFirstOrderInGrid"/> + <!--Add end date to date range filter (past date)--> + <click selector="{{AdminDataGridHeaderSection.filters}}" stepKey="openOrderFilterForOrderDateTo" after="seeSecondOrderInGrid"/> + <fillField selector="{{AdminDataGridHeaderSection.filterFieldInput('created_at[to]')}}" userInput="01/10/2018" stepKey="fillOrderDateToFilter" after="openOrderFilterForOrderDateTo"/> + <click selector="{{AdminDataGridHeaderSection.applyFilters}}" stepKey="applyFilterOrderDateTo" after="fillOrderDateToFilter"/> + <!--Dont see our orders in the grid--> + <dontSee selector="{{AdminDataGridTableSection.column('Bill')}}" userInput="{{Simple_US_Customer.fullname}}" stepKey="dontSeeFirstOrderInGrid" after="applyFilterOrderDateTo"/> + <dontSee selector="{{AdminDataGridTableSection.column('Bill')}}" userInput="{{BillingAddressTX.fullname}}" stepKey="dontSeeSecondOrderInGrid" after="dontSeeFirstOrderInGrid"/> + <!--Filter order grid by status--> + <comment userInput="Admin filters order grid by 'Status'" stepKey="filterOrderGridByStatusComment" after="dontSeeSecondOrderInGrid"/> + <actionGroup ref="clearFiltersAdminDataGrid" stepKey="clearFilterBeforeStatusFilter" after="filterOrderGridByStatusComment"/> + <actionGroup ref="filterOrderGridByStatus" stepKey="filterOrderGridByPendingStatus" after="clearFilterBeforeStatusFilter"> + <argument name="status" value="OrderStatus.pending"/> + </actionGroup> + <dontSee selector="{{AdminDataGridTableSection.column('Status')}}" userInput="{{OrderStatus.closed}}" stepKey="dontSeeClosedStatusInOrderGrid" after="filterOrderGridByPendingStatus"/> + <see selector="{{AdminDataGridTableSection.column('Status')}}" userInput="{{OrderStatus.pending}}" stepKey="seePendingStatusInOrderGrid" after="dontSeeClosedStatusInOrderGrid"/> + <actionGroup ref="filterOrderGridByStatus" stepKey="filterOrderGridByClosedStatus" after="seePendingStatusInOrderGrid"> + <argument name="status" value="OrderStatus.closed"/> + </actionGroup> + <see selector="{{AdminDataGridTableSection.column('Status')}}" userInput="{{OrderStatus.closed}}" stepKey="seeClosedStatusInOrderGrid" after="filterOrderGridByClosedStatus"/> + <dontSee selector="{{AdminDataGridTableSection.column('Status')}}" userInput="{{OrderStatus.pending}}" stepKey="dontSeePendingStatusInOrderGrid" after="seeClosedStatusInOrderGrid"/> + + <!--Sort order grid--> + <actionGroup ref="resetAdminDataGridToDefaultView" stepKey="resetOrderGridForSorting" after="dontSeePendingStatusInOrderGrid"/> + <!--Sort order grid by status--> + <comment userInput="Admin sorts order grid by status" stepKey="sortOrderGridByStatusComment" after="resetOrderGridForSorting"/> + <click selector="{{AdminDataGridTableSection.columnHeader('Status')}}" stepKey="clickStatusToSortAsc" after="sortOrderGridByStatusComment"/> + <grabTextFrom selector="{{AdminDataGridTableSection.gridCell('1', 'Status')}}" stepKey="getOrderStatusFirstRow" after="clickStatusToSortAsc"/> + <grabTextFrom selector="{{AdminDataGridTableSection.gridCell('2', 'Status')}}" stepKey="getOrderStatusSecondRow" after="getOrderStatusFirstRow"/> + <assertGreaterThanOrEqual expected="$getOrderStatusFirstRow" actual="$getOrderStatusSecondRow" stepKey="checkStatusSortOrderAsc" after="getOrderStatusSecondRow"/> + <!--@TODO improve sort assertion and check price and date column when MQE-690 is resolved--> + + <!--Use paging on order grid--> + <actionGroup ref="resetAdminDataGridToDefaultView" stepKey="resetAdminGridBeforePaging" after="checkStatusSortOrderAsc"/> + <comment userInput="Admin uses paging on order grid" stepKey="usePagingOrderGridComment" after="resetAdminGridBeforePaging"/> + <actionGroup ref="adminDataGridSelectCustomPerPage" stepKey="select1OrderPerPage" after="usePagingOrderGridComment"> + <!--@TODO Change this to scalar when MQE-498 is implemented--> + <argument name="perPage" value="Const.one"/> + </actionGroup> + <seeNumberOfElements selector="{{AdminDataGridTableSection.rows}}" userInput="1" stepKey="see1RowOnFirstPage" after="select1OrderPerPage"/> + <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="1" stepKey="seeOnFirstPageOrderGrid" after="see1RowOnFirstPage"/> + <click selector="{{AdminDataGridPaginationSection.nextPage}}" stepKey="clickNextPageOrderGrid" after="seeOnFirstPageOrderGrid"/> + <seeInField selector="{{AdminDataGridPaginationSection.currentPage}}" userInput="2" stepKey="seeOnSecondPageOrderGrid" after="clickNextPageOrderGrid"/> + <seeNumberOfElements selector="{{AdminDataGridTableSection.rows}}" userInput="1" stepKey="see1RowOnSecondPage" after="seeOnSecondPageOrderGrid"/> + <actionGroup ref="adminDataGridSelectPerPage" stepKey="select50OrdersPerPage" after="see1RowOnSecondPage"> + <!--@TODO Change this to scalar when MQE-498 is implemented--> + <argument name="perPage" value="Const.fifty"/> + </actionGroup> + <seeNumberOfElements selector="{{AdminDataGridTableSection.rows}}" parameterArray="[2,50]" stepKey="seeCorrectNumberOfRowsPerPage" after="select50OrdersPerPage"/> + + <!--Add column to order grid--> + <!--@TODO Change to action group when MQE-498 is implemented--> + <comment userInput="Admin adds column to order grid" stepKey="adminAddsColumnOrderGrid" after="seeCorrectNumberOfRowsPerPage"/> + <dontSeeElement selector="{{AdminDataGridTableSection.columnHeader('Customer Email')}}" stepKey="dontSeeCustomerEmailColumnInGrid" after="adminAddsColumnOrderGrid"/> + <click selector="{{AdminDataGridHeaderSection.columnsToggle}}" stepKey="openOrderGridColumnOptions" after="dontSeeCustomerEmailColumnInGrid"/> + <checkOption selector="{{AdminDataGridHeaderSection.columnCheckbox('Customer Email')}}" stepKey="addCustomerEmailColumnToOrderGrid" after="openOrderGridColumnOptions"/> + <click selector="{{AdminDataGridHeaderSection.columnsToggle}}" stepKey="closeOrderGridColumnOptions" after="addCustomerEmailColumnToOrderGrid"/> + <seeElement selector="{{AdminDataGridTableSection.columnHeader('Customer Email')}}" stepKey="seeCustomerEmailColumnInGrid" after="closeOrderGridColumnOptions"/> + <!--Remove column from order grid--> + <!--@TODO Change to action group when MQE-498 is implemented--> + <comment userInput="Admin removes column from order grid" stepKey="adminRemovesColumnOrderGrid" after="seeCustomerEmailColumnInGrid"/> + <seeElement selector="{{AdminDataGridTableSection.columnHeader('Purchase Point')}}" stepKey="seePurchasePointColumnInGrid" after="adminRemovesColumnOrderGrid"/> + <click selector="{{AdminDataGridHeaderSection.columnsToggle}}" stepKey="openOrderGridColumnOptionsPurchasePoint" after="seePurchasePointColumnInGrid"/> + <uncheckOption selector="{{AdminDataGridHeaderSection.columnCheckbox('Purchase Point')}}" stepKey="removePurchasePointColumnFromGrid" after="openOrderGridColumnOptionsPurchasePoint"/> + <click selector="{{AdminDataGridHeaderSection.columnsToggle}}" stepKey="closeOrderGridColumnOptionsPurchasePoint" after="removePurchasePointColumnFromGrid"/> + <dontSeeElement selector="{{AdminDataGridTableSection.columnHeader('Purchase Point')}}" stepKey="dontSeePurchasePointColumnInGrid" after="closeOrderGridColumnOptionsPurchasePoint"/> + <!--END admin uses order grid--> + + <!--Delete store view created as prerequisites--> + <comment userInput="Clean up store view" stepKey="cleanUpStoreView" before="deleteStoreView"/> + <actionGroup ref="AdminDeleteStoreViewActionGroup" stepKey="deleteStoreView"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/composer.json index 9c1805b3df12a..cd4c0fde66877 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Sales/composer.json @@ -12,12 +12,15 @@ }, "require": { "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-test-module-backend": "100.0.0-dev", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", + "magento/magento2-functional-test-module-ui": "100.0.0-dev", + "magento/magento2-functional-test-module-payment": "100.0.0-dev", + "magento/magento2-functional-test-module-quote": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { "magento/magento2-functional-test-module-authorization": "100.0.0-dev", - "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", "magento/magento2-functional-test-module-checkout": "100.0.0-dev", "magento/magento2-functional-test-module-config": "100.0.0-dev", @@ -26,8 +29,6 @@ "magento/magento2-functional-test-module-eav": "100.0.0-dev", "magento/magento2-functional-test-module-gift-message": "100.0.0-dev", "magento/magento2-functional-test-module-media-storage": "100.0.0-dev", - "magento/magento2-functional-test-module-payment": "100.0.0-dev", - "magento/magento2-functional-test-module-quote": "100.0.0-dev", "magento/magento2-functional-test-module-reports": "100.0.0-dev", "magento/magento2-functional-test-module-sales-rule": "100.0.0-dev", "magento/magento2-functional-test-module-sales-sequence": "100.0.0-dev", @@ -35,7 +36,6 @@ "magento/magento2-functional-test-module-store": "100.0.0-dev", "magento/magento2-functional-test-module-tax": "100.0.0-dev", "magento/magento2-functional-test-module-theme": "100.0.0-dev", - "magento/magento2-functional-test-module-ui": "100.0.0-dev", "magento/magento2-functional-test-module-widget": "100.0.0-dev", "magento/magento2-functional-test-module-wishlist": "100.0.0-dev" }, diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/ActionGroup/StorefrontSalesRuleActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/ActionGroup/StorefrontSalesRuleActionGroup.xml new file mode 100644 index 0000000000000..65b40abb72fd8 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/ActionGroup/StorefrontSalesRuleActionGroup.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Apply Sales Rule Coupon to the cart --> + <actionGroup name="StorefrontApplyCouponActionGroup"> + <arguments> + <argument name="coupon"/> + </arguments> + <waitForElement selector="{{StorefrontSalesRuleCartCouponSection.couponHeader}}" time="30" stepKey="waitForCouponHeader" /> + <conditionalClick selector="{{StorefrontSalesRuleCartCouponSection.couponHeader}}" dependentSelector="{{StorefrontSalesRuleCartCouponSection.discountBlockActive}}" visible="false" stepKey="clickCouponHeader" /> + <waitForElementVisible selector="{{StorefrontSalesRuleCartCouponSection.couponField}}" stepKey="waitForCouponField" /> + <fillField userInput="{{coupon.code}}" selector="{{StorefrontSalesRuleCartCouponSection.couponField}}" stepKey="fillCouponField"/> + <click selector="{{StorefrontSalesRuleCartCouponSection.applyButton}}" stepKey="clickApplyButton"/> + </actionGroup> + + <!-- Cancel Sales Rule Coupon applied to the cart --> + <actionGroup name="StorefrontCancelCouponActionGroup"> + <waitForElement selector="{{StorefrontSalesRuleCartCouponSection.couponHeader}}" time="30" stepKey="waitForCouponHeader" /> + <conditionalClick selector="{{StorefrontSalesRuleCartCouponSection.couponHeader}}" dependentSelector="{{StorefrontSalesRuleCartCouponSection.discountBlockActive}}" visible="false" stepKey="clickCouponHeader" /> + <waitForElementVisible selector="{{StorefrontSalesRuleCartCouponSection.couponField}}" stepKey="waitForCouponField" /> + <click selector="{{StorefrontSalesRuleCartCouponSection.cancelButton}}" stepKey="clickCancelButton"/> + </actionGroup> + + <!-- Check applied discount in cart summary --> + <actionGroup name="StorefrontCheckCouponAppliedActionGroup"> + <arguments> + <argument name="rule"/> + <argument name="discount"/> + </arguments> + <waitForElementVisible selector="{{CheckoutCartSummarySection.discountTotal}}" stepKey="waitForDiscountTotal" /> + <see userInput="{{rule.store_labels[1][store_label]}}" selector="{{CheckoutCartSummarySection.discountLabel}}" stepKey="assertDiscountLabel" /> + <see userInput="-${{discount}}" selector="{{CheckoutCartSummarySection.discountTotal}}" stepKey="assertDiscountTotal" /> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/QuoteData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/QuoteData.xml new file mode 100644 index 0000000000000..389cda03235bc --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/QuoteData.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <!-- @TODO: Get rid off this workaround and its usages after MQE-498 is implemented --> + <entity name="E2EB2CQuoteWith10PercentDiscount" type="Quote"> + <data key="subtotal">480.00</data> + <data key="shipping">15.00</data> + <data key="discount">48.00</data> + <data key="total">447.00</data> + <data key="shippingMethod">Flat Rate - Fixed</data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/SalesCouponData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/SalesCouponData.xml new file mode 100644 index 0000000000000..c216bb10242b4 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/SalesCouponData.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="ApiSalesRuleCoupon" type="SalesRuleCoupon"> + <data key="code" unique="suffix">salesCoupon</data> + <data key="times_used">0</data> + <data key="is_primary">1</data> + <data key="type">0</data> + <var key="rule_id" entityType="SalesRule" entityKey="rule_id"/> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/SalesRuleData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/SalesRuleData.xml index f26ce7dea1ece..d89d3f44776e4 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/SalesRuleData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/SalesRuleData.xml @@ -5,8 +5,40 @@ * See COPYING.txt for license details. */ --> + <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="ApiSalesRule" type="SalesRule"> + <data key="name" unique="suffix">salesRule</data> + <data key="description">Sales Rule Descritpion</data> + <array key="website_ids"> + <item>1</item> + </array> + <array key="customer_group_ids"> + <item>0</item> + <item>1</item> + <item>3</item> + </array> + <data key="uses_per_customer">2</data> + <data key="is_active">true</data> + <data key="stop_rules_processing">true</data> + <data key="is_advanced">true</data> + <data key="sort_order">2</data> + <data key="simple_action">by_percent</data> + <data key="discount_amount">10</data> + <data key="discount_qty">2</data> + <data key="discount_step">0</data> + <data key="apply_to_shipping">false</data> + <data key="times_used">1</data> + <data key="is_rss">true</data> + <data key="coupon_type">SPECIFIC_COUPON</data> + <data key="use_auto_generation">false</data> + <data key="uses_per_coupon">0</data> + <data key="simple_free_shipping">0</data> + <requiredEntity type="SalesRuleLabel">SalesRuleLabelDefault</requiredEntity> + <requiredEntity type="SalesRuleLabel">SalesRuleLabelStore1</requiredEntity> + </entity> + <entity name="SimpleSalesRule" type="SalesRule"> <data key="name" unique="suffix">SimpleSalesRule</data> <data key="is_active">true</data> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/SalesRuleLabelData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/SalesRuleLabelData.xml new file mode 100644 index 0000000000000..6798b34a7557a --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Data/SalesRuleLabelData.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="SalesRuleLabelDefault" type="SalesRuleLabel"> + <data key="store_id">0</data> + <data key="store_label" unique="suffix">Sales Rule (Default) </data> + </entity> + <entity name="SalesRuleLabelStore1" type="SalesRuleLabel"> + <data key="store_id">1</data> + <data key="store_label" unique="suffix">Sales Rule (Store 1) </data> + </entity> +</entities> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-condition-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-condition-meta.xml new file mode 100644 index 0000000000000..82b3e3de28fea --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-condition-meta.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateSalesRuleCondition" dataType="SalesRuleCondition" type="create"> + <field key="condition_type" required="true">string</field> + <array key="conditions" required="true"> + <value>SalesRuleCondition</value> + </array> + <field key="aggregator_type" required="true">string</field> + <field key="operator" required="true">string</field> + <field key="attribute_name" required="true">string</field> + <field key="value" required="true">mixed</field> + <field key="extension_attributes">empty_extension_attribute</field> + </operation> + + <operation name="UpdateSalesRuleCondition" dataType="SalesRuleCondition" type="update"> + <field key="condition_type">string</field> + <array key="conditions"> + <value>SalesRuleCondition</value> + </array> + <field key="aggregator_type">string</field> + <field key="operator">string</field> + <field key="attribute_name">string</field> + <field key="value">mixed</field> + <field key="extension_attributes">empty_extension_attribute</field> + </operation> +</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-coupon-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-coupon-meta.xml new file mode 100644 index 0000000000000..6b5e4a1a6cab6 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-coupon-meta.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateSalesRuleCoupon" dataType="SalesRuleCoupon" type="create" auth="adminOauth" url="/V1/coupons" method="POST"> + <contentType>application/json</contentType> + <object key="coupon" dataType="SalesRuleCoupon"> + <field key="coupon_id">integer</field> + <field key="rule_id" required="true">integer</field> + <field key="code" required="true">string</field> + <field key="usage_limit">integer</field> + <field key="usage_per_customer">integer</field> + <field key="times_used" required="true">integer</field> + <field key="expiration_date">string</field> + <field key="is_primary">boolean</field> + <field key="created_at">string</field> + <field key="type">integer</field> + <field key="extension_attributes">empty_extension_attribute</field> + </object> + </operation> + + <operation name="UpdateSalesRuleCoupon" dataType="SalesRuleCoupon" type="update" auth="adminOauth" url="/V1/coupons" method="PUT"> + <contentType>application/json</contentType> + <object key="coupon" dataType="SalesRuleCoupon"> + <field key="coupon_id" required="true">integer</field> + <field key="rule_id" required="true">integer</field> + <field key="code" required="true">string</field> + <field key="usage_limit">integer</field> + <field key="usage_per_customer">integer</field> + <field key="times_used" required="true">integer</field> + <field key="expiration_date">string</field> + <field key="is_primary">boolean</field> + <field key="created_at">string</field> + <field key="type">integer</field> + <field key="extension_attributes">empty_extension_attribute</field> + </object> + </operation> + + <operation name="DeleteSalesRuleCoupon" dataType="SalesRuleCoupon" type="delete" auth="adminOauth" url="/V1/coupons/{coupon_id}" method="DELETE"> + <contentType>application/json</contentType> + </operation> +</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-label-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-label-meta.xml new file mode 100644 index 0000000000000..17429d38a3254 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-label-meta.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> + <operation name="CreateSalesRuleLabel" dataType="SalesRuleLabel" type="create"> + <field key="store_id" required="true">integer</field> + <field key="store_label" required="true">string</field> + <field key="extension_attributes">empty_extension_attribute</field> + </operation> + + <operation name="UpdateSalesRuleLabel" dataType="SalesRuleLabel" type="update"> + <field key="store_id">integer</field> + <field key="store_label">string</field> + <field key="extension_attributes">empty_extension_attribute</field> + </operation> +</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-meta.xml index 63795e3e6b2de..f71431ff97dda 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-meta.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule-meta.xml @@ -10,68 +10,85 @@ <operation name="CreateSalesRule" dataType="SalesRule" type="create" auth="adminOauth" url="/V1/salesRules" method="POST"> <contentType>application/json</contentType> <object key="rule" dataType="SalesRule"> + <field key="rule_id">integer</field> <field key="name" required="true">string</field> - <field key="description">string</field> - <field key="is_active">boolean</field> + <array key="store_labels"> + <value>SalesRuleLabel</value> + </array> <field key="from_date">string</field> <field key="to_date">string</field> - <field key="uses_per_customer">integer</field> - <field key="sort_order">integer</field> - <field key="simple_action">string</field> - <field key="discount_amount">integer</field> - <field key="discount_qty">integer</field> - <field key="discount_step">integer</field> - <field key="times_used">integer</field> - <field key="uses_per_coupon">integer</field> - <field key="apply_to_shipping">boolean</field> - <field key="is_rss">boolean</field> - <field key="use_auto_generation">boolean</field> - <field key="coupon_type">string</field> - <field key="simple_free_shipping">string</field> - <field key="stop_rules_processing">boolean</field> - <field key="is_advanced">boolean</field> + <field key="uses_per_customer" required="true">integer</field> + <field key="is_active" required="true">boolean</field> + <field key="condition">SalesRuleCondition</field> + <field key="action_condition">SalesRuleCondition</field> + <field key="stop_rules_processing" required="true">boolean</field> + <array key="product_ids"> + <value>integer</value> + </array> + <field key="sort_order" required="true">integer</field> + <field key="simple_action" required="true">string</field> + <field key="discount_amount" required="true">number</field> + <field key="discount_qty" required="true">number</field> + <field key="discount_step" required="true">integer</field> + <field key="apply_to_shipping" required="true">boolean</field> + <field key="times_used" required="true">integer</field> + <field key="is_rss" required="true">boolean</field> + <field key="coupon_type" required="true">string</field> + <field key="use_auto_generation" required="true">boolean</field> + <field key="uses_per_coupon" required="true">integer</field> + <field key="simple_free_shipping" required="true">string</field> + <field key="extension_attributes">empty_extension_attribute</field> + <field key="description" required="true">string</field> + <array key="customer_group_ids" required="true"> + <value>integer</value> + </array> + <array key="website_ids" required="true"> + <value>integer</value> + </array> + </object> + </operation> + + <operation name="UpdateSalesRule" dataType="SalesRule" type="update" auth="adminOauth" url="/V1/salesRules" method="PUT"> + <contentType>application/json</contentType> + <object key="rule" dataType="SalesRule"> + <field key="rule_id" required="true">integer</field> + <field key="name" required="true">string</field> <array key="store_labels"> - <!-- specify object name as array value --> - <value>SalesRuleStoreLabel</value> - <!-- alternatively, define object embedded in array directly --> - <!--object dataType="SalesRuleStoreLabel" key="store_labels"> - <field key="store_id">integer</field> - <field key="store_label">string</field> - </object--> + <value>SalesRuleLabel</value> </array> - <array key="product_ids"> + <field key="description" required="true">string</field> + <array key="website_ids" required="true"> <value>integer</value> </array> - <array key="customer_group_ids"> + <array key="customer_group_ids" required="true"> <value>integer</value> </array> - <array key="website_ids"> + <field key="from_date">string</field> + <field key="to_date">string</field> + <field key="uses_per_customer" required="true">integer</field> + <field key="is_active" required="true">boolean</field> + <field key="condition">SalesRuleCondition</field> + <field key="action_condition">SalesRuleCondition</field> + <field key="stop_rules_processing" required="true">boolean</field> + <array key="product_ids"> <value>integer</value> </array> - <object dataType="RuleCondition" key="condition"> - <field key="condition_type">string</field> - <array key="conditions"> - <value>integer</value> - </array> - <field key="aggregator_type">string</field> - <field key="operator">string</field> - <field key="attribute_name">string</field> - <field key="value">string</field> - <field key="extension_attributes">empty_extension_attribute</field> - </object> - <object dataType="ActionCondition" key="action_condition"> - <field key="condition_type">string</field> - <field key="aggregator_type">string</field> - <field key="operator">string</field> - <field key="attribute_name">string</field> - <field key="value">string</field> - <field key="extension_attributes">empty_extension_attribute</field> - </object> - <object dataType="ExtensionAttribute" key="extension_attributes"> - <field key="reward_points_delta">integer</field> - </object> + <field key="sort_order" required="true">integer</field> + <field key="simple_action" required="true">string</field> + <field key="discount_amount" required="true">number</field> + <field key="discount_qty" required="true">number</field> + <field key="discount_step" required="true">integer</field> + <field key="apply_to_shipping" required="true">boolean</field> + <field key="times_used" required="true">integer</field> + <field key="is_rss" required="true">boolean</field> + <field key="coupon_type" required="true">string</field> + <field key="use_auto_generation" required="true">boolean</field> + <field key="uses_per_coupon" required="true">integer</field> + <field key="simple_free_shipping" required="true">string</field> + <field key="extension_attributes">empty_extension_attribute</field> </object> </operation> + <operation name="DeleteSalesRule" dataType="SalesRule" type="delete" auth="adminOauth" url="/V1/salesRules/{rule_id}" method="DELETE"> <contentType>application/json</contentType> </operation> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule_coupon-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule_coupon-meta.xml deleted file mode 100644 index 4debb7b2e4a2a..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule_coupon-meta.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> - <operation name="CreateSalesRuleCoupon" dataType="SalesRuleCoupon" type="create" auth="adminOauth" url="/V1/coupons" method="POST"> - <contentType>application/json</contentType> - <object key="coupon" dataType="SalesRuleCoupon"> - <field key="rule_id" required="true">integer</field> - <field key="code">string</field> - <field key="usage_limit">integer</field> - <field key="usage_per_customer">integer</field> - <field key="times_used">integer</field> - <field key="expiration_date">string</field> - <field key="is_primary">boolean</field> - <field key="created_at">string</field> - <field key="type">integer</field> - </object> - </operation> - <operation name="DeleteSalesRuleCoupon" dataType="SalesRuleCoupon" type="delete" auth="adminOauth" url="/V1/coupons/{coupon_id}" method="DELETE"> - <contentType>application/json</contentType> - </operation> -</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule_store_label-meta.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule_store_label-meta.xml deleted file mode 100644 index 2661a6519ac90..0000000000000 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Metadata/sales_rule_store_label-meta.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - /** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> - -<operations xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataOperation.xsd"> - <operation name="CreateSalesRuleStoreLabel" dataType="SalesRuleStoreLabel" type="create"> - <field key="store_id">integer</field> - <field key="store_label">string</field> - </operation> -</operations> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Section/CheckoutCartSummarySection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Section/CheckoutCartSummarySection.xml new file mode 100644 index 0000000000000..68dee0de52390 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Section/CheckoutCartSummarySection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="CheckoutCartSummarySection"> + <element name="discountLabel" type="text" selector="//*[@id='cart-totals']//tr[.//th//span[contains(@class, 'discount coupon')]]"/> + <element name="discountTotal" type="text" selector="//*[@id='cart-totals']//tr[.//th//span[contains(@class, 'discount coupon')]]//td//span//span[@class='price']"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Section/StorefrontSalesRuleCartCouponSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Section/StorefrontSalesRuleCartCouponSection.xml new file mode 100644 index 0000000000000..7c0b918864db3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Section/StorefrontSalesRuleCartCouponSection.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontSalesRuleCartCouponSection"> + <element name="couponHeader" type="button" selector="//*[@id='block-discount-heading']"/> + <element name="couponField" type="text" selector="//*[@id='coupon_code']"/> + <element name="discountBlockActive" type="text" selector="//*[@class='block discount active']" /> + <element name="applyButton" type="text" selector="//*[@id='discount-coupon-form']//button[contains(@class, 'apply')]"/> + <element name="cancelButton" type="text" selector="//*[@id='discount-coupon-form']//button[contains(@class, 'cancel')]"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Test/EndToEndB2CGuestUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Test/EndToEndB2CGuestUserTest.xml new file mode 100644 index 0000000000000..6e1ba5ad1649b --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Test/EndToEndB2CGuestUserTest.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CGuestUserTest"> + <before> + <createData entity="ApiSalesRule" stepKey="createSalesRule"/> + <createData entity="ApiSalesRuleCoupon" stepKey="createSalesRuleCoupon"> + <requiredEntity createDataKey="createSalesRule"/> + </createData> + </before> + <after> + <deleteData createDataKey="createSalesRule" stepKey="deleteSalesRule"/> + </after> + + <!-- Step 5: User uses coupon codes --> + <comment userInput="Start of using coupon code" stepKey="startOfUsingCouponCode" after="endOfComparingProducts" /> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="couponOpenCart" after="startOfUsingCouponCode"/> + + <actionGroup ref="StorefrontApplyCouponActionGroup" stepKey="couponApplyCoupon" after="couponOpenCart"> + <argument name="coupon" value="$$createSalesRuleCoupon$$"/> + </actionGroup> + + <actionGroup ref="StorefrontCheckCouponAppliedActionGroup" stepKey="couponCheckAppliedDiscount" after="couponApplyCoupon"> + <argument name="rule" value="$$createSalesRule$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="discount" value="E2EB2CQuoteWith10PercentDiscount.discount"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCartActionGroup" stepKey="couponCheckCartWithDiscount" after="couponCheckAppliedDiscount"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="subtotal" value="E2EB2CQuoteWith10PercentDiscount.subtotal"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shipping" value="E2EB2CQuoteWith10PercentDiscount.shipping"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shippingMethod" value="E2EB2CQuoteWith10PercentDiscount.shippingMethod"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="total" value="E2EB2CQuoteWith10PercentDiscount.total"/> + </actionGroup> + + <actionGroup ref="StorefrontCancelCouponActionGroup" stepKey="couponCancelCoupon" after="couponCheckCartWithDiscount"/> + <actionGroup ref="StorefrontCheckCartActionGroup" stepKey="cartAssertCartAfterCancelCoupon" after="couponCancelCoupon"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="subtotal" value="E2EB2CQuote.subtotal"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shipping" value="E2EB2CQuote.shipping"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shippingMethod" value="E2EB2CQuote.shippingMethod"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="total" value="E2EB2CQuote.total"/> + </actionGroup> + <comment userInput="End of using coupon code" stepKey="endOfUsingCouponCode" after="cartAssertCartAfterCancelCoupon" /> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Test/EndToEndB2CLoggedInUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Test/EndToEndB2CLoggedInUserTest.xml new file mode 100644 index 0000000000000..fcb8028220cb1 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/Test/EndToEndB2CLoggedInUserTest.xml @@ -0,0 +1,59 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CLoggedInUserTest"> + <before> + <createData entity="ApiSalesRule" stepKey="createSalesRule"/> + <createData entity="ApiSalesRuleCoupon" stepKey="createSalesRuleCoupon"> + <requiredEntity createDataKey="createSalesRule"/> + </createData> + </before> + <after> + <deleteData createDataKey="createSalesRule" stepKey="deleteSalesRule"/> + </after> + + <!-- Step 6: User uses coupon codes --> + <comment userInput="Start of using coupon code" stepKey="startOfUsingCouponCode" after="endOfComparingProducts" /> + <actionGroup ref="StorefrontOpenCartFromMinicartActionGroup" stepKey="couponOpenCart" after="startOfUsingCouponCode"/> + + <actionGroup ref="StorefrontApplyCouponActionGroup" stepKey="couponApplyCoupon" after="couponOpenCart"> + <argument name="coupon" value="$$createSalesRuleCoupon$$"/> + </actionGroup> + + <actionGroup ref="StorefrontCheckCouponAppliedActionGroup" stepKey="couponCheckAppliedDiscount" after="couponApplyCoupon"> + <argument name="rule" value="$$createSalesRule$$"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="discount" value="E2EB2CQuoteWith10PercentDiscount.discount"/> + </actionGroup> + <actionGroup ref="StorefrontCheckCartActionGroup" stepKey="couponCheckCartWithDiscount" after="couponCheckAppliedDiscount"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="subtotal" value="E2EB2CQuoteWith10PercentDiscount.subtotal"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shipping" value="E2EB2CQuoteWith10PercentDiscount.shipping"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shippingMethod" value="E2EB2CQuoteWith10PercentDiscount.shippingMethod"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="total" value="E2EB2CQuoteWith10PercentDiscount.total"/> + </actionGroup> + + <actionGroup ref="StorefrontCancelCouponActionGroup" stepKey="couponCancelCoupon" after="couponCheckCartWithDiscount"/> + <actionGroup ref="StorefrontCheckCartActionGroup" stepKey="cartAssertCartAfterCancelCoupon" after="couponCancelCoupon"> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="subtotal" value="E2EB2CQuote.subtotal"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shipping" value="E2EB2CQuote.shipping"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="shippingMethod" value="E2EB2CQuote.shippingMethod"/> + <!-- @TODO: Change to scalar value after MQE-498 is implemented --> + <argument name="total" value="E2EB2CQuote.total"/> + </actionGroup> + <comment userInput="End of using coupon code" stepKey="endOfUsingCouponCode" after="cartAssertCartAfterCancelCoupon"/> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/composer.json index f53960051cd8d..9b914c5df71b6 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SalesRule/composer.json @@ -11,25 +11,25 @@ "sort-packages": true }, "require": { - "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-testing-framework": "~2.0.0", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", + "magento/magento2-functional-test-module-quote": "100.0.0-dev", + "magento/magento2-functional-test-module-ui": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-rule": "100.0.0-dev", "magento/magento2-functional-test-module-config": "100.0.0-dev", "magento/magento2-functional-test-module-customer": "100.0.0-dev", "magento/magento2-functional-test-module-directory": "100.0.0-dev", "magento/magento2-functional-test-module-eav": "100.0.0-dev", "magento/magento2-functional-test-module-payment": "100.0.0-dev", - "magento/magento2-functional-test-module-quote": "100.0.0-dev", "magento/magento2-functional-test-module-reports": "100.0.0-dev", "magento/magento2-functional-test-module-rule": "100.0.0-dev", "magento/magento2-functional-test-module-sales": "100.0.0-dev", "magento/magento2-functional-test-module-shipping": "100.0.0-dev", "magento/magento2-functional-test-module-store": "100.0.0-dev", - "magento/magento2-functional-test-module-ui": "100.0.0-dev", "magento/magento2-functional-test-module-widget": "100.0.0-dev" }, "autoload": { diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml index d805bd6a60969..1808424b8a465 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/AssertsTest.xml @@ -13,12 +13,6 @@ <features value="Test Asserts"/> <group value="skip"/> </annotations> - <before> - <createData entity="Simple_US_Customer" stepKey="createData1"/> - </before> - <after> - <deleteData createDataKey="createData1" stepKey="deleteData1"/> - </after> <createData entity="Simple_US_Customer" stepKey="createData2"/> <amOnUrl url="https://www.yahoo.com" stepKey="amOnPage"/> @@ -26,70 +20,58 @@ <grabTextFrom selector="#uh-logo" stepKey="grabTextFrom1"/> <!-- asserts without variable replacement --> - <comment stepKey="c1" userInput="asserts without variable replacement"/> - <assertArrayHasKey stepKey="assertArrayHasKey" expected="apple" expectedType="string" actual="['orange' => 2, 'apple' => 1]" actualType="const" message="pass"/> - <assertArrayNotHasKey stepKey="assertArrayNotHasKey" expected="kiwi" expectedType="string" actual="['orange' => 2, 'apple' => 1]" message="pass"/> - <assertArraySubset stepKey="assertArraySubset" expected="[1, 2]" actual="[1, 2, 3, 5]" message="pass"/> - <assertContains stepKey="assertContains" expected="ab" expectedType="string" actual="['item1' => 'a', 'item2' => 'ab']" message="pass"/> - <assertCount stepKey="assertCount" expected="2" expectedType="int" actual="['a', 'b']" message="pass"/> - <assertEmpty stepKey="assertEmpty" actual="[]" message="pass"/> - <assertEquals stepKey="assertEquals1" expected="text" expectedType="variable" actual="Yahoo" actualType="string" message="pass"/> - <assertEquals stepKey="assertEquals2" expected="Yahoo" expectedType="string" actual="text" actualType="variable" message="pass"/> - <assertFalse stepKey="assertFalse1" actual="0" actualType="bool" message="pass"/> - <assertFileNotExists stepKey="assertFileNotExists1" actual="/out.txt" actualType="string" message="pass"/> - <assertFileNotExists stepKey="assertFileNotExists2" actual="text" actualType="variable" message="pass"/> - <assertGreaterOrEquals stepKey="assertGreaterOrEquals" expected="2" expectedType="int" actual="5" actualType="int" message="pass"/> - <assertGreaterThan stepKey="assertGreaterThan" expected="2" expectedType="int" actual="5" actualType="int" message="pass"/> - <assertGreaterThanOrEqual stepKey="assertGreaterThanOrEqual" expected="2" expectedType="int" actual="5" actualType="int" message="pass"/> - <assertInternalType stepKey="assertInternalType1" expected="string" expectedType="string" actual="xyz" actualType="string" message="pass"/> - <assertInternalType stepKey="assertInternalType2" expected="int" expectedType="string" actual="21" actualType="int" message="pass"/> - <assertInternalType stepKey="assertInternalType3" expected="string" expectedType="string" actual="text" actualType="variable" message="pass"/> - <assertLessOrEquals stepKey="assertLessOrEquals" expected="5" expectedType="int" actual="2" actualType="int" message="pass"/> - <assertLessThan stepKey="assertLessThan" expected="5" expectedType="int" actual="2" actualType="int" message="pass"/> - <assertLessThanOrEqual stepKey="assertLessThanOrEqual" expected="5" expectedType="int" actual="2" actualType="int" message="pass"/> - <assertNotContains stepKey="assertNotContains1" expected="bc" expectedType="string" actual="['item1' => 'a', 'item2' => 'ab']" message="pass"/> - <assertNotContains stepKey="assertNotContains2" expected="bc" expectedType="string" actual="text" actualType="variable" message="pass"/> - <assertNotEmpty stepKey="assertNotEmpty1" actual="[1, 2]" message="pass"/> - <assertNotEmpty stepKey="assertNotEmpty2" actual="text" actualType="variable" message="pass"/> - <assertNotEquals stepKey="assertNotEquals" expected="2" expectedType="int" actual="5" actualType="int" message="pass" delta=""/> - <assertNotNull stepKey="assertNotNull1" actual="abc" actualType="string" message="pass"/> - <assertNotNull stepKey="assertNotNull2" actual="text" actualType="variable" message="pass"/> - <assertNotRegExp stepKey="assertNotRegExp" expected="/foo/" expectedType="string" actual="bar" actualType="string" message="pass"/> - <assertNotSame stepKey="assertNotSame" expected="log" expectedType="string" actual="tag" actualType="string" message="pass"/> - <assertRegExp stepKey="assertRegExp" expected="/foo/" expectedType="string" actual="foo" actualType="string" message="pass"/> - <assertSame stepKey="assertSame" expected="bar" expectedType="string" actual="bar" actualType="string" message="pass"/> - <assertStringStartsNotWith stepKey="assertStringStartsNotWith" expected="a" expectedType="string" actual="banana" actualType="string" message="pass"/> - <assertStringStartsWith stepKey="assertStringStartsWith" expected="a" expectedType="string" actual="apple" actualType="string" message="pass"/> - <assertTrue stepKey="assertTrue" actual="1" actualType="bool" message="pass"/> + <assertArrayHasKey stepKey="assertArrayHasKey" message="pass"> + <expectedResult type="string">apple</expectedResult> + <actualResult type="const">['orange' => 2, 'apple' => 1]</actualResult> + </assertArrayHasKey> + <assertEquals stepKey="assertEquals1" message="pass"> + <expectedResult type="variable">grabTextFrom1</expectedResult> + <actualResult type="string">Copyright © 2013-2017 Magento, Inc. All rights reserved.</actualResult> + </assertEquals> + <assertFalse stepKey="assertFalse1" message="pass"> + <actualResult type="bool">0</actualResult> + </assertFalse> + <assertGreaterOrEquals stepKey="assertGreaterOrEquals" message="pass"> + <expectedResult type="int">2</expectedResult> + <actualResult type="int">5</actualResult> + </assertGreaterOrEquals> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute1" selector="#username" attribute="class"> + <expectedResult type="string">admin__control-text</expectedResult> + </assertElementContainsAttribute> <!-- string type that use created data --> - <comment stepKey="c2" userInput="string type that use created data"/> - <assertStringStartsWith stepKey="assert1" expected="D" expectedType="string" actual="$$createData1.lastname$$, $$createData1.firstname$$" actualType="string" message="fail"/> - <assertStringStartsNotWith stepKey="assert2" expected="W" expectedType="string" actual="$createData2.firstname$ $createData2.lastname$" actualType="string" message="pass"/> - <assertEquals stepKey="assert5" expected="$$createData1.lastname$$" expectedType="string" actual="$$createData1.lastname$$" actualType="string" message="pass"/> + <assertStringStartsWith stepKey="assert1" message="fail"> + <expectedResult type="string">D</expectedResult> + <actualResult type="string">$$createData1.lastname$$, $$createData1.firstname$$</actualResult> + </assertStringStartsWith> + <assertStringStartsNotWith stepKey="assert2" message="pass"> + <expectedResult type="string">W</expectedResult> + <actualResult type="string">$createData2.firstname$, $createData2.lastname$</actualResult> + </assertStringStartsNotWith> + <assertEquals stepKey="assert5" message="pass"> + <expectedResult type="string">$$createData1.lastname$$</expectedResult> + <actualResult type="string">$$createData1.lastname$$</actualResult> + </assertEquals> + <assertElementContainsAttribute stepKey="assertElementContainsAttribute7" selector="#username" attribute="value"> + <expectedResult type="const">$createData2.firstname$</expectedResult> + </assertElementContainsAttribute> <!-- array type that use created data --> - <comment stepKey="c3" userInput="array type that use created data"/> - <assertArraySubset stepKey="assert9" expected="[$$createData1.lastname$$, $$createData1.firstname$$]" expectedType="array" actual="[$$createData1.lastname$$, $$createData1.firstname$$, 1]" actualType="array" message="pass"/> - <assertArraySubset stepKey="assert10" expected="[$createData2.firstname$, $createData2.lastname$]" expectedType="array" actual="[$createData2.firstname$, $createData2.lastname$, 1]" actualType="array" message="pass"/> - <assertArrayHasKey stepKey="assert3" expected="lastname" expectedType="string" actual="['lastname' => $$createData1.lastname$$, 'firstname' => $$createData1.firstname$$]" actualType="array" message="pass"/> - <assertArrayHasKey stepKey="assert4" expected="lastname" expectedType="string" actual="['lastname' => $createData2.lastname$, 'firstname' => $createData2.firstname$]" actualType="array" message="pass"/> - - <!-- comment this section before running this test --> - <comment stepKey="c4" userInput="comment this section before running this test"/> - <assertInstanceOf stepKey="assertInstanceOf" expected="User::class" actual="text" actualType="variable" message="pass"/> - <assertNotInstanceOf stepKey="assertNotInstanceOf" expected="User::class" actual="21" actualType="int" message="pass"/> - <assertFileExists stepKey="assertFileExists2" actual="text" actualType="variable" message="pass"/> - <assertFileExists stepKey="assert6" actual="AssertCest.php" actualType="string" message="pass"/> - <assertIsEmpty stepKey="assertIsEmpty" actual="text" actualType="variable" message="pass"/> - <assertNull stepKey="assertNull" actual="text" actualType="variable" message="pass"/> - <expectException stepKey="expectException" expected="new MyException('exception msg')" actual="function() {$this->doSomethingBad();}"/> - <fail stepKey="fail" message="fail"/> - <fail stepKey="assert7" message="$createData2.firstname$ $createData2.lastname$"/> - <fail stepKey="assert8" message="$$createData1.firstname$$ $$createData1.lastname$$"/> - <!-- comment end --> - <comment stepKey="c5" userInput="comment end"/> - - <deleteData createDataKey="createData2" stepKey="deleteData2"/> + <assertArraySubset stepKey="assert9" message="pass"> + <expectedResult type="array">[$$createData1.lastname$$, $$createData1.firstname$$]</expectedResult> + <actualResult type="array">[$$createData1.lastname$$, $$createData1.firstname$$, 1]</actualResult> + </assertArraySubset> + <assertArraySubset stepKey="assert10" message="pass"> + <expectedResult type="array">[$createData2.firstname$, $createData2.lastname$]</expectedResult> + <actualResult type="array">[$createData2.firstname$, $createData2.lastname$, 1]</actualResult> + </assertArraySubset> + <assertArrayHasKey stepKey="assert3" message="pass"> + <expectedResult type="string">lastname</expectedResult> + <actualResult type="array">['lastname' => $$createData1.lastname$$, 'firstname' => $$createData1.firstname$$]</actualResult> + </assertArrayHasKey> + <assertArrayHasKey stepKey="assert4" message="pass"> + <expectedResult type="string">lastname</expectedResult> + <actualResult type="array">['lastname' => $createData2.lastname$, 'firstname' => $createData2.firstname$]</actualResult> + </assertArrayHasKey> </test> </tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml index 1c2d9a54bef6d..a96f456655049 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/SampleTests/Test/CreateConfigurableProductByApiTest.xml @@ -19,7 +19,7 @@ <createData stepKey="baseConfigProductHandle" entity="BaseConfigurableProduct" > <requiredEntity createDataKey="categoryHandle"/> </createData> - <createData stepKey="productAttributeHandle" entity="productAttributeWithTwoOptions"/> + <createData stepKey="productAttributeHandle" entity="productDropDownAttribute"/> <createData stepKey="productAttributeOption1Handle" entity="productAttributeOption1"> <requiredEntity createDataKey="productAttributeHandle"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Search/Section/StorefrontQuickSearchSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Search/Section/StorefrontQuickSearchSection.xml new file mode 100644 index 0000000000000..5770b43901e23 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Search/Section/StorefrontQuickSearchSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontQuickSearchSection"> + <element name="searchPhrase" type="input" selector="#search"/> + <element name="searchButton" type="button" selector="button.action.search"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Search/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Search/composer.json index 04b875efb6014..fdc828cd35a8a 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Search/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Search/composer.json @@ -11,15 +11,15 @@ "sort-packages": true }, "require": { - "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-testing-framework": "~2.0.0", + "magento/magento2-functional-test-module-catalog-search": "100.0.0-dev", + "magento/magento2-functional-test-module-ui": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog-search": "100.0.0-dev", "magento/magento2-functional-test-module-reports": "100.0.0-dev", - "magento/magento2-functional-test-module-store": "100.0.0-dev", - "magento/magento2-functional-test-module-ui": "100.0.0-dev" + "magento/magento2-functional-test-module-store": "100.0.0-dev" }, "autoload": { "psr-4": { diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/ActionGroup/AdminShipmentActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/ActionGroup/AdminShipmentActionGroup.xml new file mode 100644 index 0000000000000..3f420c2051067 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/ActionGroup/AdminShipmentActionGroup.xml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + + <actionGroup name="verifyBasicShipmentInformation"> + <arguments> + <argument name="customer" defaultValue=""/> + <argument name="shippingAddress" defaultValue=""/> + <argument name="billingAddress" defaultValue=""/> + <argument name="customerGroup" defaultValue="GeneralCustomerGroup"/> + </arguments> + <see selector="{{AdminShipmentOrderInformationSection.customerName}}" userInput="{{customer.firstname}}" stepKey="seeCustomerName"/> + <see selector="{{AdminShipmentOrderInformationSection.customerEmail}}" userInput="{{customer.email}}" stepKey="seeCustomerEmail"/> + <see selector="{{AdminShipmentOrderInformationSection.customerGroup}}" userInput="{{customerGroup.code}}" stepKey="seeCustomerGroup"/> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{billingAddress.street[0]}}" stepKey="seeBillingAddressStreet"/> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{billingAddress.city}}" stepKey="seeBillingAddressCity"/> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{billingAddress.country_id}}" stepKey="seeBillingAddressCountry"/> + <see selector="{{AdminShipmentAddressInformationSection.billingAddress}}" userInput="{{billingAddress.postcode}}" stepKey="seeBillingAddressPostcode"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.street[0]}}" stepKey="seeShippingAddressStreet"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.city}}" stepKey="seeShippingAddressCity"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.country_id}}" stepKey="seeShippingAddressCountry"/> + <see selector="{{AdminShipmentAddressInformationSection.shippingAddress}}" userInput="{{shippingAddress.postcode}}" stepKey="seeShippingAddressPostcode"/> + </actionGroup> + + <actionGroup name="seeProductInShipmentItems"> + <arguments> + <argument name="product"/> + </arguments> + <see selector="{{AdminShipmentItemsSection.skuColumn}}" userInput="{{product.sku}}" stepKey="seeProductSkuInGrid"/> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Data/ShippingMethodData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Data/ShippingMethodData.xml new file mode 100644 index 0000000000000..1c5139a5d7350 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Data/ShippingMethodData.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="DefaultFlatRateMethod" type="shipping"> + <data key="enabled">Yes</data> + <data key="title">Flat Rate</data> + <data key="methodName">Fixed</data> + <data key="type">Per Item</data> + <data key="price">5.00</data> + <data key="calculateHandlingFee">Fixed</data> + <data key="handlingFee">0.00</data> + <data key="errorMessage">This shipping method is not available. To use this shipping method, please contact us.</data> + <data key="applicableCountries">All Allowed Countries</data> + <data key="showIfNotApplicable">No</data> + </entity> +</entities> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Page/AdminShipmentNewPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Page/AdminShipmentNewPage.xml new file mode 100644 index 0000000000000..e1d7f8f451397 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Page/AdminShipmentNewPage.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminShipmentNewPage" url="order_shipment/new/order_id/" area="admin" module="Shipping"> + <section name="AdminShipmentMainActionsSection"/> + <section name="AdminShipmentOrderInformationSection"/> + <section name="AdminShipmentAddressInformationSection"/> + <section name="AdminShipmentPaymentShippingSection"/> + <section name="AdminShipmentItemsSection"/> + <section name="AdminShipmentTotalSection"/> + </page> +</pages> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentAddressInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentAddressInformationSection.xml new file mode 100644 index 0000000000000..ddfd21836b8d6 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentAddressInformationSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminShipmentAddressInformationSection"> + <element name="billingAddress" type="text" selector=".order-billing-address address"/> + <element name="billingAddressEdit" type="button" selector=".order-billing-address .actions a"/> + <element name="shippingAddress" type="text" selector=".order-shipping-address address"/> + <element name="shippingAddressEdit" type="button" selector=".order-shipping-address .actions a"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentItemsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentItemsSection.xml new file mode 100644 index 0000000000000..562ad729fe7f3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentItemsSection.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminShipmentItemsSection"> + <element name="itemName" type="text" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-product .product-title" parameterized="true"/> + <element name="itemSku" type="text" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-product .product-sku-block" parameterized="true"/> + <element name="itemQty" type="text" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-ordered-qty .qty-table" parameterized="true"/> + <element name="itemQtyToShip" type="input" selector=".order-shipment-table tbody:nth-of-type({{row}}) .col-qty input.qty-item"/> + <element name="nameColumn" type="text" selector=".order-shipment-table .col-product .product-title"/> + <element name="skuColumn" type="text" selector=".order-shipment-table .col-product .product-sku-block"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentMainActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentMainActionsSection.xml new file mode 100644 index 0000000000000..5cd843e0ad8c4 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentMainActionsSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminShipmentMainActionsSection"> + <element name="submitShipment" type="button" selector="button.action-default.save.submit-button"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentOrderInformationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentOrderInformationSection.xml new file mode 100644 index 0000000000000..9076ad5c249f9 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentOrderInformationSection.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminShipmentOrderInformationSection"> + <element name="orderId" type="text" selector="div.order-information span.title > a" timeout="30"/> + <element name="orderDate" type="text" selector=".order-information table.order-information-table tr:first-of-type > td"/> + <element name="orderStatus" type="text" selector=".order-information table.order-information-table #order_status"/> + <element name="purchasedFrom" type="text" selector=".order-information table.order-information-table tr:last-of-type > td"/> + <element name="customerName" type="text" selector=".order-account-information table tr:first-of-type > td span"/> + <element name="customerEmail" type="text" selector=".order-account-information table tr:nth-of-type(2) > td a"/> + <element name="customerGroup" type="text" selector=".order-account-information table tr:nth-of-type(3) > td"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentPaymentShippingSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentPaymentShippingSection.xml new file mode 100644 index 0000000000000..a97bb4813917c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentPaymentShippingSection.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminShipmentPaymentShippingSection"> + <element name="PaymentMethod" type="text" selector=".order-payment-method .order-payment-method-title"/> + <element name="CurrencyInformation" type="text" selector=".order-payment-method .order-payment-currency"/> + <element name="PaymentAdditional" type="text" selector=".order-payment-method .order-payment-additional"/> + <element name="ShippingMethod" type="text" selector=".order-shipping-address .shipping-description-title"/> + <element name="ShippingPrice" type="text" selector=".order-shipping-address .shipping-description-content .price"/> + <element name="AddTrackingNumber" type="button" selector="#tracking_numbers_table tfoot [data-ui-id='shipment-tracking-add-button']"/> + <element name="Carrier" type="select" selector="#tracking_numbers_table tr:nth-of-type({{row}}) .col-carrier select" parameterized="true"/> + <element name="Title" type="input" selector="#tracking_numbers_table tr:nth-of-type({{row}}) .col-title input" parameterized="true"/> + <element name="Number" type="input" selector="#tracking_numbers_table tr:nth-of-type({{row}} .col-number input)" parameterized="true"/> + <element name="Delete" type="button" selector="#tracking_numbers_table tr:nth-of-type({{row}} .col-delete button.action-delete)" parameterized="true"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentTotalSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentTotalSection.xml new file mode 100644 index 0000000000000..7496bfbdf228d --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Section/AdminShipmentTotalSection.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminShipmentTotalSection"> + <element name="CommentText" type="textarea" selector="#shipment_comment_text"/> + <element name="AppendComments" type="checkbox" selector=".order-totals input#notify_customer"/> + <element name="EmailCopy" type="checkbox" selector=".order-totals input#send_email"/> + </section> +</sections> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Test/EndToEndB2CAdminTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Test/EndToEndB2CAdminTest.xml new file mode 100644 index 0000000000000..9e5a1c9f26cf9 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Shipping/Test/EndToEndB2CAdminTest.xml @@ -0,0 +1,50 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CAdminTest"> + <!--Ship Order--> + <comment userInput="Admin creates shipment" stepKey="adminCreatesShipmentComment" before="clickShipAction"/> + <click selector="{{AdminOrderDetailsMainActionsSection.ship}}" stepKey="clickShipAction" after="clickOrderIdLinkOnInvoice"/> + <seeInCurrentUrl url="{{AdminShipmentNewPage}}" stepKey="seeOrderShipmentUrl" after="clickShipAction"/> + + <see selector="{{AdminShipmentOrderInformationSection.orderStatus}}" userInput="Processing" stepKey="seeShipmentOrderStatus" after="seeOrderShipmentUrl"/> + <actionGroup ref="verifyBasicShipmentInformation" stepKey="checkBasicShipmentOrderInfo" after="seeShipmentOrderStatus"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="shippingAddress" value="US_Address_TX"/> + <argument name="billingAddress" value="US_Address_TX"/> + </actionGroup> + + <!--Submit Shipment--> + <click selector="{{AdminShipmentMainActionsSection.submitShipment}}" stepKey="clickSubmitShipment" after="checkBasicShipmentOrderInfo"/> + <!--Shipment created successfully--> + <seeInCurrentUrl url="{{AdminOrderDetailsPage}}" stepKey="seeViewOrderPageShipping" after="clickSubmitShipment"/> + <see selector="{{AdminHeaderSection.pageTitle}}" userInput="$getOrderId" stepKey="seeOrderIdInPageNameAfterShip" after="seeViewOrderPageShipping"/> + <see selector="{{AdminOrderDetailsMessagesSection.successMessage}}" userInput="The shipment has been created." stepKey="seeShipmentCreateSuccess" after="seeOrderIdInPageNameAfterShip"/> + <see selector="{{AdminOrderDetailsInformationSection.orderStatus}}" userInput="Complete" stepKey="seeOrderComplete" after="seeShipmentCreateSuccess"/> + <see selector="{{AdminOrderItemsOrderedSection.itemQty('1')}}" userInput="Shipped 1" stepKey="seeShippedQuantity" after="seeOrderComplete"/> + + <click selector="{{AdminOrderDetailsOrderViewSection.shipments}}" stepKey="clickOrderShipmentsTab" after="seeShippedQuantity"/> + <waitForLoadingMaskToDisappear stepKey="waitForShipmentTabLoad" after="clickOrderShipmentsTab"/> + <see selector="{{AdminOrderShipmentsTabSection.gridRow('1')}}" userInput="{{Simple_US_Customer.firstname}}" stepKey="seeOrderShipmentInTabGrid" after="waitForShipmentTabLoad"/> + <click selector="{{AdminOrderShipmentsTabSection.viewGridRow('1')}}" stepKey="clickRowToViewShipment" after="seeOrderShipmentInTabGrid"/> + <see selector="{{AdminShipmentOrderInformationSection.orderId}}" userInput="$getOrderId" stepKey="seeOrderIdOnShipment" after="clickRowToViewShipment"/> + <actionGroup ref="verifyBasicShipmentInformation" stepKey="checkShipmentOrderInformation" after="seeOrderIdOnShipment"> + <argument name="customer" value="Simple_US_Customer"/> + <argument name="shippingAddress" value="US_Address_TX"/> + <argument name="billingAddress" value="US_Address_TX"/> + </actionGroup> + <actionGroup ref="seeProductInShipmentItems" stepKey="seeSimpleProductInShipmentItems" after="checkShipmentOrderInformation"> + <argument name="product" value="SimpleProduct"/> + </actionGroup> + <actionGroup ref="seeProductInShipmentItems" stepKey="seeConfigurableProductInShipmentItems" after="seeSimpleProductInShipmentItems"> + <argument name="product" value="BaseConfigurableProduct"/> + </actionGroup> + <click selector="{{AdminShipmentOrderInformationSection.orderId}}" stepKey="clickOrderIdOnShipment" after="seeConfigurableProductInShipmentItems"/> + </test> +</tests> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/ActionGroup/AdminCreateStoreViewActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/ActionGroup/AdminCreateStoreViewActionGroup.xml index 4cf0e64ed467e..1a532119b66c9 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/ActionGroup/AdminCreateStoreViewActionGroup.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/ActionGroup/AdminCreateStoreViewActionGroup.xml @@ -20,10 +20,9 @@ <fillField selector="{{AdminNewStoreSection.storeCodeTextField}}" userInput="{{customStore.code}}" stepKey="enterStoreViewCode" /> <selectOption selector="{{AdminNewStoreSection.statusDropdown}}" userInput="Enabled" stepKey="setStatus" /> <click selector="{{AdminNewStoreViewActionsSection.saveButton}}" stepKey="clickSaveStoreView" /> - <waitForElementVisible selector=".action-primary.action-accept" stepKey="waitForModal" /> - <seeInSource html="'Warning message'" stepKey="seeWarning" /> - <click selector=".action-primary.action-accept" stepKey="dismissModal" /> - <waitForPageLoad stepKey="waitForPageLoad2"/> + <waitForElementVisible selector="{{AdminConfirmationModalSection.ok}}" stepKey="waitForModal" /> + <see selector="{{AdminConfirmationModalSection.title}}" userInput="Warning message" stepKey="seeWarning" /> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="dismissModal" /> <waitForElementVisible selector="{{AdminStoresGridSection.storeFilterTextField}}" stepKey="waitForPageReolad"/> <see userInput="You saved the store view." stepKey="seeSavedMessage" /> </actionGroup> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/ActionGroup/AdminDeleteStoreViewActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/ActionGroup/AdminDeleteStoreViewActionGroup.xml new file mode 100644 index 0000000000000..2e884ee262e63 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/ActionGroup/AdminDeleteStoreViewActionGroup.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<!-- Test XML Example --> +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <actionGroup name="AdminDeleteStoreViewActionGroup"> + <amOnPage url="{{AdminSystemStorePage.url}}" stepKey="navigateToStoresIndex"/> + <waitForPageLoad stepKey="waitStoreIndexPageLoad" /> + <fillField selector="{{AdminStoresGridSection.storeFilterTextField}}" userInput="{{customStore.name}}" stepKey="fillStoreViewFilterField"/> + <click selector="{{AdminStoresGridSection.searchButton}}" stepKey="clickSearch"/> + <click selector="{{AdminStoresGridSection.storeNameInFirstRow}}" stepKey="clickStoreViewInGrid"/> + <waitForPageLoad stepKey="waitForStoreViewPage"/> + <click selector="{{AdminNewStoreViewActionsSection.delete}}" stepKey="clickDeleteStoreView"/> + <selectOption selector="{{AdminStoreBackupOptionsSection.createBackupSelect}}" userInput="No" stepKey="dontCreateDbBackup"/> + <click selector="{{AdminNewStoreViewActionsSection.delete}}" stepKey="clickDeleteStoreViewAgain"/> + <waitForElementVisible selector="{{AdminConfirmationModalSection.title}}" stepKey="waitingForWarningModal"/> + <click selector="{{AdminConfirmationModalSection.ok}}" stepKey="confirmStoreDelete"/> + <wait time="10" stepKey="extraWait"/> + <see userInput="You deleted the store view." stepKey="seeDeleteMessage"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Data/StoreData.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Data/StoreData.xml index dccc561333ad0..79b1785158c4b 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Data/StoreData.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Data/StoreData.xml @@ -6,6 +6,11 @@ */ --> <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/DataGenerator/etc/dataProfileSchema.xsd"> + <entity name="_defaultStore" type="store"> + <data key="name">Default Store View</data> + <data key="code">default</data> + <data key="is_active">1</data> + </entity> <entity name="customStore" type="store"> <!--data key="group_id">customStoreGroup.id</data--> <data key="name" unique="suffix">store</data> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Page/AdminSystemStoreDeletePage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Page/AdminSystemStoreDeletePage.xml new file mode 100644 index 0000000000000..7b68d3c77e682 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Page/AdminSystemStoreDeletePage.xml @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminSystemStoreDeletePage" url="system_store/deleteStore" module="Store" area="admin"> + <section name="AdminStoreBackupOptionsSection"/> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Page/AdminSystemStoreEditPage.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Page/AdminSystemStoreEditPage.xml new file mode 100644 index 0000000000000..f6533b4494754 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Page/AdminSystemStoreEditPage.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<pages xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/PageObject.xsd"> + <page name="AdminSystemStoreEditPage" url="system_store/editStore" module="Store" area="admin"> + <section name="AdminNewStoreViewMainActionsSection"/> + <section name="AdminNewStoreSection"/> + </page> +</pages> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminNewStoreViewActionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminNewStoreViewActionsSection.xml index 5c731682e427c..f41ae17364a42 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminNewStoreViewActionsSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminNewStoreViewActionsSection.xml @@ -7,8 +7,9 @@ --> <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="AdminNewStoreViewActionsSection"> - <element name="backButton" type="button" selector="#back"/> - <element name="resetButton" type="button" selector="#reset"/> - <element name="saveButton" type="button" selector="#save"/> + <element name="backButton" type="button" selector="#back" timeout="30"/> + <element name="delete" type="button" selector="#delete" timeout="30"/> + <element name="resetButton" type="button" selector="#reset" timeout="30"/> + <element name="saveButton" type="button" selector="#save" timeout="30"/> </section> </sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminStoreBackupOptionsSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminStoreBackupOptionsSection.xml new file mode 100644 index 0000000000000..3767311d76fe7 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminStoreBackupOptionsSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminStoreBackupOptionsSection"> + <element name="createBackupSelect" type="select" selector="select#store_create_backup"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminStoresGridSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminStoresGridSection.xml index eb283ed17b354..b28f9c37485fb 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminStoresGridSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Store/Section/AdminStoresGridSection.xml @@ -10,7 +10,7 @@ <element name="storeGrpFilterTextField" type="input" selector="#storeGrid_filter_group_title"/> <element name="websiteFilterTextField" type="input" selector="#storeGrid_filter_website_title"/> <element name="storeFilterTextField" type="input" selector="#storeGrid_filter_store_title"/> - <element name="searchButton" type="button" selector=".admin__data-grid-header button[title=Search]"/> + <element name="searchButton" type="button" selector=".admin__data-grid-header button[title=Search]" timeout="30"/> <element name="resetButton" type="button" selector="button[title='Reset Filter']"/> <element name="websiteNameInFirstRow" type="text" selector=".col-website_title>a"/> <element name="storeGrpNameInFirstRow" type="text" selector=".col-group_title>a"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Theme/Section/StorefrontFooterSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Theme/Section/StorefrontFooterSection.xml new file mode 100644 index 0000000000000..8fd7d03283df1 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Theme/Section/StorefrontFooterSection.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontFooterSection"> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Theme/Section/StorefrontMessagesSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Theme/Section/StorefrontMessagesSection.xml new file mode 100644 index 0000000000000..981d12d0921a0 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Theme/Section/StorefrontMessagesSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontMessagesSection"> + <element name="message" type="text" + selector="//main//div[contains(@class, 'messages')]//div[contains(@class, 'message')]/div[contains(text(), '{{var1}}')]" + parameterized="true" + /> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Theme/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Theme/composer.json index bc334e7ebc070..b70bf72bfa9e5 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Theme/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Theme/composer.json @@ -11,7 +11,7 @@ "sort-packages": true }, "require": { - "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-testing-framework": "~2.0.0", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/ActionGroup/AdminDataGridFilterActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/ActionGroup/AdminDataGridFilterActionGroup.xml new file mode 100644 index 0000000000000..6c9ee30a970a3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/ActionGroup/AdminDataGridFilterActionGroup.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!--Search grid with keyword search--> + <actionGroup name="searchAdminDataGridByKeyword"> + <arguments> + <argument name="keyword"/> + </arguments> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clickClearFilters"/> + <fillField selector="{{AdminDataGridHeaderSection.search}}" userInput="{{keyword}}" stepKey="fillKeywordSearchField"/> + <click selector="{{AdminDataGridHeaderSection.submitSearch}}" stepKey="clickKeywordSearch"/> + </actionGroup> + + <!--Reset data grid to default view--> + <actionGroup name="resetAdminDataGridToDefaultView"> + <click selector="{{AdminDataGridHeaderSection.bookmarkToggle}}" stepKey="openViewBookmarks"/> + <click selector="{{AdminDataGridHeaderSection.bookmarkOption('Default View')}}" stepKey="selectDefaultGridView"/> + <see selector="{{AdminDataGridHeaderSection.bookmarkToggle}}" userInput="Default View" stepKey="seeDefaultViewSelected"/> + </actionGroup> + + <!--Clear all filters in grid--> + <actionGroup name="clearFiltersAdminDataGrid"> + <conditionalClick selector="{{AdminDataGridHeaderSection.clearFilters}}" dependentSelector="{{AdminDataGridHeaderSection.clearFilters}}" visible="true" stepKey="clearExistingOrderFilters"/> + </actionGroup> +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/ActionGroup/AdminDataGridPaginationActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/ActionGroup/AdminDataGridPaginationActionGroup.xml new file mode 100644 index 0000000000000..e5c81ba34be3d --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/ActionGroup/AdminDataGridPaginationActionGroup.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + + <actionGroup name="adminDataGridSelectPerPage"> + <arguments> + <argument name="perPage"/> + </arguments> + <click selector="{{AdminDataGridPaginationSection.perPageDropdown}}" stepKey="clickPerPageDropdown"/> + <click selector="{{AdminDataGridPaginationSection.perPageOption(perPage)}}" stepKey="selectCustomPerPage"/> + <waitForLoadingMaskToDisappear stepKey="waitForGridLoad"/> + </actionGroup> + + <actionGroup name="adminDataGridSelectCustomPerPage"> + <arguments> + <argument name="perPage"/> + </arguments> + <click selector="{{AdminDataGridPaginationSection.perPageDropdown}}" stepKey="clickPerPageDropdown"/> + <click selector="{{AdminDataGridPaginationSection.perPageOption('Custom')}}" stepKey="selectCustomPerPage"/> + <fillField selector="{{AdminDataGridPaginationSection.perPageInput}}" userInput="{{perPage}}" stepKey="fillCustomPerPage"/> + <click selector="{{AdminDataGridPaginationSection.perPageApplyInput}}" stepKey="applyCustomPerPage"/> + <waitForLoadingMaskToDisappear stepKey="waitForGridLoad"/> + </actionGroup> + +</actionGroups> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/AdminDataGridHeaderSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/AdminDataGridHeaderSection.xml new file mode 100644 index 0000000000000..c383a05fd16f1 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/AdminDataGridHeaderSection.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminDataGridHeaderSection"> + <!--Search by keyword element--> + <element name="search" type="input" selector="#fulltext"/> + <element name="submitSearch" type="button" selector=".data-grid-search-control-wrap > button.action-submit" timeout="30"/> + <!--Filters--> + <element name="filters" type="button" selector="button[data-action='grid-filter-expand']" timeout="30"/> + <element name="filterFieldInput" type="input" selector=".admin__data-grid-filters input[name='{{name}}']" parameterized="true"/> + <element name="filterFieldSelect" type="select" selector=".admin__data-grid-filters select[name='{{name}}']" parameterized="true"/> + <element name="cancelFilters" type="button" selector="button[data-action='grid-filter-cancel']" timeout="30"/> + <element name="applyFilters" type="button" selector="button[data-action='grid-filter-apply']" timeout="30"/> + <element name="clearFilters" type="button" selector=".admin__data-grid-header [data-action='grid-filter-reset']" timeout="30"/> + <!--Grid view bookmarks--> + <element name="bookmarkToggle" type="button" selector="div.admin__data-grid-action-bookmarks button[data-bind='toggleCollapsible']" timeout="30"/> + <element name="bookmarkOption" type="button" selector="//div[contains(@class, 'admin__data-grid-action-bookmarks')]/ul/li/div/a[text() = '{{label}}']" parameterized="true" timeout="30"/> + <!--Visible columns management--> + <element name="columnsToggle" type="button" selector="div.admin__data-grid-action-columns button[data-bind='toggleCollapsible']" timeout="30"/> + <element name="columnCheckbox" type="checkbox" selector="//div[contains(@class,'admin__data-grid-action-columns')]//div[contains(@class, 'admin__field-option')]//label[text() = '{{column}}']/preceding-sibling::input" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/AdminDataGridPaginationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/AdminDataGridPaginationSection.xml new file mode 100644 index 0000000000000..d52d5ee4bb8a3 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/AdminDataGridPaginationSection.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminDataGridPaginationSection"> + <element name="perPageDropdown" type="select" selector=".admin__data-grid-pager-wrap .selectmenu"/> + <element name="perPageOption" type="button" selector="//div[@class='admin__data-grid-pager-wrap']//div[@class='selectmenu-items _active']//li//button[text()='{{label}}']" parameterized="true"/> + <element name="perPageInput" type="input" selector="//div[@class='admin__data-grid-pager-wrap']//div[@class='selectmenu-items _active']//li//div[@class='selectmenu-item-edit']//input"/> + <element name="perPageApplyInput" type="button" selector="//div[@class='admin__data-grid-pager-wrap']//div[@class='selectmenu-items _active']//li//div[@class='selectmenu-item-edit']//button"/> + <element name="nextPage" type="button" selector="div.admin__data-grid-pager > button.action-next" timeout="30"/> + <element name="previousPage" type="button" selector="div.admin__data-grid-pager > button.action-previous" timeout="30"/> + <element name="currentPage" type="input" selector="div.admin__data-grid-pager > input[data-ui-id='current-page-input']"/> + <element name="totalPages" type="text" selector="div.admin__data-grid-pager > label"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/AdminDataGridTableSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/AdminDataGridTableSection.xml new file mode 100644 index 0000000000000..53228559f6d7c --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/AdminDataGridTableSection.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="AdminDataGridTableSection"> + <element name="firstRow" type="button" selector="tr.data-row:nth-of-type(1)"/> + <element name="columnHeader" type="button" selector="//div[@data-role='grid-wrapper']//table[contains(@class, 'data-grid')]/thead/tr/th[contains(@class, 'data-grid-th')]/span[text() = '{{label}}']" parameterized="true" timeout="30"/> + <element name="column" type="text" selector="//tr//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{col}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> + <element name="row" type="text" selector="table.data-grid tbody > tr:nth-of-type({{row}})" parameterized="true"/> + <element name="rows" type="text" selector="table.data-grid tbody > tr.data-row"/> + <!--Specific cell e.g. {{Section.gridCell('1', 'Name')}}--> + <element name="gridCell" type="text" selector="//tr[{{row}}]//td[count(//div[@data-role='grid-wrapper']//tr//th[contains(., '{{column}}')]/preceding-sibling::th) +1 ]" parameterized="true"/> + <element name="rowViewAction" type="button" selector=".data-grid tbody > tr:nth-of-type({{row}}) .action-menu-item" parameterized="true" timeout="30"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/ModalConfirmationSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/ModalConfirmationSection.xml new file mode 100644 index 0000000000000..146aea30f4633 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Ui/Section/ModalConfirmationSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="ModalConfirmationSection"> + <element name="CancelButton" type="button" selector="//footer[@class='modal-footer']/button[contains(@class, 'action-dismiss')]"/> + <element name="OkButton" type="button" selector="//footer[@class='modal-footer']/button[contains(@class, 'action-accept')]"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/ActionGroup/StorefrontCustomerWishlistActionGroup.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/ActionGroup/StorefrontCustomerWishlistActionGroup.xml new file mode 100644 index 0000000000000..122bfbe4cc1c5 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/ActionGroup/StorefrontCustomerWishlistActionGroup.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<actionGroups xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/actionGroupSchema.xsd"> + <!-- Add Product to wishlist from the category page and check message --> + <actionGroup name="StorefrontCustomerAddCategoryProductToWishlistActionGroup"> + <arguments> + <argument name="productVar"/> + </arguments> + <moveMouseOver selector="{{StorefrontCategoryProductSection.ProductInfoByName(productVar.name)}}" stepKey="addCategoryProductToWishlistMoveMouseOverProduct" /> + <click selector="{{StorefrontCategoryProductSection.ProductAddToWishlistByName(productVar.name)}}" stepKey="addCategoryProductToWishlistClickAddProductToWishlist"/> + <waitForElement selector="{{StorefrontCustomerWishlistSection.successMsg}}" time="30" stepKey="addCategoryProductToWishlistWaitForSuccessMessage"/> + <see selector="{{StorefrontCustomerWishlistSection.successMsg}}" userInput="{{productVar.name}} has been added to your Wish List." stepKey="addCategoryProductToWishlistSeeProductNameAddedToWishlist"/> + <seeCurrentUrlMatches regex="~/wishlist_id/\d+/$~" stepKey="seeCurrentUrlMatches"/> + </actionGroup> + + <!-- Add Product to wishlist from the product page and check message --> + <actionGroup name="StorefrontCustomerAddProductToWishlistActionGroup"> + <arguments> + <argument name="productVar"/> + </arguments> + <click selector="{{StorefrontProductInfoMainSection.productAddToWishlist}}" stepKey="addProductToWishlistClickAddToWishlist" /> + <waitForElement selector="{{StorefrontCustomerWishlistSection.successMsg}}" time="30" stepKey="addProductToWishlistWaitForSuccessMessage"/> + <see selector="{{StorefrontCustomerWishlistSection.successMsg}}" userInput="{{productVar.name}} has been added to your Wish List." stepKey="addProductToWishlistSeeProductNameAddedToWishlist"/> + <seeCurrentUrlMatches regex="~/wishlist_id/\d+/$~" stepKey="seeCurrentUrlMatches"/> + </actionGroup> + + <!-- Check product in wishlist --> + <actionGroup name="StorefrontCustomerCheckProductInWishlist"> + <arguments> + <argument name="productVar"/> + </arguments> + <waitForElement selector="{{StorefrontCustomerWishlistProductSection.ProductTitleByName(productVar.name)}}" time="30" stepKey="assertWishlistProductName"/> + <see userInput="${{productVar.price}}.00" selector="{{StorefrontCustomerWishlistProductSection.ProductPriceByName(productVar.name)}}" stepKey="AssertWishlistProductPrice"/> + <moveMouseOver selector="{{StorefrontCustomerWishlistProductSection.ProductInfoByName(productVar.name)}}" stepKey="wishlistMoveMouseOverProduct" /> + <seeElement selector="{{StorefrontCustomerWishlistProductSection.ProductAddToCartByName(productVar.name)}}" stepKey="AssertWishlistAddToCart" /> + <seeElement selector="{{StorefrontCustomerWishlistProductSection.ProductImageByName(productVar.name)}}" stepKey="AssertWishlistProductImage" /> + </actionGroup> + + <!-- Check product in wishlist sidebar --> + <actionGroup name="StorefrontCustomerCheckProductInWishlistSidebar"> + <arguments> + <argument name="productVar"/> + </arguments> + <waitForElement selector="{{StorefrontCustomerWishlistSidebarSection.ProductTitleByName(productVar.name)}}" time="30" stepKey="assertWishlistSidebarProductName"/> + <see userInput="${{productVar.price}}.00" selector="{{StorefrontCustomerWishlistSidebarSection.ProductPriceByName(productVar.name)}}" stepKey="AssertWishlistSidebarProductPrice"/> + <seeElement selector="{{StorefrontCustomerWishlistSidebarSection.ProductAddToCartByName(productVar.name)}}" stepKey="AssertWishlistSidebarAddToCart" /> + <seeElement selector="{{StorefrontCustomerWishlistSidebarSection.ProductImageByName(productVar.name)}}" stepKey="AssertWishlistSidebarProductImage" /> + </actionGroup> +</actionGroups> \ No newline at end of file diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCategoryProductSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCategoryProductSection.xml new file mode 100644 index 0000000000000..7229b596ddb19 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCategoryProductSection.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontCategoryProductSection"> + <element name="ProductAddToWishlistByNumber" type="text" selector="//main//li[{{var1}}]//a[contains(@class, 'towishlist')]" parameterized="true"/> + <element name="ProductAddToWishlistByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//a[contains(@class, 'towishlist')]" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCustomerWishlistProductSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCustomerWishlistProductSection.xml new file mode 100644 index 0000000000000..94681db830dd5 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCustomerWishlistProductSection.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontCustomerWishlistProductSection"> + <element name="ProductTitleByName" type="button" selector="//main//li//a[contains(text(), '{{var1}}')]" parameterized="true"/> + <element name="ProductPriceByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//span[@class='price']" parameterized="true"/> + <element name="ProductImageByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//img[@class='product-image-photo']" parameterized="true"/> + <element name="ProductInfoByName" type="text" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//div[@class='product-item-info']" parameterized="true"/> + <element name="ProductAddToCartByName" type="button" selector="//main//li[.//a[contains(text(), '{{var1}}')]]//button[contains(@class, 'action tocart primary')]" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCustomerWishlistSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCustomerWishlistSection.xml index 6111c744a30b7..5a311f2a05d40 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCustomerWishlistSection.xml +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCustomerWishlistSection.xml @@ -9,6 +9,8 @@ <sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> <section name="StorefrontCustomerWishlistSection"> + <element name="pageTitle" type="text" selector="h1.page-title"/> + <element name="successMsg" type="text" selector="div.message-success.success.message"/> <element name="productItemNameText" type="text" selector=".products-grid .product-item-name a"/> <element name="removeWishlistButton" type="button" selector=".products-grid .btn-remove.action.delete>span" timeout="30"/> <element name="emptyWishlistText" type="text" selector=".message.info.empty>span"/> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCustomerWishlistSidebarSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCustomerWishlistSidebarSection.xml new file mode 100644 index 0000000000000..d4a81137dbc86 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontCustomerWishlistSidebarSection.xml @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontCustomerWishlistSidebarSection"> + <element name="ProductTitleByName" type="button" selector="//main//ol[@id='wishlist-sidebar']//a[@class='product-item-link']/span[text()='{{var1}}']" parameterized="true"/> + <element name="ProductPriceByName" type="text" selector="//main//ol[@id='wishlist-sidebar']//a[@class='product-item-link']/span[text()='{{var1}}']//ancestor::ol//span[@class='price']" parameterized="true"/> + <element name="ProductImageByName" type="text" selector="//main//ol[@id='wishlist-sidebar']//a[@class='product-item-link']/span[text()='{{var1}}']//ancestor::ol//img[@class='product-image-photo']" parameterized="true"/> + <element name="ProductAddToCartByName" type="button" selector="//main//ol[@id='wishlist-sidebar']//a[@class='product-item-link']/span[text()='{{var1}}']//ancestor::ol//button[contains(@class, 'action tocart primary')]" parameterized="true"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontProductInfoMainSection.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontProductInfoMainSection.xml new file mode 100644 index 0000000000000..d8e16ce9a4481 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Section/StorefrontProductInfoMainSection.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd"> + <section name="StorefrontProductInfoMainSection"> + <element name="productAddToWishlist" type="button" selector="a.action.towishlist"/> + </section> +</sections> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Test/EndToEndB2CLoggedInUserTest.xml b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Test/EndToEndB2CLoggedInUserTest.xml new file mode 100644 index 0000000000000..b5a43fc471127 --- /dev/null +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/Test/EndToEndB2CLoggedInUserTest.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + /** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> + +<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Test/etc/testSchema.xsd"> + <test name="EndToEndB2CLoggedInUserTest"> + <!-- Step 5: Add products to wishlist --> + <comment userInput="Start of adding products to wishlist" stepKey="startOfAddingProductsToWishlist" after="endOfComparingProducts" /> + <!-- Add Simple Product 1 to wishlist --> + <comment userInput="Add Simple Product 1 to wishlist" stepKey="commentAddSimpleProduct1ToWishlist" after="startOfAddingProductsToWishlist" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" after="commentAddSimpleProduct1ToWishlist" stepKey="wishlistGotoCategory1"/> + <actionGroup ref="StorefrontCustomerAddCategoryProductToWishlistActionGroup" after="wishlistGotoCategory1" stepKey="wishlistAddSimpleProduct1ToWishlist"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + <actionGroup ref="StorefrontCustomerCheckProductInWishlist" after="wishlistAddSimpleProduct1ToWishlist" stepKey="wishlistCheckSimpleProduct1InWishlist"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + <actionGroup ref="StorefrontCustomerCheckProductInWishlistSidebar" after="wishlistCheckSimpleProduct1InWishlist" stepKey="wishlistCheckSimpleProduct1InWishlistSidebar"> + <argument name="productVar" value="$$createSimpleProduct1$$"/> + </actionGroup> + + <!-- Add Simple Product 2 to wishlist --> + <comment userInput="Add Simple Product 2 to wishlist" stepKey="commentAddSimpleProduct2ToWishlist" after="wishlistCheckSimpleProduct1InWishlistSidebar" /> + <click selector="{{StorefrontHeaderSection.NavigationCategoryByName($$createCategory.name$$)}}" after="commentAddSimpleProduct2ToWishlist" stepKey="wishlistGotoCategory2"/> + <click selector="{{StorefrontCategoryProductSection.ProductTitleByName($$createSimpleProduct2.name$$)}}" after="wishlistGotoCategory2" stepKey="wishlistClickSimpleProduct2"/> + <actionGroup ref="StorefrontCustomerAddProductToWishlistActionGroup" after="wishlistClickSimpleProduct2" stepKey="wishlistAddSimpleProduct2ToWishlist"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + <actionGroup ref="StorefrontCustomerCheckProductInWishlist" after="wishlistAddSimpleProduct2ToWishlist" stepKey="wishlistCheckSimpleProduct2InWishlist"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + <actionGroup ref="StorefrontCustomerCheckProductInWishlistSidebar" after="wishlistCheckSimpleProduct2InWishlist" stepKey="wishlistCheckSimpleProduct2InWishlistSidebar"> + <argument name="productVar" value="$$createSimpleProduct2$$"/> + </actionGroup> + <comment userInput="End of adding products to wishlist" after="wishlistCheckSimpleProduct2InWishlistSidebar" stepKey="endOfAddingProductsToWishlist" /> + </test> +</tests> diff --git a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/composer.json b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/composer.json index 660d4ce34c3be..91bdd392c8863 100644 --- a/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/composer.json +++ b/dev/tests/acceptance/tests/functional/Magento/FunctionalTest/Wishlist/composer.json @@ -12,14 +12,15 @@ }, "require": { "magento/magento2-functional-testing-framework": "1.0.0", + "magento/magento2-functional-test-module-catalog": "100.0.0-dev", + "magento/magento2-functional-test-module-checkout": "100.0.0-dev", + "magento/magento2-functional-test-module-customer": "100.0.0-dev", "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" }, "suggest": { "magento/magento2-functional-test-module-backend": "100.0.0-dev", - "magento/magento2-functional-test-module-catalog": "100.0.0-dev", "magento/magento2-functional-test-module-catalog-inventory": "100.0.0-dev", - "magento/magento2-functional-test-module-checkout": "100.0.0-dev", - "magento/magento2-functional-test-module-customer": "100.0.0-dev", + "magento/magento2-functional-test-module-configurable-product": "100.0.0-dev", "magento/magento2-functional-test-module-rss": "100.0.0-dev", "magento/magento2-functional-test-module-sales": "100.0.0-dev", "magento/magento2-functional-test-module-store": "100.0.0-dev", diff --git a/dev/tests/acceptance/utils/command.php b/dev/tests/acceptance/utils/command.php index 3a1ae54bda8b2..943e2e9776af4 100644 --- a/dev/tests/acceptance/utils/command.php +++ b/dev/tests/acceptance/utils/command.php @@ -17,11 +17,11 @@ } echo implode("\n", $output); } else { - http_response_code(500); + http_response_code(403); echo "Given command not found valid in Magento CLI Command list."; } } else { - http_response_code(500); + http_response_code(412); echo("Command parameter is not set."); } diff --git a/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml index f0226e0745afa..a649cb9c357ff 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule1/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModule1" setup_version="1.0"/> + <module name="Magento_TestModule1" /> </config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml index b2d84c04a8caf..93312a82384cc 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule2/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModule2" setup_version="1.0"/> + <module name="Magento_TestModule2" /> </config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml index 8863cb69e1fcc..f7940be3e768c 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule3/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModule3" setup_version="1.0"/> + <module name="Magento_TestModule3" /> </config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml index 11732fbd97aed..3a5670ccd54b0 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule4/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModule4" setup_version="1.0"/> + <module name="Magento_TestModule4" /> </config> diff --git a/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml index 1f735f68b1bf6..31c70e18a7935 100644 --- a/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModule5/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModule5" setup_version="1.0"/> + <module name="Magento_TestModule5" /> </config> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/db_schema.xml b/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/db_schema.xml index 778a4fb76d8cd..d9bba3ca5dbe8 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/db_schema.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="testmodule_default_hydrator_extension_attribute_entity" resource="default" engine="innodb"> <column xsi:type="int" name="entity_id" padding="10" unsigned="true" nullable="false" identity="true"/> <column xsi:type="int" name="customer_id" padding="10" unsigned="true" nullable="false" identity="false"/> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/module.xml index 3d10999829bf3..ca4ded8ff3190 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleDefaultHydrator/etc/module.xml @@ -1,11 +1,11 @@ <?xml version="1.0"?> <!-- /** - * Copyright © 2015 Magento. All rights reserved. + * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Module/etc/module.xsd"> - <module name="Magento_TestModuleDefaultHydrator" setup_version="2.0.0"> + <module name="Magento_TestModuleDefaultHydrator"> </module> </config> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleGraphQlQuery/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleGraphQlQuery/etc/module.xml index 5202dce8ce595..c4ad9ac7f3876 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleGraphQlQuery/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleGraphQlQuery/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModuleGraphQlQuery" setup_version="1.0"/> + <module name="Magento_TestModuleGraphQlQuery" /> </config> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleGraphQlQueryExtension/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleGraphQlQueryExtension/etc/module.xml index 419d1e92fe9ce..e6a8affe747eb 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleGraphQlQueryExtension/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleGraphQlQueryExtension/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModuleGraphQlQueryExtension" setup_version="1.0"/> + <module name="Magento_TestModuleGraphQlQueryExtension" /> </config> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/etc/module.xml index eaf0f69a596fa..cd78d204dc9ae 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleIntegrationFromConfig/etc/module.xml @@ -6,6 +6,6 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModuleIntegrationFromConfig" setup_version="0.0.1" active="true"> + <module name="Magento_TestModuleIntegrationFromConfig" active="true"> </module> </config> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/module.xml index e5ab9c1860103..afb3a091f5fb6 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleJoinDirectives/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModuleJoinDirectives" setup_version="1.0"/> + <module name="Magento_TestModuleJoinDirectives" /> </config> diff --git a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml index 4ebbe995e020e..1e3752b1e93ff 100644 --- a/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml +++ b/dev/tests/api-functional/_files/Magento/TestModuleMSC/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModuleMSC" setup_version="1.0"/> + <module name="Magento_TestModuleMSC" /> </config> diff --git a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php index 47499d56e776f..32e33e8ed9bf2 100644 --- a/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Sales/Service/V1/ShipOrderTest.php @@ -33,26 +33,59 @@ protected function setUp() } /** - * @magentoApiDataFixture Magento/Sales/_files/order_new.php + * @magentoApiDataFixture Magento/Sales/_files/order_configurable_product.php */ - public function testShipOrder() + public function testConfigurableShipOrder() { + $productsQuantity = 1; + /** @var \Magento\Sales\Model\Order $existingOrder */ $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) ->loadByIncrementId('100000001'); - $serviceInfo = [ - 'rest' => [ - 'resourcePath' => '/V1/order/' . $existingOrder->getId() . '/ship', - 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, - ], - 'soap' => [ - 'service' => self::SERVICE_READ_NAME, - 'serviceVersion' => self::SERVICE_VERSION, - 'operation' => self::SERVICE_READ_NAME . 'execute', - ], + $requestData = [ + 'orderId' => $existingOrder->getId(), ]; + $shipmentId = (int)$this->_webApiCall($this->getServiceInfo($existingOrder), $requestData); + $this->assertNotEmpty($shipmentId); + + try { + $shipment = $this->shipmentRepository->get($shipmentId); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + $this->fail('Failed asserting that Shipment was created'); + } + + $orderedQty = 0; + /** @var \Magento\Sales\Model\Order\Item $item */ + foreach ($existingOrder->getItems() as $item) { + if ($item->isDummy(true)) { + continue; + } + $orderedQty += $item->getQtyOrdered(); + } + + $this->assertEquals( + (int)$shipment->getTotalQty(), + (int)$orderedQty, + 'Failed asserting that quantity of ordered and shipped items is equal' + ); + $this->assertEquals( + $productsQuantity, + count($shipment->getItems()), + 'Failed asserting that quantity of products and sales shipment items is equal' + ); + } + + /** + * @magentoApiDataFixture Magento/Sales/_files/order_new.php + */ + public function testShipOrder() + { + /** @var \Magento\Sales\Model\Order $existingOrder */ + $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId('100000001'); + $requestData = [ 'orderId' => $existingOrder->getId(), 'items' => [], @@ -77,7 +110,7 @@ public function testShipOrder() ]; } - $result = $this->_webApiCall($serviceInfo, $requestData); + $result = $this->_webApiCall($this->getServiceInfo($existingOrder), $requestData); $this->assertNotEmpty($result); @@ -97,4 +130,85 @@ public function testShipOrder() 'Failed asserting that Order status was changed' ); } + + /** + * @magentoApiDataFixture Magento/Bundle/_files/order_with_bundle_shipped_separately.php + */ + public function testPartialShipOrderWithBundleShippedSeparately() + { + /** @var \Magento\Sales\Model\Order $existingOrder */ + $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId('100000001'); + + $requestData = [ + 'orderId' => $existingOrder->getId(), + 'items' => [], + 'comment' => [ + 'comment' => 'Test Comment', + 'is_visible_on_front' => 1, + ], + 'tracks' => [ + [ + 'track_number' => 'TEST_TRACK_0001', + 'title' => 'Simple shipment track', + 'carrier_code' => 'UPS' + ] + ] + ]; + + $shippedItemId = null; + foreach ($existingOrder->getAllItems() as $item) { + if ($item->getProductType() == 'simple') { + $requestData['items'][] = [ + 'order_item_id' => $item->getItemId(), + 'qty' => $item->getQtyOrdered(), + ]; + $shippedItemId = $item->getItemId(); + break; + } + } + + $shipmentId = $this->_webApiCall($this->getServiceInfo($existingOrder), $requestData); + $this->assertNotEmpty($shipmentId); + + try { + $shipment = $this->shipmentRepository->get($shipmentId); + } catch (\Magento\Framework\Exception\NoSuchEntityException $e) { + $this->fail('Failed asserting that Shipment was created'); + } + + $this->assertEquals(1, $shipment->getTotalQty()); + + /** @var \Magento\Sales\Model\Order $existingOrder */ + $existingOrder = $this->objectManager->create(\Magento\Sales\Model\Order::class) + ->loadByIncrementId('100000001'); + + foreach ($existingOrder->getAllItems() as $item) { + if ($item->getItemId() == $shippedItemId) { + $this->assertEquals(1, $item->getQtyShipped()); + continue; + } + $this->assertEquals(0, $item->getQtyShipped()); + } + } + + /** + * @param \Magento\Sales\Model\Order $order + * @return array + */ + private function getServiceInfo(\Magento\Sales\Model\Order $order) + { + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => '/V1/order/' . $order->getId() . '/ship', + 'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_READ_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_READ_NAME . 'execute', + ], + ]; + return $serviceInfo; + } } diff --git a/dev/tests/functional/bootstrap.php b/dev/tests/functional/bootstrap.php index 3c0fd4cc388cc..9967697124e80 100644 --- a/dev/tests/functional/bootstrap.php +++ b/dev/tests/functional/bootstrap.php @@ -51,7 +51,7 @@ function ($errNo, $errStr, $errFile, $errLine) { $errName = isset($errorNames[$errNo]) ? $errorNames[$errNo] : ""; - throw new \PHPUnit_Framework_Exception( + throw new \PHPUnit\Framework\Exception( sprintf("%s: %s in %s:%s.", $errName, $errStr, $errFile, $errLine), $errNo ); diff --git a/dev/tests/functional/composer.json b/dev/tests/functional/composer.json index 0c9f329f234a8..ff38d0d01ac0e 100644 --- a/dev/tests/functional/composer.json +++ b/dev/tests/functional/composer.json @@ -3,12 +3,12 @@ "sort-packages": true }, "require": { - "php": "7.0.2|~7.0.6|~7.1.0", - "magento/mtf": "1.0.0-rc59", + "php": "7.0.2|~7.0.6|~7.1.0|~7.2.0", + "magento/mtf": "1.0.0-rc60", "allure-framework/allure-phpunit": "~1.2.0", "doctrine/annotations": "1.4.*", - "phpunit/phpunit": "~4.8.0|~5.5.0", - "phpunit/phpunit-selenium": ">=1.2" + "phpunit/phpunit": "~6.5.0", + "phpunit/phpunit-selenium": "~4.1.0" }, "suggest": { "netwing/selenium-server-standalone": "dev-master", diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/AdminAnalyzer.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/AdminAnalyzer.php index 3d34dec8d5d01..6ba3ca6da5287 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/AdminAnalyzer.php +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/AdminAnalyzer.php @@ -74,7 +74,7 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - \PHPUnit_Util_Configuration::getInstance(MTF_PHPUNIT_FILE)->handlePHPConfiguration(); + \PHPUnit\Util\Configuration::getInstance(MTF_PHPUNIT_FILE)->handlePHPConfiguration(); $this->output = $this->objectManager->create( \Magento\Mtf\Console\Output::class, ['output' => $output] diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/HtaccessAnalyzer.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/HtaccessAnalyzer.php index 3965b44070b73..5095c725b87f1 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/HtaccessAnalyzer.php +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/HtaccessAnalyzer.php @@ -73,7 +73,7 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - \PHPUnit_Util_Configuration::getInstance(MTF_PHPUNIT_FILE)->handlePHPConfiguration(); + \PHPUnit\Util\Configuration::getInstance(MTF_PHPUNIT_FILE)->handlePHPConfiguration(); $output = $this->objectManager->create( \Magento\Mtf\Console\Output::class, ['output' => $output] diff --git a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/StorefrontAnalyzer.php b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/StorefrontAnalyzer.php index 355b0ce34e3c1..990482d77bd20 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/StorefrontAnalyzer.php +++ b/dev/tests/functional/lib/Magento/Mtf/Troubleshooting/StorefrontAnalyzer.php @@ -77,7 +77,7 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - \PHPUnit_Util_Configuration::getInstance(MTF_PHPUNIT_FILE)->handlePHPConfiguration(); + \PHPUnit\Util\Configuration::getInstance(MTF_PHPUNIT_FILE)->handlePHPConfiguration(); $output = $this->objectManager->create( \Magento\Mtf\Console\Output::class, ['output' => $output] diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory/AbstractFactory.php b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory/AbstractFactory.php index b099e8a6c10e0..e48366f9a3645 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory/AbstractFactory.php +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/Factory/AbstractFactory.php @@ -209,7 +209,7 @@ protected function _processItem(& $items, & $rewrites, $filename, $location, $pa if ($reflectionClass->isAbstract()) { return; } - $annotations = \PHPUnit_Util_Test::parseTestMethodAnnotations($className); + $annotations = \PHPUnit\Util\Test::parseTestMethodAnnotations($className); list(, $targetClassName) = explode($location . '/', $filename); $targetClassName = str_replace('.php', '', $targetClassName); diff --git a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertExportAdvancedPricing.php b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertExportAdvancedPricing.php index 577d5e2a4fd8f..565d0f432bdaf 100644 --- a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertExportAdvancedPricing.php +++ b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertExportAdvancedPricing.php @@ -37,7 +37,7 @@ public function processAssert( $this->exportData = $export->getLatest(); foreach ($products as $product) { $regexps = $this->prepareRegexpsForCheck($exportedFields, $product); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->isProductDataExists($regexps), 'A product with name ' . $product->getName() . ' was not found in exported file.' ); diff --git a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertImportAdvancedPricing.php b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertImportAdvancedPricing.php index 6fd3389aaeb01..6119dd0cbc891 100644 --- a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertImportAdvancedPricing.php +++ b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertImportAdvancedPricing.php @@ -59,7 +59,7 @@ public function processAssert( $resultArrays = $this->getPreparePrices(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $resultArrays['pageData'], $resultArrays['csvData'], 'Tier prices from page and csv are not match.' diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php index de379aea85fa7..01617cd1dcc80 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertAdvancedReportingPage.php @@ -31,7 +31,7 @@ public function processAssert(BrowserInterface $browser, $advancedReportingLink) { $this->browser = $browser; $this->browser->selectWindow(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->browser->waitUntil( function () use ($advancedReportingLink) { return ($this->browser->getUrl() === $advancedReportingLink) ? true : null; diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php index 010d9c446819d..dbeea7083d4f6 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertBIEssentialsLink.php @@ -67,7 +67,7 @@ public function processAssert( } } while ($count < self::MAX_TRY_COUNT); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isVisible, "BI Essentials Sign Up page was not opened by link.\n Actual link is '{$this->browser->getUrl()}'\n diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php index 0f65835a32aa7..e793091a819eb 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsDisabled.php @@ -25,11 +25,11 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon { $openAnalyticsConfigStep->run(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), 'Magento Advanced Reporting service is not disabled.' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), 'Subscription status: Disabled', 'Magento Advanced Reporting service subscription status is not disabled.' diff --git a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php index 8fd04e06b14bb..b26b01477940f 100644 --- a/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php +++ b/dev/tests/functional/tests/app/Magento/Analytics/Test/Constraint/AssertConfigAnalyticsEnabled.php @@ -25,12 +25,12 @@ public function processAssert(ConfigAnalytics $configAnalytics, OpenAnalyticsCon { $openAnalyticsConfigStep->run(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( (bool)$configAnalytics->getAnalyticsForm()->isAnalyticsEnabled(), 'Magento Advanced Reporting service is not enabled.' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $configAnalytics->getAnalyticsForm()->getAnalyticsStatus(), 'Subscription status: Pending', 'Magento Advanced Reporting service subscription status is not pending.' diff --git a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Constraint/AssertCreditCardNumberOnOnePageCheckout.php b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Constraint/AssertCreditCardNumberOnOnePageCheckout.php index d4abb6efd2edb..cd1dfce621806 100644 --- a/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Constraint/AssertCreditCardNumberOnOnePageCheckout.php +++ b/dev/tests/functional/tests/app/Magento/Authorizenet/Test/Constraint/AssertCreditCardNumberOnOnePageCheckout.php @@ -24,7 +24,7 @@ class AssertCreditCardNumberOnOnePageCheckout extends AbstractConstraint */ public function processAssert(CheckoutOnepage $checkoutOnepage, CreditCard $creditCard) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $creditCard->getCcNumber(), $checkoutOnepage->getAuthorizenetBlock()->getCCNumber(), 'Credit card data did persist with the values from fixture' diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/StoreGrid.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/StoreGrid.php index ae3857d8e4f6d..87a3ed048dbb9 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/StoreGrid.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/StoreGrid.php @@ -99,6 +99,18 @@ public function searchAndOpenWebsite(Website $website) $this->_rootElement->find(sprintf($this->storeName, $websiteName), Locator::SELECTOR_XPATH)->click(); } + /** + * Search and open appropriate Website by name. + * + * @param string $websiteName + * @return void + */ + public function searchAndOpenWebsiteByName($websiteName) + { + $this->search(['website_title' => $websiteName]); + $this->_rootElement->find(sprintf($this->storeName, $websiteName), Locator::SELECTOR_XPATH)->click(); + } + /** * Search and open appropriate Store View. * diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertAdminLoginPageIsAvailable.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertAdminLoginPageIsAvailable.php index 4fbd1b9e3077b..52a498e13e515 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertAdminLoginPageIsAvailable.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertAdminLoginPageIsAvailable.php @@ -23,7 +23,7 @@ class AssertAdminLoginPageIsAvailable extends AbstractConstraint public function processAssert(AdminAuthLogin $adminAuthLogin) { $adminAuthLogin->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $adminAuthLogin->getLoginBlock()->isVisible(), 'Admin session does not expire properly.' ); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertBackendPageIsAvailable.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertBackendPageIsAvailable.php index 5fa7780ba79ec..40048e8cc646c 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertBackendPageIsAvailable.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertBackendPageIsAvailable.php @@ -25,12 +25,12 @@ class AssertBackendPageIsAvailable extends AbstractConstraint */ public function processAssert(Dashboard $dashboard, $pageTitle) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $pageTitle, $dashboard->getTitleBlock()->getTitle(), 'Invalid page title is displayed.' ); - \PHPUnit_Framework_Assert::assertNotContains( + \PHPUnit\Framework\Assert::assertNotContains( self::ERROR_TEXT, $dashboard->getErrorBlock()->getContent(), "404 Error is displayed on '$pageTitle' page." diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertBestsellersOnDashboard.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertBestsellersOnDashboard.php index 58a4521590ec0..4e792cd3aedf8 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertBestsellersOnDashboard.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertBestsellersOnDashboard.php @@ -34,7 +34,7 @@ public function processAssert(OrderInjectable $order, Dashboard $dashboard) $bestsellersGrid = $dashboard->getStoreStatsBlock()->getTab('bestsellers')->getBestsellersGrid(); $products = $order->getEntityId()['products']; foreach ($products as $product) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $bestsellersGrid->isProductVisible($product), 'Bestseller ' . $product->getName() . ' is not present in report grid after refresh data.' ); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertDeveloperSectionVisibility.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertDeveloperSectionVisibility.php index e443ef5a205e4..010b3a58134aa 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertDeveloperSectionVisibility.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertDeveloperSectionVisibility.php @@ -41,23 +41,23 @@ public function processAssert(SystemConfigEdit $configEdit) $configEdit->open(); if ($_ENV['mage_mode'] === 'production') { foreach ($this->groups as $group) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $configEdit->getForm()->isGroupVisible('dev', $group), sprintf('%s group should be hidden in production mode.', $group) ); } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $configEdit->getForm()->getGroup('dev', 'debug')->isFieldVisible('dev', 'debug_debug', 'logging'), '"Log to File" should be presented in production mode.' ); } else { foreach ($this->groups as $group) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $configEdit->getForm()->isGroupVisible('dev', $group), sprintf('%s group should be visible in developer mode.', $group) ); } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $configEdit->getForm()->isGroupVisible('dev', 'debug'), 'Debug group should be visible in developer mode.' ); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchCustomerName.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchCustomerName.php index ebdf71e6a289b..842043a585024 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchCustomerName.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchCustomerName.php @@ -30,18 +30,18 @@ public function processAssert(Dashboard $dashboard, GlobalSearch $search, Custom $customer = $search->getDataFieldConfig('query')['source']->getEntity(); $customerName = $customer->getFirstname() . " " . $customer->getLastname(); $isVisibleInResult = $dashboard->getAdminPanelHeader()->isSearchResultVisible($customerName); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isVisibleInResult, 'Customer name ' . $customerName . ' is absent in search results' ); $dashboard->getAdminPanelHeader()->navigateToGrid("Customers"); $isCustomerGridVisible = $customerIndex->getCustomerGridBlock()->isVisible(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isCustomerGridVisible, 'Customer grid is not visible' ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( (string) $customer->getId(), $customerIndex->getCustomerGridBlock()->getAllIds(), 'Customer grid does not have ' . $customerName . ' in search results' diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchNoRecordsFound.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchNoRecordsFound.php index 42639f1b62e56..c7cd0f19131ce 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchNoRecordsFound.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchNoRecordsFound.php @@ -29,7 +29,7 @@ class AssertGlobalSearchNoRecordsFound extends AbstractConstraint public function processAssert(Dashboard $dashboard) { $isVisibleInResult = $dashboard->getAdminPanelHeader()->isSearchResultVisible(self::EXPECTED_RESULT); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isVisibleInResult, 'Expected text ' . self::EXPECTED_RESULT . ' is absent in search results' ); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchOrderId.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchOrderId.php index b3a1f382da419..63bf2c9c3a019 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchOrderId.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchOrderId.php @@ -30,7 +30,7 @@ public function processAssert(Dashboard $dashboard, GlobalSearch $search, OrderI $order = $search->getDataFieldConfig('query')['source']->getEntity(); $orderId = "Order #" . $order->getId(); $isVisibleInResult = $dashboard->getAdminPanelHeader()->isSearchResultVisible($orderId); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isVisibleInResult, 'Order Id ' . $order->getId() . ' is absent in search results' ); @@ -38,11 +38,11 @@ public function processAssert(Dashboard $dashboard, GlobalSearch $search, OrderI $dashboard->getAdminPanelHeader()->navigateToGrid("Orders"); $isOrderGridVisible = $orderIndex->getSalesOrderGrid()->isVisible(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isOrderGridVisible, 'Order grid is not visible' ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( (string) $order->getId(), $orderIndex->getSalesOrderGrid()->getAllIds(), 'Order grid does not have ' . $order->getId() . ' in search results' diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchPreview.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchPreview.php index 8c9668f35dde2..4f1445cf4e180 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchPreview.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchPreview.php @@ -42,7 +42,7 @@ private function adminSearchAssert($dashboard, $search, $type) { $adminSearchPreview = '"' . $search->getQuery() . '" in '. $type; $isVisibleInResult = $dashboard->getAdminPanelHeader()->isAdminSearchPreviewVisible($adminSearchPreview, $type); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isVisibleInResult, 'Search Preview for ' . $type . ' is not in search results' ); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchProductName.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchProductName.php index 66cdb038f0847..29df5cf456517 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchProductName.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertGlobalSearchProductName.php @@ -33,7 +33,7 @@ public function processAssert(Dashboard $dashboard, GlobalSearch $search) $productName = $product->getName(); $isVisibleInResult = $dashboard->getAdminPanelHeader()->isSearchResultVisible($productName); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isVisibleInResult, 'Product name ' . $productName . ' is absent in search results' ); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpUsedOnFrontend.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpUsedOnFrontend.php index a91597e3b9881..f028a0bcf65ba 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpUsedOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpUsedOnFrontend.php @@ -72,7 +72,7 @@ protected function assertUsedProtocol($expectedProtocol) $expectedProtocol .= '://'; } - \PHPUnit_Framework_Assert::assertStringStartsWith( + \PHPUnit\Framework\Assert::assertStringStartsWith( $expectedProtocol, $this->browser->getUrl(), "$expectedProtocol is not used." diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php index cf0de914b7bed..5dd43604408cf 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsAvailable.php @@ -62,12 +62,12 @@ private function verifyConfiguration(SystemConfigEdit $systemConfigEdit, ConfigD $group = $systemConfigEdit->getForm()->getGroup($tabName, $groupName); $group->setValue($tabName, $groupName, $fieldName, 'Yes'); $group->setValue($tabName, $groupName, $fieldName, 'No'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( true, $fieldName . " configuration is enabled with options Yes & No." ); } catch (\PHPUnit_Extensions_Selenium2TestCase_WebDriverException $e) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( true, $fieldName . " configuration is not enabled with options Yes & No." ); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsNotAvailable.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsNotAvailable.php index 007d7998d0466..ef6a5821733cd 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsNotAvailable.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsHeaderOptionsNotAvailable.php @@ -62,7 +62,7 @@ private function verifyConfiguration( $fieldName = $parts[2]; $isVisible = $systemConfigEdit->getForm()->getGroup($tabName, $groupName) ->isFieldVisible($tabName, $groupName, $fieldName); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( !$isVisible, $fieldName . " configuration is not visible." ); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsUsedOnBackend.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsUsedOnBackend.php index 4b04eb9690a98..5da51c8079d7f 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsUsedOnBackend.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertHttpsUsedOnBackend.php @@ -66,7 +66,7 @@ protected function assertUsedProtocol($expectedProtocol) $expectedProtocol .= '://'; } - \PHPUnit_Framework_Assert::assertStringStartsWith( + \PHPUnit\Framework\Assert::assertStringStartsWith( $expectedProtocol, $this->browser->getUrl(), "$expectedProtocol is not used." @@ -82,7 +82,7 @@ protected function assertDirectHttpUnavailable() { $fakeUrl = str_replace($this->securedProtocol, $this->unsecuredProtocol, $this->browser->getUrl()); $this->browser->open($fakeUrl); - \PHPUnit_Framework_Assert::assertStringStartsWith( + \PHPUnit\Framework\Assert::assertStringStartsWith( $this->securedProtocol, $this->browser->getUrl(), 'Merchant is not redirected to https if tries to access the Admin panel page directly via http.' diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertInterfaceLocaleAvailableOptions.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertInterfaceLocaleAvailableOptions.php index 99fe4503a699d..4ccab6c64567b 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertInterfaceLocaleAvailableOptions.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertInterfaceLocaleAvailableOptions.php @@ -28,12 +28,12 @@ public function processAssert( $dropdownLocales = [] ) { if ($_ENV['mage_mode'] === 'production') { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $locales->getList(Locales::TYPE_DEPLOYED), $dropdownLocales ); } else { - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( array_diff($dropdownLocales, $locales->getList(Locales::TYPE_ALL)) ); } diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertLocaleCodeVisibility.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertLocaleCodeVisibility.php index 983ada662b261..65bf9c3328a1a 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertLocaleCodeVisibility.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertLocaleCodeVisibility.php @@ -22,12 +22,12 @@ class AssertLocaleCodeVisibility extends AbstractConstraint public function processAssert(SystemConfigEdit $configEdit) { if ($_ENV['mage_mode'] === 'production') { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $configEdit->getForm()->getGroup('general', 'locale')->isFieldDisabled('general', 'locale', 'code'), 'Locale field should be disabled in production mode.' ); } else { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $configEdit->getForm()->getGroup('general', 'locale')->isFieldDisabled('general', 'locale', 'code'), 'Locale field should be not disabled in developer or default mode.' ); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertMenuItemNotVisible.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertMenuItemNotVisible.php index 349b31db3f9e0..9dff907999ca4 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertMenuItemNotVisible.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertMenuItemNotVisible.php @@ -25,7 +25,7 @@ public function processAssert(Dashboard $dashboard, $menuItem) { $dashboard->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $dashboard->getMenuBlock()->isMenuItemVisible($menuItem), 'Menu item ' . $menuItem . ' is supposed to be not visible.' ); diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php index 7fedd9d313237..fabf406f9a742 100644 --- a/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php +++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Constraint/AssertStoreCanBeLocalized.php @@ -59,7 +59,7 @@ public function processAssert( $cmsIndex->getStoreSwitcherBlock()->selectStoreView($store->getName()); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsIndex->getSearchBlock()->isPlaceholderContains($welcomeText), "Locale not applied." ); diff --git a/dev/tests/functional/tests/app/Magento/Backup/Test/Constraint/AssertBackupInGrid.php b/dev/tests/functional/tests/app/Magento/Backup/Test/Constraint/AssertBackupInGrid.php index 09cd48e5d068b..91163465aa963 100644 --- a/dev/tests/functional/tests/app/Magento/Backup/Test/Constraint/AssertBackupInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Backup/Test/Constraint/AssertBackupInGrid.php @@ -23,7 +23,7 @@ class AssertBackupInGrid extends AbstractConstraint */ public function processAssert(BackupIndex $backupIndex) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $backupIndex->open()->getBackupGrid()->isBackupRowVisible(), 'Backup is not present in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php index 90b5c0fa7e48f..b3a2a8bc55e1f 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/Assert3dSecureInfoIsPresent.php @@ -27,12 +27,12 @@ public function processAssert(SalesOrderView $salesOrderView, array $paymentInfo $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); $actualPaymentInformation = $infoTab->getPaymentInfoBlock()->getData(); foreach ($paymentInformation as $key => $value) { - \PHPUnit_Framework_Assert::assertArrayHasKey( + \PHPUnit\Framework\Assert::assertArrayHasKey( $key, $actualPaymentInformation, '3D Secure information is not present.' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $paymentInformation[$key], $value, '3D Secure information is not equal to information from data set.' diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertCreditCardJsValidationMessagesArePresent.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertCreditCardJsValidationMessagesArePresent.php index 28494901dcc60..28bb60ff3f186 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertCreditCardJsValidationMessagesArePresent.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertCreditCardJsValidationMessagesArePresent.php @@ -26,7 +26,7 @@ public function processAssert(CheckoutOnepage $checkoutOnepage, array $expectedE $errorMessages = $checkoutOnepage->getBraintreeBlock()->getVisibleMessages($expectedErrorMessages); foreach (array_keys($errorMessages) as $field) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedErrorMessages[$field], $errorMessages[$field], "Wrong js validation error message is displayed for field: $field." diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertDeviceDataIsPresentInBraintreeRequest.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertDeviceDataIsPresentInBraintreeRequest.php index 7eb53d728b079..8320514520b03 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertDeviceDataIsPresentInBraintreeRequest.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertDeviceDataIsPresentInBraintreeRequest.php @@ -33,7 +33,7 @@ class AssertDeviceDataIsPresentInBraintreeRequest extends AbstractConstraint public function processAssert(Log $log) { $file = $log->getFileContent(self::FILE_NAME); - \PHPUnit_Framework_Assert::assertRegExp( + \PHPUnit\Framework\Assert::assertRegExp( self::DEVICE_DATA_PATTERN, $file, 'The device data is not present in Braintree request.' diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertTransactionIsPresentInSettlementReport.php b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertTransactionIsPresentInSettlementReport.php index a3b28e611ef17..9ec9acc9e9cb7 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertTransactionIsPresentInSettlementReport.php +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Constraint/AssertTransactionIsPresentInSettlementReport.php @@ -47,7 +47,7 @@ public function processAssert( $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); $transactionId = $this->getTransactionId(); - \PHPUnit_Framework_Assert::assertNotEmpty($transactionId); + \PHPUnit\Framework\Assert::assertNotEmpty($transactionId); $this->settlementReportIndex->open(); @@ -56,7 +56,7 @@ public function processAssert( $ids = $grid->getTransactionIds(); - \PHPUnit_Framework_Assert::assertTrue(in_array($transactionId, $ids)); + \PHPUnit\Framework\Assert::assertTrue(in_array($transactionId, $ids)); } /** diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleInCategory.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleInCategory.php index 489d73b2f341a..5042eb2a2c3aa 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleInCategory.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleInCategory.php @@ -39,13 +39,13 @@ protected function assertPrice(FixtureInterface $bundle, CatalogCategoryView $ca : $priceBlock->getPrice(); } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $priceData['price_from'], $priceLow, 'Bundle price From on category page is not correct.' ); if ($bundle->getPriceView() == 'Price Range') { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $priceData['price_to'], $priceBlock->getPriceTo(), 'Bundle price To on category page is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsOnProductPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsOnProductPage.php index 1b13f47ba8a43..eb0f2bed954a4 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsOnProductPage.php @@ -43,7 +43,7 @@ public function processAssert( } $error = $this->verifyData($productOptions, $formOptions); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsSummaryOnProductPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsSummaryOnProductPage.php index d73053f4e4b61..b769d9b75722c 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsSummaryOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleItemsSummaryOnProductPage.php @@ -67,7 +67,7 @@ public function processAssert( } } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedResult, $actualResult, 'Bundle Summary Section does not contain correct bundle options data.' diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionTitleOnStorefront.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionTitleOnStorefront.php index c05106776d9ff..2b9db50362de6 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionTitleOnStorefront.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionTitleOnStorefront.php @@ -43,7 +43,7 @@ public function processAssert( $cmsIndex->getLinksBlock()->waitWelcomeMessage(); $browser->open($_ENV['app_frontend_url'] . $originalProduct->getUrlKey() . '.html'); $catalogProductView->getBundleViewBlock()->clickCustomize(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getBundleViewBlock()->getBundleBlock()->isOptionVisible( $optionTitles[$store->getStoreId()] ), diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionsDeleted.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionsDeleted.php index f47a1d90b67d6..0fb3786c24de7 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionsDeleted.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleOptionsDeleted.php @@ -41,12 +41,12 @@ public function processAssert( $productDataLength = count($productData); $formDataLength = count($productData); - \PHPUnit_Framework_Assert::assertEquals($productDataLength, $formDataLength); + \PHPUnit\Framework\Assert::assertEquals($productDataLength, $formDataLength); foreach ($productData as $index => $option) { $productAssociatedDataLength = count($option['assigned_products']); $formAssociatedDataLength = count($formData[$index]['assigned_products']); - \PHPUnit_Framework_Assert::assertEquals($productAssociatedDataLength, $formAssociatedDataLength); + \PHPUnit\Framework\Assert::assertEquals($productAssociatedDataLength, $formAssociatedDataLength); foreach ($option['assigned_products'] as $productIndex => $associatedProduct) { $associatedProduct['data']['getProductName'] = @@ -56,13 +56,13 @@ public function processAssert( $associatedProduct, $formData[$index]['assigned_products'][$productIndex] ); - \PHPUnit_Framework_Assert::assertCount(0, $errorAssociatedProducts); + \PHPUnit\Framework\Assert::assertCount(0, $errorAssociatedProducts); } unset($option['assigned_products']); unset($formData[$index]['assigned_products']); $errorFields = array_diff($option, $formData[$index]); - \PHPUnit_Framework_Assert::assertCount(0, $errorFields); + \PHPUnit\Framework\Assert::assertCount(0, $errorFields); } } diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceCalculatedOnProductPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceCalculatedOnProductPage.php index d58bfa9144f59..39e01c09bc43c 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceCalculatedOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceCalculatedOnProductPage.php @@ -45,7 +45,7 @@ public function processAssert( protected function assertPrice(BundleProduct $product, CatalogProductView $productView) { $checkoutData = $product->getCheckoutData(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $checkoutData['cartItem']['configuredPrice'], $productView->getBundleViewBlock()->getBundleSummaryBlock()->getConfiguredPriceBlock()->getPrice(), 'Bundle price calculated is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceType.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceType.php index 1d790628ea6d6..6826bb5fc8277 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceType.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceType.php @@ -101,7 +101,7 @@ protected function assertPrice( foreach ($optionPrice as $index => $item) { $item['price'] -= $item['price'] * $specialPrice; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($item['price'], 2), $cartItem->getPriceBundleOptions($index + 1), 'Bundle item ' . ($index + 1) . ' options on frontend don\'t equal to fixture.' @@ -110,7 +110,7 @@ protected function assertPrice( $sumOptionsPrice = $product->getDataFieldConfig('price')['source']->getPriceData()['cart_price']; $subTotal = number_format($cartItem->getPrice(), 2); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $sumOptionsPrice, $subTotal, 'Bundle unit price on frontend doesn\'t equal to fixture.' diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceView.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceView.php index 889f6b5f3bb2b..b89fda9c97bb8 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceView.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundlePriceView.php @@ -55,14 +55,14 @@ protected function assertPrice(BundleProduct $product, CatalogProductView $catal $priceLow = ($priceView == 'Price Range') ? $priceBlock->getPriceFrom() : $priceBlock->getPrice(); } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $priceData['price_from'], $priceLow, 'Bundle price From on product view page is not correct.' ); if ($priceView == 'Price Range') { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $priceData['price_to'], $priceBlock->getPriceTo(), 'Bundle price To on product view page is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductOnConfigureCartPage.php b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductOnConfigureCartPage.php index e6a7ec013470c..efa75981db7bf 100644 --- a/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductOnConfigureCartPage.php +++ b/dev/tests/functional/tests/app/Magento/Bundle/Test/Constraint/AssertBundleProductOnConfigureCartPage.php @@ -70,7 +70,7 @@ private function checkOptions(BundleProduct $product, array $formOptions, array } $error = $this->verifyData($productOptions, $formOptions); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnBackend.php b/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnBackend.php index 1d481fda1ab45..f035df7dcc357 100644 --- a/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnBackend.php +++ b/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnBackend.php @@ -22,12 +22,12 @@ class AssertCaptchaFieldOnBackend extends AbstractConstraint */ public function processAssert(AdminAuthLoginWithCaptcha $adminAuthLogin) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $adminAuthLogin->getLoginBlockWithCaptcha()->isVisibleCaptcha(), 'Captcha image is not present on backend login page.' ); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $adminAuthLogin->getLoginBlockWithCaptcha()->isVisibleCaptchaReloadButton(), 'Captcha reload button is not present on backend login page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnContactUsForm.php b/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnContactUsForm.php index 6be21d2e71f9f..4883d7819c288 100644 --- a/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnContactUsForm.php +++ b/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnContactUsForm.php @@ -22,12 +22,12 @@ class AssertCaptchaFieldOnContactUsForm extends AbstractConstraint */ public function processAssertRegisterForm(ContactIndex $contactIndex) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $contactIndex->getContactUs()->isVisibleCaptcha(), 'Captcha image is not displayed on the Contact Us page.' ); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $contactIndex->getContactUs()->isVisibleCaptchaReloadButton(), 'Captcha reload button is not displayed on the Contact Us page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnRegisterForm.php b/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnRegisterForm.php index 0d71784579c29..c5237b8ecc4e7 100644 --- a/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnRegisterForm.php +++ b/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnRegisterForm.php @@ -22,12 +22,12 @@ class AssertCaptchaFieldOnRegisterForm extends AbstractConstraint */ public function processAssertRegisterForm(CustomerAccountCreate $createAccountPage) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $createAccountPage->getRegisterForm()->isVisibleCaptcha(), 'Captcha image is not displayed on the storefront account register page.' ); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $createAccountPage->getRegisterForm()->isVisibleCaptchaReloadButton(), 'Captcha reload button is not displayed on the storefront account register page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnStorefront.php b/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnStorefront.php index 65581cc937035..0074ca284dd3f 100644 --- a/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnStorefront.php +++ b/dev/tests/functional/tests/app/Magento/Captcha/Test/Constraint/AssertCaptchaFieldOnStorefront.php @@ -22,12 +22,12 @@ class AssertCaptchaFieldOnStorefront extends AbstractConstraint */ public function processAssert(CustomerAccountLogin $loginPage) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $loginPage->getLoginBlockWithCaptcha()->isVisibleCaptcha(), 'Captcha image is not present on storefront login page.' ); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $loginPage->getLoginBlockWithCaptcha()->isVisibleCaptchaReloadButton(), 'Captcha reload button is not present on storefront login page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Grid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Grid.php index 67ef167e3fcdd..29efb2b4fa037 100755 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Grid.php @@ -60,6 +60,10 @@ class Grid extends DataGrid 'selector' => '[name="attribute_set_id"]', 'input' => 'select', ], + 'store_id' => [ + 'selector' => '[name="store_id"]', + 'input' => 'select', + ], ]; /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAbsenceDeleteAttributeButton.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAbsenceDeleteAttributeButton.php index f5d65559386b1..e2e5b5d2b1879 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAbsenceDeleteAttributeButton.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAbsenceDeleteAttributeButton.php @@ -23,7 +23,7 @@ class AssertAbsenceDeleteAttributeButton extends AbstractConstraint */ public function processAssert(CatalogProductAttributeNew $attributeNew) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $attributeNew->getPageActions()->checkDeleteButton(), "Button 'Delete Attribute' is present on Attribute page" ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddBeforeForPrice.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddBeforeForPrice.php index e0672b3b7ead4..1523fa5d6d179 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddBeforeForPrice.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddBeforeForPrice.php @@ -48,7 +48,7 @@ public function processAssert( ); foreach ($valuesFromForm as $value) { - \PHPUnit_Framework_Assert::assertEquals($priceTypeSymbol, $value['add_before']); + \PHPUnit\Framework\Assert::assertEquals($priceTypeSymbol, $value['add_before']); } } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddToCartButtonAbsent.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddToCartButtonAbsent.php index 09a70584b067d..65f1db34c77b8 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddToCartButtonAbsent.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddToCartButtonAbsent.php @@ -44,15 +44,15 @@ public function processAssert( while (!$isProductVisible && $catalogCategoryView->getBottomToolbar()->nextPage()) { $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); } - \PHPUnit_Framework_Assert::assertTrue($isProductVisible, 'Product is absent on category page.'); + \PHPUnit\Framework\Assert::assertTrue($isProductVisible, 'Product is absent on category page.'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisibleAddToCardButton(), "Button 'Add to Card' is present on Category page." ); $catalogCategoryView->getListProductBlock()->getProductItem($product)->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogProductView->getViewBlock()->isVisibleAddToCardButton(), "Button 'Add to Card' is present on Product page." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddToCartButtonPresent.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddToCartButtonPresent.php index 6dfff0ed17283..0eff505d59591 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddToCartButtonPresent.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddToCartButtonPresent.php @@ -44,15 +44,15 @@ public function processAssert( while (!$isProductVisible && $catalogCategoryView->getBottomToolbar()->nextPage()) { $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); } - \PHPUnit_Framework_Assert::assertTrue($isProductVisible, 'Product is absent on category page.'); + \PHPUnit\Framework\Assert::assertTrue($isProductVisible, 'Product is absent on category page.'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisibleAddToCardButton(), "Button 'Add to Card' is absent on Category page." ); $catalogCategoryView->getListProductBlock()->getProductItem($product)->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getViewBlock()->isVisibleAddToCardButton(), "Button 'Add to Card' is absent on Product page." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php index b30701728b680..74e8334cf1c19 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddedProductAttributeOnProductForm.php @@ -106,7 +106,7 @@ public function processAssert( $catalogProductEdit->getProductForm()->openSection(self::ATTRIBUTES); } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductEdit->getProductForm()->checkAttributeLabel($catalogProductAttribute), "Product Attribute is absent on Product form." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAdvancedPriceAbsentOnProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAdvancedPriceAbsentOnProductForm.php index 8a4d34e688360..e8e3d5b29d06c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAdvancedPriceAbsentOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAdvancedPriceAbsentOnProductForm.php @@ -31,7 +31,7 @@ public function processAssert(array $entities, CatalogProductEdit $productPage) ->openSection('advanced-pricing') ->getSection('advanced-pricing'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $advancedPricing->getTierPriceForm()->hasGroupPriceOptions(), 'Customer group price options is present in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeForm.php index 674fd7a7aa7a1..bea474e7ae2fa 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeForm.php @@ -37,7 +37,7 @@ public function processAssert( $attribute->getData(), $catalogProductAttributeNew->getAttributeForm()->getData($attribute) ); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeOptionsOnProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeOptionsOnProductForm.php index f0f569563f2f0..b050fcf583801 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeOptionsOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeOptionsOnProductForm.php @@ -44,7 +44,7 @@ public function processAssert( $productOptions = explode("\n", $productAttributeOptions); $diff = array_diff($options, $productOptions); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($diff), "Products attribute options are absent on product form: " . implode(', ', $diff) ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetForm.php index 1facc65617906..7f031567d980c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetForm.php @@ -40,7 +40,7 @@ public function processAssert( ]; $productSet->open(); $productSet->getGrid()->searchAndOpen($filterAttribute); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $filterAttribute['set_name'], $productSetEdit->getAttributeSetEditBlock()->getAttributeSetName(), 'The attribute set wasn\'t found.' @@ -49,7 +49,7 @@ public function processAssert( ); if ($productAttribute !== null) { $attributeLabel = $productAttribute->getFrontendLabel(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productSetEdit->getAttributeSetEditBlock()->checkProductAttribute($attributeLabel), "Product Attribute is absent on Attribute Set Groups" ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetGroupOnProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetGroupOnProductForm.php index bd6bac1f6c319..a50ef1993f009 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetGroupOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetGroupOnProductForm.php @@ -60,13 +60,13 @@ public function processAssert( ); $productBlockForm->fill($productSimple); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productEdit->getProductForm()->isCustomSectionVisible($attributeSet->getGroup()), "Product Group is absent on Product form sections." ); $productEdit->getProductForm()->openCustomSection($attributeSet->getGroup()); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productEdit->getProductForm()->checkAttributeLabel($productAttributeOriginal), "Product Attribute is absent on Product form." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetInGrid.php index d7d2ad5f047c8..c05c7396deee0 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetInGrid.php @@ -30,7 +30,7 @@ public function processAssert(CatalogProductSetIndex $productSetPage, CatalogAtt ]; $productSetPage->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productSetPage->getGrid()->isRowVisible($filterAttributeSet), 'Attribute Set \'' . $filterAttributeSet['set_name'] . '\' is absent in Attribute Set grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetNotInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetNotInGrid.php index 0e465f218ccf8..0c89e52cb0509 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetNotInGrid.php @@ -34,7 +34,7 @@ public function processAssert(CatalogProductSetIndex $productSetPage, CatalogAtt ]; $productSetPage->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $productSetPage->getGrid()->isRowVisible($filterAttributeSet), 'A "' . $filterAttributeSet['set_name'] . '" attribute set name already exists. Create a new name and try again.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetOnProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetOnProductForm.php index 2a6ed4de08fb8..659539e8093bf 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetOnProductForm.php @@ -63,7 +63,7 @@ public function processAssert( $formData = $productEdit->getProductForm()->getData($productSimple); $formAttributeSet = $formData['attribute_set_id']; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $attributeSet->getAttributeSetName(), $formAttributeSet, 'The attribute set wasn\'t found on product form.' @@ -74,7 +74,7 @@ public function processAssert( if ($attributeSetOriginal === null) { $productEdit->getProductForm()->openSection('product-details'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productEdit->getProductForm()->checkAttributeLabel($productAttribute), "Product Attribute is absent on Product form." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetSuccessDeleteMessage.php index a2a32ff59bcc3..c3d2ae3cd1bb2 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetSuccessDeleteMessage.php @@ -29,7 +29,7 @@ class AssertAttributeSetSuccessDeleteMessage extends AbstractConstraint public function processAssert(CatalogProductSetIndex $productSetIndex) { $actualMessage = $productSetIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetSuccessSaveMessage.php index fc2325d969ebf..f0ccd9a1a777c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAttributeSetSuccessSaveMessage.php @@ -29,7 +29,7 @@ class AssertAttributeSetSuccessSaveMessage extends AbstractConstraint public function processAssert(CatalogProductSetIndex $productSetIndex) { $actualMessage = $productSetIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCanSaveProduct.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCanSaveProduct.php index 4eba276384753..16cdde21bbdc5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCanSaveProduct.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCanSaveProduct.php @@ -28,7 +28,7 @@ public function processAssert( $catalogProductIndex->open()->getProductGrid()->searchAndOpen($filter); $catalogProductEdit->getFormPageActions()->save(); - \PHPUnit_Framework_Assert::assertNotEmpty( + \PHPUnit\Framework\Assert::assertNotEmpty( $catalogProductEdit->getMessagesBlock()->getSuccessMessage(), 'Can\'t save existing product.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnBackend.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnBackend.php index 49c24d893eb71..3b8993f7ceb64 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnBackend.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnBackend.php @@ -25,7 +25,7 @@ class AssertCategoryAbsenceOnBackend extends AbstractConstraint public function processAssert(CatalogCategoryIndex $catalogCategoryIndex, Category $category) { $catalogCategoryIndex->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogCategoryIndex->getTreeCategories()->isCategoryVisible($category), 'Category is displayed in backend catalog category tree.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnFrontend.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnFrontend.php index a582946f4e487..8429966b04b3e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryAbsenceOnFrontend.php @@ -40,7 +40,7 @@ public function processAssert( Category $category ) { $browser->open($_ENV['app_frontend_url'] . $category->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::NOT_FOUND_MESSAGE, $categoryView->getTitleBlock()->getTitle(), 'Wrong page is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryBreadcrumbs.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryBreadcrumbs.php index 7e3ac2ca423a3..6ddb40886757f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryBreadcrumbs.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryBreadcrumbs.php @@ -46,12 +46,12 @@ public function processAssert( $this->openCategory($category); $breadcrumbs = $this->getBreadcrumbs($category); - \PHPUnit_Framework_Assert::assertNotEmpty( + \PHPUnit\Framework\Assert::assertNotEmpty( $breadcrumbs, 'No breadcrumbs on category \'' . $category->getName() . '\' page.' ); $pageBreadcrumbs = $catalogCategoryView->getBreadcrumbs()->getText(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $breadcrumbs, $pageBreadcrumbs, 'Wrong breadcrumbs of category page.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryCannotBeDeleted.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryCannotBeDeleted.php index a0f6681113c1b..911115867c79e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryCannotBeDeleted.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryCannotBeDeleted.php @@ -22,7 +22,7 @@ class AssertCategoryCannotBeDeleted extends AbstractConstraint */ public function processAssert(CatalogCategoryEdit $catalogCategoryEdit) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $catalogCategoryEdit->getFormPageActions()->checkDeleteButton(), false, 'Delete button is available for the category.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForAssignedProducts.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForAssignedProducts.php index 06277f5cb9255..4a83b6ae7cd83 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForAssignedProducts.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForAssignedProducts.php @@ -38,7 +38,7 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $categoryUrlKey . '.html'); foreach ($products as $productFixture) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $categoryView->getListProductBlock()->getProductItem($productFixture)->isVisible(), "Products '{$productFixture->getName()}' not found in category '{$category->getName()}'." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForm.php index dc1eed8b8b987..d15a156fec897 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryForm.php @@ -53,7 +53,7 @@ public function processAssert( $fixtureData = $this->prepareFixtureData($category->getData()); $formData = $catalogCategoryEdit->getEditForm()->getData($category); $error = $this->verifyData($this->sortData($fixtureData), $this->sortData($formData)); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryInNavigationMenu.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryInNavigationMenu.php index 4f0154ba0dd15..d4dbadf8942c6 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryInNavigationMenu.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryInNavigationMenu.php @@ -31,12 +31,12 @@ public function processAssert( ) { $cmsIndex->open(); if (($category->getIncludeInMenu() == 'Yes') && ($category->getIsActive() == 'Yes')) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogCategoryView->getTopmenu()->isCategoryVisible($category->getName()), 'Expected that ' . $category->getName() . ' is visible in navigation menu, but it is not.' ); } else { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogCategoryView->getTopmenu()->isCategoryVisible($category->getName()), 'Expected that ' . $category->getName() . ' is not visible in navigation menu, but it is.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIncludeInNavigationMenu.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIncludeInNavigationMenu.php index 44200a286f8fb..6f9b4cd0ce0ff 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIncludeInNavigationMenu.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIncludeInNavigationMenu.php @@ -30,7 +30,7 @@ public function processAssert( CmsIndex $cmsIndex ) { $cmsIndex->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogCategoryView->getTopmenu()->isCategoryVisible($category->getName()), 'Expected that ' . $category->getName() . ' is visible in navigation menu.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIsNotActive.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIsNotActive.php index f4a4332c9286f..d45acd00124aa 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIsNotActive.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIsNotActive.php @@ -33,11 +33,11 @@ public function processAssert( BrowserInterface $browser ) { $browser->open($this->getCategoryUrl($category)); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $categoryView->getTopmenu()->isCategoryVisible($category->getName()), 'Category can be accessed from the navigation bar in the frontend.' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::NOT_FOUND_MESSAGE, $categoryView->getTitleBlock()->getTitle(), 'Wrong page is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryMovedMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryMovedMessage.php index c3c5eb62fcde4..02245b1649803 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryMovedMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryMovedMessage.php @@ -28,7 +28,7 @@ class AssertCategoryMovedMessage extends AbstractConstraint public function processAssert(CatalogCategoryEdit $catalogCategoryEdit) { $actualMessage = $catalogCategoryEdit->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNavigationMenu.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNavigationMenu.php index f5be8d3ae2bac..46005fe7e09d9 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNavigationMenu.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNavigationMenu.php @@ -39,7 +39,7 @@ public function processAssert( $cmsIndex->open(); foreach (array_reverse($categoriesNames) as $category) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsIndex->getTopmenu()->isCategoryVisible($category), 'Category ' . $category . ' is not visible in top menu.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNotInNavigationMenu.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNotInNavigationMenu.php index fd05c289560f1..9a0ab06946a39 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNotInNavigationMenu.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNotInNavigationMenu.php @@ -30,7 +30,7 @@ public function processAssert( CmsIndex $cmsIndex ) { $cmsIndex->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogCategoryView->getTopmenu()->isCategoryVisible($category->getName()), 'Expected that ' . $category->getName() . ' is not visible in navigation menu.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomStore.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomStore.php index 1410911cb0240..38dd7600c6eac 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomStore.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomStore.php @@ -82,7 +82,7 @@ private function verifyUnavailabilityCategoryOnMainStore(Category $category) { $this->browser->open($_ENV['app_frontend_url'] . $category->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::NOT_FOUND_MESSAGE, $this->categoryViewPage->getTitleBlock()->getTitle(), 'Category ' . $category->getName() . ' is available on Main Store, but should not.' @@ -99,7 +99,7 @@ private function verifyAvailabilityCategoryOnMainStore(Category $category) { $this->browser->open($_ENV['app_frontend_url'] . $category->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $category->getName(), $this->categoryViewPage->getTitleBlock()->getTitle(), 'Category ' . $category->getName() . ' is not available on Main Store, but should.' @@ -119,7 +119,7 @@ private function verifyCategoryOnCustomStore(Category $category) $this->browser->open($_ENV['app_frontend_url'] . $category->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $category->getName(), $this->categoryViewPage->getTitleBlock()->getTitle(), 'Category ' . $category->getName() . ' is not available on custom store.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomWebsite.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomWebsite.php index b355ac591e699..512cb7044ed8f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomWebsite.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryOnCustomWebsite.php @@ -59,7 +59,7 @@ public function processAssert( $websiteCode = $storeGroup->getDataFieldConfig('website_id')['source']->getWebsite()->getData('code'); $browser->open($_ENV['app_frontend_url'] . 'websites/' . $websiteCode . '/' . $category->getName() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $category->getName(), $categoryView->getTitleBlock()->getTitle(), 'Wrong category name is displayed on custom website store.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryPage.php index 9408f48203272..400349800cc60 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryPage.php @@ -71,7 +71,7 @@ public function processAssert( $diff = array_merge($diff, $this->verifyContent($categoryData)); $diff = array_merge($diff, $this->verifyDisplaySettings($categoryData)); $diff = array_merge($diff, $this->verifySearchEngineOptimization($categoryData)); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $diff, "Category settings on Storefront page are different.\n" . implode(' ', $diff) ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryRedirect.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryRedirect.php index 4d485e4b158ca..43748396792cf 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryRedirect.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryRedirect.php @@ -31,7 +31,7 @@ public function processAssert( ) { $browser->open($_ENV['app_frontend_url'] . $initialCategory->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $browser->getUrl(), $_ENV['app_frontend_url'] . strtolower($category->getUrlKey()) . '.html', 'URL rewrite category redirect false.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategorySaveMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategorySaveMessage.php index 9c0a1a5777bc7..e0550618c86ff 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategorySaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategorySaveMessage.php @@ -29,7 +29,7 @@ class AssertCategorySaveMessage extends AbstractConstraint public function processAssert(CatalogCategoryEdit $catalogCategoryEdit) { $actualMessage = $catalogCategoryEdit->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategorySuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategorySuccessDeleteMessage.php index 4926566eaa2a7..cbdad5865245a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategorySuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategorySuccessDeleteMessage.php @@ -29,7 +29,7 @@ class AssertCategorySuccessDeleteMessage extends AbstractConstraint public function processAssert(CatalogCategoryEdit $categoryEdit) { $actualMessage = $categoryEdit->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success delete message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryWithCustomStoreOnFrontend.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryWithCustomStoreOnFrontend.php index 11d38cdcef4db..b1000cc3ae6c5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryWithCustomStoreOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryWithCustomStoreOnFrontend.php @@ -37,7 +37,7 @@ public function processAssert( $cmsIndex->open(); $cmsIndex->getLinksBlock()->waitWelcomeMessage(); $browser->open($_ENV['app_frontend_url'] . $initialCategory->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $initialCategory->getName(), $categoryView->getTitleBlock()->getTitle(), 'Wrong category name is displayed for default store.' @@ -47,7 +47,7 @@ public function processAssert( $cmsIndex->getStoreSwitcherBlock()->selectStoreView($store); $cmsIndex->getLinksBlock()->waitWelcomeMessage(); $browser->open($_ENV['app_frontend_url'] . $initialCategory->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $category->getName(), $categoryView->getTitleBlock()->getTitle(), 'Wrong category name is displayed for ' . $store diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertDateInvalidErrorMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertDateInvalidErrorMessage.php index 9ee0175484af8..6c0de5ce81e87 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertDateInvalidErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertDateInvalidErrorMessage.php @@ -28,7 +28,7 @@ class AssertDateInvalidErrorMessage extends AbstractConstraint public function processAssert(CatalogProductEdit $productPage) { $actualMessages = $productPage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::INVALID_DATE_ERROR_MESSAGE, $actualMessages, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertImagesAreVisibleOnProductPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertImagesAreVisibleOnProductPage.php index f6baa47e44b25..0f19c0e43a99d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertImagesAreVisibleOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertImagesAreVisibleOnProductPage.php @@ -54,7 +54,7 @@ public function processAssert( $this->productView = $catalogProductView->getViewBlock(); $errors = $this->verify(); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $errors, "\nFound the following errors:\n" . implode(" \n", $errors) ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertMassProductUpdateSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertMassProductUpdateSuccessMessage.php index eed6f1be307a2..7f322507ab795 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertMassProductUpdateSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertMassProductUpdateSuccessMessage.php @@ -30,7 +30,7 @@ public function processAssert(CatalogProductIndex $productGrid, $productsCount) { $expectedMessage = sprintf(self::SUCCESS_MESSAGE, $productsCount); $actualMessage = $productGrid->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedMessage, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertPaginationCorrectOnStoreFront.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertPaginationCorrectOnStoreFront.php index c9112eff7fc38..9670041b501d0 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertPaginationCorrectOnStoreFront.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertPaginationCorrectOnStoreFront.php @@ -36,18 +36,18 @@ public function processAssert( $productsCount ) { $browser->open($_ENV['app_frontend_url'] . $category->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( true, $catalogCategoryView->getBottomToolbar()->isVisible(), 'Pagination is not visible' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $catalogCategoryView->getBottomToolbar()->getLimitedValueByIndex(0), $catalogCategoryView->getListProductBlock()->getProductsCount(), 'Count of products on 1 page does not equivalent with declared in pagination (default value)' ); $catalogCategoryView->getBottomToolbar()->nextPage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $this->calculateExpectedProductsCountOnPage( $catalogCategoryView->getBottomToolbar()->getLimitedValueByIndex(0), 2, @@ -58,13 +58,13 @@ public function processAssert( ); $catalogCategoryView->getBottomToolbar()->firstPage(); $catalogCategoryView->getBottomToolbar()->setLimiterValueByIndex(1); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $catalogCategoryView->getBottomToolbar()->getLimitedValueByIndex(1), $catalogCategoryView->getListProductBlock()->getProductsCount(), 'Count of products on 1 page does not equivalent with declared in pagination(custom value)' ); $catalogCategoryView->getBottomToolbar()->nextPage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $this->calculateExpectedProductsCountOnPage( $catalogCategoryView->getBottomToolbar()->getLimitedValueByIndex(1), 2, diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentCrossSells.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentCrossSells.php index 31763d5dd4a8e..cb2230ee3c4ff 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentCrossSells.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentCrossSells.php @@ -53,7 +53,7 @@ public function processAssert( $catalogProductView->getMessagesBlock()->waitSuccessMessage(); $checkoutCart->open(); foreach ($promotedProducts as $promotedProduct) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutCart->getCrosssellBlock()->getProductItem($promotedProduct)->isVisible(), 'Product \'' . $promotedProduct->getName() . '\' exists in cross-sell section.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentRelatedProducts.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentRelatedProducts.php index ae84cec89a83f..31f2de3012c67 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentRelatedProducts.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentRelatedProducts.php @@ -40,7 +40,7 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); foreach ($promotedProducts as $promotedProduct) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogProductView->getRelatedProductBlock()->getProductItem($promotedProduct)->isVisible(), 'Product \'' . $promotedProduct->getName() . '\' exists in related products.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentUpSells.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentUpSells.php index e828bfc847e7a..6ccddf7a75fda 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentUpSells.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAbsentUpSells.php @@ -40,7 +40,7 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); foreach ($promotedProducts as $promotedProduct) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogProductView->getUpsellBlock()->getProductItem($promotedProduct)->isVisible(), 'Product \'' . $promotedProduct->getName() . '\' exists in up-sells products.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInGrid.php index 5b4414f33abc8..9bd51890b62db 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInGrid.php @@ -36,7 +36,7 @@ public function processAssert( ]; $attributeIndex->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $attributeIndex->getGrid()->isRowVisible($filter), 'Attribute \'' . $attribute->getFrontendLabel() . '\' is present in Attribute grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInSearchOnProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInSearchOnProductForm.php index 0f4401061107c..251b56347b34e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInSearchOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInSearchOnProductForm.php @@ -35,7 +35,7 @@ public function processAssert( $filter = [ 'label' => $productAttribute->getFrontendLabel(), ]; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $newProductPage->getProductForm()->getAttributesSearchGrid()->isRowVisible($filter), 'Attribute \'' . $productAttribute->getFrontendLabel() . '\' is found in Attributes grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInTemplateGroups.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInTemplateGroups.php index a08b95272459f..c4d2ad57028c5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInTemplateGroups.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInTemplateGroups.php @@ -39,7 +39,7 @@ public function processAssert( ->getAttributes()[0] ->getAttributeCode(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $productSetEdit->getAttributeSetEditBlock()->checkProductAttribute($attributeCode), "Attribute " . $attributeCode . " is present in Attribute set's Groups section." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInUnassignedAttributes.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInUnassignedAttributes.php index c62cfe8be5f11..909bb0e2a65e6 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInUnassignedAttributes.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeAbsenceInUnassignedAttributes.php @@ -39,7 +39,7 @@ public function processAssert( ->getAttributes()[0] ->getAttributeCode(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $productSetEdit->getAttributeSetEditBlock()->checkUnassignedProductAttribute($attributeCode), "Attribute " . $attributeCode . " is present in Unassigned Attribute set's section." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeDisplayingOnFrontend.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeDisplayingOnFrontend.php index d092d74fa097e..45035b94212d1 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeDisplayingOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeDisplayingOnFrontend.php @@ -34,7 +34,7 @@ public function processAssert( ) { $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array( $attribute->getFrontendLabel(), $catalogProductView->getAdditionalInformationBlock()->getAttributeLabels() diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeDisplayingOnSearchForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeDisplayingOnSearchForm.php index f12b25cd0f327..9a162500a5b36 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeDisplayingOnSearchForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeDisplayingOnSearchForm.php @@ -33,7 +33,7 @@ public function processAssert(CatalogProductAttribute $attribute, AdvancedSearch $label = $attribute->hasData('manage_frontend_label') ? $attribute->getManageFrontendLabel() : $attribute->getFrontendLabel(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array($label, $formLabels), 'Attribute is absent on advanced search form.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeInGrid.php index f4312b55773f4..212a154c32ad7 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeInGrid.php @@ -26,7 +26,7 @@ public function processAssert(CatalogProductAttribute $attribute, CatalogProduct { $attributeIndexPage->open(); $code = $attribute->getAttributeCode(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $attributeIndexPage->getGrid()->isRowVisible(['attribute_code' => $code]), 'Attribute with attribute code "' . $code . '" is absent in attribute grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsComparable.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsComparable.php index 7d72487436619..766df5407f5cc 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsComparable.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsComparable.php @@ -41,7 +41,7 @@ public function processAssert( ? $attribute->getManageFrontendLabel() : $attribute->getFrontendLabel(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array($label, $catalogProductCompare->getCompareProductsBlock()->getComparableAttributes()), 'Attribute is absent on product compare page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php index 7b6aee2e4bd75..72dacff239d86 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterable.php @@ -53,7 +53,7 @@ public function processAssert( ? $attribute->getManageFrontendLabel() : $attribute->getFrontendLabel(); $filters = $catalogCategoryView->getLayeredNavigationBlock()->getFilters(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array(strtoupper($label), $filters), 'Attribute is absent in layered navigation on category page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php index c12b8b843b855..38b5b15a64b52 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsFilterableInSearch.php @@ -36,7 +36,7 @@ public function processAssert( $label = $attribute->hasData('manage_frontend_label') ? $attribute->getManageFrontendLabel() : $attribute->getFrontendLabel(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array(strtoupper($label), $catalogCategoryView->getLayeredNavigationBlock()->getFilters()), 'Attribute is absent in layered navigation on search page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsGlobal.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsGlobal.php index 051dbdc6eb0e0..fdf638f4d473a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsGlobal.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsGlobal.php @@ -28,7 +28,7 @@ public function processAssert( ) { $filter = ['frontend_label' => $attribute->getFrontendLabel(), 'is_global' => $attribute->getIsGlobal()]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductAttributeIndex->open()->getGrid()->isRowVisible($filter), 'Attribute is not global.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsHtmlAllowed.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsHtmlAllowed.php index 47a4ab7be3313..b3bc4d2619a43 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsHtmlAllowed.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsHtmlAllowed.php @@ -40,7 +40,7 @@ public function processAssert( ) { $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getAdditionalInformationBlock()->hasHtmlTagInAttributeValue($attribute), 'Attribute is not visible with HTML tags on frontend.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsRequired.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsRequired.php index 5f6b0a20478d7..098dbe9071c7b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsRequired.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsRequired.php @@ -51,7 +51,7 @@ public function processAssert( ? $validationErrors[$attribute->getFrontendLabel()] : ''; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::REQUIRE_MESSAGE, $actualMessage, 'JS error notice on product edit page is not equal to expected.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUnique.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUnique.php index 688d2821e95f0..390bfebbaed81 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUnique.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUnique.php @@ -61,7 +61,7 @@ public function processAssert( $actualErrorMessage = $catalogProductEdit->getMessagesBlock()->getErrorMessage(); $attributeLabel = $attribute->getFrontendLabel(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::UNIQUE_MESSAGE, $attributeLabel), $actualErrorMessage, 'JS error notice on product edit page is not equal to expected.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUsedInSortOnFrontend.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUsedInSortOnFrontend.php index 120368b651ed0..77b783aa56b57 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUsedInSortOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeIsUsedInSortOnFrontend.php @@ -37,7 +37,7 @@ public function processAssert( ? $attribute->getManageFrontendLabel() : $attribute->getFrontendLabel(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array($label, $catalogsearchResult->getListProductBlock()->getSortByValues()), 'Attribute is absent in sort dropdown on search results page on frontend.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeSaveMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeSaveMessage.php index 42f4a3ac1557f..d7d1704f861c4 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeSaveMessage.php @@ -28,7 +28,7 @@ class AssertProductAttributeSaveMessage extends AbstractConstraint public function processAssert(CatalogProductAttributeIndex $attributeIndex) { $actualMessage = $attributeIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeSuccessDeleteMessage.php index 918883a65cc34..03679c1d077a7 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAttributeSuccessDeleteMessage.php @@ -26,7 +26,7 @@ class AssertProductAttributeSuccessDeleteMessage extends AbstractConstraint public function processAssert(CatalogProductAttributeIndex $attributeIndex) { $actualMessage = $attributeIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAutoincrementedSkuNoticeMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAutoincrementedSkuNoticeMessage.php index 29a250884200f..f443489cc5e90 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAutoincrementedSkuNoticeMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductAutoincrementedSkuNoticeMessage.php @@ -26,7 +26,7 @@ public function processAssert(CatalogProductEdit $productPage, FixtureInterface { $actualMessage = $productPage->getMessagesBlock()->getNoticeMessage(); $reg = '/(SKU for product ' . $product->getName() . ' has been changed to ' . $product->getSku() . '-)(\d+.$)/'; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( preg_match($reg, $actualMessage) == 1, 'Incorrect notice that existing sku automatically changed when saving product with same sku.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareBlockOnCmsPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareBlockOnCmsPage.php index a07a1412b60de..be9958a24c336 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareBlockOnCmsPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareBlockOnCmsPage.php @@ -38,7 +38,7 @@ public function processAssert( foreach ($products as &$product) { $product = $product->getName(); } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $products, $cmsIndex->getCompareProductsBlock()->getProducts(), 'Compare product block contains NOT valid information about compared products.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php index bc9ebbc77ed4f..0079e40ef6807 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLink.php @@ -26,14 +26,14 @@ public function processAssert(array $products, CmsIndex $cmsIndex) $productQty = count($products); $qtyOnPage = $cmsIndex->getCompareLinkBlock()->getQtyInCompareList(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $productQty, $qtyOnPage, 'Qty is not correct in "Compare Products" link.' ); $compareProductUrl = '/catalog/product_compare/'; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( strpos($cmsIndex->getLinksBlock()->getLinkUrl('Compare Products'), $compareProductUrl) !== false, 'Compare product link isn\'t lead to Compare Product Page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLinkIsAbsent.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLinkIsAbsent.php index 9fe165f6ad86e..8942909176f95 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLinkIsAbsent.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareItemsLinkIsAbsent.php @@ -26,7 +26,7 @@ class AssertProductCompareItemsLinkIsAbsent extends AbstractConstraint */ public function processAssert(CmsIndex $cmsIndex) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $cmsIndex->getLinksBlock()->isLinkVisible("Compare Products"), 'The link "Compare Products..." is visible at the top of page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductComparePage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductComparePage.php index d7dd6fbdaafd4..909d753dbb58e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductComparePage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductComparePage.php @@ -65,7 +65,7 @@ public function processAssert( : number_format($product->getPrice(), 2)); $attribute = is_numeric($attributeKey) ? 'info' : 'attribute'; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $attributeValue, $comparePage->getCompareProductsBlock()->{'getProduct' . ucfirst($attribute)}($key + 1, $value), 'Product "' . $product->getName() . '" is\'n equals with data from fixture.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareRemoveLastProductMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareRemoveLastProductMessage.php index c2a0d4329c10a..cfbeeb9674480 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareRemoveLastProductMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareRemoveLastProductMessage.php @@ -27,7 +27,7 @@ public function processAssert(CatalogProductCompare $comparePage) { $comparePage->open(); $actualMessage = $comparePage->getCompareProductsBlock()->getEmptyMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessAddMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessAddMessage.php index 1558340685015..6aad328eb60d3 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessAddMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessAddMessage.php @@ -32,7 +32,7 @@ public function processAssert(CatalogProductView $catalogProductView, FixtureInt { $successMessage = sprintf(self::SUCCESS_MESSAGE, $product->getName()); $actualMessage = $catalogProductView->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $successMessage, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessRemoveAllProductsMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessRemoveAllProductsMessage.php index aaf64932d08d5..704743730242b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessRemoveAllProductsMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessRemoveAllProductsMessage.php @@ -25,7 +25,7 @@ class AssertProductCompareSuccessRemoveAllProductsMessage extends AbstractConstr public function processAssert(CatalogProductView $catalogProductView) { $actualMessage = $catalogProductView->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessRemoveMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessRemoveMessage.php index 0d3d9e83d92fa..0c39a1e616587 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessRemoveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCompareSuccessRemoveMessage.php @@ -29,7 +29,7 @@ public function processAssert(CatalogProductCompare $catalogProductCompare, Fixt { $successMessage = sprintf(self::SUCCESS_MESSAGE, $product->getName()); $actualMessage = $catalogProductCompare->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals($successMessage, $actualMessage, 'Wrong success message is displayed.'); + \PHPUnit\Framework\Assert::assertEquals($successMessage, $actualMessage, 'Wrong success message is displayed.'); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCrossSells.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCrossSells.php index 4bc3f939d3fd7..1bacce69a1708 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCrossSells.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCrossSells.php @@ -56,7 +56,7 @@ public function processAssert( } } - \PHPUnit_Framework_Assert::assertEmpty($errors, implode(" ", $errors)); + \PHPUnit\Framework\Assert::assertEmpty($errors, implode(" ", $errors)); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCustomOptionsErrors.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCustomOptionsErrors.php index d5fe7aac36a37..34531d7ee1021 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCustomOptionsErrors.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCustomOptionsErrors.php @@ -27,7 +27,7 @@ public function processAssert( ) { foreach ($products as $product) { foreach ($product->getData('custom_options') as $option) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getCustomOptionsBlock()->isJsMessageVisible($option['title']), 'Required Custom Option ' . $option['title'] . " doesn't contain JS validation error." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCustomOptionsOnProductPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCustomOptionsOnProductPage.php index b66a86daee8d5..4537aa194060c 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCustomOptionsOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductCustomOptionsOnProductPage.php @@ -95,7 +95,7 @@ public function processAssert( $fixtureCustomOptions = $this->prepareOptions($product, $actualPrice); $formCustomOptions = $catalogProductView->getViewBlock()->getOptions($product)['custom_options']; $error = $this->verifyData($fixtureCustomOptions, $formCustomOptions); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicateForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicateForm.php index 5d93496151195..f65aa33ff93e3 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicateForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicateForm.php @@ -62,7 +62,7 @@ public function processAssert( $fixtureData = $this->prepareFixtureData($product->getData()); $errors = $this->verifyData($fixtureData, $formData); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicateMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicateMessage.php index 87d656dc2e097..4c0a43665fb97 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicateMessage.php @@ -28,7 +28,7 @@ class AssertProductDuplicateMessage extends AbstractConstraint public function processAssert(CatalogProductEdit $productPage) { $actualMessages = $productPage->getMessagesBlock()->getSuccessMessages(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::DUPLICATE_MESSAGE, $actualMessages, 'Wrong duplicated message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicatedInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicatedInGrid.php index ff8e2154e0a43..d63f0b4e61600 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicatedInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductDuplicatedInGrid.php @@ -40,7 +40,7 @@ public function processAssert(FixtureInterface $product, CatalogProductIndex $pr ->search($filter); $filter['price_to'] = '$' . $filter['price_to']; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productGrid->getProductGrid()->isRowVisible($filter, false), 'Product duplicate is absent in Products grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductForm.php index 1841979578435..4f8c55a3b0264 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductForm.php @@ -69,7 +69,7 @@ public function processAssert( $fixtureData = $this->prepareFixtureData($productData, $this->sortFields); $formData = $this->prepareFormData($productPage->getProductForm()->getData($product), $this->sortFields); $error = $this->verifyData($fixtureData, $formData); - \PHPUnit_Framework_Assert::assertTrue(empty($error), $error); + \PHPUnit\Framework\Assert::assertTrue(empty($error), $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductFormattingTierPrice.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductFormattingTierPrice.php index 51c21a1700063..cd183fbf40049 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductFormattingTierPrice.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductFormattingTierPrice.php @@ -25,7 +25,7 @@ public function processAssert(CatalogProductEdit $productPage) $productPage->getProductForm()->openSection('advanced-pricing'); $productPage->getAdvancedPrice()->getFieldsData([]); $productPage->getAdvancedPrice()->getTierPriceForm()->waitTierPriceFormLocks(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $productPage->getAdvancedPrice()->getTierPriceForm()->isVisible(), 'Advanced price form still visible' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductGridIsRendered.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductGridIsRendered.php new file mode 100644 index 0000000000000..6d83c0e45639a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductGridIsRendered.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\Constraint; + +/** + * Assert that product grid is rendered correctly. + */ +class AssertProductGridIsRendered extends \Magento\Mtf\Constraint\AbstractConstraint +{ + /** + * Assert that product grid is rendered correctly. + * + * @param \Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex $catalogProductIndex + * @return void + */ + public function processAssert( + \Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex $catalogProductIndex + ) { + $productId = $catalogProductIndex->open()->getProductGrid()->getFirstItemId(); + \PHPUnit\Framework\Assert::assertNotNull( + $productId, + 'Product grid is not rendered correctly.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Product grid is rendered correctly.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductHasImageInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductHasImageInGrid.php index bc905b2bb96a5..1343505a1cbd8 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductHasImageInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductHasImageInGrid.php @@ -26,7 +26,7 @@ public function processAssert( $productGrid->open(); $productGrid->getProductGrid()->search($filter); $src = $productGrid->getProductGrid()->getBaseImageAttribute('src'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( strpos($src, '/placeholder/') === false, 'Product image is not present in product grid when it should be' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php index 47e1cfd938258..6f75741e8c753 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php @@ -62,7 +62,7 @@ public function processAssert( // Check price $this->countPrices($product, $checkoutCart); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $this->fixtureActualPrice, $this->formPrice, 'Product price in shopping cart is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php index 0a3c3ad51758d..95cfb8374d676 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php @@ -46,7 +46,7 @@ public function processAssert( $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isProductVisible, 'Product is absent on category page.' ); @@ -66,14 +66,14 @@ protected function assertPrice(FixtureInterface $product, CatalogCategoryView $c { $priceBlock = $catalogCategoryView->getListProductBlock()->getProductItem($product)->getPriceBlock(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($product->getPrice(), 2, '.', ''), $priceBlock->isOldPriceVisible() ? $priceBlock->getOldPrice() : $priceBlock->getPrice(), 'Product regular price on category page is not correct.' ); if ($product->hasData('special_price')) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($product->getSpecialPrice(), 2, '.', ''), $priceBlock->getSpecialPrice(), 'Product special price on category page is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategoryOnCustomWebsite.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategoryOnCustomWebsite.php index a08982bd0a112..696a286cb235a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategoryOnCustomWebsite.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategoryOnCustomWebsite.php @@ -45,7 +45,7 @@ public function processAssert( $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isProductVisible, 'Product is absent on the category page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCustomStoreView.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCustomStoreView.php index c96728a453652..5c5306e286c92 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCustomStoreView.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCustomStoreView.php @@ -76,7 +76,7 @@ protected function verifyProductOnMainStore(FixtureInterface $initialProduct) { $this->browser->open($_ENV['app_frontend_url'] . $initialProduct->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $initialProduct->getName(), $this->productViewPage->getViewBlock()->getProductName(), 'Product ' . $initialProduct->getName() . ' is incorrect.' @@ -97,7 +97,7 @@ protected function verifyProductOnCustomStore(FixtureInterface $updatedProduct, $this->browser->open($_ENV['app_frontend_url'] . $updatedProduct->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $updatedProduct->getName(), $this->productViewPage->getViewBlock()->getProductName(), 'Product ' . $updatedProduct->getName() . ' is not available on ' . $store->getName() . ' store.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInGrid.php index 0bd4db23d7a6d..a55c781cfb828 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInGrid.php @@ -34,7 +34,7 @@ public function processAssert(FixtureInterface $product, CatalogProductIndex $pr $this->product = $product; $productIndex->open(); $productIndex->getProductGrid()->resetFilter(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productIndex->getProductGrid()->isRowVisible($this->prepareFilter()), 'Product \'' . $this->product->getName() . '\' is absent in Products grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInStock.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInStock.php index 63a6bc9e81343..8bc552a0b00cb 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInStock.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInStock.php @@ -36,7 +36,7 @@ public function processAssert( ) { // TODO fix initialization url for frontend page $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::STOCK_AVAILABILITY, $catalogProductView->getViewBlock()->stockAvailability(), 'Control "' . self::STOCK_AVAILABILITY . '" is not visible.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMaxAllowedQty.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMaxAllowedQty.php index ec8d09f0e4fac..cb05b289105ff 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMaxAllowedQty.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMaxAllowedQty.php @@ -47,14 +47,14 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); $catalogProductView->getViewBlock()->waitLoader(); $catalogProductView->getViewBlock()->setQtyAndClickAddToCart($maxQty * 2); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $catalogProductView->getMessagesBlock()->getErrorMessage(), sprintf($this->errorMessage, $maxQty), 'The maximum purchase warning message is not appears.' ); $catalogProductView->getViewBlock()->setQtyAndClickAddToCart($maxQty); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getMessagesBlock()->waitSuccessMessage(), 'Limiting max qty is not working correctly.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMinAllowedQty.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMinAllowedQty.php index 42bdbd9f02395..b950fb216b1c5 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMinAllowedQty.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryMinAllowedQty.php @@ -47,14 +47,14 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); $catalogProductView->getViewBlock()->waitLoader(); $catalogProductView->getViewBlock()->setQtyAndClickAddToCart(1); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $catalogProductView->getMessagesBlock()->getErrorMessage(), sprintf($this->errorMessage, $minQty), 'The minimum purchase warning message is not appears.' ); $catalogProductView->getViewBlock()->setQtyAndClickAddToCart($minQty); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getMessagesBlock()->waitSuccessMessage(), 'Limiting min qty is not working correctly.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryThreshold.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryThreshold.php index 2f155bef05a5a..260fcbbbc43d7 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryThreshold.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInventoryThreshold.php @@ -44,13 +44,13 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); $isThresholdMessageDisplayed = $catalogProductView->getViewBlock() ->isThresholdMessageDisplayed($browser, $product); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $isThresholdMessageDisplayed, $thresholdItem['is_message_displayed'], 'Product inventory threshold message display is not correct.' ); if ($thresholdItem['is_message_displayed']) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_MESSAGE, $thresholdItem['expected']), $catalogProductView->getViewBlock()->getThresholdMessage(), 'Product inventory success message is not displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotDisplayingOnFrontend.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotDisplayingOnFrontend.php index 8019a3ccc76f5..4a4e3ae368a4a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotDisplayingOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotDisplayingOnFrontend.php @@ -98,7 +98,7 @@ public function processAssert( foreach ($products as $product) { $errors = array_merge($errors, $this->isNotDisplayingOnFrontendAssert($product)); } - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $errors, "In the process of checking product availability on the frontend, found the following errors:\n" . implode("\n", $errors) diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotVisibleInCompareBlock.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotVisibleInCompareBlock.php index 50a4415148f5e..bebddf6078965 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotVisibleInCompareBlock.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotVisibleInCompareBlock.php @@ -39,12 +39,12 @@ public function processAssert( $compareBlock = $customerAccountIndex->getCompareProductsBlock(); if (($countProducts > 1) && ($product !== null)) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $compareBlock->isProductVisibleInCompareBlock($product->getName()), 'The product displays on Compare Products block on my account page.' ); } else { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $compareBlock->getEmptyMessage(), 'The product displays on Compare Products block on my account page.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotVisibleInComparePage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotVisibleInComparePage.php index 81c109cf9fff5..0f81bc2660484 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotVisibleInComparePage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductIsNotVisibleInComparePage.php @@ -36,12 +36,12 @@ public function processAssert(CatalogProductCompare $comparePage, FixtureInterfa $compareBlock = $comparePage->getCompareProductsBlock(); if ($countProducts > 1) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $compareBlock->isProductVisibleInCompareBlock($product->getName()), 'The product displays on Compare Products page.' ); } else { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $compareBlock->getEmptyMessage(), 'The product displays on Compare Products page.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNameOnDifferentStoreViews.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNameOnDifferentStoreViews.php index 0567213a4c484..61861df34d2e8 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNameOnDifferentStoreViews.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNameOnDifferentStoreViews.php @@ -40,7 +40,7 @@ public function processAssert( foreach ($stores as $store) { $cmsIndex->getStoreSwitcherBlock()->selectStoreView($store->getName()); $cmsIndex->getLinksBlock()->waitWelcomeMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $productNames[$store->getStoreId()], $catalogProductView->getViewBlock()->getProductName(), sprintf('Wrong product name is displayed for %s store view.', $store->getName()) diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNoImageInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNoImageInGrid.php index fde34c58e3384..9dd2e5d51aa34 100755 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNoImageInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNoImageInGrid.php @@ -29,7 +29,7 @@ public function processAssert( $productGrid->open(); $productGrid->getProductGrid()->search($filter); $src = $productGrid->getProductGrid()->getBaseImageAttribute('src'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( strpos($src, '/placeholder/') !== false, 'Product image is displayed in product grid when it should not' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotInGrid.php index 89161b846e7f6..62472b6770a0a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotInGrid.php @@ -29,7 +29,7 @@ public function processAssert($product, CatalogProductIndex $productGrid) foreach ($products as $product) { $filter = ['sku' => $product->getSku(), 'name' => $product->getName()]; $productGrid->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $productGrid->getProductGrid()->isRowVisible($filter), "Product with sku \"{$filter['sku']}\" and name \"{$filter['name']}\" is attend in Products grid." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotSearchableBySku.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotSearchableBySku.php index fb19e801530e6..76132b93978d1 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotSearchableBySku.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotSearchableBySku.php @@ -32,7 +32,7 @@ public function processAssert( ) { $cmsIndex->open(); $cmsIndex->getSearchBlock()->search($product->getSku()); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogSearchResult->getListProductBlock()->getProductItem($product)->isVisible(), 'Product was found by SKU.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotVisibleInCategory.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotVisibleInCategory.php index a0c80e852d4b8..3fb002dd1ff9f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotVisibleInCategory.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductNotVisibleInCategory.php @@ -46,7 +46,7 @@ public function processAssert( while (!$isProductVisible && $catalogCategoryView->getBottomToolbar()->nextPage()) { $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); } - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $isProductVisible, 'Product exists on category page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductOnCustomWebsite.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductOnCustomWebsite.php index 69ec20239b654..7e1fb8b4747f8 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductOnCustomWebsite.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductOnCustomWebsite.php @@ -67,7 +67,7 @@ protected function verifyProductOnMainWebsite(FixtureInterface $product) { $this->browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::NOT_FOUND_MESSAGE, $this->productViewPage->getTitleBlock()->getTitle(), 'Product ' . $product->getName() . ' is available on Main Website, but should not.' @@ -88,7 +88,7 @@ protected function verifyProductOnCustomWebsite(FixtureInterface $product) $_ENV['app_frontend_url'] . 'websites/' . $website->getCode() . '/' . $product->getUrlKey() . '.html' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $product->getName(), $this->productViewPage->getViewBlock()->getProductName(), 'Product ' . $product->getName() . ' is not available on ' . $website->getName() . ' website.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductOutOfStock.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductOutOfStock.php index 20d476cbebe95..b87cb80c5e95a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductOutOfStock.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductOutOfStock.php @@ -35,7 +35,7 @@ public function processAssert( FixtureInterface $product ) { $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::STOCK_AVAILABILITY, $catalogProductView->getViewBlock()->stockAvailability(), 'Control \'' . self::STOCK_AVAILABILITY . '\' is not visible.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPage.php index 049ecaf053eea..4756547ed537d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPage.php @@ -62,7 +62,7 @@ public function processAssert( $this->productView = $catalogProductView->getViewBlock(); $errors = $this->verify(); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $errors, "\nFound the following errors:\n" . implode(" \n", $errors) ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPriceOnDifferentStoreViews.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPriceOnDifferentStoreViews.php index 6c76d4617e317..5f7182af0ac32 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPriceOnDifferentStoreViews.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductPriceOnDifferentStoreViews.php @@ -38,7 +38,7 @@ public function processAssert( foreach ($stores as $store) { $cmsIndex->getStoreSwitcherBlock()->selectStoreView($store->getName()); $cmsIndex->getLinksBlock()->waitWelcomeMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( '9.99', $catalogProductView->getViewBlock()->getPriceBlock()->getPrice(), sprintf('Wrong product price is displayed for %s store view.', $store->getName()) diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php index 298a167d6cb79..592044d30590f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductRelatedProducts.php @@ -44,7 +44,7 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); foreach ($promotedProducts as $promotedProduct) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getRelatedProductBlock()->getProductItem($promotedProduct)->isVisible(), 'Product \'' . $promotedProduct->getName() . '\' is absent in related products \'' . $product->getName() . '\'.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSaveMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSaveMessage.php index 0ee74bf07bd1f..d2b66d5b12524 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSaveMessage.php @@ -28,7 +28,7 @@ class AssertProductSaveMessage extends AbstractConstraint public function processAssert(CatalogProductEdit $productPage) { $actualMessages = $productPage->getMessagesBlock()->getSuccessMessages(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::SUCCESS_MESSAGE, $actualMessages, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSearchableBySku.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSearchableBySku.php index 85f8448c2c7d4..4c841969e2343 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSearchableBySku.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSearchableBySku.php @@ -68,7 +68,7 @@ public function processAssert( list($this->errorMessage, $this->successfulMessage) = [$this->successfulMessage, $this->errorMessage]; } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isVisible, $this->errorMessage ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSkuAutoGenerated.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSkuAutoGenerated.php index 62cf965177314..4985d5181275e 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSkuAutoGenerated.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSkuAutoGenerated.php @@ -26,7 +26,7 @@ public function processAssert(FixtureInterface $product, CatalogProductIndex $pr { $filter = ['sku' => $product->getName()]; $productGrid->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productGrid->getProductGrid()->isRowVisible($filter), 'SKU is not automatically generated for a product.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSpecialPriceOnProductPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSpecialPriceOnProductPage.php index 0d8ebd5ac337a..e12a7fadb3345 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSpecialPriceOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSpecialPriceOnProductPage.php @@ -66,7 +66,7 @@ public function assertPrice(FixtureInterface $product, View $productViewBlock) $fields = $product->getData(); $specialPrice = $productViewBlock->getPriceBlock()->getSpecialPrice(); if (isset($fields['special_price'])) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($fields['special_price'], 2), $specialPrice, $this->errorMessage diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSuccessDeleteMessage.php index b4c8b1d451cd5..02792b5d85728 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductSuccessDeleteMessage.php @@ -32,7 +32,7 @@ public function processAssert($product, CatalogProductIndex $productPage) $products = is_array($product) ? $product : [$product]; $deleteMessage = sprintf(self::SUCCESS_DELETE_MESSAGE, count($products)); $actualMessage = $productPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $deleteMessage, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php index ccd3f589c7e9e..eda2705914b92 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php @@ -64,7 +64,7 @@ public function processAssert( // Check price $this->countPrices($product, $checkoutCart); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $this->fixtureActualPrice, $this->formPrice, 'Product price in shopping cart is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceOnProductPage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceOnProductPage.php index e962127774e8f..233f8bea873d1 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceOnProductPage.php @@ -92,7 +92,7 @@ public function assertPrice(FixtureInterface $product, View $productViewBlock) } } - \PHPUnit_Framework_Assert::assertTrue($noError, $this->errorMessage); + \PHPUnit\Framework\Assert::assertTrue($noError, $this->errorMessage); } /** diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTypeOrderOnCreate.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTypeOrderOnCreate.php index bac64fbf29c6a..5b858f1de46f8 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTypeOrderOnCreate.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTypeOrderOnCreate.php @@ -25,7 +25,7 @@ public function processAssert(CatalogProductIndex $catalogProductIndex, array $m { $catalogProductIndex->open(); ksort($menu); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( implode("\n", $menu), $catalogProductIndex->getGridPageActionBlock()->getTypeList(), 'Order and filling of types on product page not equals to incoming data.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductUpSells.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductUpSells.php index c403f2c6eef28..f4ac8c12883db 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductUpSells.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductUpSells.php @@ -44,7 +44,7 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); foreach ($promotedProducts as $promotedProduct) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getUpsellBlock()->getProductItem($promotedProduct)->isVisible(), 'Product \'' . $promotedProduct->getName() . '\' is absent in up-sells products of a product \'' . $product->getName() . '\'.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductView.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductView.php index 6da6d7a73f54c..3f03eea70c383 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductView.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductView.php @@ -48,19 +48,19 @@ protected function assertOnProductView(CatalogProductSimple $product, CatalogPro $name = $viewBlock->getProductName(); $sku = $viewBlock->getProductSku(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $product->getName(), $name, 'Product name on product view page is not correct.' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $product->getSku(), $sku, 'Product sku on product view page is not correct.' ); if (isset($price['price_regular_price'])) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($product->getPrice(), 2), $price['price_regular_price'], 'Product regular price on product view page is not correct.' @@ -73,7 +73,7 @@ protected function assertOnProductView(CatalogProductSimple $product, CatalogPro } if ($priceComparing && isset($price['price_special_price'])) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($priceComparing, 2), $price['price_special_price'], 'Product special price on product view page is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductVisibleInCategory.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductVisibleInCategory.php index deb389c27cae4..4a99a9aea5698 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductVisibleInCategory.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductVisibleInCategory.php @@ -63,7 +63,7 @@ public function processAssert( $this->successfulMessage = 'Asserts that the product could not be found in this category.'; } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isProductVisible, $this->errorMessage ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductsQtyAndStockStatusInAdminPanel.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductsQtyAndStockStatusInAdminPanel.php index 5ce28f995d15b..6c9f2da9587c9 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductsQtyAndStockStatusInAdminPanel.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductsQtyAndStockStatusInAdminPanel.php @@ -43,7 +43,7 @@ public function processAssert( $actualQtyAndStockStatus['stock_status'] = strtolower($productData['quantity_and_stock_status']['is_in_stock']); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $actualQtyAndStockStatus, $expectedQtyAndStockStatus, 'Expected and actual products qty and status are not equal.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertResetFilterMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertResetFilterMessage.php new file mode 100644 index 0000000000000..5a8f85c9bbc15 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertResetFilterMessage.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Catalog\Test\Constraint; + +/** + * Assert that filters have been reset successfully. + */ +class AssertResetFilterMessage extends \Magento\Mtf\Constraint\AbstractConstraint +{ + /** + * Assert message that filters have been reset. + * + * @param \Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex $catalogProductIndex + * @return void + */ + public function processAssert( + \Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex $catalogProductIndex + ) { + \PHPUnit\Framework\Assert::assertContains( + 'restored the filter to its original state', + $catalogProductIndex->getMessagesBlock()->getErrorMessage(), + "Can't find proper message" + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Filters have been reset successfully.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertSubCategoryNotInNavigationMenu.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertSubCategoryNotInNavigationMenu.php index b4876c395dee1..7281550ec0c2a 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertSubCategoryNotInNavigationMenu.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertSubCategoryNotInNavigationMenu.php @@ -30,7 +30,7 @@ public function processAssert( CmsIndex $cmsIndex ) { $cmsIndex->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogCategoryView->getTopmenu()->isCategoryVisible($subcategory->getName()), 'Expected that ' . $subcategory->getName() . ' is not visible in navigation menu.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUpdatedProductStatusInGrid.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUpdatedProductStatusInGrid.php index a6169f523d3e8..6a6ed7ca6f48f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUpdatedProductStatusInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUpdatedProductStatusInGrid.php @@ -31,7 +31,7 @@ public function processAssert( ? 'Enabled' : 'Disabled'; $filter = ['status' => $productStatus]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductIndex->getProductGrid()->isRowVisible($filter), 'Product \'' . $product->getName() . '\' is absent in Products grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUsedSuperAttributeImpossibleDeleteMessages.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUsedSuperAttributeImpossibleDeleteMessages.php index 4cabca5586da1..ce6ee18373056 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUsedSuperAttributeImpossibleDeleteMessages.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertUsedSuperAttributeImpossibleDeleteMessages.php @@ -28,7 +28,7 @@ class AssertUsedSuperAttributeImpossibleDeleteMessages extends AbstractConstrain */ public function processAssert(CatalogProductAttributeNew $newPage) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_DELETE_MESSAGE, $newPage->getMessagesBlock()->getErrorMessage(), 'Wrong impossible to delete message is not displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php index 25a0ffa7c072a..a463a3edacc10 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AbstractCompareProductsTest.php @@ -163,6 +163,6 @@ protected function addProducts(array $products, AbstractConstraint $assert = nul protected function productCompareAssert(AbstractConstraint $assert, InjectableFixture $product) { $assert->configure(['catalogProductView' => $this->catalogProductView, 'product' => $product]); - \PHPUnit_Framework_Assert::assertThat($this->getName(), $assert); + \PHPUnit\Framework\Assert::assertThat($this->getName(), $assert); } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.php index b88f4c602e898..1730d8386476b 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/AddToCartCrossSellTest.php @@ -118,7 +118,7 @@ protected function addToCart(InjectableFixture $product) protected function assertAbsentCrossSellSection() { $this->checkoutCart->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $this->checkoutCart->getCrosssellBlock()->isVisible(), "Cross-sell block is present." ); @@ -145,7 +145,7 @@ protected function assertCrossSellSection(array $promotedProductNames) sort($productNames); sort($pageProductNames); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $productNames, $pageProductNames, 'Wrong products are displayed in cross-sell section.' diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/GridFilteringDeletedEntityTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/GridFilteringDeletedEntityTest.xml new file mode 100644 index 0000000000000..687ed7038f40b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/GridFilteringDeletedEntityTest.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + --> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../vendor/magento/mtf/etc/variations.xsd"> + <testCase name="Magento\Ui\Test\TestCase\GridFilteringDeletedEntityTest" summary="Grid filtering by deleted entity" ticketId="MAGETWO-88982"> + <variation name="GridFilteringDeletedEntityTestVariation1"> + <data name="tag" xsi:type="string">severity:S2</data> + <data name="steps" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="0" xsi:type="string">Magento\Store\Test\TestStep\DeleteWebsitesEntityStep</item> + </item> + </data> + <data name="fixtureName" xsi:type="string">catalogProductSimple</data> + <data name="fixtureDataSet" xsi:type="string">product_with_additional_website</data> + <data name="filters" xsi:type="array"> + <item name="0" xsi:type="array"> + <item name="name" xsi:type="string">:name</item> + </item> + </data> + <data name="pageClass" xsi:type="string">Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex</data> + <data name="gridRetriever" xsi:type="string">getProductGrid</data> + <constraint name="Magento\Catalog\Test\Constraint\AssertProductGridIsRendered"/> + <constraint name="Magento\Catalog\Test\Constraint\AssertResetFilterMessage"/> + </variation> + </testCase> +</config> diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateRelatedProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateRelatedProductsTest.php index 8b9a41274accf..d711ce75417e9 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateRelatedProductsTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateRelatedProductsTest.php @@ -185,7 +185,7 @@ protected function selectRelatedProducts($product) */ protected function assertAbsentRelatedSellSection() { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $this->catalogProductView->getRelatedProductBlock()->isVisible(), "Related section is present." ); @@ -214,7 +214,7 @@ protected function assertRelatedSection($product) asort($fixtureData); asort($pageData); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $pageData, $fixtureData, 'Wrong products are displayed in related section.' @@ -232,7 +232,7 @@ protected function assertCheckoutCart(array $checkoutProducts) $this->checkoutCart->open(); foreach ($checkoutProducts as $product) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->checkoutCart->getCartBlock()->getCartItem($product)->isVisible(), "Product {$product->getName()} absent in cart." ); diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.php index 8ddb0727f9a00..91519ca724efa 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/NavigateUpSellProductsTest.php @@ -75,7 +75,7 @@ public function test( */ protected function assertAbsentUpSellSection() { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $this->catalogProductView->getUpsellBlock()->isVisible(), "Up-sell section is present." ); @@ -101,7 +101,7 @@ protected function assertUpSellSection(array $promotedProductNames) sort($productNames); sort($pageProductNames); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $productNames, $pageProductNames, 'Wrong products are displayed in up-sell section.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertExportProduct.php b/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertExportProduct.php index 9ca8e535662bc..f51f5e2680415 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertExportProduct.php +++ b/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertExportProduct.php @@ -31,7 +31,7 @@ public function processAssert( $exportData = $export->getLatest(); foreach ($products as $product) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->isProductDataInFile( $exportedFields, $product, diff --git a/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertExportProductDate.php b/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertExportProductDate.php index 1a05cf15cb09f..65adf5923d772 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertExportProductDate.php +++ b/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertExportProductDate.php @@ -24,7 +24,7 @@ public function processAssert(ExportInterface $export, \DateTime $dateTime) { $exportData = $export->getLatest(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( (bool) strpos($exportData->getContent(), $dateTime->format('n/j/y, g')), 'Date fields in exported file are shown in not global configuration time zone.' ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertImportedProducts.php b/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertImportedProducts.php index 989a102a6cc68..c5efedf6a08d0 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertImportedProducts.php +++ b/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertImportedProducts.php @@ -91,7 +91,7 @@ public function processAssert( if ($product->getDataConfig()['type_id'] === $this->productType) { $resultProductsData = $this->getDisplayedProductData($product); $resultCsvData = $this->getResultCsv($product->getSku()); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $resultProductsData, $resultCsvData, 'Products from page and csv are not match.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertProductsOnStorefront.php b/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertProductsOnStorefront.php index 11e8807307d82..d1887d6accba0 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertProductsOnStorefront.php +++ b/dev/tests/functional/tests/app/Magento/CatalogImportExport/Test/Constraint/AssertProductsOnStorefront.php @@ -30,7 +30,7 @@ public function processAssert( ) { foreach ($entities as $entity) { $browser->open($_ENV['app_frontend_url'] . $entity->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $catalogProductView->getViewBlock()->getProductName(), $entity->getName(), "Can't find product in store front" diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php index 51a78f4d4ad91..ad2689d650ff3 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php @@ -48,7 +48,7 @@ public function processAssert( $categoryName = $product->getCategoryIds()[0]; $cmsIndexPage->getTopmenu()->selectCategoryByName($categoryName); $priceBlock = $catalogCategoryViewPage->getListProductBlock()->getProductItem($product)->getPriceBlock(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $priceBlock->isVisible(), 'Price block is not displayed for product ' . $product->getName() ); @@ -58,7 +58,7 @@ public function processAssert( $actualPrice['discount_amount'] = $actualPrice['regular'] - $actualPrice['special']; } $diff = $this->verifyData($actualPrice, $productPrice[$key]); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($diff), implode(' ', $diff) ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedProductPage.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedProductPage.php index ce0f7a73006af..7aac103c9f70b 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedProductPage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedProductPage.php @@ -59,7 +59,7 @@ public function processAssert( $actualPrice['discount_amount'] = $actualPrice['regular'] - $actualPrice['special']; } $diff = $this->verifyData($actualPrice, $productPrice[$key]); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($diff), implode(' ', $diff) ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedShoppingCart.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedShoppingCart.php index 4ecbb382e66fe..3e7fdcbb0f9fd 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleAppliedShoppingCart.php @@ -50,7 +50,7 @@ public function processAssert( $checkoutCartPage->open(); foreach ($products as $key => $product) { $actualPrice = $checkoutCartPage->getCartBlock()->getCartItem($product)->getSubtotalPrice(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $productPrice[$key]['sub_total'], $actualPrice, 'Wrong product price is displayed.' @@ -64,7 +64,7 @@ public function processAssert( $actualPrices['grand_total'] = $checkoutCartPage->getTotalsBlock()->getGrandTotal(); $expectedPrices['sub_total'] = $cartPrice['sub_total']; $expectedPrices['grand_total'] = $cartPrice['grand_total']; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedPrices, $actualPrices, 'Wrong total cart prices are displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleForm.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleForm.php index e90b0a731e88a..7db32337b995d 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleForm.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleForm.php @@ -48,7 +48,7 @@ public function processAssert( $fixtureData['discount_amount'] = floatval($fixtureData['discount_amount']); } $diff = $this->verifyData($formData, $fixtureData); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($diff), implode(' ', $diff) ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleInGrid.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleInGrid.php index a6cabf1f9678e..8ac13d407e433 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleInGrid.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleInGrid.php @@ -57,7 +57,7 @@ public function processAssert( $pageCatalogRuleIndex->open(); $errorMessage = implode(', ', $filter); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $pageCatalogRuleIndex->getCatalogRuleGrid()->isRowVisible($filter), 'Catalog Price Rule with following data: \'' . $errorMessage . '\' ' . 'is absent in Catalog Price Rule grid.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedCatalogPage.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedCatalogPage.php index b40d78f0dde08..2b87372f986eb 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedCatalogPage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedCatalogPage.php @@ -33,7 +33,7 @@ public function processAssert( $categoryName = $product->getCategoryIds()[0]; $cmsIndexPage->getTopmenu()->selectCategoryByName($categoryName); $priceBlock = $catalogCategoryViewPage->getListProductBlock()->getProductItem($product)->getPriceBlock(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $priceBlock->isSpecialPriceVisible(), "Catalog price rule is applied!\n" ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedProductPage.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedProductPage.php index f87f28df124e0..d1d792d1c432b 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedProductPage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedProductPage.php @@ -37,7 +37,7 @@ public function processAssert( $cmsIndexPage->getTopmenu()->selectCategoryByName($categoryName); $catalogCategoryViewPage->getListProductBlock()->getProductItem($product)->open(); $productPriceBlock = $catalogProductViewPage->getViewBlock()->getPriceBlock(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $productPriceBlock->isSpecialPriceVisible(), "Catalog price rule is applied!\n" ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedShoppingCart.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedShoppingCart.php index ddb824eb2fb2c..61fc3f9f527da 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotAppliedShoppingCart.php @@ -34,7 +34,7 @@ public function processAssert( $checkoutCartPage->open(); foreach ($products as $key => $product) { $actualPrice = $checkoutCartPage->getCartBlock()->getCartItem($product)->getSubtotalPrice(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $productPrice[$key]['regular'], $actualPrice, 'Wrong product price is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotInGrid.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotInGrid.php index 6362eaedd921f..4969eb59ad65f 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNotInGrid.php @@ -31,7 +31,7 @@ public function processAssert( 'name' => $catalogPriceRule->getName(), ]; $pageCatalogRuleIndex->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $pageCatalogRuleIndex->getCatalogRuleGrid()->isRowVisible($filter), 'Catalog Price Rule \'' . $filter['rule_id'] . '\', ' . 'with name \'' . $filter['name'] . '\', ' diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNoticeMessage.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNoticeMessage.php index 61412349b1a32..28af4ca04622d 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNoticeMessage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleNoticeMessage.php @@ -29,7 +29,7 @@ public function processAssert( CatalogRuleIndex $pageCatalogRuleIndex ) { $actualMessage = $pageCatalogRuleIndex->getMessagesBlock()->getNoticeMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::NOTICE_MESSAGE_RULES . self::NOTICE_MESSAGE_APPLY, $actualMessage, 'Wrong notice message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleOnOnepageCheckout.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleOnOnepageCheckout.php index 01f5485db6a4c..6fc791d9b0155 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleOnOnepageCheckout.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleOnOnepageCheckout.php @@ -63,7 +63,7 @@ public function processAssert( $actualPrices['sub_total'] = $checkoutOnepage->getReviewBlock()->getSubtotal(); $expectedPrices['grand_total'] = $cartPrice['grand_total']; $expectedPrices['sub_total'] = $cartPrice['sub_total']; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedPrices, $actualPrices, 'Wrong total cart prices are displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleSuccessDeleteMessage.php index 7dd086179315c..0b857e9c839b1 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleSuccessDeleteMessage.php @@ -25,7 +25,7 @@ class AssertCatalogPriceRuleSuccessDeleteMessage extends AbstractConstraint public function processAssert(CatalogRuleIndex $pageCatalogRuleIndex) { $actualMessage = $pageCatalogRuleIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleSuccessSaveMessage.php index fbbd0401d8743..7540f04c4a74a 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertCatalogPriceRuleSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertCatalogPriceRuleSuccessSaveMessage extends AbstractConstraint public function processAssert(CatalogRuleIndex $pageCatalogRuleIndex) { $actualMessages = $pageCatalogRuleIndex->getMessagesBlock()->getSuccessMessages(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::SUCCESS_MESSAGE, $actualMessages, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertProductAttributeIsUsedPromoRules.php b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertProductAttributeIsUsedPromoRules.php index a14ea2f32cbde..6a904276ed67b 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertProductAttributeIsUsedPromoRules.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRule/Test/Constraint/AssertProductAttributeIsUsedPromoRules.php @@ -36,7 +36,7 @@ public function processAssert( /** @var Conditions $conditionsSection */ $conditionsSection = $catalogRuleNew->getEditForm()->getSection('conditions'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $conditionsSection->isAttributeInConditions($attribute), 'Product attribute can\'t be used on promo rules conditions.' ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php index aa2c42b994402..6609fe7af2b41 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogRuleConfigurable/Test/Constraint/AssertCatalogPriceRuleAppliedCatalogPage.php @@ -48,14 +48,14 @@ public function processAssert( $categoryName = $product->getCategoryIds()[0]; $cmsIndexPage->getTopmenu()->selectCategoryByName($categoryName); $priceBlock = $catalogCategoryViewPage->getListProductBlock()->getProductItem($product)->getPriceBlock(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $priceBlock->isVisible(), 'Price block is not displayed for product ' . $product->getName() ); // Product price with applied rule displayed as usual price for Configurable products (MAGETWO-64882) $actualPrice['special'] = (float)$priceBlock->getPrice(); $diff = $this->verifyData($actualPrice, $productPrice[$key]); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($diff), implode(' ', $diff) ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchAttributeIsAbsent.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchAttributeIsAbsent.php index 6892e28aa7d08..f176f8e015d10 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchAttributeIsAbsent.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchAttributeIsAbsent.php @@ -32,7 +32,7 @@ public function processAssert(CatalogProductAttribute $attribute, AdvancedSearch $label = $attribute->hasData('manage_frontend_label') ? $attribute->getManageFrontendLabel() : $attribute->getFrontendLabel(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( in_array($label, $formLabels), 'Created custom product attribute is present in advanced search form on frontend but must be absent.' ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchEmptyTerm.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchEmptyTerm.php index 1b2238ded9c54..608e157a1fb2d 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchEmptyTerm.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchEmptyTerm.php @@ -28,7 +28,7 @@ class AssertAdvancedSearchEmptyTerm extends AbstractConstraint public function processAssert(AdvancedSearch $advancedSearch) { $actualMessage = $advancedSearch->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchNoResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchNoResult.php index 07c07a65f3002..8d5275ae33eb0 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchNoResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchNoResult.php @@ -27,7 +27,7 @@ class AssertAdvancedSearchNoResult extends AbstractConstraint */ public function processAssert(AdvancedResult $resultPage) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $resultPage->getSearchResultBlock()->isVisibleMessages(self::ERROR_MESSAGE), "The error message '" . self::ERROR_MESSAGE . "' is not visible." ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductByAttribute.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductByAttribute.php index 04957d21a74f7..b5174189c9bed 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductByAttribute.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductByAttribute.php @@ -57,7 +57,7 @@ public function processAssert( $isVisible = $catalogSearchResult->getListProductBlock()->getProductItem($product)->isVisible(); } while (!$isVisible && $catalogSearchResult->getBottomToolbar()->nextPage()); - \PHPUnit_Framework_Assert::assertTrue($isVisible, 'Product attribute is not searchable on Frontend.'); + \PHPUnit\Framework\Assert::assertTrue($isVisible, 'Product attribute is not searchable on Frontend.'); } /** diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductResult.php index 81dec247d4801..e1496042870a9 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductResult.php @@ -34,7 +34,7 @@ public function processAssert( ) { $expectedResult = $this->prepareExpectedResult($isVisibleInAdvancedSearch, $allProducts); $foundedProducts = $this->advancedSearchProducts($resultPage, $allProducts); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedResult, $foundedProducts, 'Expected and founded products not the same.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductsResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductsResult.php index 3123243c784a3..7f4a627abdc8f 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductsResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAdvancedSearchProductsResult.php @@ -79,7 +79,7 @@ public function processAssert( } } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($errors), "The following errors occurred:\n" . implode("\n", $errors) ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAttributeSearchableByLabel.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAttributeSearchableByLabel.php index 1c6ccf272383c..c1de20531c8d2 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAttributeSearchableByLabel.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertAttributeSearchableByLabel.php @@ -41,7 +41,7 @@ public function processAssert( $isVisible = $catalogSearchResult->getListProductBlock()->getProductItem($product)->isVisible(); } while (!$isVisible && $catalogSearchResult->getBottomToolbar()->nextPage()); - \PHPUnit_Framework_Assert::assertTrue($isVisible, 'Product attribute is not searchable on Frontend.'); + \PHPUnit\Framework\Assert::assertTrue($isVisible, 'Product attribute is not searchable on Frontend.'); } /** diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchNoResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchNoResult.php index 6030cf657d72b..8b12484521195 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchNoResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchNoResult.php @@ -22,7 +22,7 @@ class AssertCatalogSearchNoResult extends AbstractConstraint */ public function processAssert(CatalogsearchResult $catalogsearchResult) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogsearchResult->getListProductBlock()->isVisible(), 'Search result has been found.' ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchNoResultMessage.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchNoResultMessage.php index 32627b020123c..9ad45021bcdd1 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchNoResultMessage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchNoResultMessage.php @@ -27,7 +27,7 @@ class AssertCatalogSearchNoResultMessage extends AbstractConstraint */ public function processAssert(CatalogsearchResult $catalogSearchResult) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogSearchResult->getSearchResultBlock()->isVisibleMessages(self::NOTICE_MESSAGE), 'Wrong message is displayed or no message at all.' ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchQueryLength.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchQueryLength.php index d6fcaef79ff17..533f16d7c343c 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchQueryLength.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchQueryLength.php @@ -22,7 +22,7 @@ class AssertCatalogSearchQueryLength extends AbstractConstraint */ public function processAssert(CatalogsearchResult $catalogSearchResult) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( mb_strlen($catalogSearchResult->getSearchResultsTitleBlock()->getSearchQuery()), 128, 'Search query length is not truncated to 128 symbols.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResult.php index a35ff1176cdfe..cc236e0e539ba 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResult.php @@ -34,7 +34,7 @@ public function processAssert(CatalogSearchQuery $catalogSearch, AdvancedResult $isProductVisible = $resultPage->getListProductBlock()->getProductItem($product)->isVisible(); } while (!$isProductVisible && $resultPage->getBottomToolbar()->nextPage()); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isProductVisible, "A product with name '" . $product->getName() . "' was not found." ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResultOrder.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResultOrder.php index 3ac4983382f89..eefe0708f0163 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResultOrder.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertCatalogSearchResultOrder.php @@ -46,7 +46,7 @@ public function processAssert(CatalogSearchQuery $catalogSearch, AdvancedResult $idxInArray = array_search($productOnPage, $productsOrder, true); if (false !== $idxInArray) { if (0 !== $idxInArray) { - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $productsOrder, 'Products are in incorrect order on the search result page' ); @@ -56,7 +56,7 @@ public function processAssert(CatalogSearchQuery $catalogSearch, AdvancedResult } } while (count($productsOrder) && $resultPage->getBottomToolbar()->nextPage()); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $productsOrder, 'Products are in incorrect order on the search result page' ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertConfigurableWithDisabledOptionCatalogSearchNoResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertConfigurableWithDisabledOptionCatalogSearchNoResult.php index a7538508caa76..d7f7cc40c34fa 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertConfigurableWithDisabledOptionCatalogSearchNoResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertConfigurableWithDisabledOptionCatalogSearchNoResult.php @@ -67,7 +67,7 @@ public function processAssert( $isProductVisible = $resultPage->getListProductBlock()->getProductItem($product)->isVisible(); } while (!$isProductVisible && $resultPage->getBottomToolbar()->nextPage()); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $isProductVisible, "A product with name '" . $product->getName() . "' was found." ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductAddedToCartFromSearchResults.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductAddedToCartFromSearchResults.php index 75b435e9b2681..a5cbf201ccdf5 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductAddedToCartFromSearchResults.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductAddedToCartFromSearchResults.php @@ -42,7 +42,7 @@ public function processAssert( $productName = $product->getName(); - \PHPUnit_Framework_Assert::assertTrue($isProductVisible, "A product with name $productName was not found."); + \PHPUnit\Framework\Assert::assertTrue($isProductVisible, "A product with name $productName was not found."); $resultPage->getListProductBlock()->getProductItem($product)->clickAddToCart(); $catalogProductView->getViewBlock()->waitLoader(); if (isset($product->getCheckoutData()['options'])) { @@ -52,7 +52,7 @@ public function processAssert( $message = $resultPage->getMessagesBlock()->getSuccessMessage(); } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_MESSAGE, $productName), $message ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductCanBeOpenedFromSearchResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductCanBeOpenedFromSearchResult.php index be0e0030698e4..4eaf9f9c86536 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductCanBeOpenedFromSearchResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertProductCanBeOpenedFromSearchResult.php @@ -36,10 +36,10 @@ public function processAssert( } while (!$isProductVisible && $resultPage->getBottomToolbar()->nextPage()); $productName = $product->getName(); - \PHPUnit_Framework_Assert::assertTrue($isProductVisible, "A product with name $productName was not found."); + \PHPUnit\Framework\Assert::assertTrue($isProductVisible, "A product with name $productName was not found."); $resultPage->getListProductBlock()->getProductItem($product)->open(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $productName, $catalogProductViewPage->getViewBlock()->getProductName(), 'Wrong product page has been opened.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchAttributeTest.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchAttributeTest.php index 8a6eedf1c64f2..b2a49a5543015 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchAttributeTest.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchAttributeTest.php @@ -28,12 +28,12 @@ public function processAssert( $advancedSearch->open(); $availableAttributes = $advancedSearch->getForm()->getFormLabels(); if (isset($attributeForSearch['isVisible'])) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( (false !== array_search($attributeForSearch['name'], $availableAttributes)), 'Attribute ' . $attributeForSearch['name'] . 'was not found in Advanced Search Page.' ); } else { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( (false == array_search($attributeForSearch['name'], $availableAttributes)), 'Attribute ' . $attributeForSearch['name'] . ' was found in Advanced Search Page.' ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermForm.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermForm.php index 6fa19b9474ae6..71646664d1e97 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermForm.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermForm.php @@ -44,7 +44,7 @@ public function processAssert( $formData = $editPage->getForm()->getData($searchTerm); $fixtureData = $searchTerm->getData(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $formData, $fixtureData, 'This form "Search Term" does not match the fixture data.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermInGrid.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermInGrid.php index 5d2ccfdf7548e..428f9cc1a0705 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermInGrid.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermInGrid.php @@ -44,7 +44,7 @@ public function processAssert(CatalogSearchIndex $indexPage, CatalogSearchQuery $filters = array_filter($filters); $grid->search($filters); unset($filters['store_id']); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $grid->isRowVisible($filters, false), 'Row terms according to the filters is not found.' ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermNotInGrid.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermNotInGrid.php index ead64318ac430..646a0b1472a5c 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermNotInGrid.php @@ -38,7 +38,7 @@ public function processAssert(CatalogSearchIndex $indexPage, CatalogSearchQuery $grid->search($filters); unset($filters['store_id']); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $grid->isRowVisible($filters, false), 'Search term "' . $queryText . '" was found in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermNotOnFrontend.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermNotOnFrontend.php index a1e5b02e070e6..60fedfb160285 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermNotOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermNotOnFrontend.php @@ -29,7 +29,7 @@ public function processAssert(CmsIndex $cmsIndex, BrowserInterface $browser, Cat { $queryText = $searchTerm->getQueryText(); $cmsIndex->open()->getSearchBlock()->search($queryText); - \PHPUnit_Framework_Assert::assertNotEquals( + \PHPUnit\Framework\Assert::assertNotEquals( $browser->getUrl(), $searchTerm->getRedirect(), 'Url in the browser corresponds to Url in fixture (redirect has been performed).' diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermOnFrontend.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermOnFrontend.php index aa6295c44d3eb..e3c5a408a3873 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermOnFrontend.php @@ -53,7 +53,7 @@ public function processAssert(CmsIndex $cmsIndex, CatalogSearchQuery $searchTerm $errors[] = '- url window (' . $windowUrl . ') does not match the url redirect(' . $redirectUrl . ')'; } - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $errors, 'When checking on the frontend "Search terms" arose following errors:' . PHP_EOL . implode(PHP_EOL, $errors) ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessDeleteMessage.php index 15e7dac8205d9..c7d7c8bb6ddd4 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessDeleteMessage.php @@ -33,7 +33,7 @@ class AssertSearchTermSuccessDeleteMessage extends AbstractConstraint public function processAssert(CatalogSearchIndex $indexPage) { $actualMessage = $indexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessMassDeleteMessage.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessMassDeleteMessage.php index b2b2f284a7528..e4d7ad20af6d1 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessMassDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessMassDeleteMessage.php @@ -30,7 +30,7 @@ public function processAssert(array $searchTerms, CatalogSearchIndex $indexPage) { $actualMessage = $indexPage->getMessagesBlock()->getSuccessMessage(); $expectedMessage = sprintf(self::SUCCESS_MESSAGE, count($searchTerms)); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedMessage, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessSaveMessage.php index 4c657018c6932..239fda4dceebe 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSearchTermSuccessSaveMessage.php @@ -29,7 +29,7 @@ class AssertSearchTermSuccessSaveMessage extends AbstractConstraint public function processAssert(CatalogSearchIndex $indexPage) { $actualMessage = $indexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSuggestSearchingResult.php b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSuggestSearchingResult.php index a9beabd797f96..5a0d5411670b7 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSuggestSearchingResult.php +++ b/dev/tests/functional/tests/app/Magento/CatalogSearch/Test/Constraint/AssertSuggestSearchingResult.php @@ -45,7 +45,7 @@ public function processAssert( $isVisible = $searchBlock->isSuggestSearchVisible($queryText); } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isVisible, 'Block "Suggest Search" when searching was not found' ); diff --git a/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Constraint/AssertCategoryUrlDuplicateErrorMessage.php b/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Constraint/AssertCategoryUrlDuplicateErrorMessage.php index a3153521a6024..30cb3cc9baf57 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Constraint/AssertCategoryUrlDuplicateErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Constraint/AssertCategoryUrlDuplicateErrorMessage.php @@ -32,7 +32,7 @@ public function processAssert( Category $category ) { $actualMessage = $productPage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::ERROR_MESSAGE_TITLE, $actualMessage, 'Wrong error message is displayed.' @@ -40,7 +40,7 @@ public function processAssert( . "\nActual:\n" . $actualMessage ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $category->getUrlKey(), $actualMessage, 'Category url is not present on error message.' diff --git a/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Constraint/AssertProductUrlDuplicateErrorMessage.php b/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Constraint/AssertProductUrlDuplicateErrorMessage.php index 2e48630471541..0741a226ceaa4 100644 --- a/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Constraint/AssertProductUrlDuplicateErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/CatalogUrlRewrite/Test/Constraint/AssertProductUrlDuplicateErrorMessage.php @@ -35,7 +35,7 @@ public function processAssert( Category $category ) { $actualMessage = $productPage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::ERROR_MESSAGE_TITLE, $actualMessage, 'Wrong error message is displayed.' @@ -43,7 +43,7 @@ public function processAssert( . "\nActual:\n" . $actualMessage ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $product->getUrlKey(), $actualMessage, 'Product url is not present on error message.' @@ -51,7 +51,7 @@ public function processAssert( . "\nActual:\n" . $actualMessage ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $category->getUrlKey() . '/' . $product->getUrlKey(), $actualMessage, 'Category url is not present on error message.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnCategoryPage.php index 37e0427771b18..11b1a9ed19df0 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnCategoryPage.php @@ -41,9 +41,9 @@ public function processAssert( while (!$isProductVisible && $catalogCategoryView->getBottomToolbar()->nextPage()) { $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); } - \PHPUnit_Framework_Assert::assertTrue($isProductVisible, 'Product is absent on category page.'); + \PHPUnit\Framework\Assert::assertTrue($isProductVisible, 'Product is absent on category page.'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisibleAddToCardButton(), 'Button "Add to Cart" is present on category page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnProductPage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnProductPage.php index f326dd68d6cbc..455b91aa25456 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonAbsentOnProductPage.php @@ -30,7 +30,7 @@ public function processAssert( CatalogProductView $catalogProductView ) { $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogProductView->getViewBlock()->isVisibleAddToCardButton(), 'Button "Add to Cart" is present on product page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnCategoryPage.php index df099bb5df67c..161083ba21b00 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnCategoryPage.php @@ -40,9 +40,9 @@ public function processAssert( while (!$isProductVisible && $catalogCategoryView->getBottomToolbar()->nextPage()) { $isProductVisible = $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisible(); } - \PHPUnit_Framework_Assert::assertTrue($isProductVisible, 'Product is absent on category page.'); + \PHPUnit\Framework\Assert::assertTrue($isProductVisible, 'Product is absent on category page.'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogCategoryView->getListProductBlock()->getProductItem($product)->isVisibleAddToCardButton(), 'Button "Add to Cart" is absent on category page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnProductPage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnProductPage.php index 6997aab411b57..007349cf086f3 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddToCartButtonPresentOnProductPage.php @@ -30,7 +30,7 @@ public function processAssert( CatalogProductView $catalogProductView ) { $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getViewBlock()->isVisibleAddToCardButton(), 'Button "Add to Cart" is absent on product page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddedProductToCartSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddedProductToCartSuccessMessage.php index 3f9201ac4656e..b12339b3fc66d 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddedProductToCartSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertAddedProductToCartSuccessMessage.php @@ -30,7 +30,7 @@ class AssertAddedProductToCartSuccessMessage extends AbstractConstraint */ public function processAssert(CheckoutCart $checkoutCart, FixtureInterface $product) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_MESSAGE, $product->getName()), $checkoutCart->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressAbsentInPayment.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressAbsentInPayment.php index f16403107bff9..bfc664b963f68 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressAbsentInPayment.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressAbsentInPayment.php @@ -22,7 +22,7 @@ class AssertBillingAddressAbsentInPayment extends AbstractConstraint */ public function processAssert(CheckoutOnepage $checkoutOnepage) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutOnepage->getPaymentBlock() ->getSelectedPaymentMethodBlock() ->getBillingBlock() diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressSameAsShippingCheckbox.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressSameAsShippingCheckbox.php index 9a042ab13f048..c40e8f533d034 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressSameAsShippingCheckbox.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertBillingAddressSameAsShippingCheckbox.php @@ -29,7 +29,7 @@ public function processAssert(CheckoutOnepage $checkoutOnepage, $billingCheckbox ->getBillingBlock() ->getSameAsShippingCheckboxValue(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $billingCheckboxState, $actualResult, '"Same as Shipping" checkbox has wrong value' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCancelSuccessMessageInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCancelSuccessMessageInShoppingCart.php index ea51f2b9e5f3e..1333a07b3e1fc 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCancelSuccessMessageInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCancelSuccessMessageInShoppingCart.php @@ -28,7 +28,7 @@ class AssertCancelSuccessMessageInShoppingCart extends AbstractConstraint public function processAssert(CheckoutCart $checkoutCart) { $actualMessage = $checkoutCart->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Success message is not present or has wrong text.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartBundleOptionTitle.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartBundleOptionTitle.php index 39670d8fc487b..960b5fa492918 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartBundleOptionTitle.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartBundleOptionTitle.php @@ -26,7 +26,7 @@ class AssertCartBundleOptionTitle extends AbstractConstraint public function processAssert(CheckoutCart $checkoutCart, $optionTitle) { $checkoutCart->open(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $checkoutCart->getCartItemBlock()->getOptionsName(), $optionTitle ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php index 8b40f740fbd54..c2839651b582f 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartIsEmpty.php @@ -35,14 +35,14 @@ public function processAssert(CheckoutCart $checkoutCart, BrowserInterface $brow $checkoutCart->open(); $cartEmptyBlock = $checkoutCart->getCartEmptyBlock(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::TEXT_EMPTY_CART, $cartEmptyBlock->getText(), 'Wrong text on empty cart page.' ); $cartEmptyBlock->clickLinkToMainPage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $_ENV['app_frontend_url'], $browser->getUrl(), 'Wrong link to main page on empty cart page.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php index 9f680eb5fc0ea..144e41dca0d92 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartItemsOptions.php @@ -68,7 +68,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart) } $error = $this->verifyContainsData($productsData, $cartData, true); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartPerCustomer.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartPerCustomer.php index 1aee48ad307ad..b5324870872ca 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartPerCustomer.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCartPerCustomer.php @@ -52,7 +52,7 @@ public function processAssert( \Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep::class, ['customer' => $customer] )->run(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf( self::WELCOME_MESSAGE, $customer->getFirstname() . ' ' . $customer->getLastname() diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCheckoutErrorMessage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCheckoutErrorMessage.php index 9918df30f30aa..2631845c4976c 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCheckoutErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCheckoutErrorMessage.php @@ -23,7 +23,7 @@ class AssertCheckoutErrorMessage extends AbstractConstraint */ public function processAssert(CheckoutOnepage $checkoutOnepage, $expectedErrorMessage) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedErrorMessage, $checkoutOnepage->getMessagesBlock()->getErrorMessage(), 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCustomerIsRedirectedToCheckoutFromCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCustomerIsRedirectedToCheckoutFromCart.php index 14ed62de7e2df..7f717964059eb 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCustomerIsRedirectedToCheckoutFromCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertCustomerIsRedirectedToCheckoutFromCart.php @@ -64,7 +64,7 @@ public function processAssert( $miniShoppingCart->openMiniCart(); $miniShoppingCart->clickProceedToCheckoutButton(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( !$checkoutOnepage->getMessagesBlock()->isVisible() && $checkoutOnepage->getShippingMethodBlock()->isVisible(), 'Checkout first step is not available.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php index d93b8acee880b..4ded49525b99c 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertDiscountInShoppingCart.php @@ -28,7 +28,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart) { $checkoutCart->open(); $checkoutCart->getTotalsBlock()->waitForUpdatedTotals(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($cart->getDiscount(), 2), $checkoutCart->getTotalsBlock()->getDiscount(), 'Discount amount in the shopping cart not equals to discount amount from fixture.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailErrorValidationMessage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailErrorValidationMessage.php index f645977b04748..b5d2b9a98c013 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailErrorValidationMessage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailErrorValidationMessage.php @@ -28,7 +28,7 @@ class AssertEmailErrorValidationMessage extends AbstractConstraint public function processAssert( CheckoutOnepage $checkoutOnepage ) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::EMAIL_VALIDATION_MESSAGE, $checkoutOnepage->getShippingBlock()->getEmailError(), 'Email validation message is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailToolTips.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailToolTips.php index 73d5e1c1c088c..583a3456c5119 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailToolTips.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertEmailToolTips.php @@ -33,13 +33,13 @@ class AssertEmailToolTips extends AbstractConstraint public function processAssert( CheckoutOnepage $checkoutOnepage ) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::EMAIL_TOOLTIP, $checkoutOnepage->getShippingBlock()->getEmailTooltip(), 'Email tooltip is not correct.' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::EMAIL_INSTRUCTIONS, $checkoutOnepage->getShippingBlock()->getEmailInstructions(), 'Email instructions are not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalInShoppingCart.php index 8806f25c3fddd..9bedda350d065 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalInShoppingCart.php @@ -33,7 +33,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart, $requireRe $fixtureGrandTotal = number_format($cart->getGrandTotal(), 2); $pageGrandTotal = $checkoutCart->getTotalsBlock()->getGrandTotal(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $fixtureGrandTotal, $pageGrandTotal, 'Grand total price in the shopping cart not equals to grand total price from fixture.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalOrderReview.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalOrderReview.php index 35032515a223f..1cd12809bdc8a 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalOrderReview.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertGrandTotalOrderReview.php @@ -33,7 +33,7 @@ public function processAssert(CheckoutOnepage $checkoutOnepage, $grandTotal) $checkoutOnepage->getReviewBlock()->waitForElementNotVisible($this->waitElement); $checkoutReviewGrandTotal = $checkoutOnepage->getReviewBlock()->getGrandTotal(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($grandTotal, 2), $checkoutReviewGrandTotal, "Grand Total price: $checkoutReviewGrandTotal not equals with price from data set: $grandTotal" diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertItemsCounterInMiniShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertItemsCounterInMiniShoppingCart.php index cfe83221af310..2b9815c6f90d3 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertItemsCounterInMiniShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertItemsCounterInMiniShoppingCart.php @@ -26,7 +26,7 @@ public function processAssert(CmsIndex $cmsIndex, $totalItemsCountInShoppingCart $sidebar = $cmsIndex->getCartSidebarBlock(); $sidebar->openMiniCart(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $sidebar->getItemsQty(), $totalItemsCountInShoppingCart, 'Wrong quantity of Cart items in mini shopping cart' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertLinkGoToCartNotPresentInSummaryBlock.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertLinkGoToCartNotPresentInSummaryBlock.php index 57f4672d7f37c..f12dfceccdeaa 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertLinkGoToCartNotPresentInSummaryBlock.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertLinkGoToCartNotPresentInSummaryBlock.php @@ -21,7 +21,7 @@ public function processAssert(CheckoutOnepage $checkoutPage) { $reviewBlock = $checkoutPage->getReviewBlock(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $reviewBlock->getGoToCartLink()->isVisible(), 'Go to Cart link present in summary block' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertLinkGoToCartPresentInSummaryBlock.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertLinkGoToCartPresentInSummaryBlock.php index b798574e3d3d6..82f097f60dda3 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertLinkGoToCartPresentInSummaryBlock.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertLinkGoToCartPresentInSummaryBlock.php @@ -21,7 +21,7 @@ public function processAssert(CheckoutOnepage $checkoutPage) { $reviewBlock = $checkoutPage->getReviewBlock(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $reviewBlock->getGoToCartLink()->isVisible(), 'Go to Cart link not present in summary block' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartEmpty.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartEmpty.php index fab678fb7ffea..65a2b7879af8a 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartEmpty.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartEmpty.php @@ -27,13 +27,13 @@ class AssertMinicartEmpty extends AbstractConstraint public function processAssert( CmsIndex $cmsIndex ) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::TEXT_EMPTY_MINICART, $cmsIndex->getCartSidebarBlock()->getEmptyMessage(), 'Empty minicart message not found' ); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $cmsIndex->getCartSidebarBlock()->isItemsQtyVisible(), 'Minicart is not empty' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartItemsQty.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartItemsQty.php index f7317b04fc0ad..012c1d4eeba07 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartItemsQty.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMinicartItemsQty.php @@ -26,7 +26,7 @@ public function processAssert( $expectedItemsQty ) { $cmsIndex->open(); - \PHPUnit_Framework_Assert::assertSame( + \PHPUnit\Framework\Assert::assertSame( (int)$expectedItemsQty, $cmsIndex->getCartSidebarBlock()->getItemsQty(), 'The quantity of items in shopping cart is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMyCartLinkRedirect.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMyCartLinkRedirect.php index 5d40b56421b07..b1db3c849f5ca 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMyCartLinkRedirect.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertMyCartLinkRedirect.php @@ -29,7 +29,7 @@ public function processAssert(CmsIndex $cmsIndex) { $cmsIndex->open(); $cmsIndex->getCartSidebarBlock()->openMiniCart(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::CART_PAGE_TITLE, $cmsIndex->getTitleBlock()->getTitle(), 'Wrong page is displayed instead of the shopping cart page.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertOrderSuccessPlacedMessage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertOrderSuccessPlacedMessage.php index 0be1ce090b014..e5d4b300c2802 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertOrderSuccessPlacedMessage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertOrderSuccessPlacedMessage.php @@ -28,7 +28,7 @@ class AssertOrderSuccessPlacedMessage extends AbstractConstraint */ public function processAssert(CheckoutOnepageSuccess $checkoutOnepageSuccess) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $checkoutOnepageSuccess->getTitleBlock()->getTitle(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersNotPresentInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersNotPresentInShoppingCart.php index 53a11e65ac637..12ef4c6860270 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersNotPresentInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersNotPresentInShoppingCart.php @@ -23,11 +23,11 @@ class AssertPagersNotPresentInShoppingCart extends AbstractConstraint public function processAssert(CheckoutCart $checkoutCart) { $checkoutCart->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutCart->getTopPagerBlock()->getPagesBlock()->isVisible(), 'The top pager of Items Grid is visible.' ); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutCart->getBottomPagerBlock()->getPagesBlock()->isVisible(), 'The bottom pager of Items Grid is visible.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersPresentInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersPresentInShoppingCart.php index 77f0db05414f9..6593263013f89 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersPresentInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersPresentInShoppingCart.php @@ -22,11 +22,11 @@ class AssertPagersPresentInShoppingCart extends AbstractConstraint public function processAssert(CheckoutCart $checkoutCart) { $checkoutCart->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $checkoutCart->getTopPagerBlock()->getPagesBlock()->isVisible(), 'The top pager of Items Grid is not visible.' ); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $checkoutCart->getBottomPagerBlock()->getPagesBlock()->isVisible(), 'The bottom pager of Items Grid is not visible.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersSummaryText.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersSummaryText.php index ff11ef105a39f..fa5b3af52bc76 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersSummaryText.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPagersSummaryText.php @@ -32,12 +32,12 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart, ConfigData $pagerSize = $configSection['checkout/cart/number_items_to_display_pager']['value']; $totalItems = count($cart->getItems()); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::PAGER_SUMMARY_TEXT, $pagerSize, $totalItems), $checkoutCart->getTopPagerBlock()->getAmountToolbar()->getText(), 'Top Pager summary text isn\'t satisfy test data' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::PAGER_SUMMARY_TEXT, $pagerSize, $totalItems), $checkoutCart->getBottomPagerBlock()->getAmountToolbar()->getText(), 'Bottom Pager summary text isn\'t satisfy test data' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPaymentMethodIsAbsentOnPaymentPage.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPaymentMethodIsAbsentOnPaymentPage.php index c4199c27d678c..e625190a6cb13 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPaymentMethodIsAbsentOnPaymentPage.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPaymentMethodIsAbsentOnPaymentPage.php @@ -23,7 +23,7 @@ class AssertPaymentMethodIsAbsentOnPaymentPage extends AbstractConstraint */ public function processAssert(CheckoutOnepage $checkoutOnepage, array $payment) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutOnepage->getPaymentBlock()->isVisiblePaymentMethod($payment), 'Payment method' . $payment['method']. ' is present on Checkout Payment Page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPaymentMethodPersistence.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPaymentMethodPersistence.php index 99397e44e9657..51f9ec7ba51d4 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPaymentMethodPersistence.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPaymentMethodPersistence.php @@ -23,7 +23,7 @@ class AssertPaymentMethodPersistence extends AbstractConstraint */ public function processAssert(CheckoutOnepage $checkoutOnepage, array $payment) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutOnepage->getPaymentBlock()->isVisiblePaymentMethod($payment), 'Payment method' . $payment['method']. ' is present on Checkout Payment Page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php index 799fced1210dd..42c79c1280e38 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php @@ -53,7 +53,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart) } $error = $this->verifyData($productsData, $cartData, true); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProceedToCheckoutButton.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProceedToCheckoutButton.php index e3d056b3b5a83..b2a1a94dac448 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProceedToCheckoutButton.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProceedToCheckoutButton.php @@ -31,7 +31,7 @@ class AssertProceedToCheckoutButton extends AbstractConstraint public function processAssert(CheckoutCart $checkoutCart) { $checkoutCart->open(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::BUTTON_TITLE, $checkoutCart->getProceedToCheckoutBlock()->getTitle() ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductAbsentInMiniShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductAbsentInMiniShoppingCart.php index 1e30c9c037527..9afc9d3f0d714 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductAbsentInMiniShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductAbsentInMiniShoppingCart.php @@ -27,7 +27,7 @@ public function processAssert(CmsIndex $cmsIndex, FixtureInterface $deletedProdu { $cmsIndex->open(); $cmsIndex->getCartSidebarBlock()->openMiniCart(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $cmsIndex->getCartSidebarBlock()->getCartItem($deletedProduct)->isVisible(), 'Product ' . $deletedProduct->getName() . ' is presents in Mini Shopping Cart.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductDataInMiniShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductDataInMiniShoppingCart.php index dd11166a99ab0..530e945b7bc87 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductDataInMiniShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductDataInMiniShoppingCart.php @@ -56,7 +56,7 @@ public function processAssert(CmsIndex $cmsIndex, Cart $cart) } $error = $this->verifyData($productsData, $miniCartData, true); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductIsNotEditable.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductIsNotEditable.php index c1bd5f8f2c1c1..224f5ea91acd1 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductIsNotEditable.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductIsNotEditable.php @@ -25,7 +25,7 @@ class AssertProductIsNotEditable extends AbstractConstraint public function processAssert(CheckoutCart $checkoutCart, array $products) { foreach ($products as $product) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutCart->getCartBlock()->getCartItem($product)->isEditButtonVisible(), 'Added product is editable.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductPresentInMiniShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductPresentInMiniShoppingCart.php index f923b53e0f6c4..80499a3e20627 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductPresentInMiniShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductPresentInMiniShoppingCart.php @@ -27,7 +27,7 @@ public function processAssert(CmsIndex $cmsIndex, array $products) $cmsIndex->open(); foreach ($products as $product) { $cmsIndex->getCartSidebarBlock()->openMiniCart(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsIndex->getCartSidebarBlock()->getCartItem($product)->isVisible(), 'Product ' . $product->getName() . ' is absent in Mini Shopping Cart.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductPresentInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductPresentInShoppingCart.php index ca1dbbf450222..241c334f710ab 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductPresentInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductPresentInShoppingCart.php @@ -26,7 +26,7 @@ public function processAssert(CheckoutCart $checkoutCart, array $products) { $checkoutCart->open(); foreach ($products as $product) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $checkoutCart->getCartBlock()->getCartItem($product)->isVisible(), 'Product ' . $product->getName() . ' is absent in shopping cart.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php index f128905e74a0a..40eb41e127245 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php @@ -53,7 +53,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart) } $error = $this->verifyData($productsData, $cartData, true); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductsAbsentInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductsAbsentInShoppingCart.php index 8f734c64dbbeb..49e5e089b5803 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductsAbsentInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductsAbsentInShoppingCart.php @@ -25,7 +25,7 @@ public function processAssert(CheckoutCart $checkoutCart, array $products) { $checkoutCart->open(); foreach ($products as $product) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutCart->getCartBlock()->getCartItem($product)->isVisible(), 'Product ' . $product->getName() . ' is present in shopping cart.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingAddressJsValidationMessagesIsAbsent.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingAddressJsValidationMessagesIsAbsent.php index c446333560b14..e2625d8c962e7 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingAddressJsValidationMessagesIsAbsent.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingAddressJsValidationMessagesIsAbsent.php @@ -28,7 +28,7 @@ public function processAssert(CheckoutOnepage $checkoutOnepage) /** @var \Magento\Mtf\Client\ElementInterface $field */ foreach ($requiredFields as $field) { $errorContainer = $field->find("div .field-error"); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $errorContainer->isVisible(), 'Js validation error messages must be absent for required fields after checkout start.' ); diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingInShoppingCart.php index fa9b7d488b3ac..3d36228586544 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingInShoppingCart.php @@ -35,7 +35,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart, $requireRe $fixtureShippingAmount = number_format((float)$cart->getShippingAmount(), 2); $pageShippingAmount = $checkoutCart->getTotalsBlock()->getShippingPrice(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $fixtureShippingAmount, $pageShippingAmount, 'Shipping amount in the shopping cart not equals to shipping amount from fixture.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingMethodAvailableInCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingMethodAvailableInCart.php index 3dfb3bc195dd0..5fad47c960069 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingMethodAvailableInCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingMethodAvailableInCart.php @@ -32,7 +32,7 @@ public function processAssert(CheckoutCart $checkoutCart, array $shippingExists, $checkoutCart->open(); } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $checkoutCart->getShippingBlock()->isShippingCarrierMethodVisible( $shippingExists['shipping_service'], $shippingExists['shipping_method'] diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingTotalOrderReview.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingTotalOrderReview.php index 9fccf0a8afc86..99221b91156b9 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingTotalOrderReview.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertShippingTotalOrderReview.php @@ -25,7 +25,7 @@ public function processAssert(CheckoutOnepage $checkoutOnepage, $shippingTotal) { $reviewShippingTotal = $checkoutOnepage->getReviewBlock()->getShippingExclTax(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $reviewShippingTotal, number_format($shippingTotal, 2), 'Shipping price: \'' . $reviewShippingTotal diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubTotalOrderReview.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubTotalOrderReview.php index be3fc1ebf38e2..270ba0d77090d 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubTotalOrderReview.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubTotalOrderReview.php @@ -25,7 +25,7 @@ public function processAssert(CheckoutOnepage $checkoutOnepage, $subTotal) { $reviewSubTotal = $checkoutOnepage->getReviewBlock()->getSubtotal(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $reviewSubTotal, number_format($subTotal, 2), 'Subtotal price: \'' . $reviewSubTotal diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInMiniShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInMiniShoppingCart.php index be68cc17eec14..e69c17397d345 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInMiniShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInMiniShoppingCart.php @@ -27,7 +27,7 @@ public function processAssert(CmsIndex $cmsIndex, Cart $cart) $cmsIndex->open(); $fixtureSubtotal = number_format($cart->getSubtotal(), 2); $miniCartSubtotal = $cmsIndex->getCartSidebarBlock()->getSubtotal(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $fixtureSubtotal, $miniCartSubtotal, 'Subtotal price in mini shopping cart is not equal to subtotal price from fixture.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php index cd6e29410d571..2ee9caa251a74 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php @@ -57,7 +57,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart, $requireRe } $error = $this->verifyData($productsData, $cartData, true); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTaxInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTaxInShoppingCart.php index b571f499ef437..c0648f8a75922 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTaxInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTaxInShoppingCart.php @@ -35,7 +35,7 @@ public function processAssert(CheckoutCart $checkoutCart, Cart $cart, $requireRe $fixtureTaxAmount = number_format((float)$cart->getTaxAmount(), 2); $pageTaxAmount = $checkoutCart->getTotalsBlock()->getTax(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $fixtureTaxAmount, $pageTaxAmount, 'Tax amount in the shopping cart not equals to tax amount from fixture.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTaxTotalOrderReview.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTaxTotalOrderReview.php index 4d88a0db9b1f9..954cd02b7a448 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTaxTotalOrderReview.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTaxTotalOrderReview.php @@ -25,7 +25,7 @@ public function processAssert(CheckoutOnepage $checkoutOnepage, $taxTotal) { $reviewTaxTotal = $checkoutOnepage->getReviewBlock()->getTax(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $reviewTaxTotal, number_format($taxTotal, 2), "Tax price '$reviewTaxTotal' not equals with price from data set '$taxTotal'." diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTopDestinationsInSelect.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTopDestinationsInSelect.php index 7240185a71848..516a534ac7ef3 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTopDestinationsInSelect.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertTopDestinationsInSelect.php @@ -24,7 +24,7 @@ class AssertTopDestinationsInSelect extends AbstractConstraint public function processAssert(CheckoutCart $checkoutCart, array $topDestinations) { $checkoutCart->open(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $topDestinations, $checkoutCart->getShippingBlock()->getTopCountries(), 'Top countries are different from the ones selected as Top Destinations.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyInCheckoutSummaryBlock.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyInCheckoutSummaryBlock.php index 5ceda33949db2..0df2866141297 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyInCheckoutSummaryBlock.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyInCheckoutSummaryBlock.php @@ -41,7 +41,7 @@ public function processAssert( } } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $checkoutSummaryMaxVisibleCartItemsCount, $presentItems, 'Wrong quantity of visible Cart items in checkout summary block.' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyInMiniShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyInMiniShoppingCart.php index 317a26b7545b6..04a34a829c662 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyInMiniShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyInMiniShoppingCart.php @@ -40,7 +40,7 @@ public function processAssert(CmsIndex $cmsIndex, Cart $cart, $minicartMaxVisibl } } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $minicartMaxVisibleCartItemsCount, $presentItems, 'Wrong quantity of visible Cart items in mini shopping cart' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyMessageInMiniShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyMessageInMiniShoppingCart.php index 4afdfb4ecb808..8f7c2efb11122 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyMessageInMiniShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyMessageInMiniShoppingCart.php @@ -44,7 +44,7 @@ public function processAssert(CmsIndex $cmsIndex, $minicartMaxVisibleCartItemsCo $counterMessage = sprintf(self::ITEMS_COUNTER_MASSAGE, $totalItemsCountInShoppingCart); } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $counterMessage, $sidebar->getVisibleItemsCounter(), 'Wrong counter text of visible Cart items in mini shopping cart' diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyMessageOnCheckoutSummaryBlock.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyMessageOnCheckoutSummaryBlock.php index 09c4e4e15158d..b3756b48b2646 100644 --- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyMessageOnCheckoutSummaryBlock.php +++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertVisibleItemsQtyMessageOnCheckoutSummaryBlock.php @@ -55,7 +55,7 @@ public function processAssert( $count = $reviewBlock->getVisibleItemsCounter(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $counterMessage, $count, 'Wrong counter text of visible Cart items in mini shopping cart' diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermAbsentInGrid.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermAbsentInGrid.php index 85d080a36a5bd..7fa9fb7bf2e32 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermAbsentInGrid.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermAbsentInGrid.php @@ -26,7 +26,7 @@ class AssertTermAbsentInGrid extends AbstractConstraint public function processAssert(CheckoutAgreementIndex $agreementIndex, CheckoutAgreement $agreement) { $agreementIndex->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $agreementIndex->getAgreementGridBlock()->isRowVisible(['name' => $agreement->getName()]), 'Checkout Agreement \'' . $agreement->getName() . '\' is present in agreement grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermAbsentOnCheckout.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermAbsentOnCheckout.php index 7ff1a2a104f1b..9d4c245767dcd 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermAbsentOnCheckout.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermAbsentOnCheckout.php @@ -59,7 +59,7 @@ public function processAssert( )->run(); $objectManager->create(\Magento\Checkout\Test\TestStep\SelectPaymentMethodStep::class, $paymentData)->run(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutOnepage->getAgreementReview()->checkAgreement($agreement), 'Checkout Agreement \'' . $agreement->getName() . '\' is present in the Place order step.' ); diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermInGrid.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermInGrid.php index 1045e11a087e6..27ecba1f97e46 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermInGrid.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermInGrid.php @@ -26,7 +26,7 @@ class AssertTermInGrid extends AbstractConstraint public function processAssert(CheckoutAgreementIndex $agreementIndex, CheckoutAgreement $agreement) { $agreementIndex->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $agreementIndex->getAgreementGridBlock()->isRowVisible(['name' => $agreement->getName()]), 'Checkout Agreement \'' . $agreement->getName() . '\' is absent in agreement grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermOnCheckout.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermOnCheckout.php index 68169c2c2acdc..cbf57310a6e32 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermOnCheckout.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermOnCheckout.php @@ -75,7 +75,7 @@ public function processAssert( $objectManager->create(\Magento\Checkout\Test\TestStep\SelectPaymentMethodStep::class, $paymentData)->run(); $paymentBlock->getSelectedPaymentMethodBlock()->clickPlaceOrder(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::NOTIFICATION_MESSAGE, $checkoutOnepage->getAgreementReview()->getNotificationMassage(), 'Notification required message of Terms and Conditions is absent.' diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermRequireMessageOnMultishippingCheckout.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermRequireMessageOnMultishippingCheckout.php index 63b6eb9a41e6d..fba4690f23f82 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermRequireMessageOnMultishippingCheckout.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermRequireMessageOnMultishippingCheckout.php @@ -69,7 +69,7 @@ public function processAssert( ['agreementValue' => 'No'] )->run(); $stepFactory->create(\Magento\Multishipping\Test\TestStep\PlaceOrderStep::class)->run(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::NOTIFICATION_MESSAGE, $page->getAgreementReview()->getNotificationMassage(), 'Notification required message of Terms and Conditions is absent.' diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermSuccessDeleteMessage.php index d5ebf891f9c6c..aae1217b65344 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermSuccessDeleteMessage.php @@ -28,7 +28,7 @@ class AssertTermSuccessDeleteMessage extends AbstractConstraint */ public function processAssert(CheckoutAgreementIndex $agreementIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $agreementIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success delete message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermSuccessSaveMessage.php index b309fbd604db0..afa9ac8340fb6 100644 --- a/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/CheckoutAgreements/Test/Constraint/AssertTermSuccessSaveMessage.php @@ -28,7 +28,7 @@ class AssertTermSuccessSaveMessage extends AbstractConstraint */ public function processAssert(CheckoutAgreementIndex $agreementIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_SAVE_MESSAGE, $agreementIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertAuthorizationLinkIsVisibleOnStoreFront.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertAuthorizationLinkIsVisibleOnStoreFront.php index bbfd1f8285bfa..5f06bfd370160 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertAuthorizationLinkIsVisibleOnStoreFront.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertAuthorizationLinkIsVisibleOnStoreFront.php @@ -23,7 +23,7 @@ class AssertAuthorizationLinkIsVisibleOnStoreFront extends AbstractConstraint public function processAssert(CmsIndex $cmsIndex) { $cmsIndex->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsIndex->getLinksBlock()->isAuthorizationVisible(), "Authorization link is not visible on the Store Front." ); diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockDeleteMessage.php index ef26c5fba934e..07edc9c6dcb88 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockDeleteMessage.php @@ -25,7 +25,7 @@ class AssertCmsBlockDeleteMessage extends AbstractConstraint public function processAssert(CmsBlockIndex $cmsBlockIndex) { $actualMessage = $cmsBlockIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockInGrid.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockInGrid.php index 1aed72d712052..5f071e92feec5 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockInGrid.php @@ -53,7 +53,7 @@ public function processAssert(CmsBlock $cmsBlock, CmsBlockIndex $cmsBlockIndex) $pieces = explode('/', $filter['store_id']); $filter['store_id'] = end($pieces); } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsBlockIndex->getCmsBlockGrid()->isRowVisible($filter, false, false), 'CMS Block with ' . 'title \'' . $filter['title'] . '\', ' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotInGrid.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotInGrid.php index ab117e85cbcb9..f4422af332a08 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotInGrid.php @@ -50,7 +50,7 @@ public function processAssert(CmsBlock $cmsBlock, CmsBlockIndex $cmsBlockIndex) $filter['update_time_from'] = date("M j, Y", strtotime($cmsBlock->getUpdateTime())); } - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $cmsBlockIndex->getCmsBlockGrid()->isRowVisible($filter, true, false), 'CMS Block with ' . 'title \'' . $filter['title'] . '\', ' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotOnCategoryPage.php index 56cee9e3623f9..11f6677f4a867 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotOnCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockNotOnCategoryPage.php @@ -54,7 +54,7 @@ public function processAssert( $cmsIndex->getTopmenu()->selectCategoryByName($category->getName()); $categoryViewContent = $catalogCategoryView->getViewBlock()->getContent(); - \PHPUnit_Framework_Assert::assertNotEquals( + \PHPUnit\Framework\Assert::assertNotEquals( $cmsBlock->getContent(), $categoryViewContent, 'Wrong block content on category is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockOnCategoryPage.php index 81eb0b6c408f7..d63791cf6b04b 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockOnCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockOnCategoryPage.php @@ -49,7 +49,7 @@ public function processAssert( $cmsIndex->getTopmenu()->selectCategoryByName($category->getName()); $categoryViewContent = $catalogCategoryView->getViewBlock()->getContent(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $cmsBlock->getContent(), $categoryViewContent, 'Wrong block content on category is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockSuccessSaveMessage.php index 53a3d9abddc0a..b1c44d28bdf64 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsBlockSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertCmsBlockSuccessSaveMessage extends AbstractConstraint public function processAssert(CmsBlockIndex $cmsBlockIndex) { $actualMessage = $cmsBlockIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_SAVE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDeleteMessage.php index a254ca71540ef..8752f40341a48 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDeleteMessage.php @@ -25,7 +25,7 @@ class AssertCmsPageDeleteMessage extends AbstractConstraint public function processAssert(CmsPageIndex $cmsIndex) { $actualMessage = $cmsIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDisabledOnFrontend.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDisabledOnFrontend.php index d1b9d0d4bca39..8ba2199d8cd6e 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDisabledOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDisabledOnFrontend.php @@ -38,7 +38,7 @@ public function processAssert( $filter = ['title' => $cms->getTitle()]; $cmsIndex->getCmsPageGridBlock()->searchAndPreview($filter); $browser->selectWindow(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::NOT_FOUND_MESSAGE, $frontCmsIndex->getTitleBlock()->getTitle(), 'Wrong page is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDuplicateErrorMessage.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDuplicateErrorMessage.php index 2c3e4bbecfe4f..6f5df3904ef13 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDuplicateErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageDuplicateErrorMessage.php @@ -31,7 +31,7 @@ public function processAssert(CmsPageIndex $cmsIndex, CmsPage $cmsPage) { $actualMessage = $cmsIndex->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::ERROR_MESSAGE_TITLE, $actualMessage, 'Wrong error message is displayed.' @@ -39,7 +39,7 @@ public function processAssert(CmsPageIndex $cmsIndex, CmsPage $cmsPage) . "\nActual:\n" . $actualMessage ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $cmsPage->getIdentifier(), $actualMessage, 'CMS page url is not present on error message.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageForm.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageForm.php index e2d4a5563234a..ab7f544bf4352 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageForm.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageForm.php @@ -52,7 +52,7 @@ public function processAssert( $storeId = explode('/', $cms->getStoreId()); $cmsFixtureData['store_id'] = array_pop($storeId); $errors = $this->verifyData($cmsFixtureData, $cmsFormData); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } /** diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageFormSingleStoreMode.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageFormSingleStoreMode.php index 397d578c6b5be..bf47e08309ce8 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageFormSingleStoreMode.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageFormSingleStoreMode.php @@ -35,6 +35,6 @@ public function processAssert( $cmsFormData = $cmsPageNew->getPageForm()->getData($cms); $cmsFixtureData = $cms->getData(); $errors = $this->verifyData($cmsFixtureData, $cmsFormData); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } } diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageInGrid.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageInGrid.php index 00ca9d112b501..d78e563b0373d 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageInGrid.php @@ -30,7 +30,7 @@ public function processAssert(CmsPageIndex $cmsIndex, CmsPage $cms, $expectedSta 'is_active' => $expectedStatus ]; $cmsIndex->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsIndex->getCmsPageGridBlock()->isRowVisible($filter, true, false), 'Cms page \'' . $cms->getTitle() . '\' is not present in pages grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageNotInGrid.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageNotInGrid.php index d5928c5c5ad11..ca0d6f43e99d6 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageNotInGrid.php @@ -27,7 +27,7 @@ public function processAssert(CmsPageIndex $cmsIndex, CmsPage $cmsPage) $filter = [ 'title' => $cmsPage->getTitle(), ]; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $cmsIndex->getCmsPageGridBlock()->isRowVisible($filter), 'Cms page \'' . $cmsPage->getTitle() . '\' is present in pages grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageOnFrontend.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageOnFrontend.php index ca3fabfca4a76..93a32a12360ad 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageOnFrontend.php @@ -33,7 +33,7 @@ public function processAssert( ) { $browser->open($_ENV['app_frontend_url'] . $cms->getIdentifier()); $fixtureContent = $cms->getContent(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $displayContent != null ? $displayContent : $fixtureContent['content'], $frontCmsPage->getCmsPageBlock()->getPageContent(), 'Wrong content is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagePreview.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagePreview.php index 7ea81866d6834..b9b3649b48fec 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagePreview.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagePreview.php @@ -47,21 +47,21 @@ public function processAssert( $browser->selectWindow(); $fixtureContent = $cms->getContent(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $displayContent != null ? $displayContent : $fixtureContent['content'], $frontCmsPage->getCmsPageBlock()->getPageContent(), 'Wrong content is displayed.' ); if (isset($fixtureContent['widget'])) { foreach ($fixtureContent['widget']['dataset'] as $widget) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $frontCmsPage->getCmsPageBlock()->isWidgetVisible($widget['widget_type'], $widget['anchor_text']), 'Widget \'' . $widget['widget_type'] . '\' is not displayed.' ); } } if ($cms->getContentHeading()) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $cms->getContentHeading(), $frontCmsIndex->getTitleBlock()->getTitle(), 'Wrong title is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageSuccessSaveMessage.php index b4e0bd644558f..0770db6da6fa9 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPageSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertCmsPageSuccessSaveMessage extends AbstractConstraint public function processAssert(CmsPageIndex $cmsIndex) { $actualMessage = $cmsIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_SAVE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagesOnFrontendMultipleStoreViews.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagesOnFrontendMultipleStoreViews.php index ec0fc08b8c218..9128db56a23a0 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagesOnFrontendMultipleStoreViews.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertCmsPagesOnFrontendMultipleStoreViews.php @@ -37,7 +37,7 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $cmsPage->getIdentifier()); $storeName = $cmsPage->getDataFieldConfig('store_id')['source']->getStore()->getData()['name']; $cmsIndex->getStoreSwitcherBlock()->selectStoreView($storeName); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $displayContent != null ? $displayContent : $cmsPage->getContent()['content'], $frontCmsPage->getCmsPageBlock()->getPageContent(), 'Wrong content page ' . $cmsPage->getTitle() . ' is displayed on store ' . $storeName . '.' diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php index 8175ee2f107e1..bb19fdd0c6c53 100644 --- a/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php +++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php @@ -41,7 +41,7 @@ public function processAssert( ? $urlRewrite->getRequestPath() : $cmsPage->getTitle(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $_ENV['app_frontend_url'] . $url, $browser->getUrl(), 'URL rewrite CMS Page redirect false.' diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/Constraint/AssertAdminAccountSharing.php b/dev/tests/functional/tests/app/Magento/Config/Test/Constraint/AssertAdminAccountSharing.php index 21fecac4cf93c..3159d480ee93c 100644 --- a/dev/tests/functional/tests/app/Magento/Config/Test/Constraint/AssertAdminAccountSharing.php +++ b/dev/tests/functional/tests/app/Magento/Config/Test/Constraint/AssertAdminAccountSharing.php @@ -20,7 +20,7 @@ class AssertAdminAccountSharing extends AbstractConstraint */ public function processAssert(AdminAccountSharing $adminAccountSharing) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $adminAccountSharing->getAdminForm()->adminAccountSharingAvailability(), 'Admin Account Sharing Option is not available' ); diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductIsNotDisplayedSeparately.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductIsNotDisplayedSeparately.php index 126fe5ff73183..797979b56511e 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductIsNotDisplayedSeparately.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductIsNotDisplayedSeparately.php @@ -61,7 +61,7 @@ public function processAssert( } } - \PHPUnit_Framework_Assert::assertEmpty($errors, implode(' ', $errors)); + \PHPUnit\Framework\Assert::assertEmpty($errors, implode(' ', $errors)); } /** diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductsGeneratedSku.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductsGeneratedSku.php index 965c3d8d7276b..4c47851e7dcb7 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductsGeneratedSku.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductsGeneratedSku.php @@ -30,7 +30,7 @@ public function processAssert(CatalogProductIndex $productGrid, ConfigurableProd $filter = ['name' => $variation['name']]; $productGrid->getProductGrid()->search($filter); $itemId = $productGrid->getProductGrid()->getFirstItemId(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $product->getSku(), $productGrid->getProductGrid()->getColumnValue($itemId, 'SKU'), 'Product sku is not generated from parent sku.' diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductsInGrid.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductsInGrid.php index ba36128daa36d..ce7a85ee603a4 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductsInGrid.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertChildProductsInGrid.php @@ -52,7 +52,7 @@ public function processAssert(CatalogProductIndex $productGrid, ConfigurableProd } } - \PHPUnit_Framework_Assert::assertEmpty($errors, implode(' ', $errors)); + \PHPUnit\Framework\Assert::assertEmpty($errors, implode(' ', $errors)); } /** diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableAttributesAbsentOnProductPage.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableAttributesAbsentOnProductPage.php index bfb25ede7bbd7..85079e0a210b6 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableAttributesAbsentOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableAttributesAbsentOnProductPage.php @@ -37,7 +37,7 @@ public function processAssert( foreach ($deletedProductAttributes as $attribute) { $attributeLabel = $attribute->getFrontendLabel(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( isset($pageOptions[$attributeLabel]), "Configurable attribute '$attributeLabel' found on product page on frontend." ); diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableAttributesBlockIsAbsentOnProductPage.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableAttributesBlockIsAbsentOnProductPage.php index 9dc2a3eccae43..81f9427bdf26c 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableAttributesBlockIsAbsentOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableAttributesBlockIsAbsentOnProductPage.php @@ -34,7 +34,7 @@ public function processAssert( ConfigurableProduct $product ) { $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogProductView->getConfigurableAttributesBlock()->isVisible(), "Configurable attributes are present on product page on frontend." ); diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductDuplicateForm.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductDuplicateForm.php index cb9e068b5727b..02cb304325c24 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductDuplicateForm.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductDuplicateForm.php @@ -44,7 +44,7 @@ public function processAssert( $fixtureData = $this->prepareFixtureData($productData, $this->sortFields); $formData = $this->prepareFormData($productPage->getProductForm()->getData($product), $this->sortFields); $error = $this->verifyData($fixtureData, $formData); - \PHPUnit_Framework_Assert::assertTrue(empty($error), $error); + \PHPUnit\Framework\Assert::assertTrue(empty($error), $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCart.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCart.php index d5cae4bdd4601..15acb782eef49 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCart.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCart.php @@ -41,7 +41,7 @@ public function processAssert( $checkoutData = $product->getCheckoutData(); $price = $checkoutCart->getCartBlock()->getCartItem($product)->getPrice(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $checkoutData['cartItem']['price'], $price, 'Product price in shopping cart is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCategory.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCategory.php index 7bd776db9b350..95232bad69966 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCategory.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableProductInCategory.php @@ -28,14 +28,14 @@ protected function assertPrice(FixtureInterface $product, CatalogCategoryView $c $priceBlock = $catalogCategoryView->getListProductBlock()->getProductItem($product)->getPriceBlock(); $priceData = $product->getDataFieldConfig('price')['source']->getPriceData(); $price = isset($priceData['category_price']) ? $priceData['category_price'] : $product->getPrice(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($price, 2, '.', ''), $priceBlock->isOldPriceVisible() ? $priceBlock->getOldPrice() : $priceBlock->getPrice(), 'Product regular price on category page is not correct.' ); if ($product->hasData('special_price')) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($product->getSpecialPrice(), 2, '.', ''), $priceBlock->getSpecialPrice(), 'Product special price on category page is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php index a95b097fede73..bb20f9cc4c3ba 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php @@ -58,7 +58,7 @@ public function processAssert( */ public function assertPrice(CatalogProductView $view, $price, $currency = '') { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $price, $view->getViewBlock()->getPriceBlock()->getPrice($currency), 'Wrong price is displayed on Product page.' diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertOutOfStockOptionIsAbsentOnProductPage.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertOutOfStockOptionIsAbsentOnProductPage.php index 1679d06218e0c..36c2c42a2db1b 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertOutOfStockOptionIsAbsentOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertOutOfStockOptionIsAbsentOnProductPage.php @@ -38,7 +38,7 @@ public function processAssert( $productOptions = $catalogProductView->getConfigurableAttributesBlock()->getSelectOptionsData($option); } $option = $this->isOptionAbsent($outOfStockOption, $productOptions); - \PHPUnit_Framework_Assert::assertTrue($option, 'Out of stock option is present on product page.'); + \PHPUnit\Framework\Assert::assertTrue($option, 'Out of stock option is present on product page.'); } /** diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php index e3b2480c9383f..c5b3c23403534 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeAbsenceInVariationsSearch.php @@ -47,7 +47,7 @@ public function processAssert( $variationsTab = $newProductPage->getProductForm()->getSection(self::TAB_VARIATIONS); $variationsTab->createConfigurations(); $attributesGrid = $variationsTab->getAttributeBlock()->getAttributesGrid(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $attributesGrid->isRowVisible(['frontend_label' => $productAttribute->getFrontendLabel()]), "Product attribute found in Attribute Search form." ); diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeIsConfigurable.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeIsConfigurable.php index 4148ebf074538..1387e9aed20c0 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeIsConfigurable.php +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertProductAttributeIsConfigurable.php @@ -41,7 +41,7 @@ public function processAssert( $variationsSection = $productBlockForm->getSection('variations'); $variationsSection->createConfigurations(); $attributesGrid = $variationsSection->getAttributeBlock()->getAttributesGrid(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $attributesGrid->isRowVisible(['frontend_label' => $attribute->getFrontendLabel()]), "Product attribute is absent on the product page." ); diff --git a/dev/tests/functional/tests/app/Magento/Contact/Test/Constraint/AssertContactUsSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Contact/Test/Constraint/AssertContactUsSuccessMessage.php index ae75a16494dbe..ef1dc8fabc3e9 100644 --- a/dev/tests/functional/tests/app/Magento/Contact/Test/Constraint/AssertContactUsSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Contact/Test/Constraint/AssertContactUsSuccessMessage.php @@ -32,7 +32,7 @@ class AssertContactUsSuccessMessage extends AbstractConstraint */ public function processAssert(ContactIndex $contactIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE_PART_1 . self::SUCCESS_MESSAGE_PART_2, $contactIndex->getMessagesBlock()->getMessage(), 'Wrong message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnCatalogPage.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnCatalogPage.php index 548afaf5cdac8..d9f1941e2ac4e 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnCatalogPage.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnCatalogPage.php @@ -41,7 +41,7 @@ public function processAssert( preg_match('`(.*?)\d`', $price, $matches); $symbolOnPage = isset($matches[1]) ? $matches[1] : null; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $currencySymbol->getCustomCurrencySymbol(), $symbolOnPage, 'Wrong Currency Symbol is displayed on Category page.' diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPage.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPage.php index 5f42c93e51bf2..bcf982275e357 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPage.php @@ -42,7 +42,7 @@ public function processAssert( preg_match('`(.*?)\d`', $price, $matches); $symbolOnPage = isset($matches[1]) ? $matches[1] : null; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $currencySymbol->getCustomCurrencySymbol(), $symbolOnPage, 'Wrong Currency Symbol is displayed on Product page.' diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPageCustomWebsite.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPageCustomWebsite.php index efeb7b640e518..8b85b00e42769 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPageCustomWebsite.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPageCustomWebsite.php @@ -37,7 +37,7 @@ public function processAssert( $priceBlock = $catalogProductView->getViewBlock()->getPriceBlock(); $symbolOnPage = $priceBlock->getCurrencySymbol(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $currencySymbol['customWebsite'], $symbolOnPage, 'Wrong Currency Symbol is displayed on Product page on Custom website.' diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPageMainWebsite.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPageMainWebsite.php index 0b75707c79932..268862e349c46 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPageMainWebsite.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolOnProductPageMainWebsite.php @@ -35,7 +35,7 @@ public function processAssert( $priceBlock = $catalogProductView->getViewBlock()->getPriceBlock(); $symbolOnPage = $priceBlock->getCurrencySymbol(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $currencySymbol['mainWebsite'], $symbolOnPage, 'Wrong Currency Symbol is displayed on Product page on the Main Website.' diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolSuccessSaveMessage.php index b2a2ba242220c..07eb1d430cdaf 100644 --- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Constraint/AssertCurrencySymbolSuccessSaveMessage.php @@ -26,7 +26,7 @@ class AssertCurrencySymbolSuccessSaveMessage extends AbstractConstraint public function processAssert(SystemCurrencySymbolIndex $currencySymbolIndex) { $actualMessage = $currencySymbolIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_SAVE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressCreatedFrontend.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressCreatedFrontend.php index 763c6cd159ca0..abfee067a73de 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressCreatedFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressCreatedFrontend.php @@ -32,7 +32,7 @@ public function processAssert(CustomerAccountIndex $customerAccountIndex, Addres )->render(); $isAddressExists = $customerAccountIndex->getAdditionalAddressBlock() ->isAdditionalAddressExists($addressRenderer); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isAddressExists, 'Customers address is absent in customer address book.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressDeletedFrontend.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressDeletedFrontend.php index fc920521eca4c..54e724fea7300 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressDeletedFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAdditionalAddressDeletedFrontend.php @@ -30,7 +30,7 @@ public function processAssert(CustomerAccountIndex $customerAccountIndex) $customerAccountIndex->open(); $customerAccountIndex->getAccountMenuBlock()->openMenuItem('Address Book'); $actualText = $customerAccountIndex->getAdditionalAddressBlock()->getBlockText(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( self::EXPECTED_MESSAGE == $actualText, 'Expected text is absent in Additional Address block.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAddressDeletedBackend.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAddressDeletedBackend.php index 407bc22e19044..b4edec660c531 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAddressDeletedBackend.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAddressDeletedBackend.php @@ -43,7 +43,7 @@ public function processAssert( ['address' => $deletedAddress] ); $addressToSearch = $addressRenderer->render(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( in_array($addressToSearch, $actualAddresses), 'Deleted address is present on backend during order creation' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAddressDeletedFrontend.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAddressDeletedFrontend.php index f11f955cb9797..a9dc473fe453e 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAddressDeletedFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertAddressDeletedFrontend.php @@ -54,7 +54,7 @@ public function processAssert( $isAddressDeleted = true; } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isAddressDeleted, 'Customer address was not deleted.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertChangePasswordFailMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertChangePasswordFailMessage.php index 361a9d697e430..8d14811554149 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertChangePasswordFailMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertChangePasswordFailMessage.php @@ -28,7 +28,7 @@ class AssertChangePasswordFailMessage extends AbstractConstraint */ public function processAssert(CustomerAccountEdit $customerAccountEdit) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::FAIL_MESSAGE, $customerAccountEdit->getMessages()->getErrorMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertChangingWebsiteChangeCountries.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertChangingWebsiteChangeCountries.php index dbdcad25a3f89..0ad21548e17c3 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertChangingWebsiteChangeCountries.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertChangingWebsiteChangeCountries.php @@ -37,7 +37,7 @@ public function processAssert( $countriesList = $tab->getCountriesList(1); sort($countriesList); sort($expectedList); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $countriesList, $expectedList, 'Wrong country list is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerAddressSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerAddressSuccessSaveMessage.php index 9ed1b3a4cf4ca..02189cbd60183 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerAddressSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerAddressSuccessSaveMessage.php @@ -29,7 +29,7 @@ class AssertCustomerAddressSuccessSaveMessage extends AbstractConstraint public function processAssert(CustomerAccountIndex $customerAccountIndex) { $successMessage = $customerAccountIndex->getMessages()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $successMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendBackButton.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendBackButton.php index d1ffc7393c36d..6aaa90f2eceed 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendBackButton.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendBackButton.php @@ -25,7 +25,7 @@ class AssertCustomerBackendBackButton extends AbstractConstraint public function processAssert(CustomerIndexEdit $customerEditPage, CustomerIndex $customerGridPage) { $customerEditPage->getPageActionsBlock()->back(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $customerGridPage->getCustomerGridBlock()->isVisible(), 'Clicking on "Back" button does not redirect to customers grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendDuplicateErrorMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendDuplicateErrorMessage.php index 805f4d923385a..a6f6e8f935cb1 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendDuplicateErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendDuplicateErrorMessage.php @@ -28,7 +28,7 @@ class AssertCustomerBackendDuplicateErrorMessage extends AbstractConstraint public function processAssert(CustomerIndex $customerIndexPage) { $actualMessage = $customerIndexPage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_SAVE_MESSAGE, $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendFormTitle.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendFormTitle.php index 9d73f8f1b2960..c0d1a0aa2fe16 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendFormTitle.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendFormTitle.php @@ -28,7 +28,7 @@ class AssertCustomerBackendFormTitle extends AbstractConstraint */ public function processAssert(CustomerAccountIndex $pageCustomerIndex, Customer $customer) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $customer->getFirstname() . ' ' . $customer->getLastname(), $pageCustomerIndex->getTitleBlock()->getTitle(), 'Wrong page title is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendRequiredFields.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendRequiredFields.php index a6f749a14b3f1..31fafc8edcbd2 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendRequiredFields.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerBackendRequiredFields.php @@ -30,11 +30,11 @@ public function processAssert(CustomerIndexNew $customerNewPage, array $expected { $actualRequiredFields = $customerNewPage->getCustomerForm()->getJsErrors(); foreach ($expectedRequiredFields as $field) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( isset($actualRequiredFields[$field]), "Field '$field' is not highlighted with an JS error." ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::REQUIRE_MESSAGE, $actualRequiredFields[$field], "Field '$field' is not highlighted as required." diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddressFrontendAddressBook.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddressFrontendAddressBook.php index 36c5b41a86623..275e82a06421d 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddressFrontendAddressBook.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddressFrontendAddressBook.php @@ -44,7 +44,7 @@ public function processAssert( $validated && ($billingAddressRendered == $this->createAddressRenderer($billingAddress)->render()); } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $validated, 'Customer default address on address book tab is not matching the fixture.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddresses.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddresses.php index 07e4717fda4a6..b5e1e5b5e98d7 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddresses.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDefaultAddresses.php @@ -39,7 +39,7 @@ public function processAssert(CustomerAccountIndex $customerAccountIndex, Addres $shippingDataDiff = $this->verifyForm($pattern, $defaultShippingAddress); $dataDiff = array_merge($billingDataDiff, $shippingDataDiff); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $dataDiff, 'Billing or shipping form was filled incorrectly.' . "\nLog:\n" . implode(";\n", $dataDiff) diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDoesNotHaveDefaultAddresses.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDoesNotHaveDefaultAddresses.php index 8794c681d969e..cd75a8c68c89a 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDoesNotHaveDefaultAddresses.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerDoesNotHaveDefaultAddresses.php @@ -48,7 +48,7 @@ public function processAssert(CustomerAccountIndex $customerAccountIndex) ] ]; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedAddressesTextValues, $actualAddressesTextValues, 'Customer has default shipping/billing address but should not.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerFailRegisterMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerFailRegisterMessage.php index 943a80868a18e..316cf09d77162 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerFailRegisterMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerFailRegisterMessage.php @@ -23,7 +23,7 @@ class AssertCustomerFailRegisterMessage extends AbstractConstraint public function processAssert(CustomerAccountCreate $registerPage) { $errorMessage = $registerPage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertNotEmpty( + \PHPUnit\Framework\Assert::assertNotEmpty( $errorMessage, 'No error message is displayed.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForgotPasswordSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForgotPasswordSuccessMessage.php index 73fc3489fc96d..38ea62e719fd6 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForgotPasswordSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForgotPasswordSuccessMessage.php @@ -29,7 +29,7 @@ public function processAssert( CustomerAccountLogin $customerLogin, Customer $customer ) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_MESSAGE, $customer->getEmail()), $customerLogin->getMessages()->getSuccessMessage(), 'Wrong forgot password message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForm.php index 0edf85ea4bfc7..d7f2dc433eba8 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerForm.php @@ -91,7 +91,7 @@ public function processAssert( $dataForm = $pageCustomerIndexEdit->getCustomerForm()->getDataCustomer($customer, $address); $dataDiff = $this->verify($data, $dataForm); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($dataDiff), 'Customer data on edit page(backend) not equals to passed from fixture.' . "\nFailed values: " . implode(', ', $dataDiff) @@ -148,13 +148,13 @@ private function assertCustomerGroupName(Customer $customer, array $formData) $customerGroupName = $customer->getGroupId(); if ($customerGroupName) { - \PHPUnit_Framework_Assert::assertNotEmpty( + \PHPUnit\Framework\Assert::assertNotEmpty( $formData['customer']['group_id'], 'Customer Group value is empty.' ); if (!empty($formData['customer']['group_id'])) { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $customerGroupName, $formData['customer']['group_id'], 'Customer Group name is incorrect.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupAlreadyExists.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupAlreadyExists.php index d00c60cf9b65c..3f80e3b7bf1ea 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupAlreadyExists.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupAlreadyExists.php @@ -25,7 +25,7 @@ class AssertCustomerGroupAlreadyExists extends AbstractConstraint public function processAssert(CustomerGroupNew $customerGroupNew) { $actualMessage = $customerGroupNew->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupChangedToDefaultOnCustomerForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupChangedToDefaultOnCustomerForm.php index a318f8e27707b..10e31f333be43 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupChangedToDefaultOnCustomerForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupChangedToDefaultOnCustomerForm.php @@ -33,7 +33,7 @@ public function processAssert( ) { $customerIndexEdit->open(['id' => $customer->getId()]); $customerFormData = $customerIndexNew->getCustomerForm()->getData($customer); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $customerFormData['group_id'] == $defaultCustomerGroup->getCustomerGroupCode(), "Customer group not set to default after group was deleted." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupFieldsDisabled.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupFieldsDisabled.php index 4bcebf9772be4..b29f703ceb731 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupFieldsDisabled.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupFieldsDisabled.php @@ -27,7 +27,7 @@ public function processAssert( array $disabledFields ) { foreach ($disabledFields as $field) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $customerGroupEdit->getPageMainForm()->isFieldDisabled($field), "Field $field is not disabled." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupForm.php index b0c42134800d8..f5a7f3a262a60 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupForm.php @@ -55,7 +55,7 @@ public function processAssert( $customerGroupIndex->getCustomerGroupGrid()->searchAndOpen($filter); $formData = $customerGroupNew->getPageMainForm()->getData(); $dataDiff = $this->verifyForm($formData, $data); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($dataDiff), 'Customer Group form was filled incorrectly.' . "\nLog:\n" . implode(";\n", $dataDiff) diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupInGrid.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupInGrid.php index 19cc467b8f4d2..ff7bf2bab6742 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupInGrid.php @@ -32,7 +32,7 @@ public function processAssert( ) { $customerGroupIndex->open(); $filter = ['code' => $customerGroup->getCustomerGroupCode()]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $customerGroupIndex->getCustomerGroupGrid()->isRowVisible($filter), 'Group with type \'' . $customerGroup->getCustomerGroupCode() . '\'is absent in customer groups grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotInGrid.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotInGrid.php index c6ecba9b7cfbf..03542995dcbd4 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotInGrid.php @@ -28,7 +28,7 @@ public function processAssert( ) { $customerGroupIndex->open(); $filter = ['code' => $customerGroup->getCustomerGroupCode()]; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $customerGroupIndex->getCustomerGroupGrid()->isRowVisible($filter), 'Group with name \'' . $customerGroup->getCustomerGroupCode() . '\' in customer groups grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnCartPriceRuleForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnCartPriceRuleForm.php index 010d537651ff8..625b140fc165e 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnCartPriceRuleForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnCartPriceRuleForm.php @@ -32,7 +32,7 @@ public function processAssert( /** @var RuleInformation $ruleInformationTab */ $ruleInformationTab = $promoQuoteNew->getSalesRuleForm()->getSection('rule_information'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $ruleInformationTab->isVisibleCustomerGroup($customerGroup), "Customer group {$customerGroup->getCustomerGroupCode()} is still in cart price rule page." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnCatalogPriceRuleForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnCatalogPriceRuleForm.php index 08a7e3039a1ca..ae2083bd8888f 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnCatalogPriceRuleForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnCatalogPriceRuleForm.php @@ -32,7 +32,7 @@ public function processAssert( /** @var RuleInformation $ruleInformationSection */ $ruleInformationSection = $catalogRuleNew->getEditForm()->getSection('rule_information'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $ruleInformationSection->isVisibleCustomerGroup($customerGroup), "Customer group {$customerGroup->getCustomerGroupCode()} is still in catalog price rule page." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnProductForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnProductForm.php index f04f6d6c2a7c0..da8a48f8805a0 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupNotOnProductForm.php @@ -36,7 +36,7 @@ public function processAssert( /** @var AdvancedPricing $advancedPricingTab */ $advancedPricingTab = $catalogProductNew->getProductForm()->getSection('advanced-pricing'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $advancedPricingTab->getTierPriceForm()->isVisibleCustomerGroup($customerGroup), "Customer group {$customerGroup->getCustomerGroupCode()} is still in tier price form on product page." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCartPriceRuleForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCartPriceRuleForm.php index 493b85b2347f1..831160fa2d57d 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCartPriceRuleForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCartPriceRuleForm.php @@ -36,7 +36,7 @@ public function processAssert( /** @var RuleInformation $ruleInformationTab */ $ruleInformationTab = $promoQuoteNew->getSalesRuleForm()->getSection('rule_information'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $ruleInformationTab->isVisibleCustomerGroup($customerGroup), "Customer group {$customerGroup->getCustomerGroupCode()} not in cart price rule page." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCatalogPriceRuleForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCatalogPriceRuleForm.php index accda8f9a1b9c..2e4f6cdd7455a 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCatalogPriceRuleForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCatalogPriceRuleForm.php @@ -36,7 +36,7 @@ public function processAssert( /** @var RuleInformation $ruleInformationSection */ $ruleInformationSection = $catalogRuleNew->getEditForm()->getSection('rule_information'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $ruleInformationSection->isVisibleCustomerGroup($customerGroup), "Customer group {$customerGroup->getCustomerGroupCode()} not in catalog price rule page." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCustomerForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCustomerForm.php index c69c37477cc03..4025a73ed432b 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCustomerForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnCustomerForm.php @@ -51,7 +51,7 @@ public function processAssert( $customerFixtureData = $customer->getData(); $diff = array_diff($customerFixtureData, $customerFormData); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($diff), "Customer group {$customerGroup->getCustomerGroupCode()} not in account information page." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnProductForm.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnProductForm.php index 6241bc9e40e04..2fe5a7dee8492 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupOnProductForm.php @@ -36,7 +36,7 @@ public function processAssert( /** @var AdvancedPricing $advancedPricingTab */ $advancedPricingTab = $catalogProductNew->getProductForm()->getSection('advanced-pricing'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $advancedPricingTab->getTierPriceForm()->isVisibleCustomerGroup($customerGroup), "Customer group {$customerGroup->getCustomerGroupCode()} not in tier price form on product page." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupSuccessDeleteMessage.php index 7dd66de818538..cc01cfbffbdd9 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupSuccessDeleteMessage.php @@ -25,7 +25,7 @@ class AssertCustomerGroupSuccessDeleteMessage extends AbstractConstraint public function processAssert(CustomerGroupIndex $customerGroupIndex) { $actualMessage = $customerGroupIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupSuccessSaveMessage.php index 3db4bddd08a7d..681da9f220ebe 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerGroupSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertCustomerGroupSuccessSaveMessage extends AbstractConstraint public function processAssert(CustomerGroupIndex $customerGroupIndex) { $actualMessage = $customerGroupIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInGrid.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInGrid.php index c58b58a095000..470aecc4a15e0 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInGrid.php @@ -62,7 +62,7 @@ public function processAssert( $errorMessage .= 'is absent in Customer grid.'; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $pageCustomerIndex->getCustomerGridBlock()->isRowVisible($filter, false), $errorMessage ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInfoSuccessSavedMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInfoSuccessSavedMessage.php index b0c1fa97793a5..2cbb7f2ba1a72 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInfoSuccessSavedMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInfoSuccessSavedMessage.php @@ -29,7 +29,7 @@ class AssertCustomerInfoSuccessSavedMessage extends AbstractConstraint public function processAssert(CustomerAccountIndex $customerAccountIndex) { $successMessage = $customerAccountIndex->getMessages()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $successMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInvalidEmail.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInvalidEmail.php index 1a8d20a883b6e..7ea3747cc7927 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInvalidEmail.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerInvalidEmail.php @@ -29,7 +29,7 @@ public function processAssert(CustomerIndexNew $pageCustomerIndexNew) $expectMessage = self::ERROR_EMAIL_MESSAGE; $actualMessage = $pageCustomerIndexNew->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectMessage, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerIsLockedOnBackend.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerIsLockedOnBackend.php index 9285fc9e0d4fa..132f5d44e41c4 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerIsLockedOnBackend.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerIsLockedOnBackend.php @@ -32,7 +32,7 @@ public function processAssert( Customer $customer ) { $customerIndexEdit->open(['id' => $customer->getId()]); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::CUSTOMER_LOCKED_ACCOUNT, $customerIndexEdit->getCustomerForm()->getPersonalInformation('Account Lock'), 'Incorrect customer account status.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogin.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogin.php index 770890192c95d..e138ce9159fe1 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogin.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogin.php @@ -29,7 +29,7 @@ public function processAssert(CmsIndex $cmsIndex, Customer $customer) ['customer' => $customer] )->run(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $cmsIndex->getLinksBlock()->isAuthorizationVisible(), "Authorisation link is visible after Login attempt." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLoginErrorMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLoginErrorMessage.php index d28faa7ff6fa7..83784563f4fa2 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLoginErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLoginErrorMessage.php @@ -29,7 +29,7 @@ class AssertCustomerLoginErrorMessage extends AbstractConstraint public function processAssert( CustomerAccountLogin $customerLogin ) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $customerLogin->getMessages()->getErrorMessage(), 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogout.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogout.php index 5bdf198177c20..9e6b3dfad4966 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogout.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerLogout.php @@ -41,7 +41,7 @@ public function processAssert(CustomerAccountIndex $customerAccountIndex, CmsInd $cmsIndex->getCmsPageBlock()->waitUntilTextIsVisible(self::LOGOUT_PAGE_TITLE); $cmsIndex->getCmsPageBlock()->waitUntilTextIsVisible(self::HOME_PAGE_TITLE); $cmsIndex->getCmsPageBlock()->waitPageInit(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsIndex->getLinksBlock()->isLinkVisible('Sign In'), "Customer wasn't logged out." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerMassDeleteSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerMassDeleteSuccessMessage.php index 30a353a98cc14..bf60ee2db98dc 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerMassDeleteSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerMassDeleteSuccessMessage.php @@ -29,7 +29,7 @@ class AssertCustomerMassDeleteSuccessMessage extends AbstractConstraint */ public function processAssert($customersQtyToDelete, CustomerIndex $customerIndexPage) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_DELETE_MESSAGE, $customersQtyToDelete), $customerIndexPage->getMessagesBlock()->getSuccessMessage(), 'Wrong delete message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerNameFrontend.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerNameFrontend.php index f8fd647a7e4c2..ef455d1fc48f6 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerNameFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerNameFrontend.php @@ -35,7 +35,7 @@ public function processAssert( $infoBlock = $customerAccountIndex->getInfoBlock()->getContactInfoContent(); $infoBlock = explode(PHP_EOL, $infoBlock); $nameInDashboard = $infoBlock[0]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $nameInDashboard == $customerName, 'Customer name in Contact info block is not matching the fixture.' ); @@ -43,7 +43,7 @@ public function processAssert( $customerAccountIndex->getInfoBlock()->openEditContactInfo(); $nameInEdit = $customerAccountEdit->getAccountInfoForm()->getFirstName() . " " . $customerAccountEdit->getAccountInfoForm()->getLastName(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $nameInEdit == $customerName, 'Customer name on Account info tab is not matching the fixture.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerNotInGrid.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerNotInGrid.php index a176ac0c57894..3b9e8d8b5bbbb 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerNotInGrid.php @@ -28,7 +28,7 @@ public function processAssert( CustomerIndex $customerIndexPage ) { $customerIndexPage->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $customerIndexPage->getCustomerGridBlock()->isRowVisible(['email' => $customer->getEmail()]), 'Customer with email ' . $customer->getEmail() . 'is present in Customer grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnAuthorizationPopup.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnAuthorizationPopup.php index e7bb34e44562a..f08a83fd03de5 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnAuthorizationPopup.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnAuthorizationPopup.php @@ -29,7 +29,7 @@ public function processAssert( $cartPage->open(); $cartPage->getProceedToCheckoutBlock()->proceedToCheckout(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $checkoutPage->getAuthenticationPopupBlock()->isPasswordAutocompleteOff(), 'Password field autocomplete is not off.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnSignIn.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnSignIn.php index 656f8ff640571..b989e72f5b02d 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnSignIn.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordAutocompleteOnSignIn.php @@ -23,7 +23,7 @@ class AssertCustomerPasswordAutocompleteOnSignIn extends AbstractConstraint public function processAssert(CustomerAccountLogin $loginPage) { $loginPage->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $loginPage->getLoginBlock()->isPasswordAutocompleteOff(), 'Password field autocomplete is not off.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordChanged.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordChanged.php index 1827b89b07597..9e7a46a383696 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordChanged.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerPasswordChanged.php @@ -52,7 +52,7 @@ public function processAssert( ['customer' => $customer] )->run(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $customerAccountIndex->getAccountMenuBlock()->isVisible(), 'Customer Account Dashboard is not visible.' ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerRedirectToDashboard.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerRedirectToDashboard.php index e5201d18b3fd4..da8f49485d634 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerRedirectToDashboard.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerRedirectToDashboard.php @@ -34,7 +34,7 @@ class AssertCustomerRedirectToDashboard extends AbstractConstraint */ public function processAssert(CustomerAccountIndex $accountIndexPage) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::DASHBOARD_MESSAGE, $accountIndexPage->getTitleBlock()->getTitle(), 'Wrong dashboard title is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessDeleteMessage.php index c9ccace314aa9..886c71e016d63 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessDeleteMessage.php @@ -25,7 +25,7 @@ class AssertCustomerSuccessDeleteMessage extends AbstractConstraint public function processAssert(CustomerIndex $customerIndexPage) { $actualMessage = $customerIndexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessRegisterMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessRegisterMessage.php index b313c102c78e4..f418a176ac82e 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessRegisterMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessRegisterMessage.php @@ -25,7 +25,7 @@ class AssertCustomerSuccessRegisterMessage extends AbstractConstraint public function processAssert(CustomerAccountCreate $registerPage) { $actualMessage = $registerPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessSaveMessage.php index f50029cc01930..a1241b738f06d 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertCustomerSuccessSaveMessage.php @@ -26,7 +26,7 @@ class AssertCustomerSuccessSaveMessage extends AbstractConstraint public function processAssert(CustomerIndex $pageCustomerIndex) { $actualMessage = $pageCustomerIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertMassActionSuccessUpdateMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertMassActionSuccessUpdateMessage.php index 9877ea3d53e03..8c8e1de7b98ed 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertMassActionSuccessUpdateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertMassActionSuccessUpdateMessage.php @@ -35,7 +35,7 @@ class AssertMassActionSuccessUpdateMessage extends AbstractConstraint public function processAssert(array $customers, CustomerIndex $pageCustomerIndex) { $actualMessage = $pageCustomerIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals(sprintf(self::UPDATE_MESSAGE, count($customers)), $actualMessage); + \PHPUnit\Framework\Assert::assertEquals(sprintf(self::UPDATE_MESSAGE, count($customers)), $actualMessage); } /** diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertNoDeleteForSystemCustomerGroup.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertNoDeleteForSystemCustomerGroup.php index 667fa15dcbc15..e8eb62ab05c95 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertNoDeleteForSystemCustomerGroup.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertNoDeleteForSystemCustomerGroup.php @@ -23,7 +23,7 @@ class AssertNoDeleteForSystemCustomerGroup extends AbstractConstraint */ public function processAssert(CustomerGroupEdit $customerGroupEdit) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $customerGroupEdit->getPageMainActions()->checkDeleteButton(), "Delete button is visible." ); diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertWrongPassConfirmationMessage.php b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertWrongPassConfirmationMessage.php index 0c3dba11f7882..11b44fd6fce52 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertWrongPassConfirmationMessage.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Constraint/AssertWrongPassConfirmationMessage.php @@ -35,7 +35,7 @@ public function processAssert(Customer $customer, CustomerAccountEdit $customerA { $validationMessages = $customerAccountEdit->getAccountInfoForm()->getValidationMessages($customer); if (isset($validationMessages['password_confirmation'])) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::CONFIRMATION_MESSAGE, $validationMessages['password_confirmation'], 'Wrong password confirmation validation text message.' diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.php b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.php index bf3cc61e7fc09..753eb28a38ce3 100644 --- a/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/Customer/Test/TestCase/UpdateCustomerFrontendEntityTest.php @@ -149,7 +149,7 @@ public function test( $this->customerAccountEdit->getAccountInfoForm()->fill($customer); $this->customerAccountEdit->getAccountInfoForm()->submit(); - \PHPUnit_Framework_Assert::assertThat($this->getName(), $assertCustomerInfoSuccessSavedMessage); + \PHPUnit\Framework\Assert::assertThat($this->getName(), $assertCustomerInfoSuccessSavedMessage); $this->cmsIndex->getCmsPageBlock()->waitPageInit(); $this->customerAccountIndex->getDashboardAddress()->editBillingAddress(); diff --git a/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/Constraint/AssertExportCustomerAddresses.php b/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/Constraint/AssertExportCustomerAddresses.php index fa9eb6b6f6a78..ea868bb5eac70 100644 --- a/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/Constraint/AssertExportCustomerAddresses.php +++ b/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/Constraint/AssertExportCustomerAddresses.php @@ -32,7 +32,7 @@ public function processAssert( $exportData = $export->getLatest(); foreach ($customer->getDataFieldConfig('address')['source']->getAddresses() as $address) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->isAddressDataInFile( $exportedFields, $customer, diff --git a/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/Constraint/AssertImportCustomerAddresses.php b/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/Constraint/AssertImportCustomerAddresses.php index 5d379aae8b701..18b2d44a22ff1 100644 --- a/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/Constraint/AssertImportCustomerAddresses.php +++ b/dev/tests/functional/tests/app/Magento/CustomerImportExport/Test/Constraint/AssertImportCustomerAddresses.php @@ -91,7 +91,7 @@ public function processAssert( $resultArrays = $this->getPrepareAddresses(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $resultArrays['pageData'], $resultArrays['csvData'], 'Addresses from page and csv are not match.' diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnCatalogPage.php b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnCatalogPage.php index 61634f71096f5..a2f3c96463174 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnCatalogPage.php +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnCatalogPage.php @@ -42,7 +42,7 @@ public function processAssert( $priceBlock = $catalogCategoryView->getListProductBlock()->getProductItem($product)->getPriceBlock(); $actualPrice = $priceBlock->getPrice(''); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $basePrice, $actualPrice, 'Wrong price is displayed on Category page.' @@ -52,7 +52,7 @@ public function processAssert( $cmsIndex->getTopmenu()->selectCategoryByName($categoryName); $actualPrice = $priceBlock->getPrice(''); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $convertedPrice, $actualPrice, 'Wrong price is displayed on Category page.' diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php index 7a8ea29daf834..64fb44f37dbd5 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php @@ -43,7 +43,7 @@ public function processAssert( */ public function assertPrice(CatalogProductView $view, $price, $currency = '') { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $price, $view->getViewBlock()->getPriceBlock()->getPrice($currency), 'Wrong price is displayed on Product page.' diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateSuccessSaveMessage.php index 7d700a74c3b51..80d0098e2d188 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertCurrencyRateSuccessSaveMessage extends AbstractConstraint public function processAssert(SystemCurrencyIndex $currencyIndexPage) { $actualMessage = $currencyIndexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertShippingPriceWithCustomCurrency.php b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertShippingPriceWithCustomCurrency.php index 252b672fb62bb..a76e773e28c02 100644 --- a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertShippingPriceWithCustomCurrency.php +++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertShippingPriceWithCustomCurrency.php @@ -47,7 +47,7 @@ public function processAssert( ['products' => [$product]] )->run(); $testStepFactory->create(\Magento\Checkout\Test\TestStep\ProceedToCheckoutStep::class)->run(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $shippingAmount, $checkoutOnepage->getShippingMethodBlock()->getShippingMethodAmount($shipping), 'Shipping amount is not correct in the checkout page.' diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AbstractAssertTaxCalculationAfterCheckoutDownloadable.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AbstractAssertTaxCalculationAfterCheckoutDownloadable.php index d29f25f4e43d3..5771218e53f97 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AbstractAssertTaxCalculationAfterCheckoutDownloadable.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AbstractAssertTaxCalculationAfterCheckoutDownloadable.php @@ -59,7 +59,7 @@ public function processAssert( $prices = $this->preparePrices($prices); //Order review prices verification $message = 'Prices on order review should be equal to defined in dataset.'; - \PHPUnit_Framework_Assert::assertEquals($prices, array_filter($actualPrices), $message); + \PHPUnit\Framework\Assert::assertEquals($prices, array_filter($actualPrices), $message); $checkoutOnepage->getPaymentBlock()->placeOrder(); $checkoutOnepageSuccess->getSuccessBlock()->getGuestOrderId(); @@ -70,6 +70,6 @@ public function processAssert( //Frontend order prices verification $message = 'Prices on order view page should be equal to defined in dataset.'; - \PHPUnit_Framework_Assert::assertEquals($prices, array_filter($actualPrices), $message); + \PHPUnit\Framework\Assert::assertEquals($prices, array_filter($actualPrices), $message); } } diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPricesDownloadable.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPricesDownloadable.php index d8022e387486b..d4cad16fa82b1 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPricesDownloadable.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPricesDownloadable.php @@ -71,6 +71,6 @@ public function processAssert( $actualPrices = $this->getTotals($actualPrices); //Prices verification $message = 'Prices from dataset should be equal to prices on frontend'; - \PHPUnit_Framework_Assert::assertEquals($prices, array_filter($actualPrices), $message); + \PHPUnit\Framework\Assert::assertEquals($prices, array_filter($actualPrices), $message); } } diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AssertDownloadableLinksData.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AssertDownloadableLinksData.php index 60c611ed9c070..a537fff86c823 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AssertDownloadableLinksData.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AssertDownloadableLinksData.php @@ -62,7 +62,7 @@ public function processAssert( $pageOptions = $catalogProductView->getViewBlock()->getOptions($product); $pageDownloadableLinks = $this->preparePageData($pageOptions['downloadable_options']['downloadable_links']); $error = $this->verifyData($fixtureDownloadableLinks, $pageDownloadableLinks); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AssertDownloadableSamplesData.php b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AssertDownloadableSamplesData.php index f2ae9f009be66..34587b5a44c1a 100644 --- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AssertDownloadableSamplesData.php +++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/Constraint/AssertDownloadableSamplesData.php @@ -58,7 +58,7 @@ public function processAssert( ? $this->preparePageData($pageOptions['downloadable_options']['downloadable_sample']) : []; $error = $this->verifyData($fixtureSampleLinks, $pageSampleLinks); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Email/Test/Constraint/AssertEmailTemplateSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Email/Test/Constraint/AssertEmailTemplateSuccessSaveMessage.php index 748da41e9815a..aafadb72b1ae2 100644 --- a/dev/tests/functional/tests/app/Magento/Email/Test/Constraint/AssertEmailTemplateSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Email/Test/Constraint/AssertEmailTemplateSuccessSaveMessage.php @@ -21,7 +21,7 @@ class AssertEmailTemplateSuccessSaveMessage extends AbstractConstraint public function processAssert(EmailTemplateIndex $emailTemplateIndex) { $actualMessage = $emailTemplateIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInBackendOrder.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInBackendOrder.php index 3d001cd80f707..9d37f7430c032 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInBackendOrder.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInBackendOrder.php @@ -74,7 +74,7 @@ public function processAssert( } $errors = $this->verifyData($expectedData, $actualData); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } /** diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrder.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrder.php index a310cb2b2ee49..5f383904a96f7 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrder.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrder.php @@ -50,7 +50,7 @@ public function processAssert( $orderHistory->open(); $orderHistory->getOrderHistoryBlock()->openOrderById($orderId); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedData, $customerOrderView->getGiftMessageForOrderBlock()->getGiftMessage(), 'Wrong gift message is displayed on order.' diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrderItems.php b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrderItems.php index 6347a518ed784..484db6e3ca7c7 100644 --- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrderItems.php +++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/Constraint/AssertGiftMessageInFrontendOrderItems.php @@ -66,7 +66,7 @@ public function processAssert( $expectedData = []; } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedData, $customerOrderView->getGiftMessageForItemBlock()->getGiftMessage($product->getName()), 'Wrong gift message is displayed on "' . $product->getName() . '" item.' diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPricesOnGroupedProductPage.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPricesOnGroupedProductPage.php index 34f4be91bd083..336a959694488 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPricesOnGroupedProductPage.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPricesOnGroupedProductPage.php @@ -76,6 +76,6 @@ public function processAssert( $actualPrices = $this->getTotals($actualPrices); //Prices verification $message = 'Prices from dataset should be equal to prices on frontend.'; - \PHPUnit_Framework_Assert::assertEquals($prices, $actualPrices, $message); + \PHPUnit\Framework\Assert::assertEquals($prices, $actualPrices, $message); } } diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductForm.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductForm.php index 87658d9a88b12..691bb86ca0f1f 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductForm.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductForm.php @@ -40,7 +40,7 @@ public function processAssert( $fieldsFixture['associated'] = $this->prepareGroupedOptions($fieldsFixture['associated']); $errors = $this->verifyData($fieldsFixture, $fieldsForm); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } /** diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductInItemsOrderedGrid.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductInItemsOrderedGrid.php index 340d1ffbe297e..8688dc71aa8c2 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductInItemsOrderedGrid.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductInItemsOrderedGrid.php @@ -49,7 +49,7 @@ public function processAssert(OrderCreateIndex $orderCreateIndex, array $product } $data = $this->prepareData($products, $orderCreateIndex->getCreateBlock()->getItemsBlock()); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $data['fixtureData'], $data['pageData'], 'Grouped product data on order create page not equals to passed from fixture.' diff --git a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductsDefaultQty.php b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductsDefaultQty.php index 8df7c62dca43f..1a2d5304e6ce2 100644 --- a/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductsDefaultQty.php +++ b/dev/tests/functional/tests/app/Magento/GroupedProduct/Test/Constraint/AssertGroupedProductsDefaultQty.php @@ -52,7 +52,7 @@ public function processAssert( $pageQtyData = $this->sortDataByPath($pageQtyData, '::name'); $error = $this->verifyData($fixtureQtyData, $pageQtyData); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertExportNoDataErrorMessage.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertExportNoDataErrorMessage.php index fca15644dee43..25e4d4b39174e 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertExportNoDataErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertExportNoDataErrorMessage.php @@ -28,7 +28,7 @@ public function processAssert(AdminExportIndex $adminExportIndex) { $actualMessage = $adminExportIndex->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckData.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckData.php index 358d9aefee251..810883f58eafd 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckData.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckData.php @@ -36,7 +36,7 @@ public function processAssert(AdminImportIndex $adminImportIndex, ImportData $im : count($file->getEntities()); $message = $adminImportIndex->getMessagesBlock()->getNoticeMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::RESULT_MESSAGE, $rowsCount, $entitiesCount), $message, 'Wrong validation result message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckDataErrorMessage.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckDataErrorMessage.php index 1ffdcb3956be3..555976e6cac33 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckDataErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckDataErrorMessage.php @@ -28,9 +28,9 @@ public function processAssert(AdminImportIndex $adminImportIndex) { $actualMessage = $adminImportIndex->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertNotFalse($actualMessage, 'Error message is absent.'); + \PHPUnit\Framework\Assert::assertNotFalse($actualMessage, 'Error message is absent.'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( static::ERROR_MESSAGE, $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckDataErrorMessagesList.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckDataErrorMessagesList.php index 1394270c82814..af8493df3ff9d 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckDataErrorMessagesList.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckDataErrorMessagesList.php @@ -24,8 +24,8 @@ public function processAssert(array $patterns, AdminImportIndex $adminImportInde { $messages = $adminImportIndex->getMessagesBlock()->getErrorsList(); - \PHPUnit_Framework_Assert::assertNotFalse($messages, 'Errors messages block is absent.'); - \PHPUnit_Framework_Assert::assertNotEmpty($messages, 'Errors messages is absent.'); + \PHPUnit\Framework\Assert::assertNotFalse($messages, 'Errors messages block is absent.'); + \PHPUnit\Framework\Assert::assertNotEmpty($messages, 'Errors messages is absent.'); $errors = []; foreach ($messages as $message) { @@ -34,7 +34,7 @@ public function processAssert(array $patterns, AdminImportIndex $adminImportInde } } - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $errors, 'This assertions contains next errors:' . PHP_EOL . implode(PHP_EOL, $errors) ); diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportSuccessMessage.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportSuccessMessage.php index 2ecd646855f76..ca75e3b203f63 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportSuccessMessage.php @@ -28,7 +28,7 @@ class AssertImportSuccessMessage extends AbstractConstraint public function processAssert(AdminImportIndex $adminImportIndex) { $validationMessage = $adminImportIndex->getMessagesBlock()->getImportResultMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $validationMessage, 'Wrong validation result is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertProductAttributeAbsenceForExport.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertProductAttributeAbsenceForExport.php index 1854b32faf04f..5281b211d76a6 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertProductAttributeAbsenceForExport.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertProductAttributeAbsenceForExport.php @@ -37,7 +37,7 @@ public function processAssert( 'attribute_code' => $attribute->getAttributeCode(), ]; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $exportIndex->getFilterExport()->isRowVisible($filter), 'Attribute \'' . $attribute->getFrontendLabel() . '\' is present in Filter export grid' ); diff --git a/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertIndexerStatus.php b/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertIndexerStatus.php index 147511a63dc11..f28ed21361658 100644 --- a/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertIndexerStatus.php +++ b/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertIndexerStatus.php @@ -38,7 +38,7 @@ public function processAssert(IndexManagement $indexManagement, array $indexers, $indexManagement->open(); foreach ($indexers as $indexer) { $indexerStatus = $indexManagement->getMainBlock()->getIndexerStatus($indexer); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedStatus, $indexerStatus, 'Wrong ' . $indexer . ' status is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertUpdateByScheduleSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertUpdateByScheduleSuccessSaveMessage.php index 4476ac686802b..7e7587e553d5a 100644 --- a/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertUpdateByScheduleSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Indexer/Test/Constraint/AssertUpdateByScheduleSuccessSaveMessage.php @@ -29,7 +29,7 @@ class AssertUpdateByScheduleSuccessSaveMessage extends AbstractConstraint public function processAssert(IndexManagement $indexManagement, array $indexers) { $actualMessage = $indexManagement->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_SAVE_MESSAGE, count($indexers)), $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php index 4ebdd127b9d9e..f59ff908cc175 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAdminUriAutogenerated.php @@ -27,7 +27,7 @@ class AssertAdminUriAutogenerated extends AbstractConstraint */ public function processAssert(Install $installPage) { - \PHPUnit_Framework_Assert::assertRegExp( + \PHPUnit\Framework\Assert::assertRegExp( self::ADMIN_URI_PATTERN, $installPage->getWebConfigBlock()->getAdminUriCheck(), 'Unexpected Backend Frontname pattern.' diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAgreementTextPresent.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAgreementTextPresent.php index fab5a1f3558af..600e97a545cca 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAgreementTextPresent.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertAgreementTextPresent.php @@ -34,13 +34,13 @@ class AssertAgreementTextPresent extends AbstractConstraint public function processAssert(Install $installPage) { try { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::LICENSE_AGREEMENT_TEXT, $installPage->getLicenseBlock()->getLicense(), 'License agreement text is absent.' ); } catch (\Exception $e) { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::DEFAULT_LICENSE_AGREEMENT_TEXT, $installPage->getLicenseBlock()->getLicense(), 'License agreement text is absent.' diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertCurrencySelected.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertCurrencySelected.php index b512dc3b5e006..9e6eb0159e743 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertCurrencySelected.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertCurrencySelected.php @@ -23,7 +23,7 @@ class AssertCurrencySelected extends AbstractConstraint */ public function processAssert($currencySymbol, Dashboard $dashboardPage) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( strpos($dashboardPage->getMainBlock()->getRevenuePrice(), $currencySymbol) !== false, 'Selected currency symbol not displays on dashboard.' ); diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertDevdocsLink.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertDevdocsLink.php index 27cd62cfa1936..3e5dfe62d527c 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertDevdocsLink.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertDevdocsLink.php @@ -27,7 +27,7 @@ class AssertDevdocsLink extends AbstractConstraint */ public function processAssert(DevdocsInstall $devdocsInstallPage) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::DEVDOCS_TITLE_TEXT, $devdocsInstallPage->getDevdocsBlock()->getDevdocsTitle(), 'Developer Documentation link is wrong.' diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertGenerationFilePathCheck.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertGenerationFilePathCheck.php index 3e637416137c6..6afe876525f13 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertGenerationFilePathCheck.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertGenerationFilePathCheck.php @@ -38,14 +38,14 @@ public function processAssert(PathChecker $pathChecker) ]; foreach ($existsPaths as $path) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $pathChecker->pathExists($path), 'Path "' . $path . '" does not exist.' ); } foreach ($nonExistsPaths as $path) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $pathChecker->pathExists($path), 'Path "' . $path . '" exists.' ); diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertKeyCreated.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertKeyCreated.php index 4d4fcd14c915d..cec2921b2c080 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertKeyCreated.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertKeyCreated.php @@ -24,7 +24,7 @@ class AssertKeyCreated extends AbstractConstraint */ public function processAssert(Install $installPage, InstallConfig $installConfig) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $installConfig->getKeyValue(), $installPage->getInstallBlock()->getAdminInfo()['encryption_key'], 'Selected encryption key on install page not equals to data from fixture.' diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php index 50ed5d2664511..236b9805ea1c6 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertLanguageSelected.php @@ -24,7 +24,7 @@ class AssertLanguageSelected extends AbstractConstraint public function processAssert($languageTemplate, CmsIndex $indexPage) { $indexPage->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $indexPage->getFooterBlock()->isLinkVisible($languageTemplate), 'Selected language not displays on frontend.' ); diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertRewritesEnabled.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertRewritesEnabled.php index 13236d8aa0e6e..ca6180fc97dd1 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertRewritesEnabled.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertRewritesEnabled.php @@ -29,7 +29,7 @@ public function processAssert(Category $category, CmsIndex $homePage, BrowserInt $homePage->open(); $homePage->getTopmenu()->selectCategoryByName($category->getName()); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( strpos($browser->getUrl(), 'index.php') === false, 'Apache redirect for category does not work.' ); diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSecureUrlEnabled.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSecureUrlEnabled.php index dc819bd18f7b6..f5d029620a32b 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSecureUrlEnabled.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSecureUrlEnabled.php @@ -34,13 +34,13 @@ public function processAssert( CustomerAccountLogin $customerAccountLogin ) { $dashboard->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( strpos($browser->getUrl(), 'https://') !== false, 'Secure Url is not displayed on backend.' ); $customerAccountLogin->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( strpos($browser->getUrl(), 'https://') !== false, 'Secure Url is not displayed on frontend.' ); diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSuccessInstall.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSuccessInstall.php index ad498dd02e67f..3f0c240834aad 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSuccessInstall.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSuccessInstall.php @@ -79,14 +79,14 @@ public function processAssert(Install $installPage, InstallConfig $installConfig private function checkInstallData(array $allData, array $adminData, array $dbData) { foreach ($this->adminFieldsList as $field) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $allData[$field['fixture']], $adminData[$field['pageData']], 'Wrong admin information is displayed.' ); } foreach ($this->dbFieldsList as $field) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $allData[$field['fixture']], $dbData[$field['pageData']], 'Wrong database information is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSuccessfulReadinessCheck.php b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSuccessfulReadinessCheck.php index 4fc2490362a0e..2c3e74ef873b3 100644 --- a/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSuccessfulReadinessCheck.php +++ b/dev/tests/functional/tests/app/Magento/Install/Test/Constraint/AssertSuccessfulReadinessCheck.php @@ -37,17 +37,17 @@ class AssertSuccessfulReadinessCheck extends AbstractConstraint */ public function processAssert(Install $installPage) { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::PHP_VERSION_MESSAGE, $installPage->getReadinessBlock()->getPhpVersionCheck(), 'PHP version is incorrect.' ); - \PHPUnit_Framework_Assert::assertRegExp( + \PHPUnit\Framework\Assert::assertRegExp( self::PHP_EXTENSIONS_REGEXP, $installPage->getReadinessBlock()->getPhpExtensionsCheck(), 'PHP extensions missed.' ); - \PHPUnit_Framework_Assert::assertRegExp( + \PHPUnit\Framework\Assert::assertRegExp( self::FILE_PERMISSION_REGEXP, $installPage->getReadinessBlock()->getFilePermissionCheck(), 'File permissions does not meet requirements.' diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertEmailValidationErrorGenerated.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertEmailValidationErrorGenerated.php index f9f3bd5800495..93c24b89131f9 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertEmailValidationErrorGenerated.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertEmailValidationErrorGenerated.php @@ -34,7 +34,7 @@ public function processAssert( break; } } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $emailJsError, 'Failed to validate email address (' . $integration->getEmail() . ') when saving integration.' ); diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIncorrectUserPassword.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIncorrectUserPassword.php index dbdd8f0c3708a..b0b2f6dbae8ab 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIncorrectUserPassword.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIncorrectUserPassword.php @@ -27,7 +27,7 @@ public function processAssert( IntegrationIndex $integrationIndexPage ) { $actualMessage = $integrationIndexPage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationForm.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationForm.php index 3d9b826bb162b..85111c12aa0b9 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationForm.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationForm.php @@ -70,7 +70,7 @@ public function processAssert( unset($formData['current_password']); unset($data['current_password']); $dataDiff = $this->verifyForm($formData, $data); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $dataDiff, 'Integration form was filled incorrectly.' . "\nLog:\n" . implode(";\n", $dataDiff) diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationInGrid.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationInGrid.php index 985cc56b8177c..64fa30ca6a06f 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationInGrid.php @@ -36,7 +36,7 @@ public function processAssert( ]; $integrationIndexPage->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $integrationIndexPage->getIntegrationGrid()->isRowVisible($filter), 'Integration \'' . $filter['name'] . '\' is absent in Integration grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationNameDuplicationErrorMessage.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationNameDuplicationErrorMessage.php index d947e842830c8..4b9f6c017fe48 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationNameDuplicationErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationNameDuplicationErrorMessage.php @@ -30,7 +30,7 @@ public function processAssert( ) { $expectedMessage = sprintf(self::ERROR_DUPLICATE_INTEGRATION_NAME, $integration->getName()); $actualMessage = $integrationIndexPage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedMessage, $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationNotInGrid.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationNotInGrid.php index e1916b01e6669..1d9240ac82aa6 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationNotInGrid.php @@ -28,7 +28,7 @@ public function processAssert(IntegrationIndex $integrationIndexPage, Integratio $filter = ['name' => $integration->getName()]; $integrationIndexPage->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $integrationIndexPage->getIntegrationGrid()->isRowVisible($filter), 'Integration \'' . $filter['name'] . '\' is present in Integration grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationResourcesPopup.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationResourcesPopup.php index 1e2f2aac8d5d3..32c75c224f588 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationResourcesPopup.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationResourcesPopup.php @@ -31,7 +31,7 @@ public function processAssert(IntegrationIndex $integrationIndex, Integration $i : [$integration->getResources()]; $formResources = $integrationIndex->getIntegrationGrid()->getResourcesPopup()->getStructure($resourceDepth); $result = $this->verifyResources($formResources, $fixtureResources); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $result, "Integration resources is not correct.\nLog:\n" . $result ); diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessActivationMessage.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessActivationMessage.php index c728ed9cde8a9..c984eaae41a3a 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessActivationMessage.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessActivationMessage.php @@ -31,7 +31,7 @@ public function processAssert( ) { $expectedMessage = sprintf(self::SUCCESS_ACTIVATION_MESSAGE, $integration->getName()); $actualMessage = $integrationIndexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedMessage, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessDeleteMessage.php index 1c7a1b6f3b1d8..04e0d2a090abe 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessDeleteMessage.php @@ -29,7 +29,7 @@ public function processAssert(IntegrationIndex $integrationIndexPage, Integratio { $expectedMessage = sprintf(self::SUCCESS_DELETE_MESSAGE, $integration->getName()); $actualMessage = $integrationIndexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedMessage, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessReauthorizeMessage.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessReauthorizeMessage.php index b7387974c07e0..b2db5b905b0ee 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessReauthorizeMessage.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessReauthorizeMessage.php @@ -32,7 +32,7 @@ public function processAssert( IntegrationIndex $integrationIndexPage, Integration $integration ) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_REAUTHORIZE_MESSAGE, $integration->getName()), $integrationIndexPage->getMessagesBlock()->getSuccessMessage(), "Wrong success message is displayed." diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessSaveMessage.php index d1fdc99e64c30..75dc1adbf293f 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessSaveMessage.php @@ -36,7 +36,7 @@ public function processAssert( : $integration->getName(); $expectedMessage = sprintf(self::SUCCESS_SAVE_MESSAGE, $name); $actualMessage = $integrationIndexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedMessage, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessSaveMessageNotPresent.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessSaveMessageNotPresent.php index a9636517c8ee9..b307091cfb606 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessSaveMessageNotPresent.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationSuccessSaveMessageNotPresent.php @@ -33,7 +33,7 @@ public function processAssert( } else { $noSuccessMessage = true; } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $noSuccessMessage, 'Integration is not saved.' ); diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationTokensAfterReauthorize.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationTokensAfterReauthorize.php index 9834b03e1867f..b9adb6bfa2f3e 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationTokensAfterReauthorize.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationTokensAfterReauthorize.php @@ -61,7 +61,7 @@ public function processAssert( $actualData = $integrationNew->getIntegrationForm()->getData(); $errors = $this->checkTokens($actualData, $integration->getData()); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $errors, "Integration tokens was changed incorrectly.\nLog:\n" . implode(";\n", $errors) ); diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationTokensPopup.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationTokensPopup.php index 8adc425443262..22fddd2b17289 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationTokensPopup.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertIntegrationTokensPopup.php @@ -56,7 +56,7 @@ public function processAssert(IntegrationIndex $integrationIndex) $errors[] = 'Field with key: ' . $key . '" is empty in integration tokens.'; } } - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $errors, "Integration tokens is not correct.\nLog:\n" . implode(";\n", $errors) ); diff --git a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertNoAlertPopup.php b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertNoAlertPopup.php index a1f1b75ce565b..cb59be6634df4 100644 --- a/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertNoAlertPopup.php +++ b/dev/tests/functional/tests/app/Magento/Integration/Test/Constraint/AssertNoAlertPopup.php @@ -27,7 +27,7 @@ public function processAssert( if ($isAlertPresent) { $integrationNew->getFormPageActions()->acceptAlert(); } - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $isAlertPresent, 'Saving an integration should not cause alert.' ); diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertCategoryLayeredNavigation.php b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertCategoryLayeredNavigation.php index ac3d613811eb4..e610b131cec60 100644 --- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertCategoryLayeredNavigation.php +++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertCategoryLayeredNavigation.php @@ -39,7 +39,7 @@ public function processAssert( $this->browser = $browser; $this->openCategory($category->getDataFieldConfig('parent_id')['source']->getParentCategory()); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogCategoryView->getLayeredNavigationBlock()->isCategoryVisible($category, 1), 'Category ' . $category->getName() . ' is absent in Layered Navigation.' ); @@ -47,7 +47,7 @@ public function processAssert( $productsOnCategoryPage = $catalogCategoryView->getListProductBlock()->getProductNames(); $productsInCategory = $category->getDataFieldConfig('category_products')['source']->getProducts(); foreach ($productsInCategory as $product) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array($product->getName(), $productsOnCategoryPage), 'Product ' . $product->getName() . ' is absent on category page.' ); diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertCategorySortingOnFilteredProductList.php b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertCategorySortingOnFilteredProductList.php index ddda01b8fdf94..3cf996fbc6cbd 100644 --- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertCategorySortingOnFilteredProductList.php +++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertCategorySortingOnFilteredProductList.php @@ -62,7 +62,7 @@ function ($productKey) { } } $catalogCategoryView->getTopToolbar()->applySorting($sortBy); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( array_map( function ($index) { return $this->products[$index]->getName(); diff --git a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php index ea80e5ac22480..9fa1fa01bacca 100644 --- a/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php +++ b/dev/tests/functional/tests/app/Magento/LayeredNavigation/Test/Constraint/AssertFilterProductList.php @@ -53,7 +53,7 @@ public function processAssert( sort($productNames); $pageProductNames = $catalogCategoryView->getListProductBlock()->getProductNames(); sort($pageProductNames); - \PHPUnit_Framework_Assert::assertEquals($productNames, $pageProductNames); + \PHPUnit\Framework\Assert::assertEquals($productNames, $pageProductNames); } $catalogCategoryView->getLayeredNavigationBlock()->clearAll(); } diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMapOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMapOnCategoryPage.php index 734c06b003d3e..5d59fd4c452ae 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMapOnCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMapOnCategoryPage.php @@ -37,14 +37,14 @@ public function processAssert( $productBlock = $catalogCategoryView->getMsrpListProductBlock()->getProductItem($product); $productBlock->openMapBlock(); $mapBlock = $productBlock->getMapBlock(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $product->getMsrp(), $mapBlock->getOldPrice(), 'Displayed on Category page MAP is incorrect.' ); $priceData = $product->getDataFieldConfig('price')['source']->getPriceData(); $price = isset($priceData['category_price']) ? $priceData['category_price'] : $product->getPrice(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $price, $mapBlock->getActualPrice(), 'Displayed on Category page price is incorrect.' diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMapOnProductView.php b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMapOnProductView.php index c3699ea7bc2f5..3b35cbe7eca5d 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMapOnProductView.php +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMapOnProductView.php @@ -41,14 +41,14 @@ public function processAssert( $viewBlock = $catalogProductView->getMsrpViewBlock(); $viewBlock->openMapBlock(); $mapBlock = $viewBlock->getMapBlock(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $product->getMsrp(), $mapBlock->getOldPrice(), 'Displayed on Product view page MAP is incorrect.' ); $priceData = $product->getDataFieldConfig('price')['source']->getPriceData(); $price = isset($priceData['category_price']) ? $priceData['category_price'] : $product->getPrice(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $price, $mapBlock->getActualPrice(), 'Displayed on Product view page price is incorrect.' diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpInShoppingCart.php index d491309100d3e..4615ef47eb393 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpInShoppingCart.php +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpInShoppingCart.php @@ -54,7 +54,7 @@ public function processAssert( $priceData = $product->getDataFieldConfig('price')['source']->getPriceData(); $productPrice = isset($priceData['category_price']) ? $priceData['category_price'] : $product->getPrice(); $unitPrice = $checkoutCart->getCartBlock()->getCartItem($product)->getPrice(); - \PHPUnit_Framework_Assert::assertEquals($productPrice, $unitPrice, 'Incorrect unit price is displayed in Cart'); + \PHPUnit\Framework\Assert::assertEquals($productPrice, $unitPrice, 'Incorrect unit price is displayed in Cart'); } /** diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpOnCategoryPage.php index 7ef9e44bacad8..f77a6dbe4cad2 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpOnCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpOnCategoryPage.php @@ -35,18 +35,18 @@ public function processAssert( $cmsIndex->getTopmenu()->selectCategoryByName($product->getCategoryIds()[0]); $productBlock = $catalogCategoryView->getMsrpListProductBlock()->getProductItem($product); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productBlock->isVisible(), 'Product is invisible on Category page.' ); $priceBlock = $productBlock->getPriceBlock(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $product->getMsrp(), $priceBlock->getOldPrice(), 'Displayed on Category page MSRP is incorrect.' ); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $priceBlock->isRegularPriceVisible(), 'Regular price on Category page is visible and not expected.' ); diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpOnProductView.php b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpOnProductView.php index fb0d9803dbae3..2b8683c7c0e22 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpOnProductView.php +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertMsrpOnProductView.php @@ -40,12 +40,12 @@ public function processAssert( $viewBlock = $catalogProductView->getMsrpViewBlock(); $priceBlock = $viewBlock->getPriceBlock(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $product->getMsrp(), $priceBlock->getOldPrice(), 'Displayed on Product view page MSRP is incorrect' ); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $priceBlock->isRegularPriceVisible(), 'Regular price on Product view page is visible and not expected.' ); diff --git a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertProductEditPageAdvancedPricingFields.php b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertProductEditPageAdvancedPricingFields.php index a9860ab7b7715..d1b56bcf5c0f8 100644 --- a/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertProductEditPageAdvancedPricingFields.php +++ b/dev/tests/functional/tests/app/Magento/Msrp/Test/Constraint/AssertProductEditPageAdvancedPricingFields.php @@ -33,7 +33,7 @@ public function processAssert(CatalogProductEdit $catalogProductEdit, FixtureInt $catalogProductEdit->getProductForm()->openSection('advanced-pricing'); $advancedPricing = $catalogProductEdit->getProductForm()->getSection('advanced-pricing'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $advancedPricing->checkField($this->manufacturerFieldTitle), '"Manufacturer\'s Suggested Retail Price" field is not correct.' ); diff --git a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Constraint/AssertMultishippingOrderSuccessPlacedMessage.php b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Constraint/AssertMultishippingOrderSuccessPlacedMessage.php index 4a5853cae0026..c023e5c375372 100644 --- a/dev/tests/functional/tests/app/Magento/Multishipping/Test/Constraint/AssertMultishippingOrderSuccessPlacedMessage.php +++ b/dev/tests/functional/tests/app/Magento/Multishipping/Test/Constraint/AssertMultishippingOrderSuccessPlacedMessage.php @@ -31,7 +31,7 @@ class AssertMultishippingOrderSuccessPlacedMessage extends AbstractConstraint */ public function processAssert(MultishippingCheckoutSuccess $multishippingCheckoutSuccess) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $multishippingCheckoutSuccess->getTitleBlock()->getTitle(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertCustomerIsSubscribedToNewsletter.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertCustomerIsSubscribedToNewsletter.php index 106f0c2da3792..254d0209c7d9f 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertCustomerIsSubscribedToNewsletter.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertCustomerIsSubscribedToNewsletter.php @@ -35,7 +35,7 @@ public function processAssert( ]; $subscriberIndex->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $subscriberIndex->getSubscriberGrid()->isRowVisible($filter), 'Customer with email \'' . $customer->getEmail() . '\' is absent in Newsletter Subscribers grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterForm.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterForm.php index 30e69a90f3ac7..6f606171b9eed 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterForm.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterForm.php @@ -30,7 +30,7 @@ public function processAssert(TemplateIndex $templateIndex, TemplateEdit $templa $templateIndex->open()->getNewsletterTemplateGrid()->searchAndOpen(['code' => $template->getCode()]); $errors = $this->verifyData($template->getData(), $templateEdit->getEditForm()->getData($template)); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } /** diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterInGrid.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterInGrid.php index 531aa6f0e2343..f5156f0417df1 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterInGrid.php @@ -34,7 +34,7 @@ public function processAssert( ) { $templateIndex->open(); $filter = ['code' => $template->getCode()]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $templateIndex->getNewsletterTemplateGrid()->isRowVisible($filter), 'Newsletter \'' . $template->getCode() . '\'is absent in newsletter template grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterPreview.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterPreview.php index 426d1d9e97d1d..c990e79ad0824 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterPreview.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterPreview.php @@ -33,7 +33,7 @@ public function processAssert( $browser->selectWindow(); $content = $templatePreview->getContent()->getPageContent(); $browser->closeWindow(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $newsletter->getText(), $content, 'Template content not correct information.' diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueue.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueue.php index 753414d0ff52a..1283ca4af9a9e 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueue.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueue.php @@ -33,7 +33,7 @@ class AssertNewsletterQueue extends AbstractAssertForm public function processAssert(TemplateQueue $templateQueue, Template $newsletter) { $dataDiff = $this->verifyData($newsletter->getData(), $templateQueue->getEditForm()->getData($newsletter)); - \PHPUnit_Framework_Assert::assertEmpty($dataDiff, $dataDiff); + \PHPUnit\Framework\Assert::assertEmpty($dataDiff, $dataDiff); } /** diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueForm.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueForm.php index 89df51175b069..9041b4d866bfc 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueForm.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueForm.php @@ -33,7 +33,7 @@ public function processAssert( $indexQueue->getQueueTemplateGrid()->searchAndOpen(['newsletter_subject' => $queue->getNewsletterSubject()]); $dataDiff = $this->verifyData($queue->getData(), $templateQueue->getEditForm()->getData($queue)); - \PHPUnit_Framework_Assert::assertEmpty($dataDiff, $dataDiff); + \PHPUnit\Framework\Assert::assertEmpty($dataDiff, $dataDiff); } /** diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php index e29c585f0f011..c191ec4df44d2 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php @@ -36,7 +36,7 @@ public function processAssert( $indexQueue->open(); $indexQueue->getQueueTemplateGrid()->search(['newsletter_subject' => $queue->getNewsletterSubject()]); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $indexQueue->getQueueTemplateGrid()->isRowVisible($filter, false, false), 'Newsletter Queue \'' . $queue->getNewsletterSubject() . '\' is absent in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSaveMessage.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSaveMessage.php index 4e240d6edd0c1..8803f464996cb 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSaveMessage.php @@ -29,7 +29,7 @@ public function processAssert( TemplateQueueIndex $indexQueue ) { $actualMessages = $indexQueue->getMessagesBlock()->getSuccessMessages(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::SUCCESS_MESSAGE, $actualMessages, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterSuccessCreateMessage.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterSuccessCreateMessage.php index 863d19af5ec16..cc025604be837 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterSuccessCreateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterSuccessCreateMessage.php @@ -30,7 +30,7 @@ class AssertNewsletterSuccessCreateMessage extends AbstractConstraint public function processAssert(TemplateIndex $templateIndex) { $actualMessage = $templateIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheFlushSuccessMessage.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheFlushSuccessMessage.php index 393f3a4cbaec1..9ff35698a3e9a 100644 --- a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheFlushSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheFlushSuccessMessage.php @@ -23,7 +23,7 @@ class AssertCacheFlushSuccessMessage extends AbstractConstraint */ public function processAssert(AdminCache $adminCache, $successMessage) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $successMessage, $adminCache->getMessagesBlock()->getSuccessMessage(), 'Action is not successful.' diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidateNotice.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidateNotice.php index 7fb18cd86690a..da82d3c9eb576 100644 --- a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidateNotice.php +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidateNotice.php @@ -35,12 +35,12 @@ public function processAssert(AdminCache $adminCache, array $caches) $adminCache->getSystemMessageDialog()->closePopup(); foreach ($caches as $cacheType => $cacheStatus) { if ($cacheStatus === 'Invalidated') { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $this->cacheTypes[$cacheType], $adminCache->getSystemMessageBlock()->getContent() ); } else { - \PHPUnit_Framework_Assert::assertNotContains( + \PHPUnit\Framework\Assert::assertNotContains( $this->cacheTypes[$cacheType], $adminCache->getSystemMessageBlock()->getContent() ); diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidatePopUp.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidatePopUp.php index 86eda10b2e162..ad1fcb4d62ec0 100644 --- a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidatePopUp.php +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidatePopUp.php @@ -34,12 +34,12 @@ public function processAssert(AdminCache $adminCache, array $caches) { foreach ($caches as $cacheType => $cacheStatus) { if ($cacheStatus === 'Invalidated') { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $this->cacheTypes[$cacheType], $adminCache->getSystemMessageDialog()->getPopupText() ); } else { - \PHPUnit_Framework_Assert::assertNotContains( + \PHPUnit\Framework\Assert::assertNotContains( $this->cacheTypes[$cacheType], $adminCache->getSystemMessageDialog()->getPopupText() ); diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheIsRefreshableAndInvalidated.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheIsRefreshableAndInvalidated.php index 660b77c35f848..6498802c6cc30 100644 --- a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheIsRefreshableAndInvalidated.php +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheIsRefreshableAndInvalidated.php @@ -39,7 +39,7 @@ public function processAssert(AdminCache $adminCache, $cacheTags) $adminCache->open(); $adminCache->getGridBlock()->massaction($items, 'Refresh'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_MESSAGE, count($items)), $adminCache->getMessagesBlock()->getSuccessMessage(), 'Cache is Invalid and refreshable.' diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheStatus.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheStatus.php index d130b7712ee8c..76bd5f6ad3dc9 100644 --- a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheStatus.php +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheStatus.php @@ -35,7 +35,7 @@ public function processAssert(AdminCache $adminCache, array $caches) { $adminCache->open(); foreach ($caches as $cacheType => $cacheStatus) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $adminCache->getGridBlock()->isCacheStatusCorrect($this->cacheTypes[$cacheType], $cacheStatus), $this->cacheTypes[$cacheType] . " cache status in grid does not equal to " . $cacheStatus ); diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertFlushStaticFilesCacheButtonVisibility.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertFlushStaticFilesCacheButtonVisibility.php index d578d06e112f8..8eeecc83633c0 100644 --- a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertFlushStaticFilesCacheButtonVisibility.php +++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertFlushStaticFilesCacheButtonVisibility.php @@ -25,12 +25,12 @@ class AssertFlushStaticFilesCacheButtonVisibility extends AbstractConstraint public function processAssert(AdminCache $adminCache) { if ($_ENV['mage_mode'] === 'production') { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $adminCache->getAdditionalBlock()->isFlushCacheButtonVisible(self::FLUSH_STATIC_FILES_CACHE), self::FLUSH_STATIC_FILES_CACHE . ' button should not be visible in production mode.' ); } else { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $adminCache->getAdditionalBlock()->isFlushCacheButtonVisible(self::FLUSH_STATIC_FILES_CACHE), self::FLUSH_STATIC_FILES_CACHE . ' button should be visible in developer or default mode.' ); diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php index 45f3d0aaca4d5..455b0bf6129fa 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertCardRequiredFields.php @@ -39,7 +39,7 @@ public function processAssert(OrderCreateIndex $orderCreateIndex, CreditCard $cr ->getJsErrors(); $creditCardEmpty = $creditCard->get('visa_empty'); foreach (array_keys($creditCardEmpty) as $field) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( isset($actualRequiredFields[$field]), "Field '$field' is not highlighted with an JS error." ); @@ -47,7 +47,7 @@ public function processAssert(OrderCreateIndex $orderCreateIndex, CreditCard $cr if (in_array($field, ['cc_number', 'cc_cid'])) { $expected = self::VALID_NUMBER_MESSAGE; } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expected, $actualRequiredFields[$field], "Field '$field' is not highlighted as required." diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreActive.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreActive.php index 96a7749e908f6..6c2ce58cdcd05 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreActive.php +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreActive.php @@ -25,7 +25,7 @@ class AssertFieldsAreActive extends AbstractConstraint public function processAssert(SystemConfigEditSectionPayment $configEditSectionPayment, array $fieldIds) { foreach ($fieldIds as $fieldId) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $configEditSectionPayment->getPaymentsConfigBlock()->isFieldDisabled($fieldId), 'Field is disabled.' ); diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreDisabled.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreDisabled.php index 2116fd92d4fa2..a5f277c5f0437 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreDisabled.php +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreDisabled.php @@ -25,7 +25,7 @@ class AssertFieldsAreDisabled extends AbstractConstraint public function processAssert(SystemConfigEditSectionPayment $configEditSectionPayment, array $fieldIds) { foreach ($fieldIds as $fieldId) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $configEditSectionPayment->getPaymentsConfigBlock()->isFieldDisabled($fieldId), 'Field is active.' ); diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreEnabled.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreEnabled.php index f34efad507bc8..d65c0095382f4 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreEnabled.php +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsAreEnabled.php @@ -25,7 +25,7 @@ class AssertFieldsAreEnabled extends AbstractConstraint public function processAssert(SystemConfigEditSectionPayment $configEditSectionPayment, array $fieldIds) { foreach ($fieldIds as $fieldId) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $configEditSectionPayment->getPaymentsConfigBlock()->isFieldEnabled($fieldId), 'Field is active.' ); diff --git a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsArePresent.php b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsArePresent.php index 1725c27ea9e50..a69e5e36450c3 100644 --- a/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsArePresent.php +++ b/dev/tests/functional/tests/app/Magento/Payment/Test/Constraint/AssertFieldsArePresent.php @@ -25,7 +25,7 @@ class AssertFieldsArePresent extends AbstractConstraint public function processAssert(SystemConfigEditSectionPayment $configEditSectionPayment, array $fieldIds) { foreach ($fieldIds as $fieldId) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $configEditSectionPayment->getPaymentsConfigBlock()->isFieldPresent($fieldId), 'Field is active.' ); diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/AssertExpressCancelledMessage.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/AssertExpressCancelledMessage.php index f3fe41a68edcb..102a87b84980e 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/AssertExpressCancelledMessage.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/AssertExpressCancelledMessage.php @@ -27,7 +27,7 @@ class AssertExpressCancelledMessage extends AbstractConstraint */ public function processAssert(CheckoutCart $checkoutCart) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $checkoutCart->getMessagesBlock()->getSuccessMessage(), 'Success message about Express Checkout cancellation is not present or wrong.' diff --git a/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/Sandbox/AssertTotalPaypalReview.php b/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/Sandbox/AssertTotalPaypalReview.php index 6d65d6d887b49..5cbba6b9ab368 100644 --- a/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/Sandbox/AssertTotalPaypalReview.php +++ b/dev/tests/functional/tests/app/Magento/Paypal/Test/Constraint/Sandbox/AssertTotalPaypalReview.php @@ -25,7 +25,7 @@ public function processAssert(ExpressReview $expressReview, $total) { $reviewTotal = $expressReview->getExpressMainReviewBlock()->getReviewBlock()->getTotal(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $reviewTotal, number_format($total, 2), 'Total price: \'' . $reviewTotal diff --git a/dev/tests/functional/tests/app/Magento/Persistent/Test/Constraint/AssertCustomerIsRedirectedToCheckout.php b/dev/tests/functional/tests/app/Magento/Persistent/Test/Constraint/AssertCustomerIsRedirectedToCheckout.php index 1550f6e86ee4c..c40db5c164e62 100644 --- a/dev/tests/functional/tests/app/Magento/Persistent/Test/Constraint/AssertCustomerIsRedirectedToCheckout.php +++ b/dev/tests/functional/tests/app/Magento/Persistent/Test/Constraint/AssertCustomerIsRedirectedToCheckout.php @@ -23,7 +23,7 @@ class AssertCustomerIsRedirectedToCheckout extends AbstractConstraint public function processAssert(CheckoutOnepage $checkoutOnepage) { $checkoutOnepage->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( !$checkoutOnepage->getMessagesBlock()->isVisible() && $checkoutOnepage->getShippingMethodBlock()->isVisible(), 'Checkout first step is not available.' diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertGetVideoInfoDataIsCorrect.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertGetVideoInfoDataIsCorrect.php index a0727f3c7f973..894cb1b8a3502 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertGetVideoInfoDataIsCorrect.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertGetVideoInfoDataIsCorrect.php @@ -38,7 +38,7 @@ public function processAssert( $imagesTab = $editProductPage->getProductForm()->getSection('images-and-videos'); $result = $imagesTab->clickFirstVideo()->getVideoDialog()->validate($video); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $result, 'Video data received from external service is not correct.' ); diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertNoVideoCategoryView.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertNoVideoCategoryView.php index 46d6b5d2324e0..6c9771613fe33 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertNoVideoCategoryView.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertNoVideoCategoryView.php @@ -31,7 +31,7 @@ public function processAssert( $cmsIndex->open(); $cmsIndex->getTopmenu()->selectCategoryByName($product->getCategoryIds()[0]); $src = $catalogCategoryView->getListProductBlock()->getProductItem($product)->getBaseImageSource(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( strpos($src, '/placeholder/') !== false, 'Product image is displayed on category view when it should not.' ); diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertNoVideoProductView.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertNoVideoProductView.php index 91079931b31a4..5fd0aa00221a0 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertNoVideoProductView.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertNoVideoProductView.php @@ -29,7 +29,7 @@ public function processAssert( InjectableFixture $product ) { $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogProductView->getViewBlock()->isVideoVisible(), 'Product video is displayed on product view when it should not.' ); diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoCategoryView.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoCategoryView.php index f8f25d9e3a6b8..0b3aa227486de 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoCategoryView.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoCategoryView.php @@ -32,7 +32,7 @@ public function processAssert( $cmsIndex->open(); $cmsIndex->getTopmenu()->selectCategoryByName($product->getCategoryIds()[0]); $src = $catalogCategoryView->getListProductBlock()->getProductItem($product)->getBaseImageSource(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( strpos($src, '/placeholder/') !== false, 'Video preview image is not displayed on category view when it should.' ); diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoConfigurableProductView.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoConfigurableProductView.php index fff7dddca485a..813d56f152344 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoConfigurableProductView.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoConfigurableProductView.php @@ -36,22 +36,22 @@ public function processAssert( //open product page $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); // assert video and video data of configurable product is presented on page - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getViewBlock()->isVideoVisible(), 'Product video is not displayed on product view when it should.' ); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getViewBlock()->checkVideoDataPresence($youtubeDataCode), 'Configurable product video data is not displayed on product view when it should.' ); // select configurable product variation $catalogProductView->getConfigurableAttributesBlock()->selectConfigurableOption($product, $variation); // assert video and video data of simple product option is presented on page - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getViewBlock()->isVideoVisible(), 'Configurable product variation video is not displayed on product view when it should.' ); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getViewBlock()->checkVideoDataPresence($vimeoDataCode), 'Configurable product variation video data is not displayed on product view when it should.' ); diff --git a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoProductView.php b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoProductView.php index 96128e321bd88..8b4488a63e0e8 100755 --- a/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoProductView.php +++ b/dev/tests/functional/tests/app/Magento/ProductVideo/Test/Constraint/AssertVideoProductView.php @@ -29,7 +29,7 @@ public function processAssert( InjectableFixture $product ) { $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getViewBlock()->isVideoVisible(), 'Product video is not displayed on product view when it should.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertAbandonedCartCustomerInfoResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertAbandonedCartCustomerInfoResult.php index f848284113b61..d4e3ececb4ec2 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertAbandonedCartCustomerInfoResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertAbandonedCartCustomerInfoResult.php @@ -45,7 +45,7 @@ public function processAssert(AbandonedCarts $abandonedCarts, $products, Custome $abandonedCarts->getGridBlock()->search($filter); $filter['created_at'] = date('M j, Y'); $filter['updated_at'] = date('M j, Y'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $abandonedCarts->getGridBlock()->isRowVisible($filter, false, false), 'Expected customer info is absent in Abandoned Carts report grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertBestsellerReportResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertBestsellerReportResult.php index 0c81a2b2b5f38..cdfac1066b0b6 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertBestsellerReportResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertBestsellerReportResult.php @@ -36,7 +36,7 @@ public function processAssert(Bestsellers $bestsellers, OrderInjectable $order, 'orders' => $product->getCheckoutData()['qty'], ]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $bestsellers->getGridBlock()->isRowVisible($filter, false), 'Bestseller does not present in report grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCouponReportResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCouponReportResult.php index 932ddad46483e..6bcdff4b9626a 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCouponReportResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCouponReportResult.php @@ -37,7 +37,7 @@ public function processAssert(SalesCouponReportView $salesCouponReportView, Orde 'subtotal' => $currency . number_format($data['price']['subtotal'], 2), 'discount' => $discount, ]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $salesCouponReportView->getGridBlock()->isRowVisible($filter, false), "Coupon with code - '$couponCode' is not visible." ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCustomerOrderCountReportResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCustomerOrderCountReportResult.php index 4b01906e2d657..7227bc298c485 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCustomerOrderCountReportResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCustomerOrderCountReportResult.php @@ -31,7 +31,7 @@ public function processAssert( ) { $filter = $this->prepareFilter($customer, $columns, $report); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $customerOrdersReport->getGridBlock()->isRowVisible($filter, false), 'Order does not present in count grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCustomerOrderTotalReportResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCustomerOrderTotalReportResult.php index fabe17f49dc55..a3adf8302c394 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCustomerOrderTotalReportResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertCustomerOrderTotalReportResult.php @@ -31,7 +31,7 @@ public function processAssert( ) { $filter = $this->prepareFilter($customer, $columns, $report); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $customerTotalsReport->getGridBlock()->isRowVisible($filter, false), 'Order does not present in report grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertDownloadsReportResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertDownloadsReportResult.php index 6b1e7eacec777..9d4e5360ccb94 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertDownloadsReportResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertDownloadsReportResult.php @@ -40,7 +40,7 @@ public function processAssert(OrderInjectable $order, DownloadsReport $downloads ]; $downloadsReport->getGridBlock()->search($filter); $filter[] = $downloads; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $downloadsReport->getGridBlock()->isRowVisible($filter, false), "Downloads report link {$link['title']} is not present in reports grid." ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertInvoiceReportIntervalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertInvoiceReportIntervalResult.php index 5428b893d9e10..17b7426ceb741 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertInvoiceReportIntervalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertInvoiceReportIntervalResult.php @@ -32,7 +32,7 @@ public function processAssert(OrderInjectable $order, array $invoiceReport, arra $this->searchInInvoiceReportGrid($invoiceReport); $invoiceResult = $this->salesInvoiceReport->getGridBlock()->getLastResult(); $prepareInitialResult = $this->prepareExpectedResult($initialInvoiceResult); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $prepareInitialResult, $invoiceResult, "Invoice report interval result not contains actual data." diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertInvoiceReportTotalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertInvoiceReportTotalResult.php index ca3cf75603d1b..207bba94028ac 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertInvoiceReportTotalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertInvoiceReportTotalResult.php @@ -28,7 +28,7 @@ public function processAssert(OrderInjectable $order, array $invoiceReport, arra $this->searchInInvoiceReportGrid($invoiceReport); $invoiceResult = $this->salesInvoiceReport->getGridBlock()->getTotalResult(); $prepareInitialResult = $this->prepareExpectedResult($initialInvoiceTotalResult); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $prepareInitialResult, $invoiceResult, "Grand total Invoice result is not correct." diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLifetimeStatisticsUpdatedMessage.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLifetimeStatisticsUpdatedMessage.php index 60f8f98ee4554..575043242cc88 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLifetimeStatisticsUpdatedMessage.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLifetimeStatisticsUpdatedMessage.php @@ -28,7 +28,7 @@ class AssertLifetimeStatisticsUpdatedMessage extends AbstractConstraint public function processAssert(Statistics $reportStatistics) { $successMessage = $reportStatistics->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::LIFETIME_STATISTICS_UPDATED_MESSAGE, $successMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLowStockProductInGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLowStockProductInGrid.php index 8175a76bb5fdc..6854956f69b0c 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLowStockProductInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertLowStockProductInGrid.php @@ -26,7 +26,7 @@ class AssertLowStockProductInGrid extends AbstractConstraint public function processAssert(CatalogProductSimple $product, ProductLowStock $productLowStock) { $productLowStock->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productLowStock->getLowStockGrid()->isRowVisible(['name' => $product->getName()]), 'Product with Low Stock is absent in Low Stock grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertNewAccountsReportTotalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertNewAccountsReportTotalResult.php index 263fe3c97a4db..29983bbb24433 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertNewAccountsReportTotalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertNewAccountsReportTotalResult.php @@ -25,7 +25,7 @@ class AssertNewAccountsReportTotalResult extends AbstractConstraint public function processAssert(CustomerAccounts $customerAccounts, $total) { $totalForm = $customerAccounts->getGridBlock()->getTotalResults(); - \PHPUnit_Framework_Assert::assertEquals($total, $totalForm); + \PHPUnit\Framework\Assert::assertEquals($total, $totalForm); } /** diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertOrderedProductResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertOrderedProductResult.php index 85369b730de79..bfb771060f54f 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertOrderedProductResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertOrderedProductResult.php @@ -37,7 +37,7 @@ public function processAssert(OrderedProductsReport $orderedProducts, OrderInjec $product = $products[$key]; $productQty[$key] = $product->getCheckoutData()['qty']; } - \PHPUnit_Framework_Assert::assertEquals($totalQuantity, $productQty); + \PHPUnit\Framework\Assert::assertEquals($totalQuantity, $productQty); } /** diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductInCartResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductInCartResult.php index 445aac584be5d..54b5b76502ce2 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductInCartResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductInCartResult.php @@ -27,7 +27,7 @@ class AssertProductInCartResult extends AbstractConstraint public function processAssert(ShopCartProductReport $shopCartProductReport, CatalogProductSimple $product, $carts) { $shopCartProductReport->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $shopCartProductReport->getGridBlock()->isProductVisible($product, $carts), 'Product is absent in Products in Carts report grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReportByCustomerInGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReportByCustomerInGrid.php index 914f1d6039e3c..039118e6b9f89 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReportByCustomerInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReportByCustomerInGrid.php @@ -47,7 +47,7 @@ public function processAssert( $customerReportReview->getGridBlock()->openReview($customer); $reviewIndex->getReviewGrid()->search($filter); unset($filter['visible_in']); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $reviewIndex->getReviewGrid()->isRowVisible($filter, false), 'Customer review is absent in Review grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReportByCustomerNotInGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReportByCustomerNotInGrid.php index e057af25af678..fff57fa4d258a 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReportByCustomerNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReportByCustomerNotInGrid.php @@ -47,7 +47,7 @@ public function processAssert( $customerReportReview->getGridBlock()->openReview($customer); $reviewIndex->getReviewGrid()->search($filter); unset($filter['visible_in']); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $reviewIndex->getReviewGrid()->isRowVisible($filter, false), 'Customer review is present in Review grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewIsAvailableForProduct.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewIsAvailableForProduct.php index 67975e240c2c4..11e15df66b3b1 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewIsAvailableForProduct.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewIsAvailableForProduct.php @@ -40,7 +40,7 @@ public function processAssert( unset($assertProductReviewInGrid->filter['visible_in']); $filter = $assertProductReviewInGrid->prepareFilter($product, $review->getData(), ''); $reviewIndex->getReviewGrid()->resetFilter(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $reviewIndex->getReviewGrid()->isRowVisible($filter, false), 'Review for ' . $product->getName() . ' product is not visible in reports grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewReportIsVisibleInGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewReportIsVisibleInGrid.php index bafb17c7f2fae..0b6bb7c5b0ad4 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewReportIsVisibleInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewReportIsVisibleInGrid.php @@ -27,7 +27,7 @@ public function processAssert(ProductReportReview $productReportReview, Review $ { $productReportReview->open(); $name = $review->getDataFieldConfig('entity_id')['source']->getEntity()->getName(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productReportReview->getGridBlock()->isRowVisible(['title' => $name], false), 'Review for ' . $name . ' product is not visible in reports grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewsQtyByCustomer.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewsQtyByCustomer.php index 1f4fa26de55de..de48407fdcebc 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewsQtyByCustomer.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewsQtyByCustomer.php @@ -31,7 +31,7 @@ public function processAssert( ) { $customerName = $customer->getFirstname() . ' ' . $customer->getLastname(); $customerReportReview->open(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $reviewsCount, $customerReportReview->getGridBlock()->getQtyReview($customerName), 'Wrong qty review in Customer Reviews Report grid.' diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductViewsReportTotalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductViewsReportTotalResult.php index 9c84cb5e4e74a..7ae1fcb2b6e34 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductViewsReportTotalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductViewsReportTotalResult.php @@ -27,7 +27,7 @@ public function processAssert(ProductReportView $productReportView, $total, arra { $total = explode(', ', $total); $totalForm = $productReportView->getGridBlock()->getViewsResults($productsList); - \PHPUnit_Framework_Assert::assertEquals($totalForm, $total); + \PHPUnit\Framework\Assert::assertEquals($totalForm, $total); } /** diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRecentStatisticsUpdatedMessage.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRecentStatisticsUpdatedMessage.php index a6ce5f3b7ddf2..d8f6bbaef0e59 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRecentStatisticsUpdatedMessage.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRecentStatisticsUpdatedMessage.php @@ -28,7 +28,7 @@ class AssertRecentStatisticsUpdatedMessage extends AbstractConstraint public function processAssert(Statistics $reportStatistics) { $successMessage = $reportStatistics->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::RECENT_STATISTICS_UPDATED_MESSAGE, $successMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRefundReportIntervalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRefundReportIntervalResult.php index c7cfa1d6aadc1..2def81b453b54 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRefundReportIntervalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertRefundReportIntervalResult.php @@ -39,7 +39,7 @@ public function processAssert( $this->searchInSalesReportGrid($refundsReport); $salesResult = $refundsReportPage->getGridBlock()->getLastResult(); $prepareInitialResult = $this->prepareExpectedResult($initialRefundsResult); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $prepareInitialResult, $salesResult, "Refund total Sales result is not correct." diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertReportStatisticsNoticeMessage.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertReportStatisticsNoticeMessage.php index 4650905fc4147..f68666366a663 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertReportStatisticsNoticeMessage.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertReportStatisticsNoticeMessage.php @@ -40,7 +40,7 @@ public function processAssert( $date = $this->getLastUpdatedDate(); $currentDateTime = $currentDate->format('M j, Y, g'); $displayedDateTime = date('M j, Y, g', strtotime($date)); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $currentDateTime, $displayedDateTime, "Message in Sales Reports Page is displayed in an incorrect timezone." diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertReportsUpdatedTimezone.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertReportsUpdatedTimezone.php index 00d29a47281ad..4cbf3ceacefda 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertReportsUpdatedTimezone.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertReportsUpdatedTimezone.php @@ -27,7 +27,7 @@ public function processAssert(Statistics $reportStatistics) $currentDate = new \DateTime(); $currentDate->setTimezone(new \DateTimeZone($_ENV['magento_timezone'])); foreach ($dates as $date) { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $currentDate->format('M j, Y, g'), date('M j, Y, g', strtotime($date['updated_at'])), "Reports 'Updated' column values are displayed in an incorrect timezone." diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportIntervalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportIntervalResult.php index c28023f8411cd..745450aa2c024 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportIntervalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportIntervalResult.php @@ -35,7 +35,7 @@ public function processAssert( $this->searchInSalesReportGrid($salesReport); $salesResult = $this->prepareSalesResult($salesReportPage->getGridBlock()->getLastResult()); $prepareInitialResult = $this->prepareSalesResult($this->prepareExpectedResult($initialSalesResult)); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $prepareInitialResult, $salesResult, "Grand total Sales result is not correct." diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportTotalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportTotalResult.php index 137788441b6d6..5f435e4822904 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportTotalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSalesReportTotalResult.php @@ -35,7 +35,7 @@ public function processAssert( $this->searchInSalesReportGrid($salesReport); $salesResult = $this->prepareSalesResult($salesReportPage->getGridBlock()->getTotalResult()); $prepareInitialResult = $this->prepareSalesResult($this->prepareExpectedResult($initialSalesTotalResult)); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $prepareInitialResult, $salesResult, "Grand total Sales result is not correct." diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSearchTermReportForm.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSearchTermReportForm.php index 2031dc38d89c8..ed8950579486b 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSearchTermReportForm.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSearchTermReportForm.php @@ -43,7 +43,7 @@ public function processAssert( $dataDiff = $this->verifyData($filter, $catalogSearchEdit->getForm()->getData()); - \PHPUnit_Framework_Assert::assertEmpty($dataDiff, $dataDiff); + \PHPUnit\Framework\Assert::assertEmpty($dataDiff, $dataDiff); } /** diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSearchTermsInGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSearchTermsInGrid.php index eb33b40a82e58..6421f79aaad4a 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSearchTermsInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertSearchTermsInGrid.php @@ -31,7 +31,7 @@ public function processAssert(SearchIndex $searchIndex, $productName, $countProd 'num_results' => $countProducts, 'popularity' => $countSearch, ]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $searchIndex->getSearchGrid()->isRowVisible($filter), 'Search terms report is absent in Search Terms grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportIntervalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportIntervalResult.php index fe72467d82ff5..94692f922e8aa 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportIntervalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportIntervalResult.php @@ -28,7 +28,7 @@ public function processAssert(OrderInjectable $order, array $shippingReport, arr $shipmentResult = $this->salesShippingReport->getGridBlock()->getLastResult(); $prepareInitialResults = $this->prepareExpectedResult($initialShippingResult, $shipmentResult); list($prepareInitialResult, $shipmentResult) = $prepareInitialResults; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $prepareInitialResult, $shipmentResult, "Shipment report interval result not contains actual data." diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportTotalResult.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportTotalResult.php index 1cf0fcf530348..16e92554e3984 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportTotalResult.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertShippingReportTotalResult.php @@ -28,7 +28,7 @@ public function processAssert(OrderInjectable $order, array $shippingReport, arr $shipmentResult = $this->salesShippingReport->getGridBlock()->getTotalResult(); $prepareInitialResults = $this->prepareExpectedResult($initialShippingTotalResult, $shipmentResult); list($prepareInitialResult, $shipmentResult) = $prepareInitialResults; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $prepareInitialResult, $shipmentResult, "Grand total Shipment result is not correct." diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportInGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportInGrid.php index 17e6c545dbd4a..3f22780b8a01c 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportInGrid.php @@ -39,7 +39,7 @@ public function processAssert( 'tax_amount' => $taxAmount, ]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $salesTaxReport->getGridBlock()->isRowVisible($filter, false), "Tax Report is not visible in grid on tax report page." ); diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportNotInGrid.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportNotInGrid.php index 76267dac55eb1..095c83a7e5fb0 100644 --- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertTaxReportNotInGrid.php @@ -43,7 +43,7 @@ public function processAssert( 'tax_amount' => $taxAmount, ]; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $salesTaxReport->getGridBlock()->isRowVisible($filter, false), "Tax Report is visible in grid on tax report page." ); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php index d4d219245b7eb..83a8b44a8b322 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php @@ -27,7 +27,7 @@ public function processAssert(RatingIndex $ratingIndex, Rating $productRating) $filter = ['rating_code' => $productRating->getRatingCode()]; $ratingIndex->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $ratingIndex->getRatingGrid()->isRowVisible($filter), "Product Rating " . $productRating->getRatingCode() . " is absent on product Rating grid." ); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInProductPage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInProductPage.php index 6b8738281bc93..e89b1ea9a9851 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInProductPage.php @@ -43,7 +43,7 @@ public function processAssert( } $rating = $productRating ? $productRating : $review->getDataFieldConfig('ratings')['source']->getRatings()[0]; $reviewForm = $catalogProductView->getReviewFormBlock(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $reviewForm->isVisibleRating($rating), 'Product rating "' . $rating->getRatingCode() . '" is not displayed.' ); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInGrid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInGrid.php index 93ea7d8abcccd..b4e720ad622d4 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInGrid.php @@ -27,7 +27,7 @@ public function processAssert(RatingIndex $ratingIndex, Rating $productRating) $filter = ['rating_code' => $productRating->getRatingCode()]; $ratingIndex->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $ratingIndex->getRatingGrid()->isRowVisible($filter), "Product Rating " . $productRating->getRatingCode() . " exists on product Rating grid." ); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInProductPage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInProductPage.php index df18d81c69be1..4a2d11e1bb9f7 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInProductPage.php @@ -36,7 +36,7 @@ public function processAssert( $catalogProductView->getReviewSummary()->getAddReviewLink()->click(); $reviewForm = $catalogProductView->getReviewFormBlock(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $reviewForm->isVisibleRating($productRating), 'Product rating "' . $productRating->getRatingCode() . '" is displayed.' ); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingOnReviewPage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingOnReviewPage.php index 1058c2f141dfd..d992791759eaf 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingOnReviewPage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingOnReviewPage.php @@ -44,7 +44,7 @@ public function processAssert( $ratingForm = $reviewEdit->getReviewForm()->getData(); $ratingForm = $this->sortDataByPath($ratingForm['ratings'], '::title'); $error = $this->verifyData($ratingReview, $ratingForm); - \PHPUnit_Framework_Assert::assertTrue(empty($error), $error); + \PHPUnit\Framework\Assert::assertTrue(empty($error), $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessDeleteMessage.php index 949f4b346eddd..f803f8c4b8b5b 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessDeleteMessage.php @@ -25,7 +25,7 @@ class AssertProductRatingSuccessDeleteMessage extends AbstractConstraint public function processAssert(RatingIndex $ratingIndex) { $actualMessage = $ratingIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessSaveMessage.php index 0da2ac94168e0..edd11c3fed0a7 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertProductRatingSuccessSaveMessage extends AbstractConstraint public function processAssert(RatingIndex $ratingIndex) { $actualMessage = $ratingIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewBackendSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewBackendSuccessSaveMessage.php index de6991bd08b5c..7297196efc9e7 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewBackendSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewBackendSuccessSaveMessage.php @@ -28,7 +28,7 @@ class AssertProductReviewBackendSuccessSaveMessage extends AbstractConstraint */ public function processAssert(ReviewIndex $reviewIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $reviewIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewForm.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewForm.php index aa45406b3212b..615fe93aecc64 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewForm.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewForm.php @@ -54,7 +54,7 @@ public function processAssert(ReviewIndex $reviewIndex, Review $review, ReviewEd $error = $this->verifyData($fixtureData, $formData); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } /** diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewInGrid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewInGrid.php index 9bc9bb4e8b98e..9cbd72ce47658 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewInGrid.php @@ -53,7 +53,7 @@ public function processAssert( $reviewIndex->open(); $reviewIndex->getReviewGrid()->search($filter); unset($filter['visible_in']); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $reviewIndex->getReviewGrid()->isRowVisible($filter, false), 'Review is absent in Review grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewInGridOnCustomerPage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewInGridOnCustomerPage.php index ce7d675c2f3f4..0b46e23b3e8bc 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewInGridOnCustomerPage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewInGridOnCustomerPage.php @@ -48,7 +48,7 @@ public function processAssert( $reviewsGrid = $customerIndexEdit->getCustomerForm()->getTab('product_reviews')->getReviewsGrid(); $reviewsGrid->search($filter); unset($filter['visible_in']); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $reviewsGrid->isRowVisible($filter, false), 'Review is absent in Review grid on customer page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewIsAbsentOnProductPage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewIsAbsentOnProductPage.php index 9a32353a02a87..d16bbdf4811a5 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewIsAbsentOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewIsAbsentOnProductPage.php @@ -36,12 +36,12 @@ public function processAssert(CatalogProductView $catalogProductView) { $catalogProductView->getViewBlock()->selectTab('Reviews'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $catalogProductView->getCustomerReviewBlock()->isVisibleReviewItem(), 'No reviews below the form required.' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::NO_REVIEW_LINK_TEXT, trim($catalogProductView->getReviewSummary()->getAddReviewLink()->getText()), sprintf('"%s" link is not available', self::NO_REVIEW_LINK_TEXT) diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewMassActionSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewMassActionSuccessDeleteMessage.php index 5cf7238875a73..3680d9daca3f6 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewMassActionSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewMassActionSuccessDeleteMessage.php @@ -36,7 +36,7 @@ public function processAssert(Review $review, ReviewIndex $reviewIndex) { $reviews = is_array($review) ? $review : [$review]; $deleteMessage = sprintf(self::SUCCESS_DELETE_MESSAGE, count($reviews)); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $deleteMessage, $reviewIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewMassActionSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewMassActionSuccessMessage.php index 6603008b76d14..bf08bf6cf6cb2 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewMassActionSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewMassActionSuccessMessage.php @@ -32,7 +32,7 @@ public function processAssert(Review $review, ReviewIndex $reviewIndex) { $reviews = is_array($review) ? $review : [$review]; $successMessage = sprintf(self::SUCCESS_MESSAGE, count($reviews)); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $successMessage, $reviewIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewNotInGrid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewNotInGrid.php index ae5f2d0f4915b..59d21f1d2f472 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewNotInGrid.php @@ -56,7 +56,7 @@ public function processAssert( $reviewIndex->getReviewGrid()->search($filter); unset($filter['visible_in']); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $reviewIndex->getReviewGrid()->isRowVisible($filter, false), 'Review available in grid' ); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewNotOnProductPage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewNotOnProductPage.php index 149e566a34dfd..71db324783568 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewNotOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewNotOnProductPage.php @@ -37,7 +37,7 @@ public function processAssert( $reviewBlock = $catalogProductView->getCustomerReviewBlock(); $catalogProductView->getViewBlock()->selectTab('Reviews'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $reviewBlock->isVisibleReviewItem(), 'Error, product review is displayed.' ); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewOnProductPage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewOnProductPage.php index 320d3a894835f..fe9822ddd45ae 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductReviewOnProductPage.php @@ -42,7 +42,7 @@ public function processAssert( $reviewBlock = $catalogProductView->getCustomerReviewBlock(); $catalogProductView->getViewBlock()->selectTab('Reviews'); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( sprintf("You're reviewing:\n%s", $product->getName()), $catalogProductView->getReviewFormBlock()->getLegend()->getText() ); @@ -54,7 +54,7 @@ public function processAssert( } } - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $errors, 'The Review contains the following errors:' . PHP_EOL . implode(PHP_EOL, $errors) ); diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewCreationSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewCreationSuccessMessage.php index 9b9646cfb184a..f35596cddcb24 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewCreationSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewCreationSuccessMessage.php @@ -28,7 +28,7 @@ class AssertReviewCreationSuccessMessage extends AbstractConstraint public function processAssert(CatalogProductView $catalogProductView) { $actualMessage = $catalogProductView->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewLinksIsPresentOnProductPage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewLinksIsPresentOnProductPage.php index 20685a58064dc..8a3e85ab34c24 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewLinksIsPresentOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewLinksIsPresentOnProductPage.php @@ -36,18 +36,18 @@ public function processAssert(Browser $browser, CatalogProductView $catalogProdu $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html'); // Verify add review link - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogProductView->getReviewSummary()->getAddReviewLink()->isVisible(), 'Add review link is not visible on product page.' ); // Verify view review link $viewReviewLink = $catalogProductView->getReviewSummary()->getViewReviewLink(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $viewReviewLink->isVisible(), 'View review link is not visible on product page.' ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( '1', $viewReviewLink->getText(), 'There is more than 1 approved review.' diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewSuccessSaveMessage.php index f48397dc9213b..97f8c86639dde 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertReviewSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertReviewSuccessSaveMessage extends AbstractConstraint public function processAssert(ReviewIndex $reviewIndex) { $actualMessage = $reviewIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertSetApprovedProductReview.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertSetApprovedProductReview.php index 075505a404147..b7612ff3351f6 100644 --- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertSetApprovedProductReview.php +++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertSetApprovedProductReview.php @@ -70,7 +70,7 @@ protected function flushCacheStorageWithAssert() $this->cachePage->open(); $this->cachePage->getActionsBlock()->flushCacheStorage(); $this->cachePage->getModalBlock()->acceptAlert(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->cachePage->getActionsBlock()->isStorageCacheFlushed(), 'Cache is not flushed.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentMessageInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentMessageInCommentsHistory.php index 3f89e5fff0d71..9e1c08a906fa3 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentMessageInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentMessageInCommentsHistory.php @@ -39,7 +39,7 @@ public function processAssert(SalesOrderView $salesOrderView, OrderIndex $orderI $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); - \PHPUnit_Framework_Assert::assertContains(self::$message, $latestComment['comment']); + \PHPUnit\Framework\Assert::assertContains(self::$message, $latestComment['comment']); } /** diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentSuccessMessagePresent.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentSuccessMessagePresent.php index 1b15b20e4ffec..4433cbd6dc339 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentSuccessMessagePresent.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAcceptPaymentSuccessMessagePresent.php @@ -29,7 +29,7 @@ class AssertAcceptPaymentSuccessMessagePresent extends AbstractConstraint */ public function processAssert(SalesOrderView $salesOrderView) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::$successAcceptMessage, $salesOrderView->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php index 574ac9d249ed0..055b850141b0e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertAuthorizationInCommentsHistory.php @@ -43,7 +43,7 @@ public function processAssert( $orderComments = $infoTab->getCommentsHistoryBlock()->getComments(); $commentsMessages = array_column($orderComments, 'comment'); - \PHPUnit_Framework_Assert::assertRegExp( + \PHPUnit\Framework\Assert::assertRegExp( sprintf(self::AUTHORIZED_AMOUNT_PATTERN, $prices['grandTotal']), implode('. ', $commentsMessages), 'Incorrect authorized amount value for the order #' . $orderId diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCancelInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCancelInCommentsHistory.php index 05acfd07ead98..f4b893a7c700a 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCancelInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCancelInCommentsHistory.php @@ -41,7 +41,7 @@ public function processAssert( $comments = $infoTab->getCommentsHistoryBlock()->getComments(); $commentsMessages = array_column($comments, 'comment'); - \PHPUnit_Framework_Assert::assertRegExp( + \PHPUnit\Framework\Assert::assertRegExp( sprintf($this->canceledAmountPattern, $prices['grandTotal']), implode('. ', $commentsMessages), 'Incorrect canceled amount value for the order #' . $orderId diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php index 451f656d5e1b6..1e38108c3c3e6 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCaptureInCommentsHistory.php @@ -52,7 +52,7 @@ public function processAssert( $comments = array_values($comments); foreach ($capturedPrices as $key => $capturedPrice) { - \PHPUnit_Framework_Assert::assertRegExp( + \PHPUnit\Framework\Assert::assertRegExp( sprintf(self::CAPTURED_AMOUNT_PATTERN, preg_quote(number_format($capturedPrice, 2, '.', ''))), $comments[$key]['comment'], 'Incorrect captured amount value for the order #' . $orderId diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCartSectionIsEmptyOnBackendOrderPage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCartSectionIsEmptyOnBackendOrderPage.php index b00ad1cee42b9..cbe3aab2a7ecf 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCartSectionIsEmptyOnBackendOrderPage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCartSectionIsEmptyOnBackendOrderPage.php @@ -24,7 +24,7 @@ public function processAssert(OrderCreateIndex $orderCreateIndex) { $orderCreateIndex->open(); $backendOrderSidebarBlock = $orderCreateIndex->getBackendOrderSidebarBlock()->noItemsInCartCheck(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $backendOrderSidebarBlock, "Customer's Shopping Cart section on Order Create backend page is not empty." ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCartSectionWithProductsOnBackendOrderPage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCartSectionWithProductsOnBackendOrderPage.php index dc7790fbe0f31..400ba83d66309 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCartSectionWithProductsOnBackendOrderPage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCartSectionWithProductsOnBackendOrderPage.php @@ -28,7 +28,7 @@ public function processAssert(OrderCreateIndex $orderCreateIndex, array $product $expectedItemNames[] = $product->getName(); } $itemsNames = $orderCreateIndex->getBackendOrderSidebarBlock()->getCartItemsNames(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sort($expectedItemNames), sort($itemsNames), "Customer's Shopping Cart section on Order Create backend page doesn't contain correct products." diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoButton.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoButton.php index 5a91a40dabae0..e3b12274604ad 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoButton.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoButton.php @@ -28,7 +28,7 @@ public function processAssert(SalesOrderView $salesOrderView, OrderIndex $orderI { $orderIndex->open(); $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $salesOrderView->getPageActions()->isActionButtonVisible('Credit Memo'), 'Credit memo button is absent on order view page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoItems.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoItems.php index ed5c060a3df48..f0019051213b1 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoItems.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertCreditMemoItems.php @@ -43,7 +43,7 @@ public function processAssert( $creditMemoIndex->getCreditMemoGrid()->searchAndOpen($filter); $itemsData = $this->preparePageItems($salesCreditMemoView->getItemsBlock()->getData()); $error = $this->verifyData($productsData, $itemsData); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentMessageInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentMessageInCommentsHistory.php index 04c4f4ea89815..254388a595e5e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentMessageInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentMessageInCommentsHistory.php @@ -40,7 +40,7 @@ public function processAssert(SalesOrderView $salesOrderView, OrderIndex $orderI $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); - \PHPUnit_Framework_Assert::assertContains(self::$message, $latestComment['comment']); + \PHPUnit\Framework\Assert::assertContains(self::$message, $latestComment['comment']); } /** diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentSuccessMessagePresent.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentSuccessMessagePresent.php index 08923d715c71d..bf8949ed0c867 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentSuccessMessagePresent.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertDenyPaymentSuccessMessagePresent.php @@ -29,7 +29,7 @@ class AssertDenyPaymentSuccessMessagePresent extends AbstractConstraint */ public function processAssert(SalesOrderView $salesOrderView) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::$successDenyMessage, $salesOrderView->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceInInvoicesGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceInInvoicesGrid.php index 9b0067d8f2e34..bc2f11be623cd 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceInInvoicesGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceInInvoicesGrid.php @@ -43,7 +43,7 @@ public function processAssert(InvoiceIndex $invoiceIndex, OrderInjectable $order $invoiceIndex->getInvoicesGrid()->search($filter); $filter['grand_total_from'] = number_format($amount[$key]['grand_invoice_total'], 2); $filter['grand_total_to'] = number_format($amount[$key]['grand_invoice_total'], 2); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $invoiceIndex->getInvoicesGrid()->isRowVisible($filter, false, false), 'Invoice is absent in invoices grid on invoice index page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceInInvoicesTab.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceInInvoicesTab.php index eda14b36798c3..392b1d1ad1331 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceInInvoicesTab.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceInInvoicesTab.php @@ -47,7 +47,7 @@ public function processAssert( $grid->search($filter); $filter['amount_from'] = number_format($amount[$key]['grand_invoice_total'], 2); unset($filter['amount_to']); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $grid->isRowVisible($filter, false, false), 'Invoice is absent on invoices tab.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php index 2b92133ff4dc7..db039fdbd8f99 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceItems.php @@ -46,7 +46,7 @@ public function processAssert( $invoiceIndex->getInvoicesGrid()->searchAndOpen($filter); $itemsData = $this->preparePageItems($salesInvoiceView->getItemsBlock()->getData()); $error = $this->verifyData($productsData, $itemsData); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } } diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceNotInInvoicesGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceNotInInvoicesGrid.php index 17a3206777a61..56beda6db2202 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceNotInInvoicesGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceNotInInvoicesGrid.php @@ -42,7 +42,7 @@ public function processAssert(InvoiceIndex $invoiceIndex, OrderInjectable $order $invoiceIndex->getInvoicesGrid()->search($filter); $filter['grand_total_from'] = number_format($amount[$key]['grand_invoice_total'], 2); $filter['grand_total_to'] = number_format($amount[$key]['grand_invoice_total'], 2); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $invoiceIndex->getInvoicesGrid()->isRowVisible($filter, false, false), 'Invoice is present in invoices grid on invoice index page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceStatusInOrdersGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceStatusInOrdersGrid.php index 451a4d1bb905c..0253d1c12d8db 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceStatusInOrdersGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceStatusInOrdersGrid.php @@ -35,7 +35,7 @@ public function processAssert( 'order_id' => $orderId, 'status' => $invoiceStatus, ]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $grid->isRowVisible($filter), 'Invoice status is incorrect.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceSuccessCreateMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceSuccessCreateMessage.php index b61561f50b60f..12dbcbc0a27ae 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceSuccessCreateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceSuccessCreateMessage.php @@ -27,7 +27,7 @@ class AssertInvoiceSuccessCreateMessage extends AbstractConstraint */ public function processAssert(SalesOrderView $salesOrderView) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_CREATE_MESSAGE, $salesOrderView->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceWithShipmentSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceWithShipmentSuccessMessage.php index 3f034bbca1b24..afbe2dda07dcd 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceWithShipmentSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoiceWithShipmentSuccessMessage.php @@ -27,7 +27,7 @@ class AssertInvoiceWithShipmentSuccessMessage extends AbstractConstraint */ public function processAssert(SalesOrderView $salesOrderView) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $salesOrderView->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoicedAmountOnFrontend.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoicedAmountOnFrontend.php index caed93731109d..c5f35cd42392f 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoicedAmountOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoicedAmountOnFrontend.php @@ -38,7 +38,7 @@ public function processAssert( $orderHistory->getOrderHistoryBlock()->openOrderById($order->getId()); $customerOrderView->getOrderViewBlock()->openLinkByName('Invoices'); foreach ($ids['invoiceIds'] as $key => $invoiceId) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($order->getPrice()['invoice'][$key]['grand_invoice_total'], 2), $invoiceView->getInvoiceBlock()->getItemBlock($invoiceId)->getGrandTotal() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoicedOrderOnDashboard.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoicedOrderOnDashboard.php index 8e0ee651d23f6..744e05c1b587f 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoicedOrderOnDashboard.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertInvoicedOrderOnDashboard.php @@ -35,7 +35,7 @@ public function processAssert( )->run()['dashboardOrder']['quantity']; $invoicedOrdersQty = $orderQty - $dashboardOrder['quantity']; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $invoicedOrdersQty, $expectedOrdersQuantityOnDashboard, 'Order quantity om admin dashboard is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertItemsOrderedSectionContainsProducts.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertItemsOrderedSectionContainsProducts.php index 86a90a7327196..c6b33de864c0d 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertItemsOrderedSectionContainsProducts.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertItemsOrderedSectionContainsProducts.php @@ -27,7 +27,7 @@ public function processAssert(OrderCreateIndex $orderCreateIndex, array $product $expectedItemNames[] = $product->getName(); } $itemsNames = $orderCreateIndex->getCreateBlock()->getItemsBlock()->getItemsNames(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sort($expectedItemNames), sort($itemsNames), "Items Ordered section on Create Order page on backend doesn't contain correct products." diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertItemsOrderedSectionOnBackendOrderIsEmpty.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertItemsOrderedSectionOnBackendOrderIsEmpty.php index 79f398e9ac346..4fb61f74304ee 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertItemsOrderedSectionOnBackendOrderIsEmpty.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertItemsOrderedSectionOnBackendOrderIsEmpty.php @@ -27,7 +27,7 @@ class AssertItemsOrderedSectionOnBackendOrderIsEmpty extends AbstractConstraint */ public function processAssert(OrderCreateIndex $orderCreateIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $orderCreateIndex->getCreateBlock()->getItemsBlock()->getEmptyTextMessage(), self::TEXT_MESSAGE, 'Items Ordered section on Create Order page on backend is not empty.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoCreditMemoButton.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoCreditMemoButton.php index 21239242b3c89..22ba984b489e2 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoCreditMemoButton.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoCreditMemoButton.php @@ -28,7 +28,7 @@ public function processAssert(SalesOrderView $salesOrderView, OrderIndex $orderI { $orderIndex->open(); $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $salesOrderView->getPageActions()->isActionButtonVisible('Credit Memo'), 'Credit memo button is present on order view page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoInvoiceButton.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoInvoiceButton.php index 0c663d54bd6bc..f8b15bfc6ca41 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoInvoiceButton.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertNoInvoiceButton.php @@ -28,7 +28,7 @@ public function processAssert(SalesOrderView $salesOrderView, OrderIndex $orderI { $orderIndex->open(); $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $salesOrderView->getPageActions()->isActionButtonVisible('Invoice'), 'Invoice button is present on order view page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOnlineInvoiceCannotBeCreated.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOnlineInvoiceCannotBeCreated.php index 5b9f56c1450f5..fa43a807caef1 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOnlineInvoiceCannotBeCreated.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOnlineInvoiceCannotBeCreated.php @@ -40,7 +40,7 @@ public function processAssert( $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); $salesOrderView->getPageActions()->invoice(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::OFFLINE_INVOICE_MESSAGE, $orderInvoiceNew->getTotalsBlock()->getCaptureOfflineMessage(), 'Message incorrect or is not present.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderAddresses.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderAddresses.php index ba1636970164b..bd33a39443ed2 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderAddresses.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderAddresses.php @@ -44,7 +44,7 @@ public function processAssert( $orderBillingAddress = $salesOrderView->getAddressesBlock()->getCustomerBillingAddress(); $orderShippingAddress = $salesOrderView->getAddressesBlock()->getCustomerShippingAddress(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $selectedBillingAddress == $orderBillingAddress && $selectedShippingAddress == $orderShippingAddress, 'Billing and shipping addresses from the address book and from the order page are not the same.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderBillingAndShippingAddressesAreDifferent.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderBillingAndShippingAddressesAreDifferent.php index 072aef2f6c637..548f2e9b15a71 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderBillingAndShippingAddressesAreDifferent.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderBillingAndShippingAddressesAreDifferent.php @@ -28,7 +28,7 @@ public function processAssert( $orderBillingAddress = $salesOrderView->getAddressesBlock()->getCustomerBillingAddress(); $orderShippingAddress = $salesOrderView->getAddressesBlock()->getCustomerShippingAddress(); - \PHPUnit_Framework_Assert::assertNotEquals( + \PHPUnit\Framework\Assert::assertNotEquals( $orderBillingAddress, $orderShippingAddress, "Billing and shipping addresses on order page are the same but shouldn't." diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsAvailable.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsAvailable.php index 5ada4a3cb9a30..5059959ea8ac1 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsAvailable.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsAvailable.php @@ -34,7 +34,7 @@ public function processAssert(SalesOrderView $salesOrderView, $orderButtonsAvail } } - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $absentButtons, "Next buttons was not found on page: \n" . implode(";\n", $absentButtons) ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsUnavailable.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsUnavailable.php index 42fe4863da9fb..b3a4c571a89ba 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsUnavailable.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderButtonsUnavailable.php @@ -40,7 +40,7 @@ public function processAssert( $matches[] = $button; } } - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $matches, 'Buttons are present on order page.' . "\nLog:\n" . implode(";\n", $matches) diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderByDateInOrdersGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderByDateInOrdersGrid.php index 1dc11278edca7..1d66fc4e7e5ca 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderByDateInOrdersGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderByDateInOrdersGrid.php @@ -31,7 +31,7 @@ public function processAssert(OrderInjectable $order, OrderIndex $orderIndex) ]; $orderIndex->open(); $orderIndex->getSalesOrderGrid()->search($filter); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $orderIndex->getSalesOrderGrid()->isFirstRowVisible(), 'Order with following id ' . $order->getId() . ' is absent in Orders grid with applied date.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php index f8c3d8da399cd..fffb0746d4967 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionFailMessage.php @@ -28,7 +28,7 @@ class AssertOrderCancelMassActionFailMessage extends AbstractConstraint */ public function processAssert(OrderIndex $orderIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::FAIL_CANCEL_MESSAGE, $orderIndex->getMessagesBlock()->getErrorMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionSuccessMessage.php index 195ca78a53bb0..853aea8d370bd 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelMassActionSuccessMessage.php @@ -29,7 +29,7 @@ class AssertOrderCancelMassActionSuccessMessage extends AbstractConstraint */ public function processAssert(OrderIndex $orderIndex, $ordersCount) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_CANCEL_MESSAGE, $ordersCount), $orderIndex->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelSuccessMessage.php index fe1c1c3993d88..f48e40fa6fd57 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCancelSuccessMessage.php @@ -27,7 +27,7 @@ class AssertOrderCancelSuccessMessage extends AbstractConstraint */ public function processAssert(SalesOrderView $salesOrderView) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_CANCEL_MESSAGE, $salesOrderView->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCommentsHistoryNotifyStatus.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCommentsHistoryNotifyStatus.php index 225051d9f3cc0..95f1254d9be81 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCommentsHistoryNotifyStatus.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderCommentsHistoryNotifyStatus.php @@ -37,7 +37,7 @@ public function processAssert( $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $latestComment['is_customer_notified'], (bool)$sendMail ? 'Customer Notified' : 'Customer Not Notified' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php index 4bdd286db72b1..5f2712bab87fc 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGrandTotal.php @@ -33,7 +33,7 @@ public function processAssert( $salesOrder->open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($prices['grandTotal'], 2, '.', ','), $salesOrderView->getOrderTotalsBlock()->getGrandTotal(), 'Grand Total price does not equal to price from data set.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGraphImageIsVisible.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGraphImageIsVisible.php index e41619fdf62ef..2d69d052ed567 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGraphImageIsVisible.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderGraphImageIsVisible.php @@ -33,7 +33,7 @@ public function processAssert( ['argumentsList' => $argumentsList] )->run(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $dashboard->getMainBlock()->isGraphImageVisible(), 'Graph image is not visible on admin dashboard.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGrid.php index 855e12507f16a..0bd55817c4f92 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGrid.php @@ -46,7 +46,7 @@ public function assert(OrderInjectable $order, OrderIndex $orderIndex, $status, 'status' => $status ]; $errorMessage = implode(', ', $filter); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $orderIndex->getSalesOrderGrid()->isRowVisible(array_filter($filter)), 'Order with following data \'' . $errorMessage . '\' is absent in Orders grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGridOnFrontend.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGridOnFrontend.php index 07a42b165d609..7df33e2af23f0 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGridOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderInOrdersGridOnFrontend.php @@ -56,7 +56,7 @@ public function processAssert( )->run(); $customerAccountIndex->getAccountMenuBlock()->openMenuItem('My Orders'); $errorMessage = implode(', ', $filter); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $orderHistory->getOrderHistoryBlock()->isOrderVisible($filter), 'Order with following data \'' . $errorMessage . '\' is absent in Orders block on frontend.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderItemsPagerDisplayedOnFrontend.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderItemsPagerDisplayedOnFrontend.php index 230e4604a771f..90541ff822143 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderItemsPagerDisplayedOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderItemsPagerDisplayedOnFrontend.php @@ -49,11 +49,11 @@ public function processAssert( )->run(); $customerAccountIndex->getAccountMenuBlock()->openMenuItem('My Orders'); $orderHistory->getOrderHistoryBlock()->openOrderById($orderId); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $customerOrderView->getOrderViewBlock()->isTopPagerDisplayed(), 'Order items top pager is expected to be displayed for order '. $orderId ); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $customerOrderView->getOrderViewBlock()->isBottomPagerDisplayed(), 'Order items bottom pager is expected to be displayed for order '. $orderId ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderItemsPagerHiddenOnFrontend.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderItemsPagerHiddenOnFrontend.php index 11af4214ed471..2b0056e0acf49 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderItemsPagerHiddenOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderItemsPagerHiddenOnFrontend.php @@ -49,11 +49,11 @@ public function processAssert( )->run(); $customerAccountIndex->getAccountMenuBlock()->openMenuItem('My Orders'); $orderHistory->getOrderHistoryBlock()->openOrderById($orderId); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $customerOrderView->getOrderViewBlock()->isTopPagerDisplayed(), 'Order items top pager is expected to be hidden for order '. $orderId ); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $customerOrderView->getOrderViewBlock()->isBottomPagerDisplayed(), 'Order items bottom pager is expected to be hidden for order '. $orderId ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderMassOnHoldSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderMassOnHoldSuccessMessage.php index 51d4ba030151f..77b2a35ad7b9b 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderMassOnHoldSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderMassOnHoldSuccessMessage.php @@ -33,7 +33,7 @@ class AssertOrderMassOnHoldSuccessMessage extends AbstractConstraint */ public function processAssert(OrderIndex $orderIndex, $ordersCount) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_ON_HOLD_MESSAGE, $ordersCount), $orderIndex->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderNotInOrdersGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderNotInOrdersGrid.php index 6691db8aa6dbc..8dec0fa1e9648 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderNotInOrdersGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderNotInOrdersGrid.php @@ -29,7 +29,7 @@ public function processAssert(OrderInjectable $order, OrderIndex $orderIndex) $filter = ['id' => $data['id']]; $orderIndex->open(); $errorMessage = implode(', ', $filter); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $orderIndex->getSalesOrderGrid()->isRowVisible($filter), 'Order with following data \'' . $errorMessage . '\' is present in Orders grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderNotVisibleOnMyAccount.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderNotVisibleOnMyAccount.php index 561ec5d2c9984..6b87906a17255 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderNotVisibleOnMyAccount.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderNotVisibleOnMyAccount.php @@ -43,7 +43,7 @@ public function processAssert( ['customer' => $customer] )->run(); $customerAccountIndex->getAccountMenuBlock()->openMenuItem('My Orders'); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $orderHistory->getOrderHistoryBlock()->isVisible() && $orderHistory->getOrderHistoryBlock()->isOrderVisible($filter), 'Order with following data \'' . implode(', ', $filter) . '\' is present in Orders block on frontend.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderOnHoldFailMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderOnHoldFailMessage.php index 8382471a7e4bf..7cb063246bfb1 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderOnHoldFailMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderOnHoldFailMessage.php @@ -28,7 +28,7 @@ class AssertOrderOnHoldFailMessage extends AbstractConstraint */ public function processAssert(OrderIndex $orderIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::FAIL_ON_HOLD_MESSAGE, $orderIndex->getMessagesBlock()->getErrorMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderOnHoldSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderOnHoldSuccessMessage.php index c62a3ff22f712..17f10dc984aac 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderOnHoldSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderOnHoldSuccessMessage.php @@ -42,7 +42,7 @@ public function processAssert(OrderIndex $orderIndex, $ordersCount = null) ? sprintf(self::MULTIPLE_SUCCESS_ON_HOLD_MESSAGE, $ordersCount) : self::SINGLE_SUCCESS_ON_HOLD_MESSAGE; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $successOnHoldMessage, $orderIndex->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderPaymentInformation.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderPaymentInformation.php index bfc08585cac1b..db9426d9769b0 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderPaymentInformation.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderPaymentInformation.php @@ -37,7 +37,7 @@ public function processAssert( $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); $actualPaymentInformation = $infoTab->getPaymentInfoBlock()->getData(); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( array_diff($paymentInfo, $actualPaymentInformation), 'Payment Information missmatch with expected values.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseFailMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseFailMessage.php index afed45b8772be..f8aed71388f11 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseFailMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseFailMessage.php @@ -28,7 +28,7 @@ class AssertOrderReleaseFailMessage extends AbstractConstraint */ public function processAssert(OrderIndex $orderIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::FAIL_RELEASE_MESSAGE, $orderIndex->getMessagesBlock()->getErrorMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseSuccessMessage.php index e5cf722cdcd75..b0226779f273d 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderReleaseSuccessMessage.php @@ -29,7 +29,7 @@ class AssertOrderReleaseSuccessMessage extends AbstractConstraint */ public function processAssert(OrderIndex $orderIndex, $ordersCount) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_RELEASE_MESSAGE, $ordersCount), $orderIndex->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusDuplicateStatus.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusDuplicateStatus.php index 0c5dc5b58d549..13ef0afda8424 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusDuplicateStatus.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusDuplicateStatus.php @@ -26,7 +26,7 @@ class AssertOrderStatusDuplicateStatus extends AbstractConstraint public function processAssert(OrderStatusNew $orderStatusNewPage) { $actualMessage = $orderStatusNewPage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::DUPLICATE_MESSAGE, $actualMessage, 'Wrong duplicate message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusInGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusInGrid.php index 01064e2b352a0..c4ce44b197d97 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusInGrid.php @@ -44,7 +44,7 @@ public function processAssert( $filter = ['label' => $defaultState, 'state' => $state]; } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $orderStatusIndexPage->getOrderStatusGrid()->isRowVisible($filter, true, false), 'Order status \'' . $orderStatusLabel . '\' is absent in Order Status grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCanceled.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCanceled.php index e51692b260535..1f19a304d7748 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCanceled.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCanceled.php @@ -35,7 +35,7 @@ public function processAssert( /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $infoTab->getOrderStatus(), 'Canceled' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php index 46f6ebba51fe1..c3e8558df7fcc 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusIsCorrect.php @@ -38,7 +38,7 @@ public function processAssert( /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $infoTab->getOrderStatus(), $orderStatus ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusNotAssigned.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusNotAssigned.php index dd0722bbcf848..c89504147bcc5 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusNotAssigned.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusNotAssigned.php @@ -30,7 +30,7 @@ class AssertOrderStatusNotAssigned extends AbstractConstraint public function processAssert(OrderStatus $orderStatus, OrderStatusIndex $orderStatusIndex) { $statusLabel = $orderStatus->getLabel(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $orderStatusIndex->open()->getOrderStatusGrid()->isRowVisible( ['label' => $statusLabel, 'state' => $orderStatus->getState()] ), diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessAssignMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessAssignMessage.php index 3ceebd8b8a799..6d6c6999ba170 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessAssignMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessAssignMessage.php @@ -28,7 +28,7 @@ class AssertOrderStatusSuccessAssignMessage extends AbstractConstraint */ public function processAssert(OrderStatusIndex $orderStatusIndexPage) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $orderStatusIndexPage->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessCreateMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessCreateMessage.php index e4162b0f11343..6b7dc33875a14 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessCreateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessCreateMessage.php @@ -30,7 +30,7 @@ class AssertOrderStatusSuccessCreateMessage extends AbstractConstraint public function processAssert(OrderStatusIndex $orderStatusIndexPage) { $actualMessage = $orderStatusIndexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessUnassignMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessUnassignMessage.php index f614c95b51e6c..6d15b772ea6c3 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessUnassignMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderStatusSuccessUnassignMessage.php @@ -28,7 +28,7 @@ class AssertOrderStatusSuccessUnassignMessage extends AbstractConstraint */ public function processAssert(OrderStatusIndex $orderStatusIndexPage) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $orderStatusIndexPage->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderSuccessCreateMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderSuccessCreateMessage.php index abea680544a83..791e782df2807 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderSuccessCreateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderSuccessCreateMessage.php @@ -31,7 +31,7 @@ class AssertOrderSuccessCreateMessage extends AbstractConstraint */ public function processAssert(SalesOrderView $salesOrderView) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $salesOrderView->getMessagesBlock()->getSuccessMessage(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderSuccessVoidedMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderSuccessVoidedMessage.php index 91e3ec9acdd92..b2f86afc1ce5e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderSuccessVoidedMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderSuccessVoidedMessage.php @@ -32,7 +32,7 @@ class AssertOrderSuccessVoidedMessage extends AbstractConstraint public function processAssert(OrderStatusIndex $orderStatusIndexPage) { $actualMessage = $orderStatusIndexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderTotalPaid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderTotalPaid.php index c4bfd385162b1..d04cf8698ab96 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderTotalPaid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderTotalPaid.php @@ -32,7 +32,7 @@ public function processAssert( $salesOrder->open(); $salesOrder->getSalesOrderGrid()->searchAndOpen(['id' => $orderId]); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($prices['totalPaid'], 2, '.', ','), $salesOrderView->getOrderTotalsBlock()->getTotalPaid(), 'Total Paid price does not equal to price from data set.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductInCustomerShoppingCartOnBackendGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductInCustomerShoppingCartOnBackendGrid.php index a749ee25e3261..3d760d6c1cab1 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductInCustomerShoppingCartOnBackendGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductInCustomerShoppingCartOnBackendGrid.php @@ -34,7 +34,7 @@ public function processAssert( $customerIndexEdit->open(['id' => $customer->getId()]); $customerIndexEdit->getPageActionsBlock()->manageShoppingCart(); foreach ($productsInCart as $product) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $product->getName(), $checkoutIndex->getItemsBlock()->getItemName($product), 'Product ' . $product->getName() . " is not present in grid on customer's shopping cart on backend." diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductInItemsOrderedGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductInItemsOrderedGrid.php index 256b89cfa3dc5..af91955d4e39b 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductInItemsOrderedGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertProductInItemsOrderedGrid.php @@ -47,7 +47,7 @@ public function processAssert(OrderCreateIndex $orderCreateIndex, array $product $this->productsIsConfigured = $productsIsConfigured; $data = $this->prepareData($products, $orderCreateIndex->getCreateBlock()->getItemsBlock()); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $data['fixtureData'], $data['pageData'], 'Product data on order create page not equals to passed from fixture.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php index 4b56297f5eba6..e0e4cc874f72e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCommentsHistory.php @@ -52,7 +52,7 @@ public function processAssert( $refundedPrices = $order->getPrice()['refund']; foreach ($refundedPrices as $key => $refundedPrice) { - \PHPUnit_Framework_Assert::assertRegExp( + \PHPUnit\Framework\Assert::assertRegExp( sprintf(self::REFUNDED_AMOUNT_PATTERN, $refundedPrice['grand_creditmemo_total']), $comments[$key]['comment'], 'Incorrect refunded amount value for the order #' . $orderId diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCreditMemoTab.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCreditMemoTab.php index 6352fd99eebf6..b87b15523ab90 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCreditMemoTab.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInCreditMemoTab.php @@ -44,7 +44,7 @@ public function processAssert( 'amount_from' => $amount[$key]['grand_creditmemo_total'], 'amount_to' => $amount[$key]['grand_creditmemo_total'] ]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $grid->isRowVisible($filter, true, false), 'Credit memo is absent on credit memos tab.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInRefundsGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInRefundsGrid.php index 615c25ee50594..b0bb452581427 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInRefundsGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundInRefundsGrid.php @@ -38,7 +38,7 @@ public function processAssert(CreditMemoIndex $creditMemoIndex, OrderInjectable $creditMemoIndex->getCreditMemoGrid()->search($filter); $filter['grand_total_from'] = number_format($amount[$key]['grand_creditmemo_total'], 2); $filter['grand_total_to'] = number_format($amount[$key]['grand_creditmemo_total'], 2); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $creditMemoIndex->getCreditMemoGrid()->isRowVisible($filter, false, false), "Credit memo '#$creditMemoId' is absent in credit memos grid on credit memo index page." ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundNotInRefundsGrid.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundNotInRefundsGrid.php index 24ab9227ae6b8..6808776e6f714 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundNotInRefundsGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundNotInRefundsGrid.php @@ -38,7 +38,7 @@ public function processAssert(CreditMemoIndex $creditMemoIndex, OrderInjectable $creditMemoIndex->getCreditMemoGrid()->search($filter); $filter['grand_total_from'] = number_format($amount[$key]['grand_creditmemo_total'], 2); $filter['grand_total_to'] = number_format($amount[$key]['grand_creditmemo_total'], 2); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $creditMemoIndex->getCreditMemoGrid()->isRowVisible($filter, false, false), "Credit memo '#$creditMemoId' is present in credit memos grid on credit memo index page." ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php index 9a7c34d7e6d66..0d78c4b72e168 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundOrderStatusInCommentsHistory.php @@ -35,7 +35,7 @@ public function processAssert( $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $infoTab->getOrderStatus(), $latestComment['status'] ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundSuccessCreateMessage.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundSuccessCreateMessage.php index 3d606a859406c..13567cf5904ce 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundSuccessCreateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundSuccessCreateMessage.php @@ -27,7 +27,7 @@ class AssertRefundSuccessCreateMessage extends AbstractConstraint */ public function processAssert(SalesOrderView $salesOrderView) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_CREATE_MESSAGE, $salesOrderView->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundedGrandTotalOnFrontend.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundedGrandTotalOnFrontend.php index 82c1f27c694dd..c0682ce954050 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundedGrandTotalOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertRefundedGrandTotalOnFrontend.php @@ -37,7 +37,7 @@ public function processAssert( $orderHistory->getOrderHistoryBlock()->openOrderById($order->getId()); $customerOrderView->getOrderViewBlock()->openLinkByName('Refunds'); foreach ($ids['creditMemoIds'] as $key => $creditMemoId) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($order->getPrice()['refund'][$key]['grand_creditmemo_total'], 2), $creditMemoView->getCreditMemoBlock()->getItemBlock($creditMemoId)->getGrandTotal() ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderButtonIsNotVisibleOnFrontend.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderButtonIsNotVisibleOnFrontend.php index f040e7e9e292c..ab09b4e6c8a4e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderButtonIsNotVisibleOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderButtonIsNotVisibleOnFrontend.php @@ -56,7 +56,7 @@ public function processAssert( )->run(); $customerAccountIndex->getAccountMenuBlock()->openMenuItem('My Orders'); $errorMessage = implode(', ', $filter); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $orderHistory->getOrderHistoryBlock()->isReorderButtonPresentByOrderId($filter['id']), '"Reorder" button for order with following data \'' . $errorMessage . '\' is present in Orders block on frontend.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php index 8c602049cddff..1a47e51765143 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertReorderStatusIsCorrect.php @@ -36,7 +36,7 @@ public function processAssert( /** @var \Magento\Sales\Test\Block\Adminhtml\Order\View\Tab\Info $infoTab */ $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $previousOrderStatus, $infoTab->getOrderStatus(), 'Order status is incorrect on order page in backend.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderBillingAddress.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderBillingAddress.php index dbc4a4a9f45c2..e17d2b3ceb833 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderBillingAddress.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderBillingAddress.php @@ -29,7 +29,7 @@ public function processAssert(SalesGuestPrint $salesGuestPrint, Address $billing ['address' => $billingAddress, 'type' => 'html'] ); $expectedBillingAddress = $addressRenderer->render(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedBillingAddress, $salesGuestPrint->getInfoBlock()->getBillingAddress(), "Billing address was printed incorrectly." diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderGrandTotal.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderGrandTotal.php index f252a8397ea97..e54f9a68c1e3d 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderGrandTotal.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderGrandTotal.php @@ -23,7 +23,7 @@ class AssertSalesPrintOrderGrandTotal extends AbstractConstraint */ public function processAssert(SalesGuestPrint $salesGuestPrint, array $prices) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format(array_sum($prices), 2), $salesGuestPrint->getViewBlock()->getItemBlock()->getGrandTotal(), "Grand total was printed incorrectly." diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderPaymentMethod.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderPaymentMethod.php index 6b8c817904b5e..f93959514a074 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderPaymentMethod.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderPaymentMethod.php @@ -23,7 +23,7 @@ class AssertSalesPrintOrderPaymentMethod extends AbstractConstraint */ public function processAssert(SalesGuestPrint $salesGuestPrint, $paymentMethod) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $salesGuestPrint->getInfoBlock()->isPaymentMethodVisible($paymentMethod), "Payment method was printed incorrect on sales guest print page." ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderProducts.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderProducts.php index f758225257b72..7ec6ed27d6f35 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderProducts.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertSalesPrintOrderProducts.php @@ -36,7 +36,7 @@ public function processAssert(SalesGuestPrint $salesGuestPrint, array $products) } } - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } /** diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertTransactionStatus.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertTransactionStatus.php index 46fd23da0dcd9..2168b69fa2f2f 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertTransactionStatus.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertTransactionStatus.php @@ -38,7 +38,7 @@ public function processAssert( foreach ($transactions as $transaction) { foreach ($actualTransactions as $actualTransaction) { if ($actualTransaction['transactionType'] === $transaction['transactionType']) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $transaction['statusIsClosed'], $actualTransaction['statusIsClosed'], 'The ' . $transaction['transactionType'] . ' transaction status is not closed.' diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertUnholdButton.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertUnholdButton.php index b0915650cc1a1..6cf79cc333ca5 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertUnholdButton.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertUnholdButton.php @@ -32,7 +32,7 @@ public function processAssert(OrderIndex $orderIndex, SalesOrderView $salesOrder { $orderIndex->open(); $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $salesOrderView->getPageActions()->isActionButtonVisible('Unhold'), 'Button "Unhold" is absent on order page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertVoidInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertVoidInCommentsHistory.php index bb627876bfd66..8fb7dbc07508e 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertVoidInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertVoidInCommentsHistory.php @@ -42,7 +42,7 @@ public function processAssert( $infoTab = $salesOrderView->getOrderForm()->openTab('info')->getTab('info'); $latestComment = $infoTab->getCommentsHistoryBlock()->getLatestComment(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::VOIDED_AMOUNT . $prices['grandTotal'], $latestComment['comment'], 'Incorrect voided amount value for the order #' . $orderId diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleConditionIsApplied.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleConditionIsApplied.php index a4995f81cd826..8d0f404441368 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleConditionIsApplied.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleConditionIsApplied.php @@ -25,7 +25,7 @@ protected function assert() $actualPrices['discount'] = $this->checkoutCart->getTotalsBlock()->getDiscount(); $expectedPrices = $this->cartPrice; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedPrices, $actualPrices, 'Wrong total cart prices are displayed.' diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleConditionIsNotApplied.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleConditionIsNotApplied.php index 31714491c49b5..c051d6e9fd7fd 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleConditionIsNotApplied.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleConditionIsNotApplied.php @@ -25,7 +25,7 @@ protected function assert() $shippingPrice = $this->checkoutCart->getTotalsBlock()->getShippingPrice(); $grandTotal = number_format(($grandTotal - $shippingPrice), 2); } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $subTotal, $grandTotal, 'Shopping cart subtotal: \'' . $subTotal . '\' not equals with grand total: \'' . $grandTotal . '\'' diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleForm.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleForm.php index 50f36a13549d7..ffdeadc015f8d 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleForm.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleForm.php @@ -65,7 +65,7 @@ public function processAssert( $fixtureData = array_merge($fixtureData, $salesRuleAdditional->getData()); } $dataDiff = $this->verify($fixtureData, $formData); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($dataDiff), 'Sales rule data on edit page(backend) not equals to passed from fixture.' . "\nFailed values:\n " . implode(";\n ", $dataDiff) diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleFreeShippingIsApplied.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleFreeShippingIsApplied.php index f31cb5ac013eb..b018d07913235 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleFreeShippingIsApplied.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleFreeShippingIsApplied.php @@ -22,7 +22,7 @@ protected function assert() { $shippingPrice = $this->checkoutCart->getTotalsBlock()->getShippingPrice(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $shippingPrice, self::FREE_SHIPPING_PRICE, 'Current shipping price: \'' . $shippingPrice diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleIsNotPresentedInGrid.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleIsNotPresentedInGrid.php index 5851b6fb1e450..d0c1db7993a42 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleIsNotPresentedInGrid.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleIsNotPresentedInGrid.php @@ -24,7 +24,7 @@ class AssertCartPriceRuleIsNotPresentedInGrid extends AbstractConstraint */ public function processAssert(PromoQuoteIndex $promoQuoteIndex, SalesRule $salesRule) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $promoQuoteIndex->getPromoQuoteGrid()->isRowVisible(['name' => $salesRule->getName()]), 'Sales rule \'' . $salesRule->getName() . '\' is present in cart price rules grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleSuccessDeleteMessage.php index 381de91030a61..68c3910afccd1 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleSuccessDeleteMessage.php @@ -29,7 +29,7 @@ class AssertCartPriceRuleSuccessDeleteMessage extends AbstractConstraint public function processAssert(PromoQuoteIndex $promoQuoteIndex) { $actualMessage = $promoQuoteIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleSuccessSaveMessage.php index 454b894b44df0..c90bc3bffb904 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertCartPriceRuleSuccessSaveMessage extends AbstractConstraint public function processAssert(PromoQuoteIndex $promoQuoteIndex) { $actualMessage = $promoQuoteIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertSalesRuleOnPrintOrder.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertSalesRuleOnPrintOrder.php index 35fdd7194d55c..320df06822eee 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertSalesRuleOnPrintOrder.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertSalesRuleOnPrintOrder.php @@ -23,7 +23,7 @@ class AssertSalesRuleOnPrintOrder extends AbstractConstraint */ public function processAssert(SalesGuestPrint $salesGuestPrint, array $prices) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( abs($prices['discount']), $salesGuestPrint->getViewSalesRule()->getItemBlock()->getSalesRuleDiscount(), "Sales rule amount not equals." diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupDeleteMessage.php index 911a1580364cf..01d6542017bbe 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupDeleteMessage.php @@ -25,7 +25,7 @@ class AssertSynonymGroupDeleteMessage extends AbstractConstraint public function processAssert(SynonymGroupIndex $synonymGroupIndex) { $actualMessage = $synonymGroupIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupInGrid.php b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupInGrid.php index 04cca7609f45f..7f20e00ac360b 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupInGrid.php @@ -40,12 +40,12 @@ public function processAssert( $this->prepareFilter($synonymGroup, $synonymFilter); $synonymGroupIndex->getSynonymGroupGrid()->search($this->filter); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $synonymGroupIndex->getSynonymGroupGrid()->isRowVisible($this->filter, false, false), 'Synonym Group is absent in Synonym grid' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( count($synonymGroupIndex->getSynonymGroupGrid()->getAllIds()), 1, 'There is more than one synonyms founded' diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupSuccessSaveMessage.php index 243405292ed41..77f999fe9bba6 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertSynonymGroupSuccessSaveMessage extends AbstractConstraint public function processAssert(SynonymGroupIndex $synonymGroupIndex) { $actualMessage = $synonymGroupIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_SAVE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupsSearch.php b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupsSearch.php index fc89d6d070d0f..04ef3616d21ac 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupsSearch.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymGroupsSearch.php @@ -28,7 +28,7 @@ public function processAssert(array $synonymGroups, array $searchQueries, Synony foreach ($searchQueries as $query) { $synonymGroupIndex->getSynonymGroupGrid()->fullTextSearch($query['query']); foreach ($query['results'] as $key => $result) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $result, $synonymGroupIndex->getSynonymGroupGrid()->isRowVisible( ['synonyms' => $synonymGroups[$key]->getData()['synonyms']], diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymMergeErrorMessage.php b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymMergeErrorMessage.php index 647f14d494338..873a2aee2bd80 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymMergeErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymMergeErrorMessage.php @@ -25,7 +25,7 @@ class AssertSynonymMergeErrorMessage extends AbstractConstraint public function processAssert(SynonymGroupNew $synonymGroupNew) { $actualMessage = $synonymGroupNew->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::ERROR_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymRestrictedAccess.php b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymRestrictedAccess.php index 26de8e0c76923..5b105302375a4 100644 --- a/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymRestrictedAccess.php +++ b/dev/tests/functional/tests/app/Magento/Search/Test/Constraint/AssertSynonymRestrictedAccess.php @@ -31,7 +31,7 @@ public function processAssert(Dashboard $dashboard, SynonymGroupIndex $synonymGr { $synonymGroupIndex->open(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::ACCESS_DENIED_TEXT, $dashboard->getErrorBlock()->getContent(), 'Synonym group index page is available.' diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerEmailChanged.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerEmailChanged.php index df7ba8cac9945..239c1040721d5 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerEmailChanged.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerEmailChanged.php @@ -46,7 +46,7 @@ public function processAssert( ['customer' => $customer] )->run(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $customerAccountIndex->getAccountMenuBlock()->isVisible(), 'Customer Account Dashboard is not visible.' ); diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerIsLocked.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerIsLocked.php index ab9c001a3d65b..a634e0ebba26c 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerIsLocked.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerIsLocked.php @@ -26,7 +26,7 @@ class AssertCustomerIsLocked extends AbstractConstraint public function processAssert( CustomerAccountLogin $customerLogin ) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::CUSTOMER_LOCKED_MESSAGE, $customerLogin->getMessages()->getErrorMessage(), 'Wrong message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerPasswordRequiredClasses.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerPasswordRequiredClasses.php index 2618734b85fdb..a6ddcc4e10aba 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerPasswordRequiredClasses.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerPasswordRequiredClasses.php @@ -31,7 +31,7 @@ public function processAssert(CustomerAccountCreate $registerPage, ConfigData $c $characterClassesNumber = $config ->getData('section')['customer/password/required_character_classes_number']['value']; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::EXPECTED_MAX_CHARACTERS, $characterClassesNumber) . self::EXPECTED_MESSAGE, $errorMessage, 'Wrong expected message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerResetPasswordFailed.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerResetPasswordFailed.php index 914e9d88d15a1..e0bbe26696930 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerResetPasswordFailed.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertCustomerResetPasswordFailed.php @@ -26,7 +26,7 @@ class AssertCustomerResetPasswordFailed extends AbstractConstraint */ public function processAssert(CustomerAccountForgotPassword $customerForgotPassword) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::TOO_MANY_RESET_REQUESTS_MESSAGE, $customerForgotPassword->getMessagesBlock()->getErrorMessage(), 'Wrong customer reset password failed message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertDefaultAccountInformation.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertDefaultAccountInformation.php index f747f383dfe0b..7b2e0d4361558 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertDefaultAccountInformation.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertDefaultAccountInformation.php @@ -25,22 +25,22 @@ public function processAssert( ) { $infoForm = $customerAccountEdit->getAccountInfoForm(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $infoForm->isEmailVisible(), 'Email text field should not be visible.' ); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $infoForm->isCurrentPasswordVisible(), 'Current Password text field should not be visible.' ); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $infoForm->isPasswordVisible(), 'New Password text field should not be visible.' ); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $infoForm->isConfirmPasswordVisible(), 'Password Confirmation text field should not be visible.' ); diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php index 4a64a278482bf..15d8992d953b8 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordIsNotSecureEnoughMessage.php @@ -26,7 +26,7 @@ public function processAssert(CustomerAccountCreate $registerPage) $expectedErrorMessage = 'Minimum of different classes of characters in password is 3.' . ' Classes of characters: Lower Case, Upper Case, Digits, Special Characters.'; $errorMessage = $registerPage->getRegisterForm()->getPasswordError(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedErrorMessage, $errorMessage, 'The messages are not equal.' diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordLengthErrorMessage.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordLengthErrorMessage.php index 0aa8cfb4789ab..f2b1fc72ce195 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordLengthErrorMessage.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertPasswordLengthErrorMessage.php @@ -26,7 +26,7 @@ class AssertPasswordLengthErrorMessage extends AbstractConstraint public function processAssert(CustomerAccountCreate $registerPage) { $errorMessage = $registerPage->getRegisterForm()->getPasswordError(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::PASSWORD_LENGTH_ERROR_MESSAGE, $errorMessage, 'Incorrect password error message.' diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertUserIsLocked.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertUserIsLocked.php index 22abf3d552464..92376f42e5d98 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertUserIsLocked.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertUserIsLocked.php @@ -27,7 +27,7 @@ public function processAssert( AdminAuthLogin $adminAuth ) { $ignoreCase = true; - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::USER_ACCOUNT_DISABLED_MESSAGE, $adminAuth->getMessagesBlock()->getErrorMessage(), 'Message "' . self::USER_ACCOUNT_DISABLED_MESSAGE . '" is not visible.', diff --git a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertUserPasswordResetFailed.php b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertUserPasswordResetFailed.php index 7faa93c94edb0..c3307935686e9 100644 --- a/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertUserPasswordResetFailed.php +++ b/dev/tests/functional/tests/app/Magento/Security/Test/Constraint/AssertUserPasswordResetFailed.php @@ -26,7 +26,7 @@ class AssertUserPasswordResetFailed extends AbstractConstraint */ public function processAssert(AdminAuthLogin $adminAuth) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::TOO_MANY_RESET_REQUESTS_MESSAGE, $adminAuth->getMessagesBlock()->getErrorMessage(), 'Wrong user reset password failed message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertApplicationVersion.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertApplicationVersion.php index daa0919e7021d..dd47c30c4a991 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertApplicationVersion.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertApplicationVersion.php @@ -24,7 +24,7 @@ class AssertApplicationVersion extends AbstractConstraint */ public function processAssert(Dashboard $dashboard, $version) { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $version, $dashboard->getApplicationVersion()->getVersion(), 'Application version is incorrect.' diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessMessage.php index a7d26546c8f57..4a2ff92412b66 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessMessage.php @@ -24,12 +24,12 @@ class AssertSuccessMessage extends AbstractConstraint public function processAssert(SetupWizard $setupWizard, $package) { $message = "You upgraded"; - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $message, $setupWizard->getSuccessMessage()->getUpdaterStatus(), 'Success message is incorrect.' ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $package, $setupWizard->getSuccessMessage()->getUpdaterStatus(), 'Updated package is incorrect.' diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php index 5425af367ca3b..96fbc1905b5d0 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertSuccessfulReadinessCheck.php @@ -52,32 +52,32 @@ class AssertSuccessfulReadinessCheck extends AbstractConstraint */ public function processAssert(SetupWizard $setupWizard) { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::UPDATER_APPLICATION_MESSAGE, $setupWizard->getReadiness()->getUpdaterApplicationCheck(), 'Updater application check is incorrect.' ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::CRON_SCRIPT_MESSAGE, $setupWizard->getReadiness()->getCronScriptCheck(), 'Cron scripts are incorrect.' ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::DEPENDENCY_CHECK_MESSAGE, $setupWizard->getReadiness()->getDependencyCheck(), 'Dependency check is incorrect.' ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::PHP_VERSION_MESSAGE, $setupWizard->getReadiness()->getPhpVersionCheck(), 'PHP version is incorrect.' ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( self::PHP_SETTING_REGEXP, $setupWizard->getReadiness()->getSettingsCheck(), 'PHP settings check failed.' ); - \PHPUnit_Framework_Assert::assertRegExp( + \PHPUnit\Framework\Assert::assertRegExp( self::PHP_EXTENSIONS_REGEXP, $setupWizard->getReadiness()->getPhpExtensionsCheck(), 'PHP extensions missed.' diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertVersionAndEditionCheck.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertVersionAndEditionCheck.php index 639bcb2c13e0f..5ddc5794ff816 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertVersionAndEditionCheck.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/AssertVersionAndEditionCheck.php @@ -25,7 +25,7 @@ class AssertVersionAndEditionCheck extends AbstractConstraint public function processAssert(SetupWizard $setupWizard, $package, $version) { $message = "We're ready to upgrade $package to $version"; - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $message, $setupWizard->getSystemUpgrade()->getUpgradeMessage(), 'Updater application check is incorrect.' diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertExtensionAndVersionCheck.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertExtensionAndVersionCheck.php index 40ed7483d74a3..1b8550845e0cd 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertExtensionAndVersionCheck.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertExtensionAndVersionCheck.php @@ -52,7 +52,7 @@ public function processAssert(SetupWizard $setupWizard, Extension $extension, $t $message = ''; } - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $message, $setupWizard->getUpdaterExtension()->getMessage(), 'Extension name and version check is incorrect.' diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertFindExtensionOnGrid.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertFindExtensionOnGrid.php index 305c59d2a7ca9..68c0cd1960180 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertFindExtensionOnGrid.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertFindExtensionOnGrid.php @@ -24,7 +24,7 @@ class AssertFindExtensionOnGrid extends AbstractConstraint */ public function processAssert(AbstractGrid $grid, Extension $extension) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $grid->findExtensionOnGrid($extension), 'Extension is not found on the grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertSelectSeveralExtensions.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertSelectSeveralExtensions.php index 20f30023563bc..945e345d2851f 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertSelectSeveralExtensions.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertSelectSeveralExtensions.php @@ -25,7 +25,7 @@ class AssertSelectSeveralExtensions extends AbstractConstraint public function processAssert(AbstractGrid $grid, array $extensions) { $extensions = $grid->selectSeveralExtensions($extensions); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $extensions, 'Next extensions are not found on the grid: ' . $this->getExtensionsNames($extensions) ); diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertSuccessMessage.php index 8d9f418631415..0e1d1be3855dc 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertSuccessMessage.php @@ -50,12 +50,12 @@ public function processAssert(SetupWizard $setupWizard, Extension $extension, $t $message = ''; } - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $message, $setupWizard->getSuccessMessage()->getUpdaterStatus(), 'Success message is incorrect.' ); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $extension->getExtensionName(), $setupWizard->getSuccessMessage()->getUpdaterStatus(), 'Extension name is incorrect.' diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertVersionOnGrid.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertVersionOnGrid.php index 0a4dd9d0772d5..068f748da4a8b 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertVersionOnGrid.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Extension/AssertVersionOnGrid.php @@ -45,7 +45,7 @@ public function processAssert(Grid $grid, Extension $extension, $type) $version = ''; } - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $grid->getVersion($extension) === $version, 'Version of extension is not correct.' ); diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Module/AssertModuleInGrid.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Module/AssertModuleInGrid.php index 3761f077981bc..236888fbe9583 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Module/AssertModuleInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Module/AssertModuleInGrid.php @@ -24,7 +24,7 @@ class AssertModuleInGrid extends AbstractConstraint */ public function processAssert(SetupWizard $setupWizard, $moduleName) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $setupWizard->getModuleGrid()->findModuleByName($moduleName)->isVisible(), 'Module was not found in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Module/AssertSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Module/AssertSuccessMessage.php index 24d0ea0048d01..07d8564f47ef3 100644 --- a/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Module/AssertSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Setup/Test/Constraint/Module/AssertSuccessMessage.php @@ -24,7 +24,7 @@ class AssertSuccessMessage */ public function processAssert(SetupWizard $setupWizard) { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( static::SUCCESS_MESSAGE, $setupWizard->getSuccessMessage()->getDisableModuleStatus(), 'Success message is incorrect.' diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertCityBasedShippingRateChanged.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertCityBasedShippingRateChanged.php index ea5de8d06be00..9b5c8991cb675 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertCityBasedShippingRateChanged.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertCityBasedShippingRateChanged.php @@ -25,13 +25,13 @@ class AssertCityBasedShippingRateChanged extends AbstractConstraint public function processAssert(CheckoutOnepage $checkoutOnepage, $shippingMethod, $isShippingAvailable) { if ($isShippingAvailable) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $checkoutOnepage->getShippingMethodBlock()->isLoaderAppeared(), 'Shipping rate has not been changed.' ); } $shippingAvailability = $isShippingAvailable ? 'available' : 'unavailable'; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $isShippingAvailable, $checkoutOnepage->getShippingMethodBlock()->isShippingMethodAvailable($shippingMethod), "Shipping rates for {$shippingMethod['shipping_service']} should be $shippingAvailability." diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertNoShipButton.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertNoShipButton.php index 6f8be0087803b..bf0e564e7f3af 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertNoShipButton.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertNoShipButton.php @@ -32,7 +32,7 @@ public function processAssert(SalesOrderView $salesOrderView, OrderIndex $orderI { $orderIndex->open(); $orderIndex->getSalesOrderGrid()->searchAndOpen(['id' => $order->getId()]); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $salesOrderView->getPageActions()->isActionButtonVisible('Ship'), 'Ship button is present on order view page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipTotalQuantity.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipTotalQuantity.php index 6eb2db1d06994..5deb8f356f949 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipTotalQuantity.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipTotalQuantity.php @@ -40,7 +40,7 @@ public function processAssert( $orderHistory->getOrderHistoryBlock()->openOrderById($order->getId()); $customerOrderView->getOrderViewBlock()->openLinkByName('Order Shipments'); foreach ($ids['shipmentIds'] as $key => $shipmentIds) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $totalQty[$key], $shipmentView->getShipmentBlock()->getItemShipmentBlock($shipmentIds)->getTotalQty() ); diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentInShipmentsGrid.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentInShipmentsGrid.php index becaec936f9b1..3216afb1f489e 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentInShipmentsGrid.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentInShipmentsGrid.php @@ -39,7 +39,7 @@ public function processAssert(ShipmentIndex $shipmentIndex, OrderInjectable $ord 'total_qty_to' => $totalQty[$key], ]; $shipmentIndex->getShipmentsGrid()->search($filter + $filterQty); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $shipmentIndex->getShipmentsGrid()->isRowVisible($filter, false), 'Shipment is absent in shipment grid on shipment index page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentInShipmentsTab.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentInShipmentsTab.php index ff2398fdd25e2..9d7c66b88ef63 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentInShipmentsTab.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentInShipmentsTab.php @@ -43,7 +43,7 @@ public function processAssert( 'qty_from' => number_format($totalQty[$key], 4, '.', ''), 'qty_to' => number_format($totalQty[$key], 4, '.', ''), ]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $salesOrderView ->getOrderForm() ->getTab('shipments') diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentItems.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentItems.php index d619097ebe401..e4d22d2623672 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentItems.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentItems.php @@ -84,7 +84,7 @@ protected function assert( $this->shipmentPage->getShipmentsGrid()->searchAndOpen($filter); $itemsData = $this->preparePageItems($salesShipmentView->getItemsBlock()->getData()); $error = $this->verifyData($productsData, $itemsData); - \PHPUnit_Framework_Assert::assertEmpty($error, $error); + \PHPUnit\Framework\Assert::assertEmpty($error, $error); } } diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentNotInShipmentsGrid.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentNotInShipmentsGrid.php index 6f9d7d9a3ceb5..ec8ba30114b9e 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentNotInShipmentsGrid.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentNotInShipmentsGrid.php @@ -38,7 +38,7 @@ public function processAssert(ShipmentIndex $shipmentIndex, OrderInjectable $ord 'total_qty_to' => $totalQty[$key], ]; $shipmentIndex->getShipmentsGrid()->search($filter + $filterQty); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $shipmentIndex->getShipmentsGrid()->isRowVisible($filter, false), 'Shipment is present in shipment grid on shipment index page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentSuccessCreateMessage.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentSuccessCreateMessage.php index 3a7bc4962fd6a..89c52299b6efd 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentSuccessCreateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShipmentSuccessCreateMessage.php @@ -27,7 +27,7 @@ class AssertShipmentSuccessCreateMessage extends AbstractConstraint */ public function processAssert(SalesOrderView $salesOrderView) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $salesOrderView->getMessagesBlock()->getSuccessMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShippingMethodOnPrintOrder.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShippingMethodOnPrintOrder.php index 0fd18c3753ba6..c8b613325606d 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShippingMethodOnPrintOrder.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertShippingMethodOnPrintOrder.php @@ -29,7 +29,7 @@ class AssertShippingMethodOnPrintOrder extends AbstractConstraint public function processAssert(SalesGuestPrint $salesGuestPrint, $shipping) { $expected = sprintf(self::SHIPPING_TEMPLATE, $shipping['shipping_service'], $shipping['shipping_method']); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $salesGuestPrint->getInfoShipping()->isShippingMethodVisible($expected), "Shipping method was printed incorrectly." ); diff --git a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertTrackingDetailsIsPresent.php b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertTrackingDetailsIsPresent.php index a35288dd2a1f6..0fd6342fec725 100644 --- a/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertTrackingDetailsIsPresent.php +++ b/dev/tests/functional/tests/app/Magento/Shipping/Test/Constraint/AssertTrackingDetailsIsPresent.php @@ -63,7 +63,7 @@ public function processAssert( $body = $browser->find($this->mainContainer)->getText(); foreach ($resultTrackingData as $value) { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $value, $body, 'The "' . $value . '" is not present in Shipping Tracking popup.' diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertAwaitingSignifydGuaranteeInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertAwaitingSignifydGuaranteeInCommentsHistory.php index 55134b8d94548..f85e77a5c421b 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertAwaitingSignifydGuaranteeInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertAwaitingSignifydGuaranteeInCommentsHistory.php @@ -48,13 +48,13 @@ public function processAssert( array_column($orderComments, 'comment') ); - \PHPUnit_Framework_Assert::assertNotFalse( + \PHPUnit\Framework\Assert::assertNotFalse( $key, 'There is no message about awaiting the Signifyd guarantee disposition' . ' in Comments History section for the order #' . $orderId ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $this->historyCommentStatus, $orderComments[$key]['status'], 'Message about awaiting the Signifyd guarantee disposition' . diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertCaseInfoOnAdmin.php b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertCaseInfoOnAdmin.php index 9fe29f022470f..298b957131395 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertCaseInfoOnAdmin.php +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertCaseInfoOnAdmin.php @@ -68,7 +68,7 @@ public function processAssert( */ private function checkCaseGuaranteeDisposition() { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $this->signifydData->getGuaranteeDisposition(), $this->orderView->getFraudProtectionBlock()->getCaseGuaranteeDisposition(), 'Case Guarantee Disposition status is wrong for order #' . $this->orderId diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertCaseInfoOnSignifydConsole.php b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertCaseInfoOnSignifydConsole.php index 995f5092b6121..a8a1f735d004c 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertCaseInfoOnSignifydConsole.php +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertCaseInfoOnSignifydConsole.php @@ -63,7 +63,7 @@ public function processAssert( */ private function checkDeviceData() { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->signifydCases->getCaseInfoBlock()->isAvailableDeviceData(), 'Device data are not available on case page in Signifyd console.' ); @@ -77,7 +77,7 @@ private function checkDeviceData() */ private function checkShippingPrice($shippingPrice) { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $shippingPrice, $this->signifydCases->getCaseInfoBlock()->getShippingPrice(), 'Shipping price is incorrect on case page in Signifyd console.' @@ -92,7 +92,7 @@ private function checkShippingPrice($shippingPrice) */ private function checkGuaranteeDisposition($guaranteeDisposition) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $guaranteeDisposition, $this->signifydCases->getCaseInfoBlock()->getGuaranteeDisposition(), 'Guarantee disposition is incorrect on case page in Signifyd console.' @@ -107,7 +107,7 @@ private function checkGuaranteeDisposition($guaranteeDisposition) */ private function checkCvvResponse($cvvResponse) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $cvvResponse, $this->signifydCases->getCaseInfoBlock()->getCvvResponse(), 'CVV response is incorrect on case page in Signifyd console.' @@ -122,7 +122,7 @@ private function checkCvvResponse($cvvResponse) */ private function checkAvsResponse($avsResponse) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $avsResponse, $this->signifydCases->getCaseInfoBlock()->getAvsResponse(), 'AVS response is incorrect on case page in Signifyd console.' @@ -137,7 +137,7 @@ private function checkAvsResponse($avsResponse) */ private function checkOrderId($orderId) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $orderId, $this->signifydCases->getCaseInfoBlock()->getOrderId(), 'Order id is incorrect on case page in Signifyd console.' @@ -152,7 +152,7 @@ private function checkOrderId($orderId) */ private function checkOrderAmount($amount) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($amount, 2), $this->signifydCases->getCaseInfoBlock()->getOrderAmount(), 'Order amount is incorrect on case page in Signifyd console.' @@ -167,7 +167,7 @@ private function checkOrderAmount($amount) */ private function checkOrderAmountCurrency($currency) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $currency, $this->signifydCases->getCaseInfoBlock()->getOrderAmountCurrency(), 'Order amount currency is incorrect on case page in Signifyd console.' @@ -182,7 +182,7 @@ private function checkOrderAmountCurrency($currency) */ private function checkCardHolder($customerFullName) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $customerFullName, $this->signifydCases->getCaseInfoBlock()->getCardHolder(), 'Card holder name is incorrect on case page in Signifyd console.' @@ -197,7 +197,7 @@ private function checkCardHolder($customerFullName) */ private function checkBillingAddress(SignifydAddress $billingAddress) { - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $billingAddress->getStreet(), $this->signifydCases->getCaseInfoBlock()->getBillingAddress(), 'Billing address is incorrect on case page in Signifyd console.' diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydCaseInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydCaseInCommentsHistory.php index aef5c0e9abd26..ea919f9410d4d 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydCaseInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydCaseInCommentsHistory.php @@ -39,7 +39,7 @@ public function processAssert( $orderComments = $infoTab->getCommentsHistoryBlock()->getComments(); $commentsMessages = array_column($orderComments, 'comment'); - \PHPUnit_Framework_Assert::assertRegExp( + \PHPUnit\Framework\Assert::assertRegExp( self::CASE_CREATED_PATTERN, implode('. ', $commentsMessages), 'Signifyd case is not created for the order #' . $orderId diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydCaseInOrdersGrid.php b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydCaseInOrdersGrid.php index 2f08ac8f40a3e..bdf3598d4f46a 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydCaseInOrdersGrid.php +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydCaseInOrdersGrid.php @@ -34,7 +34,7 @@ public function processAssert( $ordersGrid->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $ordersGrid->getSignifydOrdersGrid()->isRowVisible(array_filter($filter)), 'Order with following data \'' . $errorMessage . '\' is absent in orders grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydGuaranteeCancelInCommentsHistory.php b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydGuaranteeCancelInCommentsHistory.php index 4b86f66730f90..618d77885736c 100644 --- a/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydGuaranteeCancelInCommentsHistory.php +++ b/dev/tests/functional/tests/app/Magento/Signifyd/Test/Constraint/AssertSignifydGuaranteeCancelInCommentsHistory.php @@ -39,7 +39,7 @@ public function processAssert( $orderComments = $infoTab->getCommentsHistoryBlock()->getComments(); $commentsMessages = array_column($orderComments, 'comment'); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $this->guaranteeCancelMessage, implode('. ', $commentsMessages), 'There is no message regarding Signifyd guarantee cancel in Comments History section for the order #' diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapContent.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapContent.php index 0ed565f50ee81..99dab9ae79c6b 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapContent.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapContent.php @@ -52,7 +52,7 @@ public function processAssert( $_ENV['app_frontend_url'] . $cmsPage->getIdentifier(), ]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->checkContent($content, $urls), 'Content of file sitemap.xml does not include one or more of next urls:' . implode("\n", $urls) diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapFailFolderSaveMessage.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapFailFolderSaveMessage.php index 50da663141e17..334d359530761 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapFailFolderSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapFailFolderSaveMessage.php @@ -27,7 +27,7 @@ class AssertSitemapFailFolderSaveMessage extends AbstractConstraint public function processAssert(SitemapIndex $sitemapPage, Sitemap $sitemap) { $actualMessage = $sitemapPage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::FAIL_FOLDER_MESSAGE, $sitemap->getSitemapPath()), $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapFailPathSaveMessage.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapFailPathSaveMessage.php index d5061eed03f0e..f73a2d6d7b25f 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapFailPathSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapFailPathSaveMessage.php @@ -27,7 +27,7 @@ class AssertSitemapFailPathSaveMessage extends AbstractConstraint public function processAssert(SitemapIndex $sitemapPage, Sitemap $sitemap) { $actualMessage = $sitemapPage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::FAIL_PATH_MESSAGE, $sitemap->getSitemapFilename()), $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapInGrid.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapInGrid.php index db89b1e662183..d8a4cb0dc641f 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapInGrid.php @@ -29,7 +29,7 @@ public function processAssert(Sitemap $sitemap, SitemapIndex $sitemapIndex) 'sitemap_filename' => $sitemap->getSitemapFilename(), 'sitemap_path' => $sitemap->getSitemapPath(), ]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $sitemapIndex->getSitemapGrid()->isRowVisible($filter), 'Sitemap with filename \'' . $sitemap->getSitemapFilename() . '\' and path \'' . $sitemap->getSitemapPath() . '\' is absent in Sitemap grid. \'' diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapNotInGrid.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapNotInGrid.php index 9acca062c8ba7..480b0163106d6 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapNotInGrid.php @@ -30,7 +30,7 @@ public function processAssert(Sitemap $sitemap, SitemapIndex $sitemapPageGrid) 'sitemap_path' => $sitemap->getSitemapPath(), 'sitemap_id' => $sitemap->getSitemapId(), ]; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $sitemapPageGrid->getSitemapGrid()->isRowVisible($filter), 'Sitemap with filename \'' . $sitemap->getSitemapFilename() . '\' and id \'' . $sitemap->getSitemapId() . '\' and path \'' diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSubmissionToRobotsTxt.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSubmissionToRobotsTxt.php index 20f8f346747c0..f5de4808a540f 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSubmissionToRobotsTxt.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSubmissionToRobotsTxt.php @@ -35,14 +35,14 @@ class AssertSitemapSubmissionToRobotsTxt extends AbstractConstraint public function processAssert(BrowserInterface $browser) { $browser->open($_ENV['app_frontend_url'] . $this->filename); - \PHPUnit_Framework_Assert::assertNotEquals( + \PHPUnit\Framework\Assert::assertNotEquals( self::HTTP_NOT_FOUND, $browser->getTitle(), 'File ' . $this->filename . ' is not readable or not exists.' ); $expectedRobotsContent = 'Sitemap: ' . $_ENV['app_frontend_url'] . 'sitemap.xml'; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( strpos($browser->getHtmlSource(), $expectedRobotsContent) !== false, 'File ' . $this->filename . ' contains incorrect data.' ); diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessDeleteMessage.php index 7c5f6a502ff12..6585d5498a960 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessDeleteMessage.php @@ -25,7 +25,7 @@ class AssertSitemapSuccessDeleteMessage extends AbstractConstraint public function processAssert(SitemapIndex $sitemapPage) { $actualMessage = $sitemapPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessGenerateMessage.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessGenerateMessage.php index 436ce0523f675..51de86ed35edf 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessGenerateMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessGenerateMessage.php @@ -33,7 +33,7 @@ public function processAssert( Sitemap $sitemap ) { $actualMessage = $sitemapPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_GENERATE_MESSAGE, $sitemap->getSitemapFilename()), $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessSaveAndGenerateMessages.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessSaveAndGenerateMessages.php index ac7cc5334f461..4c33aacbc97bc 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessSaveAndGenerateMessages.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessSaveAndGenerateMessages.php @@ -29,7 +29,7 @@ class AssertSitemapSuccessSaveAndGenerateMessages extends AbstractConstraint public function processAssert(SitemapIndex $sitemapIndex, Sitemap $sitemap) { $actualMessages = $sitemapIndex->getMessagesBlock()->getSuccessMessages(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array(self::SUCCESS_SAVE_MESSAGE, $actualMessages) && in_array(sprintf(self::SUCCESS_GENERATE_MESSAGE, $sitemap->getSitemapFilename()), $actualMessages), 'Wrong success messages is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessSaveMessage.php index a76728cffce13..2e8d1d69b0ca7 100644 --- a/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Sitemap/Test/Constraint/AssertSitemapSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertSitemapSuccessSaveMessage extends AbstractConstraint public function processAssert(SitemapIndex $sitemapPage) { $actualMessage = $sitemapPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreBackend.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreBackend.php index 301cfdf7664e0..da844aab136ac 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreBackend.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreBackend.php @@ -27,7 +27,7 @@ public function processAssert(Store $store, SystemConfig $systemConfig) { $systemConfig->open(); $isStoreVisible = $systemConfig->getPageActions()->isStoreVisible($store); - \PHPUnit_Framework_Assert::assertTrue($isStoreVisible, "Store view is not visible in dropdown on config page"); + \PHPUnit\Framework\Assert::assertTrue($isStoreVisible, "Store view is not visible in dropdown on config page"); } /** diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreCodeInUrl.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreCodeInUrl.php index 8874ff9e7356d..b008227e94c2d 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreCodeInUrl.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreCodeInUrl.php @@ -27,7 +27,7 @@ public function processAssert(CmsIndex $cmsIndex, BrowserInterface $browser, $st { $cmsIndex->open(); $cmsIndex->getLogoBlock()->clickOnLogo(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $_ENV['app_frontend_url'] . $storeCode . '/', $browser->getUrl(), sprintf('Store code \'%s\' is not present in the url: %s', $storeCode, $browser->getUrl()) diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreDisabledErrorSaveMessage.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreDisabledErrorSaveMessage.php index f6f26a84adcec..acd0f83f2681b 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreDisabledErrorSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreDisabledErrorSaveMessage.php @@ -27,7 +27,7 @@ class AssertStoreDisabledErrorSaveMessage extends AbstractConstraint */ public function processAssert(EditStore $editStore) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $editStore->getMessagesBlock()->getErrorMessage(), 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreForm.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreForm.php index ffe02e18f614f..528712e86018c 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreForm.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreForm.php @@ -34,7 +34,7 @@ public function processAssert( $formData = $storeNew->getStoreForm()->getData(); $fixtureData = $store->getData(); $errors = $this->verifyData($fixtureData, $formData); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } /** diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreFrontend.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreFrontend.php index 0df64751a2b38..8fb0fe0b02352 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreFrontend.php @@ -36,7 +36,7 @@ public function processAssert(Store $store, CmsIndex $cmsIndex) ? true // if only one store view is assigned to store group : $cmsIndex->getStoreSwitcherBlock()->isStoreViewVisible($store); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isStoreViewVisible, "Store view is not visible in dropdown on CmsIndex page" ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupForm.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupForm.php index 012900bc94fc7..c1e7801b19604 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupForm.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupForm.php @@ -45,7 +45,7 @@ public function processAssert( $storeIndex->open()->getStoreGrid()->searchAndOpenStoreGroup($storeGroup); $formData = $editGroup->getEditFormGroup()->getData(); $errors = $this->verifyData($fixtureData, $formData); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } /** diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupInGrid.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupInGrid.php index d92fde0015f9b..2ef63536a5f41 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupInGrid.php @@ -31,7 +31,7 @@ public function processAssert(StoreIndex $storeIndex, StoreGroup $storeGroup) { $storeGroupName = $storeGroup->getName(); $storeIndex->open()->getStoreGrid()->search(['group_title' => $storeGroupName]); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $storeIndex->getStoreGrid()->isStoreExists($storeGroupName), 'Store group \'' . $storeGroupName . '\' is not present in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNoDeleteButton.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNoDeleteButton.php index b7814edf80984..76207206d201e 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNoDeleteButton.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNoDeleteButton.php @@ -22,7 +22,7 @@ class AssertStoreGroupNoDeleteButton extends AbstractConstraint */ public function processAssert(NewGroupIndex $newGroupIndex) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $newGroupIndex->getFormPageActions()->checkDeleteButton(), '\'Delete\' button on StoreGroup view edit page is present when it should not.' ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNotInGrid.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNotInGrid.php index e0eb8ec1d5569..b929f118e05f4 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupNotInGrid.php @@ -31,7 +31,7 @@ public function processAssert(StoreIndex $storeIndex, StoreGroup $storeGroup) { $storeGroupName = $storeGroup->getName(); $storeIndex->open()->getStoreGrid()->search(['group_title' => $storeGroupName]); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $storeIndex->getStoreGrid()->isStoreExists($storeGroupName), 'Store group \'' . $storeGroupName . '\' is present in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupOnStoreViewForm.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupOnStoreViewForm.php index e208231edfa3c..ddd0a4f063475 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupOnStoreViewForm.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupOnStoreViewForm.php @@ -29,7 +29,7 @@ public function processAssert(StoreIndex $storeIndex, StoreNew $storeNew, StoreG { $storeGroupName = $storeGroup->getName(); $storeIndex->open()->getGridPageActions()->addStoreView(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $storeNew->getStoreForm()->isStoreVisible($storeGroupName), 'Store Group \'' . $storeGroupName . '\' is not present on StoreView Form in Store dropdown.' ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessDeleteAndBackupMessages.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessDeleteAndBackupMessages.php index be680045524dd..82f24259b8f30 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessDeleteAndBackupMessages.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessDeleteAndBackupMessages.php @@ -34,7 +34,7 @@ class AssertStoreGroupSuccessDeleteAndBackupMessages extends AbstractConstraint public function processAssert(StoreIndex $storeIndex) { $actualMessages = $storeIndex->getMessagesBlock()->getSuccessMessages(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array(self::SUCCESS_BACKUP_MESSAGE, $actualMessages) && in_array(self::SUCCESS_DELETE_MESSAGE, $actualMessages), 'Wrong success messages are displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessDeleteMessage.php index 673a3e7a4c250..65da69de2b705 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessDeleteMessage.php @@ -28,7 +28,7 @@ class AssertStoreGroupSuccessDeleteMessage extends AbstractConstraint */ public function processAssert(StoreIndex $storeIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $storeIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success delete message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessSaveMessage.php index 398f83ca30443..905cabc4f32e0 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreGroupSuccessSaveMessage.php @@ -28,7 +28,7 @@ class AssertStoreGroupSuccessSaveMessage extends AbstractConstraint */ public function processAssert(StoreIndex $storeIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $storeIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreInGrid.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreInGrid.php index 1b60d327f4e2c..ce24a43ebcf54 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreInGrid.php @@ -31,7 +31,7 @@ public function processAssert(StoreIndex $storeIndex, Store $store) { $storeName = $store->getName(); $storeIndex->open()->getStoreGrid()->search(['store_title' => $storeName]); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $storeIndex->getStoreGrid()->isStoreExists($storeName), 'Store \'' . $storeName . '\' is not present in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNoDeleteButton.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNoDeleteButton.php index 4ba69ee2b3f97..4f2c7c6106ab5 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNoDeleteButton.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNoDeleteButton.php @@ -22,7 +22,7 @@ class AssertStoreNoDeleteButton extends AbstractConstraint */ public function processAssert(StoreNew $storePage) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $storePage->getFormPageActions()->checkDeleteButton(), '\'Delete\' button on Store view edit page is present when it should not.' ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotInGrid.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotInGrid.php index ded16bf16c47a..466f6f68a865c 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotInGrid.php @@ -31,7 +31,7 @@ public function processAssert(StoreIndex $storeIndex, Store $store) { $storeName = $store->getName(); $storeIndex->open()->getStoreGrid()->search(['store_title' => $storeName]); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $storeIndex->getStoreGrid()->isStoreExists($storeName), 'Store \'' . $storeName . '\' is present in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotOnFrontend.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotOnFrontend.php index 7758006d2dcc9..793044e75d7ca 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotOnFrontend.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreNotOnFrontend.php @@ -36,7 +36,7 @@ public function processAssert(Store $store, CmsIndex $cmsIndex) ? false // if only one store view is assigned to store group : $cmsIndex->getStoreSwitcherBlock()->isStoreViewVisible($store); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $isStoreViewVisible, "Store view is visible in dropdown on CmsIndex page" ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessDeleteAndBackupMessages.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessDeleteAndBackupMessages.php index c020d8ced56ca..903a555cae867 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessDeleteAndBackupMessages.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessDeleteAndBackupMessages.php @@ -34,7 +34,7 @@ class AssertStoreSuccessDeleteAndBackupMessages extends AbstractConstraint public function processAssert(StoreIndex $storeIndex) { $actualMessages = $storeIndex->getMessagesBlock()->getSuccessMessages(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array(self::SUCCESS_BACKUP_MESSAGE, $actualMessages) && in_array(self::SUCCESS_DELETE_MESSAGE, $actualMessages), 'Wrong success messages are displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessDeleteMessage.php index 645a67dcc138c..29381e2504c8b 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessDeleteMessage.php @@ -28,7 +28,7 @@ class AssertStoreSuccessDeleteMessage extends AbstractConstraint */ public function processAssert(StoreIndex $storeIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $storeIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success delete message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessSaveMessage.php index 303ac8b72c50e..4376f0bb56cfd 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertStoreSuccessSaveMessage.php @@ -28,7 +28,7 @@ class AssertStoreSuccessSaveMessage extends AbstractConstraint */ public function processAssert(StoreIndex $storeIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $storeIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteForm.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteForm.php index 154cda6c999bc..2fd3cb265c1e1 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteForm.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteForm.php @@ -41,7 +41,7 @@ public function processAssert( $storeIndex->open()->getStoreGrid()->searchAndOpenWebsite($website); $formData = $editWebsite->getEditFormWebsite()->getData(); $errors = $this->verifyData($fixtureData, $formData); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } /** diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteInGrid.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteInGrid.php index d4031c75ed21d..f68971b3699f2 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteInGrid.php @@ -27,7 +27,7 @@ public function processAssert(StoreIndex $storeIndex, Website $website) { $websiteName = $website->getName(); $storeIndex->open()->getStoreGrid()->search(['website_title' => $websiteName]); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $storeIndex->getStoreGrid()->isWebsiteExists($website), 'Website \'' . $websiteName . '\' is not present in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteNotInGrid.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteNotInGrid.php index 7d739f6351aae..0e0398c126faf 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteNotInGrid.php @@ -27,7 +27,7 @@ public function processAssert(StoreIndex $storeIndex, Website $website) { $websiteName = $website->getName(); $storeIndex->open()->getStoreGrid()->search(['website_title' => $websiteName]); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $storeIndex->getStoreGrid()->isWebsiteExists($website), 'Website \'' . $websiteName . '\' is present in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteOnStoreForm.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteOnStoreForm.php index 4b467afff3b70..97ead5114461e 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteOnStoreForm.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteOnStoreForm.php @@ -33,7 +33,7 @@ public function processAssert(StoreIndex $storeIndex, NewGroupIndex $newGroupInd { $websiteName = $website->getName(); $storeIndex->open()->getGridPageActions()->createStoreGroup(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $newGroupIndex->getEditFormGroup()->isWebsiteVisible($websiteName), 'Website \'' . $websiteName . '\' is not present on Store Group Form in Website dropdown.' ); diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessDeleteAndBackupMessages.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessDeleteAndBackupMessages.php index e89fd4facc1eb..de6230ae8448c 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessDeleteAndBackupMessages.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessDeleteAndBackupMessages.php @@ -34,7 +34,7 @@ class AssertWebsiteSuccessDeleteAndBackupMessages extends AbstractConstraint public function processAssert(StoreIndex $storeIndex) { $actualMessages = $storeIndex->getMessagesBlock()->getSuccessMessages(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array(self::SUCCESS_BACKUP_MESSAGE, $actualMessages) && in_array(self::SUCCESS_DELETE_MESSAGE, $actualMessages), 'Wrong success messages are displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessDeleteMessage.php index a7d218ebe67fb..8ca5b8b1c4181 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessDeleteMessage.php @@ -28,7 +28,7 @@ class AssertWebsiteSuccessDeleteMessage extends AbstractConstraint */ public function processAssert(StoreIndex $storeIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $storeIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success delete message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessSaveMessage.php index ceb50cf87c8b5..7e7fe6285ef4b 100644 --- a/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Store/Test/Constraint/AssertWebsiteSuccessSaveMessage.php @@ -28,7 +28,7 @@ class AssertWebsiteSuccessSaveMessage extends AbstractConstraint */ public function processAssert(StoreIndex $storeIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $storeIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/TestStep/DeleteWebsitesEntityStep.php b/dev/tests/functional/tests/app/Magento/Store/Test/TestStep/DeleteWebsitesEntityStep.php new file mode 100644 index 0000000000000..155ed21064bcf --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Store/Test/TestStep/DeleteWebsitesEntityStep.php @@ -0,0 +1,110 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Store\Test\TestStep; + +use Magento\Backend\Test\Page\Adminhtml\EditWebsite; +use Magento\Backend\Test\Page\Adminhtml\DeleteWebsite; +use Magento\Backend\Test\Page\Adminhtml\StoreIndex; +use Magento\Backup\Test\Page\Adminhtml\BackupIndex; +use Magento\Store\Test\Fixture\Store; +use Magento\Mtf\TestStep\TestStepInterface; +use Magento\Mtf\Fixture\FixtureFactory; +use Magento\Mtf\Fixture\FixtureInterface; + +/** + * Test Step for DeleteWebsitesEntity. + */ +class DeleteWebsitesEntityStep implements TestStepInterface +{ + /* tags */ + const MVP = 'yes'; + const SEVERITY = 'S2'; + /* end tags */ + + /** + * @var BackupIndex + */ + private $backupIndex; + + /** + * @var StoreIndex + */ + private $storeIndex; + + /** + * @var EditWebsite + */ + private $editWebsite; + + /** + * @var DeleteWebsite + */ + private $deleteWebsite; + + /** + * @var FixtureFactory + */ + private $fixtureFactory; + + /** + * @var FixtureInterface + */ + private $item; + + /** + * @var string + */ + private $createBackup; + + /** + * Prepare pages for test. + * + * @param BackupIndex $backupIndex + * @param StoreIndex $storeIndex + * @param EditWebsite $editWebsite + * @param DeleteWebsite $deleteWebsite + * @param FixtureFactory $fixtureFactory + * @param FixtureInterface $item + * @param string $createBackup + */ + public function __construct( + BackupIndex $backupIndex, + StoreIndex $storeIndex, + EditWebsite $editWebsite, + DeleteWebsite $deleteWebsite, + FixtureFactory $fixtureFactory, + FixtureInterface $item, + $createBackup = 'No' + ) { + $this->storeIndex = $storeIndex; + $this->editWebsite = $editWebsite; + $this->backupIndex = $backupIndex; + $this->deleteWebsite = $deleteWebsite; + $this->item = $item; + $this->createBackup = $createBackup; + $this->fixtureFactory = $fixtureFactory; + } + + /** + * Delete specific Store View. + * + * @return void + */ + public function run() + { + $this->backupIndex->open()->getBackupGrid()->massaction([], 'Delete', true, 'Select All'); + $this->storeIndex->open(); + $websiteNames = $this->item->getWebsiteIds(); + if (is_array($websiteNames) && count($websiteNames) > 0) { + $websiteName = end($websiteNames); + $this->storeIndex->getStoreGrid()->searchAndOpenWebsiteByName($websiteName); + $this->editWebsite->getFormPageActions()->delete(); + $this->deleteWebsite->getDeleteWebsiteForm()->fillForm(['create_backup' => $this->createBackup]); + $this->deleteWebsite->getFormPageActions()->delete(); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertApiInfoTitleOnPage.php b/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertApiInfoTitleOnPage.php index 7fb2bb65dac5a..f2c96dd2f8bbc 100644 --- a/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertApiInfoTitleOnPage.php +++ b/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertApiInfoTitleOnPage.php @@ -29,7 +29,7 @@ class AssertApiInfoTitleOnPage extends AbstractConstraint */ public function processAssert(SwaggerUiPage $swaggerPage) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $swaggerPage->isElementVisible($this->titleSelector), 'REST API info title on swagger page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertEndpointContentDisplay.php b/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertEndpointContentDisplay.php index ff05075585d72..bfc2bc89b757f 100644 --- a/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertEndpointContentDisplay.php +++ b/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertEndpointContentDisplay.php @@ -31,7 +31,7 @@ public function processAssert(SwaggerUiPage $swaggerPage, $serviceName, array $e $operationContentSelector = 'div[id$="%s%s_content"]'; $operationContentSelector = sprintf($operationContentSelector, $serviceName, $endpoint); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $swaggerPage->isElementVisible($operationContentSelector), 'REST API endpoint operation content on swagger page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertServiceContentDisplay.php b/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertServiceContentDisplay.php index 3220753d48b33..06d4ff0f07bb4 100644 --- a/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertServiceContentDisplay.php +++ b/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertServiceContentDisplay.php @@ -30,7 +30,7 @@ public function processAssert(SwaggerUiPage $swaggerPage, $serviceName, array $e */ $operationSelector = 'li[id$="%s%s"]'; $operationSelector = sprintf($operationSelector, $serviceName, $endpoint); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $swaggerPage->isElementVisible($operationSelector), 'REST API service endpoints on swagger page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertSwaggerSectionLoadOnPage.php b/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertSwaggerSectionLoadOnPage.php index 3b6a8db75c0ff..af7425bbd847a 100644 --- a/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertSwaggerSectionLoadOnPage.php +++ b/dev/tests/functional/tests/app/Magento/Swagger/Test/Constraint/AssertSwaggerSectionLoadOnPage.php @@ -29,7 +29,7 @@ class AssertSwaggerSectionLoadOnPage extends AbstractConstraint */ public function processAssert(SwaggerUiPage $swaggerPage) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $swaggerPage->isElementVisible($this->swaggerSectionSelector), 'Class swagger-section on swagger page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertProductPriceWithSelectedSwatchOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertProductPriceWithSelectedSwatchOnCategoryPage.php index a6ac31a5e4c86..20cd944ffdb99 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertProductPriceWithSelectedSwatchOnCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertProductPriceWithSelectedSwatchOnCategoryPage.php @@ -25,7 +25,7 @@ public function processAssert( ) { $priceBlock = $catalogCategoryView->getListProductBlock()->getProductItem($product)->getPriceBlock(); $configuredPrice = $product->getCheckoutData()['cartItem']['subtotal']; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( number_format($configuredPrice, 2, '.', ''), $priceBlock->getPrice(), 'Product configured price on category page is not correct.' diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSelectedSwatchOptionsOnProductPage.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSelectedSwatchOptionsOnProductPage.php index bd4992520de70..7d495c54c270e 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSelectedSwatchOptionsOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSelectedSwatchOptionsOnProductPage.php @@ -28,7 +28,7 @@ public function processAssert( $this->productView->getSelectedSwatchOptions($this->product); $errors = $this->verify(); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( $errors, "\nFound the following errors:\n" . implode(" \n", $errors) ); diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchOptionsOnProductPage.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchOptionsOnProductPage.php index a92472a1f4d1d..f0dfa38228090 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchOptionsOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchOptionsOnProductPage.php @@ -35,7 +35,7 @@ public function processAssert( $expectedData = $product->getConfigurableAttributesData()['attributes_data']; foreach ($expectedData as $expectedAttributeData) { - \PHPUnit_Framework_Assert::assertArrayHasKey( + \PHPUnit\Framework\Assert::assertArrayHasKey( $expectedAttributeData['attribute_code'], $actualData, 'Attribute with code ' . $expectedAttributeData['attribute_code'] . ' is absent on Product page' @@ -54,7 +54,7 @@ public function processAssert( */ private function verifyAttribute(array $expectedAttributeData, array $actualAttributeData) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedAttributeData['attribute_code'], $actualAttributeData['attribute_code'], sprintf( @@ -63,7 +63,7 @@ private function verifyAttribute(array $expectedAttributeData, array $actualAttr $expectedAttributeData['attribute_code'] ) ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedAttributeData['attribute_id'], $actualAttributeData['attribute_id'], sprintf( @@ -72,7 +72,7 @@ private function verifyAttribute(array $expectedAttributeData, array $actualAttr $expectedAttributeData['attribute_id'] ) ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedAttributeData['label'], $actualAttributeData['label'], sprintf( @@ -92,7 +92,7 @@ private function verifyAttribute(array $expectedAttributeData, array $actualAttr private function verifyAttributeOptions(array $expectedAttributeData, array $actualAttributeData) { if (isset($expectedAttributeData['options'])) { - \PHPUnit_Framework_Assert::assertArrayHasKey( + \PHPUnit\Framework\Assert::assertArrayHasKey( 'options', $actualAttributeData, 'Swatch attribute options are missed on Product page' @@ -100,7 +100,7 @@ private function verifyAttributeOptions(array $expectedAttributeData, array $act $expectedOptionsCount = count($expectedAttributeData['options']); $actualOptionsCount = count($actualAttributeData['options']); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedOptionsCount, $actualOptionsCount, sprintf( @@ -110,7 +110,7 @@ private function verifyAttributeOptions(array $expectedAttributeData, array $act ) ); } else { - \PHPUnit_Framework_Assert::assertArrayNotHasKey( + \PHPUnit\Framework\Assert::assertArrayNotHasKey( 'options', $actualAttributeData, 'Product page must be without swatch attribute options' diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesAreNotVisibleOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesAreNotVisibleOnCategoryPage.php index 2517eb83284c9..55b42293cd22d 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesAreNotVisibleOnCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesAreNotVisibleOnCategoryPage.php @@ -31,7 +31,7 @@ public function processAssert( $isSwatchesBlockVisible = $catalogCategoryView->getListSwatchesProductBlock() ->getProductItem($product)->isSwatchesBlockVisible(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $isSwatchesBlockVisible, 'Swatches are still present on category page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesAreVisibleOnCategoryPage.php b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesAreVisibleOnCategoryPage.php index fe7d982b89ea5..ddfa2cbffae2b 100644 --- a/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesAreVisibleOnCategoryPage.php +++ b/dev/tests/functional/tests/app/Magento/Swatches/Test/Constraint/AssertSwatchesAreVisibleOnCategoryPage.php @@ -31,7 +31,7 @@ public function processAssert( $isSwatchesBlockVisible = $catalogCategoryView->getListSwatchesProductBlock() ->getProductItem($product)->isSwatchesBlockVisible(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isSwatchesBlockVisible, 'Swatches are absent on category page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertOrderTaxOnBackend.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertOrderTaxOnBackend.php index 248ce0e575ee7..eb304f9b0eefb 100755 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertOrderTaxOnBackend.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertOrderTaxOnBackend.php @@ -100,28 +100,28 @@ public function processAssert( $actualPrices = $this->getOrderTotals($actualPrices); $prices = $this->preparePrices($prices); $message = 'Prices on order view page should be equal to defined in dataset.'; - \PHPUnit_Framework_Assert::assertEquals($prices, array_filter($actualPrices), $message); + \PHPUnit\Framework\Assert::assertEquals($prices, array_filter($actualPrices), $message); $salesOrderView->getPageActions()->invoice(); //Check prices on invoice creation page $actualPrices = []; $actualPrices = $this->getInvoiceNewPrices($actualPrices, $product); $actualPrices = $this->getInvoiceNewTotals($actualPrices); $message = 'Prices on invoice new page should be equal to defined in dataset.'; - \PHPUnit_Framework_Assert::assertEquals($prices, array_filter($actualPrices), $message); + \PHPUnit\Framework\Assert::assertEquals($prices, array_filter($actualPrices), $message); $orderInvoiceNew->getTotalsBlock()->submit(); //Check prices after invoice on order page $actualPrices = []; $actualPrices = $this->getOrderPrices($actualPrices, $product); $actualPrices = $this->getOrderTotals($actualPrices); $message = 'Prices on invoice page should be equal to defined in dataset.'; - \PHPUnit_Framework_Assert::assertEquals($prices, array_filter($actualPrices), $message); + \PHPUnit\Framework\Assert::assertEquals($prices, array_filter($actualPrices), $message); $salesOrderView->getPageActions()->orderCreditMemo(); //Check prices on credit memo creation page $actualPrices = []; $actualPrices = $this->getCreditMemoNewPrices($actualPrices, $product); $actualPrices = $this->getCreditMemoNewTotals($actualPrices); $message = 'Prices on credit memo new page should be equal to defined in dataset.'; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( array_diff_key($prices, ['shipping_excl_tax' => null, 'shipping_incl_tax' => null]), array_filter($actualPrices), $message @@ -132,7 +132,7 @@ public function processAssert( $actualPrices = $this->getOrderPrices($actualPrices, $product); $actualPrices = $this->getOrderTotals($actualPrices); $message = 'Prices on credit memo page should be equal to defined in dataset.'; - \PHPUnit_Framework_Assert::assertEquals($prices, array_filter($actualPrices), $message); + \PHPUnit\Framework\Assert::assertEquals($prices, array_filter($actualPrices), $message); } /** diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertTaxCalculationAfterCheckout.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertTaxCalculationAfterCheckout.php index c61bc4578abd3..affc3132c6ccd 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertTaxCalculationAfterCheckout.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertTaxCalculationAfterCheckout.php @@ -94,7 +94,7 @@ public function processAssert( $prices = $this->preparePrices($prices); //Order review prices verification $message = 'Prices on order review should be equal to defined in dataset.'; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( array_diff_key($prices, ['cart_item_price_excl_tax' => null, 'cart_item_price_incl_tax' => null]), array_diff_key($actualPrices, ['cart_item_price_excl_tax' => null, 'cart_item_price_incl_tax' => null]), $message @@ -109,7 +109,7 @@ public function processAssert( //Frontend order prices verification $message = 'Prices on order view page should be equal to defined in dataset.'; - \PHPUnit_Framework_Assert::assertEquals($prices, $actualPrices, $message); + \PHPUnit\Framework\Assert::assertEquals($prices, $actualPrices, $message); } /** diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPrices.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPrices.php index a14a2e186f7e6..9ff0a9e6a6487 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPrices.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AbstractAssertTaxRuleIsAppliedToAllPrices.php @@ -129,7 +129,7 @@ public function processAssert( $actualPrices = $this->getTotals($actualPrices); //Prices verification $message = 'Prices from dataset should be equal to prices on frontend.'; - \PHPUnit_Framework_Assert::assertEquals($prices, $actualPrices, $message); + \PHPUnit\Framework\Assert::assertEquals($prices, $actualPrices, $message); } /** diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateForm.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateForm.php index 013a468487d74..e0ec4ae528589 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateForm.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateForm.php @@ -40,7 +40,7 @@ public function processAssert( $taxRateIndexPage->getTaxRateGrid()->searchAndOpen($filter); $formData = $taxRateNewPage->getTaxRateForm()->getData($taxRate); $dataDiff = $this->verifyForm($formData, $data); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($dataDiff), 'Tax Rate form was filled incorrectly.' . "\nLog:\n" . implode(";\n", $dataDiff) diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateInGrid.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateInGrid.php index dd40138bfdd37..ca5615b042e87 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateInGrid.php @@ -40,7 +40,7 @@ public function processAssert( : $data['zip_from'] . '-' . $data['zip_to']; $taxRateIndexPage->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $taxRateIndexPage->getTaxRateGrid()->isRowVisible($filter), 'Tax Rate \'' . $filter['code'] . '\' is absent in Tax Rate grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateInTaxRule.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateInTaxRule.php index d188c60c49fbb..2e533887f7b4b 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateInTaxRule.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateInTaxRule.php @@ -30,7 +30,7 @@ public function processAssert(TaxRuleIndex $taxRuleIndex, TaxRuleNew $taxRuleNew $taxRuleIndex->open(); $taxRuleIndex->getGridPageActions()->addNew(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $taxRuleNew->getTaxRuleForm()->isTaxRateAvailable($taxRateCode), "$taxRateCode is not present in Tax Rates multiselect on tax rule creation page." ); diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInGrid.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInGrid.php index 7a0c118451585..0cb1112288c3f 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInGrid.php @@ -31,7 +31,7 @@ public function processAssert( ]; $taxRateIndex->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $taxRateIndex->getTaxRateGrid()->isRowVisible($filter), 'Tax Rate \'' . $filter['code'] . '\' is present in Tax Rate grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInTaxRule.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInTaxRule.php index 29f11fe437ec4..2788e86b9f98f 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInTaxRule.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInTaxRule.php @@ -28,7 +28,7 @@ public function processAssert( ) { $taxRuleNew->open(); $taxRatesList = $taxRuleNew->getTaxRuleForm()->getAllTaxRates(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( in_array($taxRate->getCode(), $taxRatesList), 'Tax Rate \'' . $taxRate->getCode() . '\' is present in Tax Rule form.' ); diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessDeleteMessage.php index 480ec889a4a95..3fcadf9beda88 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessDeleteMessage.php @@ -25,7 +25,7 @@ class AssertTaxRateSuccessDeleteMessage extends AbstractConstraint public function processAssert(TaxRateIndex $taxRateIndex) { $actualMessage = $taxRateIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success delete message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessSaveMessage.php index a65ac87373149..c8fd88a785584 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertTaxRateSuccessSaveMessage extends AbstractConstraint public function processAssert(TaxRateIndex $taxRateIndexPage) { $actualMessage = $taxRateIndexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleForm.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleForm.php index 68612747a1778..c305bedf000de 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleForm.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleForm.php @@ -44,7 +44,7 @@ public function processAssert( $taxRuleNew->getTaxRuleForm()->openAdditionalSettings(); $formData = $taxRuleNew->getTaxRuleForm()->getData($taxRule); $dataDiff = $this->verifyForm($formData, $data); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( empty($dataDiff), 'Tax Rule form was filled not right.' . "\nLog:\n" . implode(";\n", $dataDiff) diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleInGrid.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleInGrid.php index dbde484925b28..33982614a71a9 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleInGrid.php @@ -37,7 +37,7 @@ public function processAssert( ]; $taxRuleIndex->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $taxRuleIndex->getTaxRuleGrid()->isRowVisible($filter), 'Tax Rule \'' . $filter['code'] . '\' is absent in Tax Rule grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleIsApplied.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleIsApplied.php index e54f7cd03793a..39695623d2cfb 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleIsApplied.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleIsApplied.php @@ -42,7 +42,7 @@ protected function assert() . "\nActual: " . $actualGrandTotal; } - \PHPUnit_Framework_Assert::assertTrue(empty($errorMessages), implode(";\n", $errorMessages)); + \PHPUnit\Framework\Assert::assertTrue(empty($errorMessages), implode(";\n", $errorMessages)); } /** diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleIsNotApplied.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleIsNotApplied.php index 94d98ae3673ec..e3a7c5d8fb8d7 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleIsNotApplied.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleIsNotApplied.php @@ -34,7 +34,7 @@ protected function assert() . "\nActual: " . $actualGrandTotal; } - \PHPUnit_Framework_Assert::assertTrue(empty($errorMessages), implode(";\n", $errorMessages)); + \PHPUnit\Framework\Assert::assertTrue(empty($errorMessages), implode(";\n", $errorMessages)); } /** diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleNotInGrid.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleNotInGrid.php index fa1259c39ecc1..122a4f5ce9c20 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleNotInGrid.php @@ -31,7 +31,7 @@ public function processAssert( ]; $taxRuleIndex->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $taxRuleIndex->getTaxRuleGrid()->isRowVisible($filter), 'Tax Rule \'' . $filter['code'] . '\' is present in Tax Rule grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleSuccessDeleteMessage.php index a71c24730accb..29d1b6bdd5e7a 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleSuccessDeleteMessage.php @@ -25,7 +25,7 @@ class AssertTaxRuleSuccessDeleteMessage extends AbstractConstraint public function processAssert(TaxRuleIndex $taxRuleIndex) { $actualMessage = $taxRuleIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success delete message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleSuccessSaveMessage.php index 59ff270c7d22d..7572bd0ed997c 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRuleSuccessSaveMessage.php @@ -29,7 +29,7 @@ class AssertTaxRuleSuccessSaveMessage extends AbstractConstraint public function processAssert(TaxRuleIndex $taxRuleIndex) { $actualMessage = $taxRuleIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxWithCrossBorderApplied.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxWithCrossBorderApplied.php index b36ae0c234162..b6e38da55dc96 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxWithCrossBorderApplied.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxWithCrossBorderApplied.php @@ -21,7 +21,7 @@ class AssertTaxWithCrossBorderApplied extends AbstractAssertTaxWithCrossBorderAp public function assert($actualPrices) { //Prices verification - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( array_diff($actualPrices[0], $actualPrices[1]), 'Prices for customers should be equal. Cross border is not applied.' ); diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxWithCrossBorderNotApplied.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxWithCrossBorderNotApplied.php index 467ec13b21f1c..749f948a81d63 100644 --- a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxWithCrossBorderNotApplied.php +++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxWithCrossBorderNotApplied.php @@ -21,7 +21,7 @@ class AssertTaxWithCrossBorderNotApplied extends AbstractAssertTaxWithCrossBorde public function assert($actualPrices) { //Prices verification - \PHPUnit_Framework_Assert::assertNotEmpty( + \PHPUnit\Framework\Assert::assertNotEmpty( array_diff($actualPrices[0], $actualPrices[1]), 'Prices for customers should be different.' ); diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFiltering.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFiltering.php index 413fa93e832cd..9bd6a76114e89 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFiltering.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFiltering.php @@ -22,7 +22,7 @@ public function processAssert(array $filterResults) { foreach ($filterResults as $itemId => $filters) { foreach ($filters as $filterName => $ids) { - \PHPUnit_Framework_Assert::assertCount( + \PHPUnit\Framework\Assert::assertCount( 1, $ids, sprintf( @@ -33,7 +33,7 @@ public function processAssert(array $filterResults) ) ); $actualItemId = $ids[0]; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $itemId, $actualItemId, sprintf( diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFullTextSearch.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFullTextSearch.php index 90e3616a027dc..ff886be2eebd7 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFullTextSearch.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridFullTextSearch.php @@ -21,7 +21,7 @@ class AssertGridFullTextSearch extends AbstractConstraint public function processAssert(array $results) { foreach ($results as $itemId => $ids) { - \PHPUnit_Framework_Assert::assertCount( + \PHPUnit\Framework\Assert::assertCount( 1, $ids, sprintf( @@ -31,7 +31,7 @@ public function processAssert(array $results) ) ); $actualItemId = $ids[0]; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $itemId, $actualItemId, sprintf( diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridSorting.php b/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridSorting.php index 06953926fa512..71c0c0317cb0e 100644 --- a/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridSorting.php +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/Constraint/AssertGridSorting.php @@ -22,7 +22,7 @@ class AssertGridSorting extends AbstractConstraint public function processAssert(array $sortingResults) { foreach ($sortingResults as $columnName => $sortingResult) { - \PHPUnit_Framework_Assert::assertNotEquals( + \PHPUnit\Framework\Assert::assertNotEquals( $sortingResult['firstIdAfterFirstSoring'], $sortingResult['firstIdAfterSecondSoring'], sprintf('Sorting for "%s" column have not changed the first item of grid!', $columnName) diff --git a/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFilteringDeletedEntityTest.php b/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFilteringDeletedEntityTest.php new file mode 100644 index 0000000000000..f1fa688339472 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Ui/Test/TestCase/GridFilteringDeletedEntityTest.php @@ -0,0 +1,137 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Ui\Test\TestCase; + +use Magento\Mtf\Fixture\FixtureFactory; +use Magento\Mtf\Fixture\FixtureInterface; +use Magento\Mtf\Page\PageFactory; +use Magento\Mtf\TestCase\Injectable; +use Magento\Ui\Test\Block\Adminhtml\DataGrid; + +/** + * Precondition: + * 1. Create items + * + * Steps: + * 1. Log in to Admin. + * 2. Go to grid page. + * 3. Apply filter by Store View. + * 4. Delete Website. + * 5. Go to grid page. + * 6. Perform Asserts. + * + * @group Ui + * @ZephyrId MAGETWO-89042 + */ +class GridFilteringDeletedEntityTest extends Injectable +{ + /* tags */ + const SEVERITY = 'S2'; + const MVP = 'no'; + /* end tags */ + + /** + * Order index page. + * + * @var PageFactory + */ + protected $pageFactory; + + /** + * Fixture factory. + * + * @var FixtureFactory + */ + protected $fixtureFactory; + + /** + * Injection data. + * + * @param PageFactory $pageFactory + * @param FixtureFactory $fixtureFactory + * @return void + */ + public function __inject(PageFactory $pageFactory, FixtureFactory $fixtureFactory) + { + $this->pageFactory = $pageFactory; + $this->fixtureFactory = $fixtureFactory; + } + + /** + * @param string $pageClass + * @param string $gridRetriever + * @param string[] $filters + * @param string $fixtureName + * @param string[] $steps + * @param array $fixtureDataSet + * @return void + */ + public function test( + $pageClass, + $gridRetriever, + array $filters, + $fixtureName, + array $steps = [], + $fixtureDataSet = null + ) { + $item = $this->createItems($fixtureName, $fixtureDataSet); + $page = $this->pageFactory->create($pageClass); + + $page->open(); + /** @var DataGrid $gridBlock */ + $gridBlock = $page->$gridRetriever(); + $gridBlock->resetFilter(); + + foreach ($filters as $itemFilters) { + $filterArray = []; + foreach ($itemFilters as $itemFiltersName => $itemFilterValue) { + if (substr($itemFilterValue, 0, 1) === ':') { + $value = $item->getData(substr($itemFilterValue, 1)); + } else { + $value = $itemFilterValue; + } + $filterArray[$itemFiltersName] = $value; + } + + $storesArray = $item->getDataFieldConfig('website_ids')['source']->getStores(); + $store = end($storesArray); + $filterArray['store_id'] = $store->getName(); + $gridBlock->search($filterArray); + } + + if (!empty($steps)) { + foreach ($steps as $step) { + $this->processSteps($item, $step); + } + } + } + + /** + * @param string $fixtureName + * @param string $fixtureDataSet + * @return FixtureInterface + */ + private function createItems($fixtureName, $fixtureDataSet) + { + $item = $this->fixtureFactory->createByCode($fixtureName, ['dataset' => $fixtureDataSet]); + $item->persist(); + return $item; + } + + /** + * @param FixtureInterface $item + * @param array $steps + * @return void + */ + private function processSteps(FixtureInterface $item, $steps) + { + foreach ($steps as $step) { + $processStep = $this->objectManager->create($step, ['item' => $item]); + $processStep->run(); + } + } +} diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertCategoryUrlWithCustomStoreView.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertCategoryUrlWithCustomStoreView.php index b44a9ec8d7dca..5b4109c9728bc 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertCategoryUrlWithCustomStoreView.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertCategoryUrlWithCustomStoreView.php @@ -43,7 +43,7 @@ public function processAssert( ); $actualUrl = strtolower($parentCategory->getUrlKey() . '/' . $categoryUpdates->getUrlKey()); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $actualUrl, $browser->getUrl(), "Category URL is not correct." diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertPageByUrlRewriteIsNotFound.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertPageByUrlRewriteIsNotFound.php index f734f224c659b..7625dd5b2c2c8 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertPageByUrlRewriteIsNotFound.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertPageByUrlRewriteIsNotFound.php @@ -36,7 +36,7 @@ public function processAssert( UrlRewrite $productRedirect ) { $browser->open($_ENV['app_frontend_url'] . $productRedirect->getRequestPath()); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::NOT_FOUND_MESSAGE, $catalogProductView->getTitleBlock()->getTitle(), 'Wrong page is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryInGrid.php index 972e5203959ba..d305ec61208e0 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryInGrid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryInGrid.php @@ -114,7 +114,7 @@ private function getCategoryId(Category $category, Category $childCategory = nul private function rowVisibleAssertion(array $filter) { $filterRow = implode(', ', $filter); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter, true, false), 'URL Rewrite with request path "' . $filterRow . '" is absent in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryNotInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryNotInGrid.php index d2ba3e45c5c81..2d06dcc3835e9 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryNotInGrid.php @@ -27,7 +27,7 @@ public function processAssert(UrlRewriteIndex $urlRewriteIndex, Category $catego { $urlRewriteIndex->open(); $filter = ['request_path' => $category->getUrlKey()]; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter), "URL Rewrite with request path '{$category->getUrlKey()}' is present in grid." ); diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryRedirect.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryRedirect.php index d236c676995cb..0236be0cb643e 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryRedirect.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCategoryRedirect.php @@ -35,7 +35,7 @@ public function processAssert( ? $urlRewrite->getRequestPath() : $category->getUrlKey() . '.html'; - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $browser->getUrl(), $_ENV['app_frontend_url'] . $url, 'URL rewrite category redirect false.' diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCustomRedirect.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCustomRedirect.php index a86e49631bdff..98a2c484770d5 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCustomRedirect.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCustomRedirect.php @@ -31,7 +31,7 @@ public function processAssert(UrlRewrite $urlRewrite, BrowserInterface $browser, $entity = $urlRewrite->getDataFieldConfig('target_path')['source']->getEntity(); $title = $entity->hasData('name') ? $entity->getName() : $entity->getContentHeading(); $pageTitle = $cmsIndex->getTitleBlock()->getTitle(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $pageTitle, $title, 'URL rewrite product redirect false.' diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCustomSearchRedirect.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCustomSearchRedirect.php index 2e39110bd6ac9..b8b26b802434a 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCustomSearchRedirect.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCustomSearchRedirect.php @@ -38,7 +38,7 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $urlRequestPath); $entity = $urlRewrite->getDataFieldConfig('target_path')['source']->getEntity(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $categoryView->getListProductBlock()->getProductItem($entity)->isVisible(), "Created entity '{$entity->getName()}' isn't found." ); diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteDeletedMessage.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteDeletedMessage.php index 9c527b5dcf1e9..07557469b0297 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteDeletedMessage.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteDeletedMessage.php @@ -29,7 +29,7 @@ class AssertUrlRewriteDeletedMessage extends AbstractConstraint public function processAssert(UrlRewriteIndex $index) { $actualMessage = $index->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteInGrid.php index 9b5e19bf60c72..0d467529b5a17 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteInGrid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteInGrid.php @@ -27,7 +27,7 @@ public function processAssert(UrlRewriteIndex $urlRewriteIndex, UrlRewrite $urlR { $urlRewriteIndex->open(); $filter = ['request_path' => $urlRewrite->getRequestPath()]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter), 'URL Rewrite with request path \'' . $urlRewrite->getRequestPath() . '\' is absent in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteNotInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteNotInGrid.php index 6427088942831..cbaaf021b81ae 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteNotInGrid.php @@ -27,7 +27,7 @@ public function processAssert(UrlRewriteIndex $urlRewriteIndex, UrlRewrite $prod { $urlRewriteIndex->open(); $filter = ['request_path' => $productRedirect->getRequestPath()]; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter), 'URL Rewrite with request path \'' . $productRedirect->getRequestPath() . '\' is present in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductInGrid.php index 6cce730128b91..82cdc917dd71d 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductInGrid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductInGrid.php @@ -93,7 +93,7 @@ public function processAssert( ], ]; foreach ($filters as $filter) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter, true, false), 'URL Rewrite with request path \'' . $filter['request_path'] . '\' is absent in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductNotInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductNotInGrid.php index 014ea8aae6e9c..910b568ccb4cf 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductNotInGrid.php @@ -27,7 +27,7 @@ public function processAssert(UrlRewriteIndex $urlRewriteIndex, FixtureInterface $urlRewriteIndex->open(); $requestPath = $product->getUrlKey() . '.html'; $filter = ['request_path' => $requestPath]; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter), 'URL Rewrite with request path \'' . $requestPath . '\' is present in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php index 95d6b331f07ef..53dcf90b772fd 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php @@ -37,7 +37,7 @@ public function processAssert( if ($product === null) { $product = $urlRewrite->getDataFieldConfig('target_path')['source']->getEntity(); } - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $catalogProductView->getTitleBlock()->getTitle(), $product->getName(), 'URL rewrite product redirect false.' diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteRedirectInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteRedirectInGrid.php index f39a11c8f8216..efed2a08ac488 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteRedirectInGrid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteRedirectInGrid.php @@ -58,7 +58,7 @@ public function processAssert( private function rowVisibleAssertion(array $filter) { $filterRow = implode(', ', $filter); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter, true, false), 'Category redirect with request path "' . $filterRow . '" is absent in grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSaveMessage.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSaveMessage.php index 94eae31b71c45..e62fec914b8de 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSaveMessage.php @@ -26,7 +26,7 @@ class AssertUrlRewriteSaveMessage extends AbstractConstraint public function processAssert(UrlRewriteIndex $index) { $actualMessage = $index->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSuccessOutsideRedirect.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSuccessOutsideRedirect.php index 803bd30d3513d..88b69a3d310ee 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSuccessOutsideRedirect.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteSuccessOutsideRedirect.php @@ -36,7 +36,7 @@ public function processAssert(UrlRewrite $urlRewrite, BrowserInterface $browser, $browser->open($_ENV['app_frontend_url'] . $urlRequestPath); $browserUrl = $browser->getUrl(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $browserUrl, $urlTargetPath, 'URL rewrite redirect false.' diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteUpdatedProductInGrid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteUpdatedProductInGrid.php index bfb156fb4619a..fb84bf02ed9b6 100644 --- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteUpdatedProductInGrid.php +++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteUpdatedProductInGrid.php @@ -37,7 +37,7 @@ public function processAssert( 'request_path' => $url, 'target_path' => $targetPath, ]; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible($filter, true, false), "URL Rewrite with request path '$url' is absent in grid." ); @@ -45,7 +45,7 @@ public function processAssert( $categoryInitial = $initialProduct->getDataFieldConfig('category_ids')['source']->getCategories()[0]; $targetPath = "catalog/product/view/id/{$initialProduct->getId()}/category/{$categoryInitial->getId()}"; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $urlRewriteIndex->getUrlRedirectGrid()->isRowVisible(['target_path' => $targetPath], true, false), "URL Rewrite with target path '$targetPath' is present in grid." ); diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertAccessTokensErrorRevokeMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertAccessTokensErrorRevokeMessage.php index cfd54cfb461dd..b1a64c7c7e713 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertAccessTokensErrorRevokeMessage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertAccessTokensErrorRevokeMessage.php @@ -28,7 +28,7 @@ class AssertAccessTokensErrorRevokeMessage extends AbstractConstraint */ public function processAssert(UserEdit $userEdit) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $userEdit->getMessagesBlock()->getErrorMessage() ); diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertImpossibleDeleteYourOwnAccount.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertImpossibleDeleteYourOwnAccount.php index 7a889c0bb0779..f557cfb8099cf 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertImpossibleDeleteYourOwnAccount.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertImpossibleDeleteYourOwnAccount.php @@ -25,7 +25,7 @@ class AssertImpossibleDeleteYourOwnAccount extends AbstractConstraint public function processAssert(UserEdit $userEdit) { $errorMessage = $userEdit->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $errorMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertImpossibleDeleteYourOwnRole.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertImpossibleDeleteYourOwnRole.php index 672f9660aca8a..58a845cf755c7 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertImpossibleDeleteYourOwnRole.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertImpossibleDeleteYourOwnRole.php @@ -25,7 +25,7 @@ class AssertImpossibleDeleteYourOwnRole extends AbstractConstraint public function processAssert(UserRoleEditRole $rolePage) { $errorMessage = $rolePage->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $errorMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertIncorrectUserPassword.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertIncorrectUserPassword.php index 4cca4361d0c6f..69561b314a007 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertIncorrectUserPassword.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertIncorrectUserPassword.php @@ -25,7 +25,7 @@ class AssertIncorrectUserPassword extends AbstractConstraint public function processAssert(Dashboard $dashboard) { $errorMessage = $dashboard->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $errorMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleInGrid.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleInGrid.php index c54955b54ab8b..770ca095eee7f 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleInGrid.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleInGrid.php @@ -30,7 +30,7 @@ public function processAssert( ) { $filter = ['rolename' => $role->hasData('rolename') ? $role->getRoleName() : $roleInit->getRoleName()]; $rolePage->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $rolePage->getRoleGrid()->isRowVisible($filter), 'Role with name \'' . $filter['rolename'] . '\' is absent in Roles grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleNotInGrid.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleNotInGrid.php index 973abd63463bb..9642bd05aa383 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleNotInGrid.php @@ -28,7 +28,7 @@ public function processAssert( ) { $filter = ['rolename' => $role->getRoleName()]; $rolePage->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $rolePage->getRoleGrid()->isRowVisible($filter), 'Role with name \'' . $role->getRoleName() . '\' is present in Roles grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleSuccessDeleteMessage.php index 1fea1e42c63cc..48333ab540680 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleSuccessDeleteMessage.php @@ -25,7 +25,7 @@ class AssertRoleSuccessDeleteMessage extends AbstractConstraint public function processAssert(UserRoleIndex $rolePage) { $successMessage = $rolePage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $successMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleSuccessSaveMessage.php index 18249e72ba203..4625f4ce86d1e 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertRoleSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertRoleSuccessSaveMessage extends AbstractConstraint public function processAssert(UserRoleIndex $rolePage) { $successMessage = $rolePage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $successMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserDuplicateMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserDuplicateMessage.php index 19a8c02d5b63f..cad6e2aa28d2b 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserDuplicateMessage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserDuplicateMessage.php @@ -25,7 +25,7 @@ class AssertUserDuplicateMessage extends AbstractConstraint public function processAssert(UserEdit $userEdit) { $failedMessage = $userEdit->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::ERROR_MESSAGE, $failedMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserFailedLoginByPermissionMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserFailedLoginByPermissionMessage.php index d13b07d3f253a..7b7f981b2635b 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserFailedLoginByPermissionMessage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserFailedLoginByPermissionMessage.php @@ -30,7 +30,7 @@ public function processAssert(AdminAuthLogin $adminAuth, User $customAdmin) $adminAuth->getLoginBlock()->fill($customAdmin); $adminAuth->getLoginBlock()->submit(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::FAILED_LOGIN_MESSAGE, $adminAuth->getMessagesBlock()->getErrorMessage(), 'Message "' . self::FAILED_LOGIN_MESSAGE . '" is not visible.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserFailedLoginMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserFailedLoginMessage.php index 23c291c4cc647..3aa4e6c21651c 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserFailedLoginMessage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserFailedLoginMessage.php @@ -33,7 +33,7 @@ public function processAssert( $adminAuth->getLoginBlock()->fill($customAdmin); $adminAuth->getLoginBlock()->submit(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::FAILED_LOGIN_MESSAGE, $adminAuth->getMessagesBlock()->getErrorMessage(), 'Message "' . self::FAILED_LOGIN_MESSAGE . '" is not visible.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInGrid.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInGrid.php index aa70058aaf667..26aa33d89c1d4 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInGrid.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInGrid.php @@ -27,7 +27,7 @@ public function processAssert(UserIndex $userIndex, User $user) $filter = ['username' => $user->getUsername()]; $userIndex->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $userIndex->getUserGrid()->isRowVisible($filter), 'User with name \'' . $user->getUsername() . '\' is absent in User grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInvalidEmailHostnameMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInvalidEmailHostnameMessage.php index 50bc4cede3e16..9e590f588c064 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInvalidEmailHostnameMessage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInvalidEmailHostnameMessage.php @@ -34,7 +34,7 @@ public function processAssert(UserEdit $userEdit, User $user) $hostname = substr($email, strpos($email, '@')+1); $expectedMessage = sprintf(self::ERROR_MESSAGE, $hostname, $email); $actualMessage = $userEdit->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedMessage, $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInvalidEmailMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInvalidEmailMessage.php index 348eca18051b8..2f68d3ceab01d 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInvalidEmailMessage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserInvalidEmailMessage.php @@ -32,7 +32,7 @@ public function processAssert(UserEdit $userEdit, User $user) { $expectedMessage = sprintf(self::ERROR_MESSAGE, $user->getEmail()); $actualMessage = $userEdit->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $expectedMessage, $actualMessage, 'Wrong error message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserNotInGrid.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserNotInGrid.php index 18aadc7b5536f..9033c2f165054 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserNotInGrid.php @@ -28,7 +28,7 @@ public function processAssert( ) { $filter = ['username' => $user->getUsername()]; $userIndex->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $userIndex->getUserGrid()->isRowVisible($filter), 'User with name \'' . $user->getUsername() . '\' is present in Users grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPasswordChangedSuccessfully.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPasswordChangedSuccessfully.php index 5014900ac89c1..adff2de77370b 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPasswordChangedSuccessfully.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPasswordChangedSuccessfully.php @@ -28,7 +28,7 @@ class AssertUserPasswordChangedSuccessfully extends AbstractConstraint public function processAssert(UserIndex $userIndex) { $errorMessage = $userIndex->getMessagesBlock()->getErrorMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::FAIL_MESSAGE, $errorMessage, 'Password update failed with error: "' . self::FAIL_MESSAGE . '"' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPermissionsOnlyConfigurationIndexPage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPermissionsOnlyConfigurationIndexPage.php index ed8636ec8cfeb..a974d8bf40b6d 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPermissionsOnlyConfigurationIndexPage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserPermissionsOnlyConfigurationIndexPage.php @@ -37,7 +37,7 @@ public function processAssert( $adminAuth->getLoginBlock()->fill($customAdmin); $adminAuth->getLoginBlock()->submit(); $configIndex->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $configIndex->getAdminForm()->isEmpty(), "Form isn't empty." ); diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserRoleRestrictedAccess.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserRoleRestrictedAccess.php index 138d4e8104581..f7c56ae1b9653 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserRoleRestrictedAccess.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserRoleRestrictedAccess.php @@ -41,11 +41,11 @@ public function processAssert( )->run(); $menuItems = $dashboard->getMenuBlock()->getTopMenuItems(); - \PHPUnit_Framework_Assert::assertEquals($menuItems, $restrictedAccess, 'Wrong display menu.'); + \PHPUnit\Framework\Assert::assertEquals($menuItems, $restrictedAccess, 'Wrong display menu.'); $browser->open($_ENV['app_backend_url'] . $denyUrl); $deniedMessage = $dashboard->getAccessDeniedBlock()->getTextFromAccessDeniedBlock(); - \PHPUnit_Framework_Assert::assertEquals(self::DENIED_ACCESS, $deniedMessage, 'Possible access to denied page.'); + \PHPUnit\Framework\Assert::assertEquals(self::DENIED_ACCESS, $deniedMessage, 'Possible access to denied page.'); } /** diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessDeleteMessage.php index a53440976dfb6..5dfd2bb9842fb 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessDeleteMessage.php @@ -29,7 +29,7 @@ class AssertUserSuccessDeleteMessage extends AbstractConstraint public function processAssert(UserIndex $userIndex) { $successMessage = $userIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $successMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessLogOut.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessLogOut.php index cc8a8b44f9dfb..8b36c437772e9 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessLogOut.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessLogOut.php @@ -28,7 +28,7 @@ public function processAssert( ) { $dashboard->getAdminPanelHeader()->logOut(); $isLoginBlockVisible = $adminAuth->getLoginBlock()->isVisible(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $isLoginBlockVisible, 'Admin user was not logged out.' ); diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessLogin.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessLogin.php index 2d91dc84f5d4b..c0c04628f744d 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessLogin.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessLogin.php @@ -28,7 +28,7 @@ public function processAssert(User $user, Dashboard $dashboard) \Magento\User\Test\TestStep\LoginUserOnBackendStep::class, ['user' => $user] )->run(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $dashboard->getAdminPanelHeader()->isLoggedIn(), 'Admin user was not logged in.' ); diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessSaveMessage.php index 15b2cecbb3996..ccb8f73d20de2 100644 --- a/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/User/Test/Constraint/AssertUserSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertUserSuccessSaveMessage extends AbstractConstraint public function processAssert(UserIndex $userIndex) { $successMessage = $userIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $successMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableForm.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableForm.php index b6bd235bcfd74..8f37a8e2175a2 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableForm.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableForm.php @@ -67,13 +67,13 @@ public function processAssert( $formData = $systemVariableNew->getSystemVariableForm()->getData(); $errors = $this->verifyData($dataOrigin, $formData); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); if ($storeOrigin !== null) { $systemVariableNew->getFormPageActions()->selectStoreView($storeOrigin->getName()); $formData = $systemVariableNew->getSystemVariableForm()->getData(); $errors = $this->verifyData($data, $formData); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } } diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableInGrid.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableInGrid.php index b5413132d4f83..8ae0233e9e9ce 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableInGrid.php @@ -37,7 +37,7 @@ public function processAssert( ]; $systemVariableIndexNew->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $systemVariableIndexNew->getSystemVariableGrid()->isRowVisible($filter), 'Custom Variable with code \'' . $filter['code'] . '\' is absent in Custom Variable grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableInPage.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableInPage.php index af5ceaab25972..0bdd9a32ee77f 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableInPage.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableInPage.php @@ -105,7 +105,7 @@ protected function getHtmlValue(SystemVariable $customVariable, SystemVariable $ */ protected function checkVariable($htmlValue, $pageContent) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $htmlValue, $pageContent, 'Wrong content is displayed on frontend page' diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableNotInCmsPageForm.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableNotInCmsPageForm.php index 6a38cf1295abc..63d57516ffa2c 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableNotInCmsPageForm.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableNotInCmsPageForm.php @@ -31,7 +31,7 @@ public function processAssert( $cmsPageForm = $cmsPageNew->getPageForm(); $variables = $cmsPageForm->getSystemVariables(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( in_array($customVariableName, $variables), 'Custom System Variable "' . $customVariableName . '" is present in Cms Page Form.' ); diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableNotInGrid.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableNotInGrid.php index efb16861d19b6..3f345d584f772 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableNotInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableNotInGrid.php @@ -32,7 +32,7 @@ public function processAssert( ]; $systemVariableIndexNew->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $systemVariableIndexNew->getSystemVariableGrid()->isRowVisible($filter), 'Custom System Variable with code \'' . $filter['code'] . '\' is present in System Variable grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableRestrictedAccess.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableRestrictedAccess.php index 0866030868699..4f08ddaf4429d 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableRestrictedAccess.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableRestrictedAccess.php @@ -29,7 +29,7 @@ public function processAssert( $systemVariable->persist(); $cmsPageNew->open(); - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $cmsPageNew->getPageForm()->isVariablesBlockVisible(), 'Access to system variables block is supposed to be restricted.' ); diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessDeleteMessage.php index 38ba795940f21..75846692e2ca3 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessDeleteMessage.php @@ -25,7 +25,7 @@ class AssertCustomVariableSuccessDeleteMessage extends AbstractConstraint public function processAssert(SystemVariableIndex $systemVariableIndexPage) { $actualMessage = $systemVariableIndexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_DELETE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessSaveMessage.php index 47b955e540cbf..feac7197b4ee4 100644 --- a/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Variable/Test/Constraint/AssertCustomVariableSuccessSaveMessage.php @@ -25,7 +25,7 @@ class AssertCustomVariableSuccessSaveMessage extends AbstractConstraint public function processAssert(SystemVariableIndex $systemVariableIndexPage) { $actualMessage = $systemVariableIndexPage->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_SAVE_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertCreditCardNotPresentOnCheckout.php b/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertCreditCardNotPresentOnCheckout.php index a839ce903a176..7aa4c89d53025 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertCreditCardNotPresentOnCheckout.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertCreditCardNotPresentOnCheckout.php @@ -24,7 +24,7 @@ public function processAssert( CheckoutOnepage $checkoutOnepage, $deletedCreditCard ) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutOnepage->getVaultPaymentBlock()->isSavedCreditCardPresent($deletedCreditCard), 'Credit card is present on checkout.' ); diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertSaveCreditCardOptionNotPresent.php b/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertSaveCreditCardOptionNotPresent.php index 94df63d4fad88..9d5725dd69c00 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertSaveCreditCardOptionNotPresent.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertSaveCreditCardOptionNotPresent.php @@ -22,7 +22,7 @@ class AssertSaveCreditCardOptionNotPresent extends AbstractConstraint */ public function processAssert(CheckoutOnepage $checkoutOnepage, $payment) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $checkoutOnepage->getVaultPaymentBlock()->isVaultVisible($payment), 'Save for later use checkbox is present.' ); diff --git a/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertStoredPaymentDeletedMessage.php b/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertStoredPaymentDeletedMessage.php index dc272a6f140aa..042541cfb2983 100644 --- a/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertStoredPaymentDeletedMessage.php +++ b/dev/tests/functional/tests/app/Magento/Vault/Test/Constraint/AssertStoredPaymentDeletedMessage.php @@ -25,7 +25,7 @@ class AssertStoredPaymentDeletedMessage extends AbstractConstraint */ public function processAssert(StoredPaymentMethods $storedPaymentMethods) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $storedPaymentMethods->getMessagesBlock()->getSuccessMessage(), 'Message of success deletion of stored payment method is not present or wrong.' diff --git a/dev/tests/functional/tests/app/Magento/Weee/Test/Constraint/AssertFptApplied.php b/dev/tests/functional/tests/app/Magento/Weee/Test/Constraint/AssertFptApplied.php index c676336362395..324f1921088a0 100644 --- a/dev/tests/functional/tests/app/Magento/Weee/Test/Constraint/AssertFptApplied.php +++ b/dev/tests/functional/tests/app/Magento/Weee/Test/Constraint/AssertFptApplied.php @@ -83,7 +83,7 @@ public function processAssert( $this->clearShoppingCart(); $actualPrices = $this->getPrices($product); //Prices verification - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $prices, $actualPrices, 'Prices on front should be equal to defined in dataset' diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertProductInCatalogNewProductsList.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertProductInCatalogNewProductsList.php index 7377dd4c7ab8d..693c9072f894a 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertProductInCatalogNewProductsList.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertProductInCatalogNewProductsList.php @@ -53,7 +53,7 @@ public function processAssert( $cmsIndex->open(); - \PHPUnit_Framework_Assert::assertContains( + \PHPUnit\Framework\Assert::assertContains( $product->getName(), $this->catalogCategoryView->getViewBlock()->getProductsFromCatalogNewProductsListBlock(), 'Product is absent on Catalog New Products List block on Category page.' diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertThemeFilterValuesOnWidgetGrid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertThemeFilterValuesOnWidgetGrid.php index 00b19b7a98504..3e56f12298e4c 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertThemeFilterValuesOnWidgetGrid.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertThemeFilterValuesOnWidgetGrid.php @@ -30,7 +30,7 @@ public function processAssert(array $widgets, WidgetInstanceIndex $widgetInstanc } $widgetInstanceIndex->open(); $actualValues = $widgetInstanceIndex->getWidgetGrid()->getThemeIdValues(); - \PHPUnit_Framework_Assert::assertEmpty( + \PHPUnit\Framework\Assert::assertEmpty( array_diff($expectedValues, $actualValues), 'Widget grid theme filter doesn\'t contain all possible values from created widgets.' ); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php index 7e6d7bc540f0e..ff3007d009b84 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php @@ -37,7 +37,7 @@ public function processAssert( } $cmsIndex->open(); $widgetText = $widget->getParameters()['anchor_text']; - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $cmsIndex->getWidgetView()->isWidgetVisible($widget, $widgetText), 'Widget is present on Home page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php index a547c04d60dbf..52efd2f850e32 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php @@ -44,21 +44,21 @@ public function processAssert( $cmsIndex->open(); $widgetText = $widget->getParameters()['anchor_text']; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsIndex->getWidgetView()->isWidgetVisible($widget, $widgetText), 'Widget with type catalog category link is absent on Home page.' ); $cmsIndex->getWidgetView()->clickToWidget($widget, $widgetText); $title = $categoryView->getTitleBlock()->getTitle(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $widget->getParameters()['entities'][0]->getName(), $title, 'Wrong category title.' ); $cmsIndex->getFooterBlock()->openAdvancedSearch(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsIndex->getWidgetView()->isWidgetVisible($widget, $widgetText), 'Widget with type catalog category link is absent on Advanced Search page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogNewProductsList.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogNewProductsList.php index 3a3eb7cf51b26..3f67b7f98a340 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogNewProductsList.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogNewProductsList.php @@ -59,11 +59,11 @@ public function processAssert( $cmsIndex->open(); $categoryName = $widget->getWidgetInstance()[0]['entities']->getName(); $cmsIndex->getTopmenu()->selectCategoryByName($categoryName); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogCategoryView->getWidgetView()->isWidgetVisible($widget, 'New Products'), 'Widget is absent on Category page.' ); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $products, $this->catalogCategoryView->getViewBlock()->getProductsFromCatalogNewProductsListBlock(), 'There are wrong products or products are absent on Catalog New Products List block on Category page.' diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php index 636af4e8032db..abda2231c935f 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php @@ -36,7 +36,7 @@ public function processAssert( $cmsIndex->open(); $widgetText = $widget->getParameters()['anchor_text']; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsIndex->getWidgetView()->isWidgetVisible($widget, $widgetText), 'Widget with type CmsPageLink is absent on Home page.' ); @@ -46,14 +46,14 @@ public function processAssert( $widget->getParameters()['entities'][0]->getContentHeading(); $cmsIndex->getWidgetView()->clickToWidget($widget, $widgetText); $pageTitle = $cmsIndex->getCmsPageBlock()->getPageTitle(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $title, $pageTitle, 'Wrong page title on Cms page.' ); $cmsIndex->getFooterBlock()->openAdvancedSearch(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $cmsIndex->getWidgetView()->isWidgetVisible($widget, $widgetText), 'Widget with type CmsPageLink is absent on Advanced Search page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetInGrid.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetInGrid.php index ea71bed02b879..edde87f6b3ada 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetInGrid.php @@ -33,7 +33,7 @@ public function processAssert(Widget $widget, WidgetInstanceIndex $widgetInstanc { $filter = ['title' => $widget->getTitle(), 'theme_id' => $widget->getThemeId()]; $widgetInstanceIndex->open(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $widgetInstanceIndex->getWidgetGrid()->isRowVisible($filter), 'Widget with title \'' . $widget->getTitle() . '\' is absent in Widget grid.' ); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php index 3c483208bf74d..8aac883984409 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php @@ -47,7 +47,7 @@ public function processAssert( $widgetText = $widget->getParameters()['anchor_text']; } $cmsIndex->getTopmenu()->selectCategoryByName($categoryName); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $catalogCategoryView->getWidgetView()->isWidgetVisible($widget, $widgetText), 'Widget is absent on Category page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnProductPage.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnProductPage.php index db911e7bf4de7..d60043e4c9efd 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnProductPage.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnProductPage.php @@ -39,7 +39,7 @@ public function processAssert( $browser->open($_ENV['app_frontend_url'] . $urlKey . '.html'); $widgetText = $widget->getParameters()['link_text']; - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $productView->getWidgetView()->isWidgetVisible($widget, $widgetText), 'Widget is absent on Product page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetProductLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetProductLink.php index 3f09eb64d9bfc..a31bc6b4a9b47 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetProductLink.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetProductLink.php @@ -39,7 +39,7 @@ public function processAssert( $cmsIndex->getTopmenu()->selectCategoryByName($widget->getWidgetInstance()[0]['entities']->getName()); $cmsIndex->getWidgetView()->clickToWidget($widget, $widget->getParameters()['anchor_text']); $title = $productView->getTitleBlock()->getTitle(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( $widget->getParameters()['entities'][0]->getName(), $title, 'Wrong product title.' diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php index 667972ff5e8d2..5a67fe43a691b 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php @@ -89,7 +89,7 @@ public function processAssert( $this->addProducts($products); $this->removeCompareProducts(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $this->catalogProductCompare->getWidgetView()->isWidgetVisible($widget, 'Recently Compared'), 'Widget is absent on Product Compare page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php index 90d166f483b66..67eeb0cdc238b 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php @@ -108,7 +108,7 @@ protected function checkRecentlyViewedBlockOnCategory( $this->cmsIndex->getTopmenu()->selectCategoryByName($category->getName()); $products = $this->catalogCategoryView->getViewBlock()->getProductsFromRecentlyViewedBlock(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( in_array($productSimple->getName(), $products), 'Product' . $productSimple->getName() . ' is absent on Recently Viewed block on Category page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetSuccessDeleteMessage.php index 29e6730677fcc..d8858e8c78cc2 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetSuccessDeleteMessage.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetSuccessDeleteMessage.php @@ -32,7 +32,7 @@ class AssertWidgetSuccessDeleteMessage extends AbstractConstraint public function processAssert(WidgetInstanceIndex $widgetInstanceIndex) { $actualMessage = $widgetInstanceIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::DELETE_MESSAGE, $actualMessage, 'Wrong widget success delete message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetSuccessSaveMessage.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetSuccessSaveMessage.php index 88f79da97bf32..8b9a245ad79f2 100644 --- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetSuccessSaveMessage.php +++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetSuccessSaveMessage.php @@ -32,7 +32,7 @@ class AssertWidgetSuccessSaveMessage extends AbstractConstraint public function processAssert(WidgetInstanceIndex $widgetInstanceIndex) { $actualMessage = $widgetInstanceIndex->getMessagesBlock()->getSuccessMessage(); - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $actualMessage, 'Wrong success message is displayed.' diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AbstractAssertWishlistProductDetails.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AbstractAssertWishlistProductDetails.php index ba9fe67b5eb4c..c006516386274 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AbstractAssertWishlistProductDetails.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AbstractAssertWishlistProductDetails.php @@ -38,6 +38,6 @@ protected function assertProductDetails( $this->sortDataByPath($expectedOptions, '::title'), $this->sortDataByPath($actualOptions, '::title') ); - \PHPUnit_Framework_Assert::assertEmpty($errors, $errors); + \PHPUnit\Framework\Assert::assertEmpty($errors, $errors); } } diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertAddProductToWishlistSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertAddProductToWishlistSuccessMessage.php index afa176cc24b1d..37859c0663517 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertAddProductToWishlistSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertAddProductToWishlistSuccessMessage.php @@ -34,7 +34,7 @@ class AssertAddProductToWishlistSuccessMessage extends AbstractConstraint */ public function processAssert(WishlistIndex $wishlistIndex, InjectableFixture $product) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_MESSAGE, $product->getName()), $wishlistIndex->getMessagesBlock()->getSuccessMessage(), "Expected success message doesn't match actual." diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertCustomerWishlistOnBackendIsEmpty.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertCustomerWishlistOnBackendIsEmpty.php index 1ae368480e0a5..f83719b0be6b4 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertCustomerWishlistOnBackendIsEmpty.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertCustomerWishlistOnBackendIsEmpty.php @@ -24,7 +24,7 @@ public function processAssert(OrderCreateIndex $orderCreateIndex) { $orderCreateIndex->open(); $orderCreateIndex->getSidebarWishlistBlock()->isSectionEmpty(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $orderCreateIndex->getSidebarWishlistBlock()->isSectionEmpty(), "Assert that customer's Wish List section on Order Create backend page is not empty." ); diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertMoveProductToWishlistSuccessMessage.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertMoveProductToWishlistSuccessMessage.php index 76a1a40140f50..bb2a65710502a 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertMoveProductToWishlistSuccessMessage.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertMoveProductToWishlistSuccessMessage.php @@ -30,7 +30,7 @@ class AssertMoveProductToWishlistSuccessMessage extends AbstractConstraint */ public function processAssert(WishlistIndex $wishlistIndex, InjectableFixture $product) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( sprintf(self::SUCCESS_MESSAGE, $product->getName()), $wishlistIndex->getMessagesBlock()->getSuccessMessage(), "Expected success move to wish list message doesn't match actual." diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductInCustomerWishlistOnBackendGrid.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductInCustomerWishlistOnBackendGrid.php index b30d54af53198..3dc486222bce6 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductInCustomerWishlistOnBackendGrid.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductInCustomerWishlistOnBackendGrid.php @@ -30,7 +30,7 @@ public function processAssert(CustomerIndexEdit $customerIndexEdit, FixtureInter /** @var Grid $wishlistGrid */ $wishlistGrid = $customerIndexEdit->getCustomerForm()->getTab('wishlist')->getSearchGridBlock(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $wishlistGrid->isRowVisible($filter), 'Product ' . $product->getName() . ' is absent in grid with configure option.' ); diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductIsPresentInCustomerBackendWishlist.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductIsPresentInCustomerBackendWishlist.php index 815c212e072e8..4a573e73188a9 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductIsPresentInCustomerBackendWishlist.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductIsPresentInCustomerBackendWishlist.php @@ -40,7 +40,7 @@ public function processAssert( /** @var \Magento\Wishlist\Test\Block\Adminhtml\Customer\Edit\Tab\Wishlist\Grid $wishlistGrid */ $wishlistGrid = $customerIndexEdit->getCustomerForm()->getTab('wishlist')->getSearchGridBlock(); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $wishlistGrid->isRowVisible(['product_name' => $product->getName()]), $product->getName() . " is not visible in customer wishlist on backend." ); diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductIsPresentInWishlist.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductIsPresentInWishlist.php index a8ff08ce48c1a..6159987940656 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductIsPresentInWishlist.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductIsPresentInWishlist.php @@ -35,7 +35,7 @@ public function processAssert( $cmsIndex->getLinksBlock()->openLink('My Account'); $customerAccountIndex->getAccountMenuBlock()->openMenuItem('My Wish List'); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $wishlistIndex->getWishlistBlock()->getProductItemsBlock()->getItemProduct($product)->isVisible(), $product->getName() . ' is not visible on Wish List page.' ); diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductPriceIsNotZero.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductPriceIsNotZero.php index 57cafc2e3fd1b..21f0e865a4340 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductPriceIsNotZero.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductPriceIsNotZero.php @@ -28,7 +28,7 @@ public function processAssert( $customerAccountIndex->getAccountMenuBlock()->openMenuItem('My Wish List'); $wishlistItem = $wishlistIndex->getWishlistBlock()->getProductItemsBlock()->getItemProduct($product); - \PHPUnit_Framework_Assert::assertNotEquals( + \PHPUnit\Framework\Assert::assertNotEquals( '0.00', $wishlistItem->getPrice(), $product->getName() . ' has zero price on Wish List page.' diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsAbsentInWishlist.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsAbsentInWishlist.php index a558293f65462..861648b491bce 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsAbsentInWishlist.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsAbsentInWishlist.php @@ -40,7 +40,7 @@ public function processAssert( $itemBlock = $wishlistIndex->getWishlistBlock()->getProductItemsBlock(); foreach ($products as $itemProduct) { - \PHPUnit_Framework_Assert::assertFalse( + \PHPUnit\Framework\Assert::assertFalse( $itemBlock->getItemProduct($itemProduct)->isVisible(), 'Product \'' . $itemProduct->getName() . '\' is present in Wish List on Frontend.' ); diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsPresentInCustomerBackendWishlist.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsPresentInCustomerBackendWishlist.php index ec0f8ceeda8e2..28515240270e2 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsPresentInCustomerBackendWishlist.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertProductsIsPresentInCustomerBackendWishlist.php @@ -33,7 +33,7 @@ public function processAssert( $customerIndexEdit->getCustomerForm()->openTab('wishlist'); $wishlistGrid = $customerIndexEdit->getCustomerForm()->getTab('wishlist')->getSearchGridBlock(); foreach ($products as $product) { - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $wishlistGrid->isRowVisible(['product_name' => $product->getName()]), $product->getName() . " is not visible in customer wishlist on backend." ); diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertWishlistIsEmpty.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertWishlistIsEmpty.php index 9ef0f03c3c6d6..3901048e7d190 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertWishlistIsEmpty.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertWishlistIsEmpty.php @@ -27,7 +27,7 @@ public function processAssert(CmsIndex $cmsIndex, WishlistIndex $wishlistIndex) { $cmsIndex->getCmsPageBlock()->waitPageInit(); $cmsIndex->getLinksBlock()->openLink("My Wish List"); - \PHPUnit_Framework_Assert::assertTrue( + \PHPUnit\Framework\Assert::assertTrue( $wishlistIndex->getWishlistBlock()->isEmptyBlockVisible(), 'Wish List is not empty.' ); diff --git a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertWishlistShareMessage.php b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertWishlistShareMessage.php index 94b8dd000f60c..d73a479494cae 100644 --- a/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertWishlistShareMessage.php +++ b/dev/tests/functional/tests/app/Magento/Wishlist/Test/Constraint/AssertWishlistShareMessage.php @@ -32,7 +32,7 @@ class AssertWishlistShareMessage extends AbstractConstraint */ public function processAssert(WishlistIndex $wishlistIndex) { - \PHPUnit_Framework_Assert::assertEquals( + \PHPUnit\Framework\Assert::assertEquals( self::SUCCESS_MESSAGE, $wishlistIndex->getMessagesBlock()->getSuccessMessage(), 'Wrong success message is displayed.' diff --git a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests.php b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests.php index 6cdeb72adbff9..5a68ac1a63e8c 100644 --- a/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests.php +++ b/dev/tests/functional/testsuites/Magento/Mtf/TestSuite/InjectableTests.php @@ -13,7 +13,7 @@ * Class InjectableTests * */ -class InjectableTests extends \PHPUnit_Framework_TestSuite +class InjectableTests extends \PHPUnit\Framework\TestSuite { /** * @var ObjectManager @@ -21,35 +21,25 @@ class InjectableTests extends \PHPUnit_Framework_TestSuite protected $objectManager; /** - * @var \PHPUnit_Framework_TestSuite + * @var \PHPUnit\Framework\TestSuite */ protected $suite; /** - * @var \PHPUnit_Framework_TestResult + * @var \PHPUnit\Framework\TestResult */ protected $result; /** * Run collected tests * - * @param \PHPUnit_Framework_TestResult $result - * @param bool $filter - * @param array $groups - * @param array $excludeGroups - * @param bool $processIsolation - * - * @return \PHPUnit_Framework_TestResult|void + * @param \PHPUnit\Framework\TestResult $result + * @return \PHPUnit\Framework\TestResult|void * * @SuppressWarnings(PHPMD.UnusedFormalParameter) */ - public function run( - \PHPUnit_Framework_TestResult $result = null, - $filter = false, - array $groups = [], - array $excludeGroups = [], - $processIsolation = false - ) { + public function run(\PHPUnit\Framework\TestResult $result = null) + { if ($result === null) { $this->result = $this->createResult(); } diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/AsyncTestData.php b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/AsyncTestData.php new file mode 100644 index 0000000000000..fc2fff50dff08 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/AsyncTestData.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleAsyncAmqp\Model; + +class AsyncTestData +{ + /** + * @var $msgValue + */ + protected $msgValue; + + /** + * @var $path + */ + protected $path; + + /** + * set path to tmp directory. + * + * @param string $path + * @return void + */ + public function setTextFilePath($path) + { + $this->path = $path; + } + + /** + * @return string + */ + public function getTextFilePath() + { + return $this->path; + } + + /** + * @param string $strValue + * @return void + */ + public function setValue($strValue) + { + $this->msgValue = $strValue; + } + + /** + * @return string + */ + public function getValue() + { + return $this->msgValue; + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/CustomHandler.php b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/CustomHandler.php new file mode 100644 index 0000000000000..5cfb980a35fd3 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/CustomHandler.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleAsyncAmqp\Model; + +class CustomHandler +{ + /** + * @param AsyncTestData $simpleDataItem + */ + public function process($simpleDataItem) + { + file_put_contents( + $simpleDataItem->getTextFilePath(), + 'custom-string-' . $simpleDataItem->getValue() . PHP_EOL, + FILE_APPEND + ); + } + + /** + * @param AsyncTestData[] $simpleDataItems + */ + public function processArray($simpleDataItems) + { + foreach ($simpleDataItems as $objItem) { + file_put_contents( + $objItem->getTextFilePath(), + 'custom-array-' . $objItem->getValue() . PHP_EOL, + FILE_APPEND + ); + } + } + + /** + * @param mixed $simpleDataItems + */ + public function processMixed($simpleDataItems) + { + /** @var AsyncTestData[] $simpleDataItems */ + $simpleDataItems = is_array($simpleDataItems) ? $simpleDataItems : [$simpleDataItems]; + foreach ($simpleDataItems as $simpleDataItem) { + if (!($simpleDataItem instanceof AsyncTestData)) { + file_put_contents( + $simpleDataItem->getTextFilePath(), + 'Invalid data item given. Was expected instance of ' . AsyncTestData::class . PHP_EOL, + FILE_APPEND + ); + continue; + } + file_put_contents( + $simpleDataItem->getTextFilePath(), + 'custom-mixed-' . $simpleDataItem->getValue() . PHP_EOL, + FILE_APPEND + ); + } + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/RequestHandler.php b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/RequestHandler.php new file mode 100644 index 0000000000000..1090c3261fc3e --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/RequestHandler.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleAsyncAmqp\Model; + +class RequestHandler +{ + /** + * @param \Magento\TestModuleAsyncAmqp\Model\AsyncTestData $simpleDataItem + */ + public function process($simpleDataItem) + { + file_put_contents( + $simpleDataItem->getTextFilePath(), + 'InvokedFromRequestHandler-' . $simpleDataItem->getValue() . PHP_EOL, + FILE_APPEND + ); + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/WildCardHandler.php b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/WildCardHandler.php new file mode 100644 index 0000000000000..e5c1f25b52187 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/Model/WildCardHandler.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleAsyncAmqp\Model; + +class WildCardHandler +{ + /** + * @param AsyncTestData $simpleDataItem + */ + public function methodOne(AsyncTestData $simpleDataItem) + { + file_put_contents( + $simpleDataItem->getTextFilePath(), + 'WildCardHandler::methodOne - wildcard.queue.one - ' . $simpleDataItem->getValue() . PHP_EOL, + FILE_APPEND + ); + } + + /** + * @param AsyncTestData $simpleDataItem + */ + public function methodTwo(AsyncTestData $simpleDataItem) + { + file_put_contents( + $simpleDataItem->getTextFilePath(), + 'WildCardHandler::methodTwo - wildcard.queue.two - ' . $simpleDataItem->getValue() . PHP_EOL, + FILE_APPEND + ); + } + + /** + * @param AsyncTestData $simpleDataItem + */ + public function methodThree(AsyncTestData $simpleDataItem) + { + file_put_contents( + $simpleDataItem->getTextFilePath(), + 'WildCardHandler::methodThree - wildcard.queue.three - ' . $simpleDataItem->getValue() . PHP_EOL, + FILE_APPEND + ); + } + + /** + * @param AsyncTestData $simpleDataItem + */ + public function methodFour(AsyncTestData $simpleDataItem) + { + file_put_contents( + $simpleDataItem->getTextFilePath(), + 'WildCardHandler::methodFour - wildcard.queue.four - ' . $simpleDataItem->getValue() . PHP_EOL, + FILE_APPEND + ); + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/communication.xml b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/communication.xml new file mode 100644 index 0000000000000..c50bc3e35bea4 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/communication.xml @@ -0,0 +1,37 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Communication/etc/communication.xsd"> + <topic name="multi.topic.queue.topic.c.deprecated" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData"> + <handler name="processAsyncReqC" type="Magento\TestModuleAsyncAmqp\Model\RequestHandler" method="process"/> + </topic> + <topic name="multi.topic.queue.topic.d.deprecated" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData"> + <handler name="processAsyncReqD" type="Magento\TestModuleAsyncAmqp\Model\RequestHandler" method="process"/> + </topic> + <topic name="multi.topic.queue.topic.c" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData"> + <handler name="processAsyncReqC" type="Magento\TestModuleAsyncAmqp\Model\RequestHandler" method="process"/> + </topic> + <topic name="multi.topic.queue.topic.d" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData"> + <handler name="processAsyncReqD" type="Magento\TestModuleAsyncAmqp\Model\RequestHandler" method="process"/> + </topic> + <topic name="multi.topic.queue.topic.y" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData"> + <handler name="processAsyncReqC" type="Magento\TestModuleAsyncAmqp\Model\RequestHandler" method="process"/> + </topic> + <topic name="multi.topic.queue.topic.z" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData"> + <handler name="processAsyncReqD" type="Magento\TestModuleAsyncAmqp\Model\RequestHandler" method="process"/> + </topic> + <topic name="mtmh.topic.1" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData"> + <handler name="mtmh.handler.1" type="Magento\TestModuleAsyncAmqp\Model\CustomHandler" method="process"/> + </topic> + <topic name="mtmh.topic.2" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData[]"> + <handler name="mtmh.handler.2" type="Magento\TestModuleAsyncAmqp\Model\CustomHandler" method="processArray"/> + </topic> + + <topic name="segment1.segment2.segment3.wildcard" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData"/> + <topic name="segment2.segment3.wildcard" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData"/> + <topic name="not.matching.wildcard.topic" request="Magento\TestModuleAsyncAmqp\Model\AsyncTestData"/> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/module.xml new file mode 100644 index 0000000000000..629a61d715cbc --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestModuleAsyncAmqp" /> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue.xml b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue.xml new file mode 100644 index 0000000000000..17895f1c796ce --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue.xml @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/queue.xsd"> + <broker topic="multi.topic.queue.topic.c.deprecated" type="amqp" exchange="magento"> + <queue consumer="queue.for.multiple.topics.test.c.deprecated" name="queue.for.multiple.topics.test.c.deprecated"/> + <queue consumer="mixed.sync.and.async.queue.consumer.deprecated" name="mixed.sync.and.async.queue.deprecated"/> + </broker> + <broker topic="multi.topic.queue.topic.d.deprecated" type="amqp" exchange="magento"> + <queue consumer="queue.for.multiple.topics.test.d.deprecated" name="queue.for.multiple.topics.test.d.deprecated"/> + </broker> +</config> + + + + + diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue_consumer.xml b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue_consumer.xml new file mode 100644 index 0000000000000..5416452ca664f --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue_consumer.xml @@ -0,0 +1,21 @@ +<!--<?xml version="1.0"?>--> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> + <consumer name="queue.for.multiple.topics.test.c" queue="queue.for.multiple.topics.test.c"/> + <consumer name="queue.for.multiple.topics.test.d" queue="queue.for.multiple.topics.test.d"/> + <consumer name="queue.for.multiple.topics.test.y" queue="queue.for.multiple.topics.test.y"/> + <consumer name="queue.for.multiple.topics.test.z" queue="queue.for.multiple.topics.test.z"/> + <consumer name="mixed.sync.and.async.queue.consumer" queue="mixed.sync.and.async.queue"/> + <consumer name="mtmh.queue.1.consumer" queue="mtmh.queue.1" handler="Magento\TestModuleAsyncAmqp\Model\CustomHandler::processMixed"/> + <consumer name="mtmh.queue.2.consumer" queue="mtmh.queue.2"/> + + <consumer name="wildcard.queue.one.consumer" queue="wildcard.queue.one" handler="Magento\TestModuleAsyncAmqp\Model\WildCardHandler::methodOne"/> + <consumer name="wildcard.queue.two.consumer" queue="wildcard.queue.two" handler="Magento\TestModuleAsyncAmqp\Model\WildCardHandler::methodTwo"/> + <consumer name="wildcard.queue.three.consumer" queue="wildcard.queue.three" handler="Magento\TestModuleAsyncAmqp\Model\WildCardHandler::methodThree"/> + <consumer name="wildcard.queue.four.consumer" queue="wildcard.queue.four" handler="Magento\TestModuleAsyncAmqp\Model\WildCardHandler::methodFour"/> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue_publisher.xml b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue_publisher.xml new file mode 100644 index 0000000000000..c6ea325a4f9e3 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue_publisher.xml @@ -0,0 +1,19 @@ +<!--<?xml version="1.0"?>--> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="multi.topic.queue.topic.c"/> + <publisher topic="multi.topic.queue.topic.d"/> + <publisher topic="multi.topic.queue.topic.y"/> + <publisher topic="multi.topic.queue.topic.z"/> + <publisher topic="mtmh.topic.1"/> + <publisher topic="mtmh.topic.2"/> + + <publisher topic="segment1.segment2.segment3.wildcard"/> + <publisher topic="segment2.segment3.wildcard"/> + <publisher topic="not.matching.wildcard.topic"/> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue_topology.xml b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue_topology.xml new file mode 100644 index 0000000000000..a4aa46e7fad76 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/etc/queue_topology.xml @@ -0,0 +1,29 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="magento" connection="amqp" type="topic"> + <binding id="async.binding1" topic="multi.topic.queue.topic.c" destinationType="queue" destination="queue.for.multiple.topics.test.c"/> + <binding id="async.binding2" topic="multi.topic.queue.topic.c" destinationType="queue" destination="mixed.sync.and.async.queue"/> + <binding id="async.binding3" topic="multi.topic.queue.topic.d" destinationType="queue" destination="queue.for.multiple.topics.test.d"/> + <binding id="async.binding4" topic="mtmh.topic.1" destinationType="queue" destination="mtmh.queue.1"/> + <binding id="async.binding5" topic="mtmh.topic.1" destinationType="queue" destination="mtmh.queue.2"/> + <binding id="async.binding6" topic="mtmh.topic.2" destinationType="queue" destination="mtmh.queue.1"/> + <binding id="async.binding7" topic="mtmh.topic.2" destinationType="queue" destination="mtmh.queue.2"/> + <binding id="async.binding8" topic="multi.topic.queue.topic.y" destinationType="queue" destination="queue.for.multiple.topics.test.y"/> + <binding id="async.binding9" topic="multi.topic.queue.topic.z" destinationType="queue" destination="queue.for.multiple.topics.test.z"/> + + <binding id="wildCardBinding1" topic="#.wildcard" destinationType="queue" destination="wildcard.queue.one"/> + <binding id="wildCardBinding2" topic="*.*.segment3.wildcard" destinationType="queue" destination="wildcard.queue.two"/> + <binding id="wildCardBinding3" topic="*.segment3.wildcard" destinationType="queue" destination="wildcard.queue.three"/> + <binding id="wildCardBinding4" topic="#.segment3.*" destinationType="queue" destination="wildcard.queue.four"/> + </exchange> +</config> + + + + diff --git a/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/registration.php b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/registration.php new file mode 100644 index 0000000000000..7f547277c5f4c --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleAsyncAmqp/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleAsyncAmqp') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestModuleAsyncAmqp', __DIR__); +} diff --git a/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/module.xml index d3f1e3bc817f0..42fe40496fb2f 100644 --- a/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/module.xml +++ b/dev/tests/integration/_files/Magento/TestModuleDirectoryZipCodes/etc/module.xml @@ -6,7 +6,7 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModuleDirectoryZipCodes" setup_version="0.0.1" active="true"> + <module name="Magento_TestModuleDirectoryZipCodes" active="true"> <sequence> <module name="Magento_Directory"/> </sequence> diff --git a/dev/tests/integration/_files/Magento/TestModuleFakePaymentMethod/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleFakePaymentMethod/etc/module.xml index de02321ca39ea..a6d0d87ec4e8f 100644 --- a/dev/tests/integration/_files/Magento/TestModuleFakePaymentMethod/etc/module.xml +++ b/dev/tests/integration/_files/Magento/TestModuleFakePaymentMethod/etc/module.xml @@ -6,7 +6,7 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModuleFakePaymentMethod" setup_version="0.0.1"> + <module name="Magento_TestModuleFakePaymentMethod"> <sequence> <module name="Magento_Sales"/> <module name="Magento_Payment"/> diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/composer.json b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/composer.json new file mode 100644 index 0000000000000..dd4cc64824881 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/composer.json @@ -0,0 +1,19 @@ +{ + "name": "magento/module-test-module-message-queue-config-override", + "description": "test module for message queue configuration", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.1.*", + "magento/module-integration": "100.1.*" + }, + "type": "magento2-module", + "version": "1.0", + "extra": { + "map": [ + [ + "*", + "Magento/TestModuleMessageQueueConfigOverride" + ] + ] + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/etc/module.xml new file mode 100644 index 0000000000000..7e355e7519070 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestModuleMessageQueueConfigOverride" /> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/etc/queue_topology.xml b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/etc/queue_topology.xml new file mode 100644 index 0000000000000..bc746fbbec44d --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/etc/queue_topology.xml @@ -0,0 +1,26 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="magento-topic-based-exchange1" connection="amqp"> + <arguments> + <argument name="alternate-exchange" xsi:type="string">magento-log-exchange</argument> + </arguments> + </exchange> + + <exchange name="magento-topic-based-exchange2" type="topic" connection="amqp"> + <arguments> + <argument name="alternate-exchange" xsi:type="string">magento-log-exchange</argument> + </arguments> + <binding id="topicBasedRouting2"> + <arguments> + <argument name="argument2" xsi:type="boolean">true</argument> + <argument name="argument3" xsi:type="number">150</argument> + </arguments> + </binding> + </exchange> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/registration.php b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/registration.php new file mode 100644 index 0000000000000..04fdd678514b1 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride/registration.php @@ -0,0 +1,15 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleMessageQueueConfigOverride') === null) { + ComponentRegistrar::register( + ComponentRegistrar::MODULE, + 'Magento_TestModuleMessageQueueConfigOverride', + __DIR__ + ); +} diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/AsyncHandler.php b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/AsyncHandler.php new file mode 100644 index 0000000000000..945dc9e801c6f --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/AsyncHandler.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleMessageQueueConfiguration; + +/** + * Class for testing asynchronous queue handlers. + * + * @SuppressWarnings(PHPMD) + */ +class AsyncHandler +{ + /** + * @param string + * @return void + */ + public function methodWithStringParam($param) + { + return; + } + + /** + * @param bool + * @return void + */ + public function methodWithBoolParam($param) + { + return; + } + + /** + * @param mixed + * @return void + */ + public function methodWithMixedParam($param) + { + return; + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/HandlerOne.php b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/HandlerOne.php new file mode 100644 index 0000000000000..db85053299e99 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/HandlerOne.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleMessageQueueConfiguration; + +/** + * Class for testing queue handlers. + */ +class HandlerOne +{ + /** + * Return true. + * + * @return bool + */ + public function handlerMethodOne() + { + return true; + } + + /** + * Return true. + * + * @return bool + */ + public function handlerMethodTwo() + { + return true; + } + + /** + * Return true. + * + * @return bool + */ + public function handlerMethodThree() + { + return true; + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/HandlerTwo.php b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/HandlerTwo.php new file mode 100644 index 0000000000000..ef62089ad8c3f --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/HandlerTwo.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleMessageQueueConfiguration; + +/** + * Class for testing queue handlers. + */ +class HandlerTwo +{ + /** + * Return true. + * + * @return bool + */ + public function handlerMethodOne() + { + return true; + } + + /** + * Return true. + * + * @return bool + */ + public function handlerMethodTwo() + { + return true; + } + + /** + * Return true. + * + * @return bool + */ + public function handlerMethodThree() + { + return true; + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/SyncHandler.php b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/SyncHandler.php new file mode 100644 index 0000000000000..801729072cadb --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/SyncHandler.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleMessageQueueConfiguration; + +/** + * Class for testing synchronous queue handlers. + */ +class SyncHandler +{ + /** + * @param string + * @return string + */ + public function methodWithStringParam($param) + { + return 'Processed: ' . $param; + } + + /** + * @param bool + * @return bool + */ + public function methodWithBoolParam($param) + { + return !$param; + } + + /** + * @param mixed + * @return mixed + */ + public function methodWithMixedParam($param) + { + return $param; + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/composer.json b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/composer.json new file mode 100644 index 0000000000000..9cc4af3df9fe9 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/composer.json @@ -0,0 +1,19 @@ +{ + "name": "magento/module-test-module-message-queue-configuration", + "description": "test module for message queue configuration", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/framework": "100.1.*", + "magento/module-integration": "100.1.*" + }, + "type": "magento2-module", + "version": "1.0", + "extra": { + "map": [ + [ + "*", + "Magento/TestModuleMessageQueueConfiguration" + ] + ] + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/communication.xml b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/communication.xml new file mode 100644 index 0000000000000..2c2c9f8be09bf --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/communication.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Communication/etc/communication.xsd"> + <topic name="deprecated.config.async.bool.topic" request="bool"> + <handler name="handler1" type="Magento\TestModuleMessageQueueConfiguration\AsyncHandler" method="methodWithBoolParam"/> + <handler name="handler2" type="Magento\TestModuleMessageQueueConfiguration\AsyncHandler" method="methodWithMixedParam"/> + </topic> + <topic name="deprecated.config.async.string.topic" request="string"/> + <topic name="deprecated.config.sync.string.topic" request="string" response="string"> + <handler name="handler1" type="Magento\TestModuleMessageQueueConfiguration\SyncHandler" method="methodWithStringParam"/> + </topic> + <topic name="deprecated.config.sync.bool.topic" schema="Magento\TestModuleMessageQueueConfiguration\SyncHandler::methodWithBoolParam"> + <handler name="handler1" type="Magento\TestModuleMessageQueueConfiguration\SyncHandler" method="methodWithBoolParam"/> + </topic> + <topic name="overlapping.topic.declaration" request="string"> + <handler name="handler1" type="Magento\TestModuleMessageQueueConfiguration\AsyncHandler" method="methodWithStringParam"/> + </topic> + <topic name="anotherTopic1" request="string"/> + <topic name="anotherTopic2" request="string"/> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/module.xml new file mode 100644 index 0000000000000..b49cdec747d42 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/module.xml @@ -0,0 +1,11 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestModuleMessageQueueConfiguration" > + </module> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue.xml b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue.xml new file mode 100644 index 0000000000000..7bd099710a13f --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue.xml @@ -0,0 +1,22 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/queue.xsd"> + <broker topic="deprecated.config.async.string.topic"> + <queue consumer="deprecatedConfigAsyncStringConsumer" name="deprecated.config.queue.1" consumerInstance="Magento\Framework\MessageQueue\BatchConsumer" maxMessages="200"/> + <queue consumer="deprecatedConfigAsyncMixedConsumer" name="deprecated.config.queue.3" handler="Magento\TestModuleMessageQueueConfiguration\AsyncHandler::methodWithMixedParam"/> + </broker> + <broker topic="deprecated.config.async.bool.topic" type="db" exchange="deprecatedExchange"> + <queue consumer="deprecatedConfigAsyncBoolConsumer" name="deprecated.config.queue.2" /> + </broker> + <broker topic="deprecated.config.sync.bool.topic" type="amqp" exchange="customExchange"> + <queue consumer="deprecatedConfigSyncBoolConsumer" name="deprecated.config.queue.4"/> + </broker> + <broker topic="overlapping.topic.declaration" type="amqp" exchange="overlappingDeprecatedExchange"> + <queue consumer="overlappingConsumerDeclaration" name="consumer.config.queue" consumerInstance="Magento\Framework\MessageQueue\BatchConsumer" maxMessages="222" handler="Magento\TestModuleMessageQueueConfiguration\AsyncHandler::methodWithMixedParam"/> + </broker> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue_consumer.xml b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue_consumer.xml new file mode 100644 index 0000000000000..47be546a1d730 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue_consumer.xml @@ -0,0 +1,15 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> + <consumer name="consumer1" queue="queue1" handler="Magento\TestModuleMessageQueueConfiguration\HandlerOne::handlerMethodOne" consumerInstance="Magento\Framework\MessageQueue\BatchConsumer" connection="amqp" maxMessages="100"/> + <consumer name="consumer2" queue="queue2" handler="Magento\TestModuleMessageQueueConfiguration\HandlerOne::handlerMethodTwo" consumerInstance="Magento\Framework\MessageQueue\BatchConsumer" connection="db"/> + <consumer name="consumer3" queue="queue3" handler="Magento\TestModuleMessageQueueConfiguration\HandlerTwo::handlerMethodOne" consumerInstance="Magento\Framework\MessageQueue\BatchConsumer"/> + <consumer name="consumer4" queue="queue4" handler="Magento\TestModuleMessageQueueConfiguration\HandlerOne::handlerMethodOne"/> + <consumer name="consumer5" queue="queue5"/> + <consumer name="overlappingConsumerDeclaration" queue="consumer.config.queue" connection="amqp"/> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue_publisher.xml b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue_publisher.xml new file mode 100644 index 0000000000000..9d86e065e05c2 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue_publisher.xml @@ -0,0 +1,22 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="topic.message.queue.config.01"> + <connection name="amqp" exchange="magento2" /> + <connection name="db" exchange="magento2" disabled="true" /> + </publisher> + <publisher topic="topic.message.queue.config.02"> + <connection name="amqp" exchange="magento2" disabled="true"/> + <connection name="db" exchange="magento2" disabled="true" /> + </publisher> + <publisher topic="topic.message.queue.config.03" disabled="true" /> + <publisher topic="topic.message.queue.config.04"> + <connection name="amqp" /> + </publisher> + <publisher topic="overlapping.topic.declaration"/> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue_topology.xml b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue_topology.xml new file mode 100644 index 0000000000000..9b72e7d2e5def --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/etc/queue_topology.xml @@ -0,0 +1,46 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="magento-topic-based-exchange1" type="topic" connection="amqp"> + <binding id="topicBasedRouting1" topic="anotherTopic1" destinationType="queue" destination="topic-queue1"> + <arguments> + <argument name="argument1" xsi:type="string">value</argument> + </arguments> + </binding> + </exchange> + + <exchange name="magento-topic-based-exchange2" connection="amqp"> + <binding id="topicBasedRouting2" topic="anotherTopic2" destination="topic-queue2" destinationType="queue"> + <arguments> + <argument name="argument1" xsi:type="string">value</argument> + </arguments> + </binding> + <arguments> + <argument name="arrayValue" xsi:type="array"> + <item name="element01" xsi:type="string">10</item> + <item name="element02" xsi:type="string">20</item> + </argument> + </arguments> + </exchange> + + <exchange name="magento-topic-based-exchange3" type="topic" connection="amqp" autoDelete="true" durable="false" internal="true" /> + + <exchange name="magento-topic-based-exchange4" type="topic" connection="amqp"> + <binding id="wildcard1" destination="topic-queue1" destinationType="queue" topic="#"> + <arguments> + <argument name="test" xsi:type="string">one</argument> + </arguments> + </binding> + <binding id="wildcard2" destination="topic-queue2" destinationType="queue" topic="*.*.*" /> + </exchange> + + <exchange name="overlappingDeprecatedExchange" type="topic" connection="amqp"> + <binding id="binding1" topic="overlapping.topic.declaration" destinationType="queue" destination="topology.config.queue" /> + <binding id="binding2" topic="deprecated.config.async.string.topic" destinationType="queue" destination="topology.config.queue" /> + </exchange> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/registration.php b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/registration.php new file mode 100644 index 0000000000000..eaffb9c79bbe3 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleMessageQueueConfiguration') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestModuleMessageQueueConfiguration', __DIR__); +} diff --git a/dev/tests/integration/_files/Magento/TestModuleSample/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleSample/etc/module.xml index 3b7f0dbbc6f45..488c79374cedb 100644 --- a/dev/tests/integration/_files/Magento/TestModuleSample/etc/module.xml +++ b/dev/tests/integration/_files/Magento/TestModuleSample/etc/module.xml @@ -6,6 +6,6 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestModuleSample" setup_version="0.0.1" active="true"> + <module name="Magento_TestModuleSample" active="true"> </module> </config> diff --git a/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/Api/ServiceInterface.php b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/Api/ServiceInterface.php new file mode 100644 index 0000000000000..71438473a7b5f --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/Api/ServiceInterface.php @@ -0,0 +1,15 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleSynchronousAmqp\Api; + +interface ServiceInterface +{ + /** + * @param string $simpleDataItem + * @return string + */ + public function execute($simpleDataItem); +} diff --git a/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/Model/RpcRequestHandler.php b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/Model/RpcRequestHandler.php new file mode 100644 index 0000000000000..4c4279a096853 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/Model/RpcRequestHandler.php @@ -0,0 +1,18 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleSynchronousAmqp\Model; + +class RpcRequestHandler +{ + /** + * @param string $simpleDataItem + * @return string + */ + public function process($simpleDataItem) + { + return $simpleDataItem . ' processed by RPC handler'; + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/communication.xml b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/communication.xml new file mode 100644 index 0000000000000..87e1dde456ae4 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/communication.xml @@ -0,0 +1,27 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Communication/etc/communication.xsd"> + <topic name="synchronous.rpc.test.deprecated" request="string" response="string"> + <handler name="processRpcRequest" type="Magento\TestModuleSynchronousAmqp\Model\RpcRequestHandler" method="process"/> + </topic> + <topic name="synchronous.rpc.test" request="string" response="string"> + <handler name="processRpcRequest" type="Magento\TestModuleSynchronousAmqp\Model\RpcRequestHandler" method="process"/> + </topic> + <topic name="magento.testModuleSynchronousAmqp.api.serviceInterface.execute" schema="Magento\TestModuleSynchronousAmqp\Api\ServiceInterface::execute"> + <handler name="processRemoteRequest" type="Magento\TestModuleSynchronousAmqp\Model\RpcRequestHandler" method="process"/> + </topic> + <topic name="sync.topic.for.mixed.sync.and.async.queue" request="string" response="string"> + <handler name="processRpcRequest" type="Magento\TestModuleSynchronousAmqp\Model\RpcRequestHandler" method="process"/> + </topic> + <topic name="multi.topic.queue.topic.a" request="string" response="string"> + <handler name="processRpcRequest" type="Magento\TestModuleSynchronousAmqp\Model\RpcRequestHandler" method="process"/> + </topic> + <topic name="multi.topic.queue.topic.b" request="string" response="string"> + <handler name="processRpcRequest" type="Magento\TestModuleSynchronousAmqp\Model\RpcRequestHandler" method="process"/> + </topic> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/di.xml b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/di.xml new file mode 100644 index 0000000000000..83b9a2d985f87 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/di.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <preference for="Magento\TestModuleSynchronousAmqp\Api\ServiceInterface" type="Magento\TestModuleSynchronousAmqp\Api\ServiceInterfaceRemote" /> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/module.xml new file mode 100644 index 0000000000000..d84a61380c600 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestModuleSynchronousAmqp"/> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue.xml b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue.xml new file mode 100644 index 0000000000000..ec196a6e3b7ff --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/queue.xsd"> + <broker topic="synchronous.rpc.test.deprecated" type="amqp" exchange="magento"> + <queue consumer="synchronousRpcTestConsumer.deprecated" name="synchronous.rpc.test.deprecated" consumerInstance="Magento\Framework\MessageQueue\Rpc\Consumer"/> + </broker> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue_consumer.xml b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue_consumer.xml new file mode 100644 index 0000000000000..6f9cc0fa758b0 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue_consumer.xml @@ -0,0 +1,14 @@ +<!--<?xml version="1.0"?>--> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> + <consumer name="synchronousRpcTestConsumer" queue="synchronous.rpc.test" consumerInstance="Magento\Framework\MessageQueue\Rpc\Consumer"/> + <consumer name="RemoteServiceTestConsumer" queue="queue.magento.testModuleSynchronousAmqp.api.serviceInterface.execute" consumerInstance="Magento\Framework\MessageQueue\Rpc\Consumer"/> + <consumer name="mixed.sync.and.async.queue.consumer" queue="mixed.sync.and.async.queue" consumerInstance="Magento\Framework\MessageQueue\Rpc\Consumer"/> + <consumer name="queue.for.multiple.topics.test.a" queue="synchronous.rpc.test" consumerInstance="Magento\Framework\MessageQueue\Rpc\Consumer"/> + <consumer name="queue.for.multiple.topics.test.b" queue="synchronous.rpc.test" consumerInstance="Magento\Framework\MessageQueue\Rpc\Consumer"/> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue_publisher.xml b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue_publisher.xml new file mode 100644 index 0000000000000..0d1e3b6850a99 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue_publisher.xml @@ -0,0 +1,14 @@ +<!--<?xml version="1.0"?>--> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="synchronous.rpc.test"/> + <publisher topic="magento.testModuleSynchronousAmqp.api.serviceInterface.execute"/> + <publisher topic="sync.topic.for.mixed.sync.and.async.queue"/> + <publisher topic="multi.topic.queue.topic.a"/> + <publisher topic="multi.topic.queue.topic.b"/> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue_topology.xml b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue_topology.xml new file mode 100644 index 0000000000000..d16636b25225f --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/etc/queue_topology.xml @@ -0,0 +1,20 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="magento" connection="amqp" type="topic"> + <binding id="sync.binding1" topic="synchronous.rpc.test" destinationType="queue" destination="synchronous.rpc.test"/> + <binding id="sync.binding2" topic="magento.testModuleSynchronousAmqp.api.serviceInterface.execute" destinationType="queue" destination="queue.magento.testModuleSynchronousAmqp.api.serviceInterface.execute"/> + <binding id="sync.binding3" topic="sync.topic.for.mixed.sync.and.async.queue" destinationType="queue" destination="mixed.sync.and.async.queue"/> + <binding id="sync.binding4" topic="multi.topic.queue.topic.a" destinationType="queue" destination="synchronous.rpc.test"/> + <binding id="sync.binding5" topic="multi.topic.queue.topic.b" destinationType="queue" destination="synchronous.rpc.test"/> + </exchange> +</config> + + + + diff --git a/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/registration.php b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/registration.php new file mode 100644 index 0000000000000..6260921e0fb44 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleSynchronousAmqp/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleSynchronousAmqp') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestModuleSynchronousAmqp', __DIR__); +} diff --git a/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/Model/Config.php b/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/Model/Config.php new file mode 100644 index 0000000000000..b74c30c6eef65 --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/Model/Config.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestModuleWysiwygConfig\Model; + +class Config implements \Magento\Framework\Data\Wysiwyg\ConfigProviderInterface +{ + /** + * Configuration override for WYSIWYG height + * @var string + */ + const CONFIG_HEIGHT = 'something_else'; + + /** + * Configuration override for WYSIWYG content css + * @var string + */ + const CONFIG_CONTENT_CSS = 'something_else.css'; + + /** + * @inheritdoc + */ + public function getConfig($config) + { + $config['height'] = self::CONFIG_HEIGHT; + $config['content_css'] = self::CONFIG_CONTENT_CSS; + + return $config; + } +} diff --git a/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/etc/adminhtml/di.xml b/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/etc/adminhtml/di.xml new file mode 100644 index 0000000000000..3366e5fc9685e --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/etc/adminhtml/di.xml @@ -0,0 +1,25 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + <type name="Magento\Cms\Model\Wysiwyg\CompositeConfigProvider"> + <arguments> + <argument name="wysiwygConfigPostProcessor" xsi:type="array"> + <item name="testAdapter" xsi:type="string">Magento\TestModuleWysiwygConfig\Model\Config</item> + </argument> + <argument name="variablePluginConfigProvider" xsi:type="array"> + <item name="testAdapter" xsi:type="string">Magento\Variable\Model\Variable\ConfigProvider</item> + </argument> + <argument name="widgetPluginConfigProvider" xsi:type="array"> + <item name="testAdapter" xsi:type="string">Magento\Widget\Model\Widget\Config</item> + </argument> + <argument name="galleryConfigProvider" xsi:type="array"> + <item name="testAdapter" xsi:type="string">Magento\Cms\Model\Wysiwyg\Gallery\DefaultConfigProvider</item> + </argument> + </arguments> + </type> +</config> diff --git a/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/etc/module.xml b/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/etc/module.xml new file mode 100644 index 0000000000000..1d5fd912894ef --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/etc/module.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestModuleWysiwygConfig" active="true"> + <sequence> + <module name="Magento_Cms"/> + </sequence> + </module> +</config> \ No newline at end of file diff --git a/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/registration.php b/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/registration.php new file mode 100644 index 0000000000000..04a6a7cbc05ba --- /dev/null +++ b/dev/tests/integration/_files/Magento/TestModuleWysiwygConfig/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestModuleWysiwygConfig') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestModuleWysiwygConfig', __DIR__); +} diff --git a/dev/tests/integration/bin/magento b/dev/tests/integration/bin/magento new file mode 100755 index 0000000000000..303fbfb217d2b --- /dev/null +++ b/dev/tests/integration/bin/magento @@ -0,0 +1,42 @@ +#!/usr/bin/env php +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +if (PHP_SAPI !== 'cli') { + echo 'bin/magento must be run as a CLI application'; + exit(1); +} + +if (isset($_SERVER['INTEGRATION_TEST_PARAMS'])) { + parse_str($_SERVER['INTEGRATION_TEST_PARAMS'], $params); + foreach ($params as $paramName => $paramValue) { + $_SERVER[$paramName] = $paramValue; + } +} else { + echo 'Test parameters are required'; + exit(1); +} + +try { + require $_SERVER['MAGE_DIRS']['base']['path'] . '/app/bootstrap.php'; +} catch (\Exception $e) { + echo 'Autoload error: ' . $e->getMessage(); + exit(1); +} +try { + $handler = new \Magento\Framework\App\ErrorHandler(); + set_error_handler([$handler, 'handler']); + $application = new Magento\Framework\Console\Cli('Magento CLI'); + $application->run(); +} catch (\Exception $e) { + while ($e) { + echo $e->getMessage(); + echo $e->getTraceAsString(); + echo "\n\n"; + $e = $e->getPrevious(); + } + exit(Cli::RETURN_FAILURE); +} diff --git a/dev/tests/integration/etc/install-config-mysql.php.dist b/dev/tests/integration/etc/install-config-mysql.php.dist index 512930ab95fc8..4766048c62375 100644 --- a/dev/tests/integration/etc/install-config-mysql.php.dist +++ b/dev/tests/integration/etc/install-config-mysql.php.dist @@ -16,4 +16,8 @@ return [ 'admin-email' => \Magento\TestFramework\Bootstrap::ADMIN_EMAIL, 'admin-firstname' => \Magento\TestFramework\Bootstrap::ADMIN_FIRSTNAME, 'admin-lastname' => \Magento\TestFramework\Bootstrap::ADMIN_LASTNAME, + 'amqp-host' => 'localhost', + 'amqp-port' => '5672', + 'amqp-user' => 'guest', + 'amqp-password' => 'guest', ]; diff --git a/dev/tests/integration/etc/install-config-mysql.travis.php.dist b/dev/tests/integration/etc/install-config-mysql.travis.php.dist index 5abe94833178e..8c41b0a0f2626 100644 --- a/dev/tests/integration/etc/install-config-mysql.travis.php.dist +++ b/dev/tests/integration/etc/install-config-mysql.travis.php.dist @@ -16,4 +16,8 @@ return [ 'admin-email' => \Magento\TestFramework\Bootstrap::ADMIN_EMAIL, 'admin-firstname' => \Magento\TestFramework\Bootstrap::ADMIN_FIRSTNAME, 'admin-lastname' => \Magento\TestFramework\Bootstrap::ADMIN_LASTNAME, + 'amqp-host' => 'localhost', + 'amqp-port' => '5672', + 'amqp-user' => 'guest', + 'amqp-password' => 'guest', ]; diff --git a/dev/tests/integration/framework/Magento/TestFramework/Application.php b/dev/tests/integration/framework/Magento/TestFramework/Application.php index 25784d0073890..29bc3de4c2441 100644 --- a/dev/tests/integration/framework/Magento/TestFramework/Application.php +++ b/dev/tests/integration/framework/Magento/TestFramework/Application.php @@ -546,7 +546,7 @@ public function install($cleanup) private function copyAppConfigFiles() { $globalConfigFiles = Glob::glob( - $this->_globalConfigDir . '/{di.xml,*/di.xml,vendor_path.php}', + $this->_globalConfigDir . '/{di.xml,*/di.xml,db_schema.xml,vendor_path.php}', Glob::GLOB_BRACE ); foreach ($globalConfigFiles as $file) { @@ -626,7 +626,7 @@ protected function _ensureDirExists($dir) { if (!file_exists($dir)) { $old = umask(0); - mkdir($dir); + mkdir($dir, 0777, true); umask($old); } elseif (!is_dir($dir)) { throw new \Magento\Framework\Exception\LocalizedException(__("'%1' is not a directory.", $dir)); diff --git a/dev/tests/integration/framework/Magento/TestFramework/Helper/Amqp.php b/dev/tests/integration/framework/Magento/TestFramework/Helper/Amqp.php new file mode 100644 index 0000000000000..ab209ab21ad89 --- /dev/null +++ b/dev/tests/integration/framework/Magento/TestFramework/Helper/Amqp.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestFramework\Helper; + +use Magento\Framework\HTTP\Client\Curl; + +/** + * Helper class to access RabbitMQ server configuration + */ +class Amqp +{ + /** + * @var Curl + */ + private $curl; + + /** + * RabbitMQ API host + * + * @var string + */ + private $host = 'http://localhost:15672/api/'; + + /** + * Initialize dependencies. + */ + public function __construct() + { + $this->curl = new Curl(); + $this->curl->setCredentials('guest', 'guest'); + $this->curl->addHeader('content-type', 'application/json'); + } + + /** + * Get declared exchanges. + * + * @return array + */ + public function getExchanges() + { + $this->curl->get($this->host . 'exchanges'); + $data = $this->curl->getBody(); + $data = json_decode($data, true); + $output = []; + foreach ($data as $value) { + $output[$value['name']] = $value; + } + return $output; + } + + /** + * Get declared exchange bindings. + * + * @return array + */ + public function getExchangeBindings($name) + { + $this->curl->get($this->host . 'exchanges/%2f/' . $name . '/bindings/source'); + $data = $this->curl->getBody(); + return json_decode($data, true); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php b/dev/tests/integration/testsuite/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php new file mode 100644 index 0000000000000..63ebbcbc2c961 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Analytics/Block/Adminhtml/System/Config/CollectionTimeLabelTest.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Analytics\Block\Adminhtml\System\Config; + +use Magento\Framework\Data\FormFactory; +use Magento\Framework\Data\Form\Element\TimeFactory; +use Magento\TestFramework\Helper\Bootstrap; +use PHPUnit\Framework\TestCase; + +/** + * Provide tests for CollectionTimeLabel block. + */ +class CollectionTimeLabelTest extends TestCase +{ + /** + * Test render will add comment considering config locale(default en_US). + * + * @magentoAppIsolation enabled + */ + public function testRenderWithDefaultLocale() + { + $result = $this->render(); + $this->assertRegExp('/<span>Pacific Standard Time/', $result); + } + + /** + * Test render will add comment considering config locale(non-default de_DE). + * + * @magentoConfigFixture default_store general/locale/code de_DE + * @magentoAppIsolation enabled + */ + public function testRenderWithNonDefaultLocale() + { + $result = $this->render(); + $this->assertRegExp('/<span>Nordamerikanische Westküsten-Normalzeit/', $result); + } + + /** + * Render 'time' element. + * + * @return string + */ + private function render() + { + $collectionTimeLabel = Bootstrap::getObjectManager()->get(CollectionTimeLabelFactory::class)->create(); + $form = Bootstrap::getObjectManager()->get(FormFactory::class)->create(); + $element = Bootstrap::getObjectManager()->get(TimeFactory::class)->create(); + $element->setForm($form); + + return $collectionTimeLabel->render($element); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/BulkManagementTest.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/BulkManagementTest.php new file mode 100644 index 0000000000000..5ecc274c5bbb8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/BulkManagementTest.php @@ -0,0 +1,145 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\AsynchronousOperations\Model; + +use Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\ObjectManagerInterface; +use Magento\AsynchronousOperations\Api\Data\OperationInterface; +use Magento\Framework\MessageQueue\BulkPublisherInterface; +use Magento\Framework\EntityManager\MetadataPool; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\EntityManager\EntityManager; +use Magento\AsynchronousOperations\Model\ResourceModel\Operation\CollectionFactory; +use Magento\AsynchronousOperations\Api\Data\BulkSummaryInterfaceFactory; +use Magento\AsynchronousOperations\Api\Data\OperationInterfaceFactory; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class BulkManagementTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \PHPUnit\Framework\MockObject_MockObject + */ + private $publisherMock; + + /** + * @var BulkManagement + */ + private $model; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->publisherMock = $this->createMock(BulkPublisherInterface::class); + + $this->model = $this->objectManager->create( + BulkManagement::class, + [ + 'publisher' => $this->publisherMock + ] + ); + } + + public function testScheduleBulk() + { + // general bulk information + $bulkUuid = '5a12c1bd-a8b5-41d4-8c00-3f5bcaa6d3c7'; + $bulkDescription = 'Bulk General Information'; + $topicName = 'example.topic.name'; + $userId = 1; + + // generate bulk operations that must be saved + $operationCount = 100; + $operations = []; + $operationFactory = $this->objectManager->get(OperationInterfaceFactory::class); + for ($index = 0; $index < $operationCount; $index++) { + /** @var OperationInterface $operation */ + $operation = $operationFactory->create(); + $operation->setBulkUuid($bulkUuid); + $operation->setTopicName($topicName); + $operation->setSerializedData(json_encode(['entity_id' => $index])); + $operations[] = $operation; + } + + $this->publisherMock->expects($this->once()) + ->method('publish') + ->with($topicName, $operations); + + // schedule bulk + $this->assertTrue($this->model->scheduleBulk($bulkUuid, $operations, $bulkDescription, $userId)); + $storedData = $this->getStoredOperationData(); + // No operations should be saved to database during bulk creation + $this->assertCount(0, $storedData); + } + + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/bulk.php + */ + public function testRetryBulk() + { + $bulkUuid = 'bulk-uuid-5'; + $topicName = 'topic-4'; + $errorCodes = [1111, 2222]; + $operations = $this->objectManager->get(CollectionFactory::class) + ->create() + ->addFieldToFilter('bulk_uuid', ['eq' => $bulkUuid]) + ->getItems(); + foreach ($operations as $operation) { + $operation->setId(null); + } + $this->publisherMock->expects($this->once()) + ->method('publish') + ->with($topicName, array_values($operations)); + $this->assertEquals(2, $this->model->retryBulk($bulkUuid, $errorCodes)); + + $operations = $this->objectManager->get(CollectionFactory::class) + ->create() + ->addFieldToFilter('bulk_uuid', ['eq' => $bulkUuid]) + ->getItems(); + // Failed operations should be removed from database during bulk retry + $this->assertCount(0, $operations); + } + + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/bulk.php + */ + public function testDeleteBulk() + { + $this->model->deleteBulk('bulk-uuid-1'); + + /** @var EntityManager $entityManager */ + $entityManager = $this->objectManager->get(EntityManager::class); + $bulkSummaryFactory = $this->objectManager->get(BulkSummaryInterfaceFactory::class); + /** @var BulkSummaryInterface $bulkSummary */ + $bulkSummary = $entityManager->load($bulkSummaryFactory->create(), 'bulk-uuid-1'); + $this->assertNull($bulkSummary->getBulkId()); + } + + /** + * Retrieve stored operation data + * + * @return array + * @throws \Exception + */ + private function getStoredOperationData() + { + /** @var MetadataPool $metadataPool */ + $metadataPool = $this->objectManager->get(MetadataPool::class); + $operationMetadata = $metadataPool->getMetadata(OperationInterface::class); + /** @var ResourceConnection $resourceConnection */ + $resourceConnection = $this->objectManager->get(ResourceConnection::class); + $connection = $resourceConnection->getConnectionByName($operationMetadata->getEntityConnectionName()); + + return $connection->fetchAll($connection->select()->from($operationMetadata->getEntityTable())); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/BulkNotificationManagementTest.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/BulkNotificationManagementTest.php new file mode 100644 index 0000000000000..f8a349e04c237 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/BulkNotificationManagementTest.php @@ -0,0 +1,81 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\AsynchronousOperations\Model; + +use Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\ObjectManagerInterface; + +class BulkNotificationManagementTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var BulkNotificationManagement + */ + private $model; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + + $this->model = $this->objectManager->create( + BulkNotificationManagement::class + ); + } + + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/bulk.php + */ + public function testAcknowledgeBulks() + { + $this->model->acknowledgeBulks(['bulk-uuid-5']); + + $acknowledgedBulks = $this->model->getAcknowledgedBulksByUser(1); + $this->assertCount(1, $acknowledgedBulks); + /** @var BulkSummaryInterface $acknowledgedBulk */ + $acknowledgedBulk = array_pop($acknowledgedBulks); + $this->assertEquals('bulk-uuid-5', $acknowledgedBulk->getBulkId()); + } + + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/acknowledged_bulk.php + */ + public function testIgnoreBulks() + { + // 'bulk-uuid-5' and 'bulk-uuid-4' are marked as acknowledged in fixture + $this->model->ignoreBulks(['bulk-uuid-5']); + + $acknowledgedBulks = $this->model->getAcknowledgedBulksByUser(1); + $this->assertCount(1, $acknowledgedBulks); + /** @var BulkSummaryInterface $acknowledgedBulk */ + $acknowledgedBulk = array_pop($acknowledgedBulks); + $this->assertEquals('bulk-uuid-4', $acknowledgedBulk->getBulkId()); + } + + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/acknowledged_bulk.php + */ + public function testGetAcknowledgedBulks() + { + // 'bulk-uuid-5' and 'bulk-uuid-4' are marked as acknowledged in fixture + $acknowledgedBulks = $this->model->getAcknowledgedBulksByUser(1); + $this->assertCount(2, $acknowledgedBulks); + } + + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/acknowledged_bulk.php + */ + public function testGetIgnoredBulks() + { + // 'bulk-uuid-5' and 'bulk-uuid-4' are marked as acknowledged in fixture. Fixture creates 5 bulks in total. + $ignoredBulks = $this->model->getIgnoredBulksByUser(1); + $this->assertCount(3, $ignoredBulks); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/BulkStatusTest.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/BulkStatusTest.php new file mode 100644 index 0000000000000..a7857bd7a2fdb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/BulkStatusTest.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\AsynchronousOperations\Model; + +use Magento\AsynchronousOperations\Api\Data\BulkSummaryInterface; + +class BulkStatusTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\AsynchronousOperations\Model\BulkStatus + */ + private $model; + + protected function setUp() + { + $this->model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\AsynchronousOperations\Model\BulkStatus::class + ); + } + + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/bulk.php + */ + public function testGetBulkStatus() + { + $this->assertEquals(BulkSummaryInterface::NOT_STARTED, $this->model->getBulkStatus('bulk-uuid-1')); + $this->assertEquals(BulkSummaryInterface::IN_PROGRESS, $this->model->getBulkStatus('bulk-uuid-2')); + $this->assertEquals(BulkSummaryInterface::FINISHED_SUCCESSFULLY, $this->model->getBulkStatus('bulk-uuid-4')); + $this->assertEquals(BulkSummaryInterface::FINISHED_WITH_FAILURE, $this->model->getBulkStatus('bulk-uuid-5')); + } + + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/bulk.php + */ + public function testGetBulksByUser() + { + /** @var \Magento\AsynchronousOperations\Model\BulkSummary[] $bulks */ + $bulksUuidArray = ['bulk-uuid-1', 'bulk-uuid-2', 'bulk-uuid-3', 'bulk-uuid-4', 'bulk-uuid-5']; + $bulks = $this->model->getBulksByUser(1); + $this->assertEquals(5, count($bulks)); + foreach ($bulks as $bulk) { + $this->assertTrue(in_array($bulk->getBulkId(), $bulksUuidArray)); + } + } + + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/bulk.php + */ + public function testGetFailedOperationsByBulkId() + { + /** @var \Magento\AsynchronousOperations\Api\Data\OperationInterface[] $operations */ + $operations = $this->model->getFailedOperationsByBulkId('bulk-uuid-1'); + $this->assertEquals([], $operations); + $operations = $this->model->getFailedOperationsByBulkId('bulk-uuid-5', 3); + foreach ($operations as $operation) { + $this->assertEquals(1111, $operation->getErrorCode()); + } + $operations = $this->model->getFailedOperationsByBulkId('bulk-uuid-5', 2); + foreach ($operations as $operation) { + $this->assertEquals(2222, $operation->getErrorCode()); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/OperationManagementTest.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/OperationManagementTest.php new file mode 100644 index 0000000000000..a9933966e5b70 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Model/OperationManagementTest.php @@ -0,0 +1,74 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\AsynchronousOperations\Model; + +use Magento\AsynchronousOperations\Api\Data\OperationInterface; +use Magento\AsynchronousOperations\Api\Data\OperationInterfaceFactory; +use Magento\Framework\EntityManager\EntityManager; + +class OperationManagementTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\AsynchronousOperations\Model\OperationManagement + */ + private $model; + + /** + * @var \Magento\AsynchronousOperations\Model\BulkStatus + */ + private $bulkStatusManagement; + + /** + * @var OperationInterfaceFactory + */ + private $operationFactory; + + /** + * @var EntityManager + */ + private $entityManager; + + protected function setUp() + { + $this->model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\AsynchronousOperations\Model\OperationManagement::class + ); + $this->bulkStatusManagement = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + \Magento\AsynchronousOperations\Model\BulkStatus::class + ); + + $this->operationFactory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + OperationInterfaceFactory::class + ); + $this->entityManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + EntityManager::class + ); + } + + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/bulk.php + */ + public function testGetBulkStatus() + { + $operations = $this->bulkStatusManagement->getFailedOperationsByBulkId('bulk-uuid-5', 3); + if (empty($operations)) { + $this->fail('Operation doesn\'t exist'); + } + /** @var OperationInterface $operation */ + $operation = array_shift($operations); + $operationId = $operation->getId(); + + $this->assertTrue($this->model->changeOperationStatus($operationId, OperationInterface::STATUS_TYPE_OPEN)); + + /** @var OperationInterface $updatedOperation */ + $updatedOperation = $this->operationFactory->create(); + $this->entityManager->load($updatedOperation, $operationId); + $this->assertEquals(OperationInterface::STATUS_TYPE_OPEN, $updatedOperation->getStatus()); + $this->assertEquals(null, $updatedOperation->getResultMessage()); + $this->assertEquals(null, $updatedOperation->getSerializedData()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Failed/SearchResultTest.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Failed/SearchResultTest.php new file mode 100644 index 0000000000000..64077eeb18bf6 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Failed/SearchResultTest.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\AsynchronousOperations\Ui\Component\DataProvider\Operation\Failed; + +use Magento\TestFramework\Helper\Bootstrap; + +/** + * Class SearchResultTest + */ +class SearchResultTest extends \PHPUnit\Framework\TestCase +{ + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/bulk.php + * @magentoDbIsolation enabled + * @magentoAppArea adminhtml + */ + public function testGetItems() + { + $objectManager = Bootstrap::getObjectManager(); + $request = $objectManager->get(\Magento\Framework\App\RequestInterface::class); + $requestData = [ + 'uuid' => 'bulk-uuid-5', + ]; + + $request->setParams($requestData); + + /** @var \Magento\AsynchronousOperations\Ui\Component\DataProvider\SearchResult $searchResult */ + $searchResult = $objectManager->create( + \Magento\AsynchronousOperations\Ui\Component\DataProvider\Operation\Failed\SearchResult::class + ); + $this->assertEquals(1, $searchResult->getTotalCount()); + $expected = $searchResult->getItems(); + $expectedItem = array_shift($expected); + $this->assertEquals('Test', $expectedItem->getMetaInformation()); + $this->assertEquals('5', $expectedItem->getEntityId()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Retriable/SearchResultTest.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Retriable/SearchResultTest.php new file mode 100644 index 0000000000000..6e0afaf1287b9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Ui/Component/DataProvider/Operation/Retriable/SearchResultTest.php @@ -0,0 +1,37 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\AsynchronousOperations\Ui\Component\DataProvider\Operation\Retriable; + +use Magento\TestFramework\Helper\Bootstrap; + +/** + * Class SearchResultTest + */ +class SearchResultTest extends \PHPUnit\Framework\TestCase +{ + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/bulk.php + * @magentoDbIsolation enabled + * @magentoAppArea adminhtml + */ + public function testGetTotalCount() + { + $objectManager = Bootstrap::getObjectManager(); + $requestData = [ + 'uuid' => 'bulk-uuid-5', + ]; + $request = $objectManager->get(\Magento\Framework\App\RequestInterface::class); + $request->setParams($requestData); + + /** + * @var \Magento\AsynchronousOperations\Ui\Component\DataProvider\Operation\Retriable\SearchResult $searchResult + */ + $searchResult = $objectManager->create( + \Magento\AsynchronousOperations\Ui\Component\DataProvider\Operation\Retriable\SearchResult::class + ); + $this->assertEquals(1, $searchResult->getTotalCount()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Ui/Component/DataProvider/SearchResultTest.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Ui/Component/DataProvider/SearchResultTest.php new file mode 100644 index 0000000000000..852308e83c270 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/Ui/Component/DataProvider/SearchResultTest.php @@ -0,0 +1,34 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\AsynchronousOperations\Ui\Component\DataProvider; + +use Magento\TestFramework\Helper\Bootstrap; + +/** + * Class SearchResultTest + */ +class SearchResultTest extends \PHPUnit\Framework\TestCase +{ + /** + * @magentoDataFixture Magento/AsynchronousOperations/_files/bulk.php + * @magentoDbIsolation enabled + * @magentoAppArea adminhtml + */ + public function testGetAllIds() + { + $objectManager = Bootstrap::getObjectManager(); + $user = $objectManager->create(\Magento\User\Model\User::class); + $user->loadByUsername(\Magento\TestFramework\Bootstrap::ADMIN_NAME); + $session = $objectManager->get(\Magento\Backend\Model\Auth\Session::class); + $session->setUser($user); + + /** @var \Magento\AsynchronousOperations\Ui\Component\DataProvider\SearchResult $searchResult */ + $searchResult = $objectManager->create( + \Magento\AsynchronousOperations\Ui\Component\DataProvider\SearchResult::class + ); + $this->assertEquals(5, $searchResult->getTotalCount()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/acknowledged_bulk.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/acknowledged_bulk.php new file mode 100644 index 0000000000000..2b5c286a28313 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/acknowledged_bulk.php @@ -0,0 +1,10 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +require __DIR__ . '/bulk.php'; + +$acknowledgedBulkTable = $resource->getTableName('magento_acknowledged_bulk'); +$acknowledgedBulkQuery = "INSERT INTO {$acknowledgedBulkTable} (`bulk_uuid`) VALUES ('bulk-uuid-4'), ('bulk-uuid-5');"; +$connection->query($acknowledgedBulkQuery); diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/acknowledged_bulk_rollback.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/acknowledged_bulk_rollback.php new file mode 100644 index 0000000000000..24fa9cfd4f418 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/acknowledged_bulk_rollback.php @@ -0,0 +1,7 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +// when bulks are removed, acknowledged bulk table will be cleared too. +require __DIR__ . '/bulk_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php new file mode 100644 index 0000000000000..787d2c10a44c4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\Bulk\OperationInterface; + +/** + * @var $resource Magento\Framework\App\ResourceConnection + */ +$resource = Bootstrap::getObjectManager()->get(\Magento\Framework\App\ResourceConnection::class); +$connection = $resource->getConnection(); +$bulkTable = $resource->getTableName('magento_bulk'); +$operationTable = $resource->getTableName('magento_operation'); + +$bulks = [ + 'not_started' => [ + 'uuid' => 'bulk-uuid-1', + 'user_id' => 1, + 'description' => 'Bulk Description', + 'operation_count' => 1, + ], + 'in_progress_success' => [ + 'uuid' => 'bulk-uuid-2', + 'user_id' => 1, + 'description' => 'Bulk Description', + 'operation_count' => 3, + ], + 'in_progress_failed' => [ + 'uuid' => 'bulk-uuid-3', + 'user_id' => 1, + 'description' => 'Bulk Description', + 'operation_count' => 2, + ], + 'finish_success' => [ + 'uuid' => 'bulk-uuid-4', + 'user_id' => 1, + 'description' => 'Bulk Description', + 'operation_count' => 1, + ], + 'finish_failed' => [ + 'uuid' => 'bulk-uuid-5', + 'user_id' => 1, + 'description' => 'Bulk Description', + 'operation_count' => 2, + ] +]; +// Only processed operations are saved into database (i.e. operations that are not in 'open' state) +$operations = [ + [ + 'bulk_uuid' => 'bulk-uuid-2', + 'topic_name' => 'topic-3', + 'serialized_data' => json_encode(['entity_id' => 2]), + 'status' => OperationInterface::STATUS_TYPE_COMPLETE, + 'error_code' => null, + 'result_message' => null, + ], + [ + 'bulk_uuid' => 'bulk-uuid-3', + 'topic_name' => 'topic-3', + 'serialized_data' => json_encode(['entity_id' => 3]), + 'status' => OperationInterface::STATUS_TYPE_RETRIABLY_FAILED, + 'error_code' => 1111, + 'result_message' => 'Something went wrong during your request', + ], + [ + 'bulk_uuid' => 'bulk-uuid-4', + 'topic_name' => 'topic-4', + 'serialized_data' => json_encode(['entity_id' => 4]), + 'status' => OperationInterface::STATUS_TYPE_COMPLETE, + 'error_code' => null, + 'result_message' => null, + ], + [ + 'bulk_uuid' => 'bulk-uuid-5', + 'topic_name' => 'topic-4', + 'serialized_data' => json_encode(['entity_id' => 5, 'meta_information' => 'Test']), + 'status' => OperationInterface::STATUS_TYPE_NOT_RETRIABLY_FAILED, + 'error_code' => 1111, + 'result_message' => 'Something went wrong during your request', + ], + [ + 'bulk_uuid' => 'bulk-uuid-5', + 'topic_name' => 'topic-4', + 'serialized_data' => json_encode(['entity_id' => 5]), + 'status' => OperationInterface::STATUS_TYPE_RETRIABLY_FAILED, + 'error_code' => 2222, + 'result_message' => 'Entity with ID=4 does not exist', + ], + +]; + +$bulkQuery = "INSERT INTO {$bulkTable} (`uuid`, `user_id`, `description`, `operation_count`)" + . " VALUES (:uuid, :user_id, :description, :operation_count);"; +foreach ($bulks as $bulk) { + $connection->query($bulkQuery, $bulk); +} + +$operationQuery = "INSERT INTO {$operationTable}" + . " (`bulk_uuid`, `topic_name`, `serialized_data`, `status`, `error_code`, `result_message`)" + . " VALUES (:bulk_uuid, :topic_name, :serialized_data, :status, :error_code, :result_message);"; +foreach ($operations as $operation) { + $connection->query($operationQuery, $operation); +} diff --git a/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk_rollback.php b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk_rollback.php new file mode 100644 index 0000000000000..e5e765ab45b50 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/AsynchronousOperations/_files/bulk_rollback.php @@ -0,0 +1,15 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +use Magento\TestFramework\Helper\Bootstrap; + +/** + * @var $resource Magento\Framework\App\ResourceConnection + */ +$resource = Bootstrap::getObjectManager()->get(\Magento\Framework\App\ResourceConnection::class); +$connection = $resource->getConnection(); +$bulkTable = $resource->getTableName('magento_bulk'); + +$connection->query("DELETE FROM {$bulkTable};"); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_separately.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_separately.php new file mode 100644 index 0000000000000..66e95b54c6cc4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_separately.php @@ -0,0 +1,204 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +require __DIR__ . '/../../../Magento/Catalog/_files/products.php'; + +/** @var $objectManager \Magento\TestFramework\ObjectManager */ +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +/** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); +$sampleProduct = $productRepository->get('simple'); +$secondSampleProduct = $productRepository->get('custom-design-simple-product'); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->setTypeId('bundle') + ->setId(3) + ->setAttributeSetId(4) + ->setWebsiteIds([1]) + ->setName('Bundle Product') + ->setSku('bundle-product') + ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH) + ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED) + ->setStockData(['use_config_manage_stock' => 1, 'qty' => 100, 'is_qty_decimal' => 0, 'is_in_stock' => 1]) + ->setPriceView(1) + ->setPriceType(1) + ->setShipmentType(1) + ->setPrice(10.0) + ->setBundleOptionsData( + [ + [ + 'title' => 'Bundle Product Items', + 'default_title' => 'Bundle Product Items', + 'type' => 'select', + 'required' => 1, + 'delete' => '', + ], + [ + 'title' => 'Bundle Product Items Option 2', + 'default_title' => 'Bundle Product Items Option 2', + 'type' => 'select', + 'required' => 1, + 'delete' => '', + ], + ] + ) + ->setBundleSelectionsData( + [ + [ + [ + 'product_id' => $sampleProduct->getId(), + 'selection_qty' => 1, + 'selection_can_change_qty' => 1, + 'delete' => '', + ], + ], + [ + [ + 'product_id' => $secondSampleProduct->getId(), + 'selection_qty' => 1, + 'selection_can_change_qty' => 1, + 'delete' => '', + ], + ] + ] + ); + +if ($product->getBundleOptionsData()) { + $options = []; + foreach ($product->getBundleOptionsData() as $key => $optionData) { + if (!(bool)$optionData['delete']) { + $option = $objectManager->create(\Magento\Bundle\Api\Data\OptionInterfaceFactory::class) + ->create(['data' => $optionData]); + $option->setSku($product->getSku()); + $option->setOptionId(null); + + $links = []; + $bundleLinks = $product->getBundleSelectionsData(); + if (!empty($bundleLinks[$key])) { + foreach ($bundleLinks[$key] as $linkData) { + if (!(bool)$linkData['delete']) { + /** @var \Magento\Bundle\Api\Data\LinkInterface$link */ + $link = $objectManager->create(\Magento\Bundle\Api\Data\LinkInterfaceFactory::class) + ->create(['data' => $linkData]); + $linkProduct = $productRepository->getById($linkData['product_id']); + $link->setSku($linkProduct->getSku()); + $link->setQty($linkData['selection_qty']); + if (isset($linkData['selection_can_change_qty'])) { + $link->setCanChangeQuantity($linkData['selection_can_change_qty']); + } + $links[] = $link; + } + } + $option->setProductLinks($links); + $options[] = $option; + } + } + } + $extension = $product->getExtensionAttributes(); + $extension->setBundleProductOptions($options); + $product->setExtensionAttributes($extension); +} +$product->save(); + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +$addressData = include __DIR__ . '/../../../Magento/Sales/_files/address_data.php'; + +$billingAddress = $objectManager->create(\Magento\Sales\Model\Order\Address::class, ['data' => $addressData]); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType('shipping'); + +$payment = $objectManager->create(\Magento\Sales\Model\Order\Payment::class); +$payment->setMethod('checkmo'); + +/** @var $product \Magento\Catalog\Model\Product */ +$product = $objectManager->create(\Magento\Catalog\Model\Product::class); +$product->load(3); + +/** @var $typeInstance \Magento\Bundle\Model\Product\Type */ +$typeInstance = $product->getTypeInstance(); +$typeInstance->setStoreFilter($product->getStoreId(), $product); +$optionCollection = $typeInstance->getOptionsCollection($product); + +$bundleOptions = []; +$bundleOptionsQty = []; +$optionsData = []; +foreach ($optionCollection as $option) { + /** @var $option \Magento\Bundle\Model\Option */ + $selectionsCollection = $typeInstance->getSelectionsCollection([$option->getId()], $product); + if ($option->isMultiSelection()) { + $optionsData[$option->getId()] = array_column($selectionsCollection->toArray(), 'product_id'); + $bundleOptions[$option->getId()] = array_column($selectionsCollection->toArray(), 'selection_id'); + } else { + $bundleOptions[$option->getId()] = $selectionsCollection->getFirstItem()->getSelectionId(); + $optionsData[$option->getId()] = $selectionsCollection->getFirstItem()->getProductId(); + } + $bundleOptionsQty[$option->getId()] = 1; +} + +$requestInfo = [ + 'product' => $product->getId(), + 'bundle_option' => $bundleOptions, + 'bundle_option_qty' => $bundleOptionsQty, + 'qty' => 1, +]; + +$orderItems = []; +/** @var \Magento\Sales\Model\Order\Item $orderItem */ +$orderItem = $objectManager->create(\Magento\Sales\Model\Order\Item::class); +$orderItem->setProductId($product->getId()); +$orderItem->setQtyOrdered(1); +$orderItem->setBasePrice($product->getPrice()); +$orderItem->setPrice($product->getPrice()); +$orderItem->setRowTotal($product->getPrice()); +$orderItem->setProductType($product->getTypeId()); +$orderItem->setProductOptions(['info_buyRequest' => $requestInfo]); + +$orderItems[] = $orderItem; + +foreach ($optionsData as $optionId => $productId) { + /** @var $selectedProduct \Magento\Catalog\Model\Product */ + $selectedProduct = $objectManager->create(\Magento\Catalog\Model\Product::class); + $selectedProduct->load($productId); + + /** @var \Magento\Sales\Model\Order\Item $orderItem */ + $orderItem = $objectManager->create(\Magento\Sales\Model\Order\Item::class); + $orderItem->setProductId($productId); + $orderItem->setQtyOrdered(1); + $orderItem->setBasePrice($selectedProduct->getPrice()); + $orderItem->setPrice($selectedProduct->getPrice()); + $orderItem->setRowTotal($selectedProduct->getPrice()); + $orderItem->setProductType($selectedProduct->getTypeId()); + $orderItem->setProductOptions(['info_buyRequest' => $requestInfo]); + $orderItems[] = $orderItem; +} + +/** @var \Magento\Sales\Model\Order $order */ +$order = $objectManager->create(\Magento\Sales\Model\Order::class); +$order->setIncrementId('100000001'); +$order->setState(\Magento\Sales\Model\Order::STATE_NEW); +$order->setStatus($order->getConfig()->getStateDefaultStatus(\Magento\Sales\Model\Order::STATE_NEW)); +$order->setCustomerIsGuest(true); +$order->setCustomerEmail('customer@null.com'); +$order->setCustomerFirstname('firstname'); +$order->setCustomerLastname('lastname'); +$order->setBillingAddress($billingAddress); +$order->setShippingAddress($shippingAddress); +$order->setAddresses([$billingAddress, $shippingAddress]); +$order->setPayment($payment); + +foreach ($orderItems as $item) { + $order->addItem($item); +} + +$order->setStoreId($objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->getStore()->getId()); +$order->setSubtotal(100); +$order->setBaseSubtotal(100); +$order->setBaseGrandTotal(100); +$order->save(); diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_separately_rollback.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_separately_rollback.php new file mode 100644 index 0000000000000..9a04b3d7ae8ce --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/order_with_bundle_shipped_separately_rollback.php @@ -0,0 +1,8 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +require __DIR__ . '/product_rollback.php'; +require __DIR__ . '/../../../Magento/Sales/_files/default_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php index 19923daf81c88..4a3d5d2e28afe 100644 --- a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php +++ b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/Product/Type/BundleTest.php @@ -104,6 +104,18 @@ public function testBundleImport() $optionSku = 'Simple ' . ($optionKey + 1 + $linkKey); $this->assertEquals($optionIdList[$optionSku], $productLink->getData('entity_id')); $this->assertEquals($optionSku, $productLink->getData('sku')); + + switch ($optionKey + 1 + $linkKey) { + case 1: + $this->assertEquals(1, (int) $productLink->getCanChangeQuantity()); + break; + case 2: + $this->assertEquals(0, (int) $productLink->getCanChangeQuantity()); + break; + case 3: + $this->assertEquals(1, (int) $productLink->getCanChangeQuantity()); + break; + } } } } diff --git a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/_files/import_bundle.csv b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/_files/import_bundle.csv index 43e3d04c62e61..fdb3f39327a06 100644 --- a/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/_files/import_bundle.csv +++ b/dev/tests/integration/testsuite/Magento/BundleImportExport/Model/Import/_files/import_bundle.csv @@ -2,4 +2,4 @@ sku,store_view_code,attribute_set_code,product_type,product_websites,name,produc Simple 1,,Default,simple,base,Simple 1,1,100,,1000,0,1,,,,, Simple 2,,Default,simple,base,Simple 2,1,200,,1000,0,1,,,,, Simple 3,,Default,simple,base,Simple 3,1,300,,1000,0,1,,,,, -Bundle 1,,Default,bundle,base,Bundle 1,1,,shipment_type=separately,0,0,1,dynamic,dynamic,Price range,dynamic,"name=Option 1,type=checkbox,required=1,sku=Simple 1,price=0.0000,default=0,default_qty=1.0000,price_type=fixed|name=Option 2,type=checkbox,required=1,sku=Simple 2,price=0.0000,default=0,default_qty=1.0000,price_type=fixed|name=Option 2,type=checkbox,required=1,sku=Simple 3,price=0.0000,default=0,default_qty=1.0000,price_type=fixed" +Bundle 1,,Default,bundle,base,Bundle 1,1,,shipment_type=separately,0,0,1,dynamic,dynamic,Price range,dynamic,"name=Option 1,type=checkbox,required=1,sku=Simple 1,price=0.0000,default=0,default_qty=1.0000,price_type=fixed,can_change_qty=1|name=Option 2,type=checkbox,required=1,sku=Simple 2,price=0.0000,default=0,default_qty=1.0000,price_type=fixed,can_change_qty=0|name=Option 2,type=checkbox,required=1,sku=Simple 3,price=0.0000,default=0,default_qty=1.0000,price_type=fixed" diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php index 17c0f451f9083..f68e509e4a8dd 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/ListTest.php @@ -55,6 +55,10 @@ public function testToolbarCoverage() $parent = $this->_getLayout()->createBlock(\Magento\Catalog\Block\Product\ListProduct::class, 'parent'); /* Prepare toolbar block */ + $this->_getLayout() + ->createBlock(\Magento\Catalog\Block\Product\ProductList\Toolbar::class, 'product_list_toolbar'); + $parent->setToolbarBlockName('product_list_toolbar'); + $toolbar = $parent->getToolbarBlock(); $this->assertInstanceOf(\Magento\Catalog\Block\Product\ProductList\Toolbar::class, $toolbar, 'Default Toolbar'); diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ActionTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ActionTest.php index 90825ab573d09..39905aeae10f5 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ActionTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/ActionTest.php @@ -84,6 +84,73 @@ public function testUpdateWebsites() } } + /** + * @magentoDataFixture Magento/ConfigurableProduct/_files/product_configurable.php + * @magentoAppArea adminhtml + * @param string $status + * @param string $productsCount + * @dataProvider updateAttributesDataProvider + */ + public function testUpdateAttributes($status, $productsCount) + { + /** @var \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry */ + $indexerRegistry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Framework\Indexer\IndexerRegistry::class); + $indexerRegistry->get(Fulltext::INDEXER_ID)->setScheduled(false); + + /** @var \Magento\Catalog\Api\ProductRepositoryInterface $productRepository */ + $productRepository = $this->objectManager->create(\Magento\Catalog\Api\ProductRepositoryInterface::class); + + /** @var \Magento\Catalog\Model\Product $product */ + $product = $productRepository->get('configurable'); + $productAttributesOptions = $product->getExtensionAttributes()->getConfigurableProductLinks(); + $attrData = ['status' => $status]; + $configurableOptionsId = []; + if (isset($productAttributesOptions)) { + foreach ($productAttributesOptions as $configurableOption) { + $configurableOptionsId[] = $configurableOption; + } + } + $this->action->updateAttributes($configurableOptionsId, $attrData, $product->getStoreId()); + + $categoryFactory = $this->objectManager->create(\Magento\Catalog\Model\CategoryFactory::class); + /** @var \Magento\Catalog\Block\Product\ListProduct $listProduct */ + $listProduct = $this->objectManager->create(\Magento\Catalog\Block\Product\ListProduct::class); + $category = $categoryFactory->create()->load(2); + $layer = $listProduct->getLayer(); + $layer->setCurrentCategory($category); + $productCollection = $layer->getProductCollection(); + $productCollection->joinField( + 'qty', + 'cataloginventory_stock_status', + 'qty', + 'product_id=entity_id', + '{{table}}.stock_id=1', + 'left' + ); + + $this->assertEquals($productsCount, $productCollection->count()); + } + + /** + * DataProvider for testUpdateAttributes + * + * @return array + */ + public function updateAttributesDataProvider() + { + return [ + [ + 'status' => 2, + 'expected_count' => 0 + ], + [ + 'status' => 1, + 'expected_count' => 1 + ], + ]; + } + public static function tearDownAfterClass() { /** @var \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry */ diff --git a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/ProductTest.php b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/ProductTest.php index a118ae99d8a1f..186c6b8a92bb1 100644 --- a/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/ProductTest.php +++ b/dev/tests/integration/testsuite/Magento/CatalogImportExport/Model/ProductTest.php @@ -97,10 +97,16 @@ public function exportImportDataProvider() 'simple-product-image' => [ [ 'Magento/CatalogImportExport/Model/Import/_files/media_import_image.php', - 'Magento/Catalog/_files/product_with_image.php' + 'Magento/Catalog/_files/product_with_image.php', ], [ 'simple', + ], + [ + "image", + "small_image", + "thumbnail", + "media_gallery" ] ], 'simple-product-crosssell' => [ @@ -134,4 +140,32 @@ public function importReplaceDataProvider() { return $this->exportImportDataProvider(); } + + /** + * Fixing https://github.com/magento-engcom/import-export-improvements/issues/50 means that during import images + * can now get renamed for this we need to skip the attribute checking and instead check that the images contain + * the right beginning part of the name. When an image is named "magento_image.jpeg" but there is already an image + * with that name it will now become "magento_image_1.jpeg" + * + * @param \Magento\Catalog\Model\Product $expectedProduct + * @param \Magento\Catalog\Model\Product $actualProduct + */ + protected function assertEqualsSpecificAttributes($expectedProduct, $actualProduct) + { + if (!empty($actualProduct->getImage()) + && !empty($expectedProduct->getImage()) + ) { + $this->assertContains('magento_image', $actualProduct->getImage()); + } + if (!empty($actualProduct->getSmallImage()) + && !empty($expectedProduct->getSmallImage()) + ) { + $this->assertContains('magento_image', $actualProduct->getSmallImage()); + } + if (!empty($actualProduct->getThumbnail()) + && !empty($expectedProduct->getThumbnail()) + ) { + $this->assertContains('magento_image', $actualProduct->getThumbnail()); + } + } } diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php new file mode 100644 index 0000000000000..6509ed62101d0 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFilesTest.php @@ -0,0 +1,114 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; + +use Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Test for \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFiles class. + */ +class DeleteFilesTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFiles + */ + private $model; + + /** + * @var \Magento\Cms\Helper\Wysiwyg\Images + */ + private $imagesHelper; + + /** + * @var \Magento\Framework\Filesystem\Directory\WriteInterface + */ + private $mediaDirectory; + + /** + * @var string + */ + private $fullDirectoryPath; + + /** + * @var string + */ + private $fileName = 'magento_small_image.jpg'; + + /** + * @inheritdoc + */ + protected function setUp() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $directoryName = 'directory1'; + $filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); + /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ + $this->imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot() . '/' . $directoryName; + $this->mediaDirectory->create($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); + $filePath = $this->fullDirectoryPath . DIRECTORY_SEPARATOR . $this->fileName; + $fixtureDir = realpath(__DIR__ . '/../../../../../Catalog/_files'); + copy($fixtureDir . '/' . $this->fileName, $filePath); + $this->model = $objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFiles::class); + } + + /** + * Execute method with correct directory path and file name to check that files under WYSIWYG media directory + * can be removed. + * + * @return void + */ + public function testExecute() + { + $this->model->getRequest()->setMethod('POST') + ->setPostValue('files', [$this->imagesHelper->idEncode($this->fileName)]); + $this->model->getStorage()->getSession()->setCurrentPath($this->fullDirectoryPath); + $this->model->execute(); + + $this->assertFalse( + $this->mediaDirectory->isExist( + $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . '/' . $this->fileName) + ) + ); + } + + /** + * Execute method with traversal file path to check that there is no ability to remove file which is not + * under media directory. + * + * @return void + */ + public function testExecuteWithWrongFileName() + { + $fileName = '/../../../../etc/env.php'; + $this->model->getRequest()->setMethod('POST') + ->setPostValue('files', [$this->imagesHelper->idEncode($fileName)]); + $this->model->getStorage()->getSession()->setCurrentPath($this->fullDirectoryPath); + $this->model->execute(); + + $this->assertTrue( + $this->mediaDirectory->isExist( + $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . $fileName) + ) + ); + } + + /** + * @inheritdoc + */ + public static function tearDownAfterClass() + { + $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Framework\Filesystem::class); + /** @var \Magento\Framework\Filesystem\Directory\WriteInterface $directory */ + $directory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + if ($directory->isExist('wysiwyg')) { + $directory->delete('wysiwyg'); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php new file mode 100644 index 0000000000000..48280d35e38fb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/DeleteFolderTest.php @@ -0,0 +1,106 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; + +use Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Test for \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFolder class. + */ +class DeleteFolderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFolder + */ + private $model; + + /** + * @var \Magento\Cms\Helper\Wysiwyg\Images + */ + private $imagesHelper; + + /** + * @var \Magento\Framework\Filesystem\Directory\WriteInterface + */ + private $mediaDirectory; + + /** + * @var string + */ + private $fullDirectoryPath; + + /** + * @inheritdoc + */ + protected function setUp() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); + $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ + $this->imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->fullDirectoryPath = $this->imagesHelper->getStorageRoot(); + $this->model = $objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\DeleteFolder::class); + } + + /** + * Execute method with correct directory path to check that directories under WYSIWYG media directory + * can be removed. + * + * @return void + */ + public function testExecute() + { + $directoryName = DIRECTORY_SEPARATOR . 'NewDirectory'; + $this->mediaDirectory->create( + $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . $directoryName) + ); + $this->model->getRequest()->setParams(['node' => $this->imagesHelper->idEncode($directoryName)]); + $this->model->execute(); + + $this->assertFalse( + $this->mediaDirectory->isExist( + $this->mediaDirectory->getRelativePath( + $this->fullDirectoryPath . $directoryName + ) + ) + ); + } + + /** + * Execute method with traversal directory path to check that there is no ability to remove folder which is not + * under media directory. + * + * @return void + */ + public function testExecuteWithWrongDirectoryName() + { + $directoryName = '/../../../etc/'; + $this->model->getRequest()->setParams(['node' => $this->imagesHelper->idEncode($directoryName)]); + $this->model->execute(); + + $this->assertTrue( + $this->mediaDirectory->isExist( + $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . $directoryName) + ) + ); + } + + /** + * @inheritdoc + */ + public static function tearDownAfterClass() + { + $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Framework\Filesystem::class); + /** @var \Magento\Framework\Filesystem\Directory\WriteInterface $directory */ + $directory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + if ($directory->isExist('wysiwyg')) { + $directory->delete('wysiwyg'); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php new file mode 100644 index 0000000000000..b20b5a04a2a50 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/NewFolderTest.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; + +use Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Test for \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\NewFolder class. + */ +class NewFolderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\NewFolder + */ + private $model; + + /** + * @var \Magento\Framework\Filesystem\Directory\WriteInterface + */ + private $mediaDirectory; + + /** + * @var string + */ + private $fullDirectoryPath; + + /** + * @var string + */ + private $dirName= 'NewDirectory'; + + /** + * @inheritdoc + */ + protected function setUp() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); + $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ + $imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->fullDirectoryPath = $imagesHelper->getStorageRoot(); + $this->model = $objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\NewFolder::class); + } + + /** + * Execute method with correct directory path to check that new folder can be created under WYSIWYG media directory. + * + * @return void + */ + public function testExecute() + { + $this->model->getRequest()->setMethod('POST') + ->setPostValue('name', $this->dirName); + $this->model->getStorage()->getSession()->setCurrentPath($this->fullDirectoryPath); + $this->model->execute(); + + $this->assertTrue( + $this->mediaDirectory->isExist( + $this->mediaDirectory->getRelativePath( + $this->fullDirectoryPath . DIRECTORY_SEPARATOR . $this->dirName + ) + ) + ); + } + + /** + * Execute method with traversal directory path to check that there is no ability to create new folder not + * under media directory. + * + * @return void + */ + public function testExecuteWithWrongPath() + { + $dirPath = '/../../../'; + $this->model->getRequest()->setMethod('POST') + ->setPostValue('name', $this->dirName); + $this->model->getStorage()->getSession()->setCurrentPath($this->fullDirectoryPath . $dirPath); + $this->model->execute(); + + $this->assertFalse( + $this->mediaDirectory->isExist( + $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . $dirPath . $this->dirName) + ) + ); + } + + /** + * @inheritdoc + */ + public static function tearDownAfterClass() + { + $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Framework\Filesystem::class); + /** @var \Magento\Framework\Filesystem\Directory\WriteInterface $directory */ + $directory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + if ($directory->isExist('wysiwyg')) { + $directory->delete('wysiwyg'); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php new file mode 100644 index 0000000000000..ba2527e3e449e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Cms/Controller/Adminhtml/Wysiwyg/Images/UploadTest.php @@ -0,0 +1,140 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Cms\Controller\Adminhtml\Wysiwyg\Images; + +use Magento\Framework\App\Filesystem\DirectoryList; + +/** + * Test for \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\Upload class. + */ +class UploadTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\Upload + */ + private $model; + + /** + * @var \Magento\Framework\Filesystem\Directory\WriteInterface + */ + private $mediaDirectory; + + /** + * @var string + */ + private $fullDirectoryPath; + + /** + * @var string + */ + private $fileName = 'magento_small_image.jpg'; + + /** + * @inheritdoc + */ + protected function setUp() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $directoryName = 'directory1'; + $filesystem = $objectManager->get(\Magento\Framework\Filesystem::class); + /** @var \Magento\Cms\Helper\Wysiwyg\Images $imagesHelper */ + $imagesHelper = $objectManager->get(\Magento\Cms\Helper\Wysiwyg\Images::class); + $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + $this->fullDirectoryPath = $imagesHelper->getStorageRoot() . DIRECTORY_SEPARATOR . $directoryName; + $this->mediaDirectory->create($this->mediaDirectory->getRelativePath($this->fullDirectoryPath)); + $this->model = $objectManager->get(\Magento\Cms\Controller\Adminhtml\Wysiwyg\Images\Upload::class); + $fixtureDir = realpath(__DIR__ . '/../../../../../Catalog/_files'); + $tmpFile = __DIR__ . DIRECTORY_SEPARATOR . $this->fileName; + copy($fixtureDir . DIRECTORY_SEPARATOR . $this->fileName, $tmpFile); + $_FILES = [ + 'image' => [ + 'name' => $this->fileName, + 'type' => 'image/png', + 'tmp_name' => $tmpFile, + 'error' => 0, + 'size' => filesize($fixtureDir), + ], + ]; + } + + /** + * Execute method with correct directory path and file name to check that file can be uploaded to the directory + * located under WYSIWYG media. + * + * @return void + */ + public function testExecute() + { + $this->model->getRequest()->setParams(['type' => 'image/png']); + $this->model->getStorage()->getSession()->setCurrentPath($this->fullDirectoryPath); + $this->model->execute(); + + $this->assertTrue( + $this->mediaDirectory->isExist( + $this->mediaDirectory->getRelativePath( + $this->fullDirectoryPath . DIRECTORY_SEPARATOR . $this->fileName + ) + ) + ); + } + + /** + * Execute method with traversal directory path to check that there is no ability to create file not + * under media directory. + * + * @return void + */ + public function testExecuteWithWrongPath() + { + $dirPath = '/../../../etc/'; + $this->model->getRequest()->setParams(['type' => 'image/png']); + $this->model->getStorage()->getSession()->setCurrentPath($dirPath); + $this->model->execute(); + + $this->assertFalse( + $this->mediaDirectory->isExist( + $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . $dirPath . $this->fileName) + ) + ); + } + + /** + * Execute method with traversal file path to check that there is no ability to create file not + * under media directory. + * + * @return void + */ + public function testExecuteWithWrongFileName() + { + $newFilename = '/../../../../etc/new_file.png'; + $_FILES['image']['name'] = $newFilename; + $_FILES['image']['tmp_name'] = __DIR__ . DIRECTORY_SEPARATOR . $this->fileName; + $this->model->getRequest()->setParams(['type' => 'image/png']); + $this->model->getStorage()->getSession()->setCurrentPath($this->fullDirectoryPath); + $this->model->execute(); + + $this->assertFalse( + $this->mediaDirectory->isExist( + $this->mediaDirectory->getRelativePath($this->fullDirectoryPath . $newFilename) + ) + ); + } + + /** + * @inheritdoc + */ + public static function tearDownAfterClass() + { + $filesystem = \Magento\TestFramework\Helper\Bootstrap::getObjectManager() + ->get(\Magento\Framework\Filesystem::class); + /** @var \Magento\Framework\Filesystem\Directory\WriteInterface $directory */ + $directory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); + if ($directory->isExist('wysiwyg')) { + $directory->delete('wysiwyg'); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/ConfigTest.php index de6290f63d93f..201a08fa539ea 100644 --- a/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/ConfigTest.php +++ b/dev/tests/integration/testsuite/Magento/Cms/Model/Wysiwyg/ConfigTest.php @@ -5,6 +5,9 @@ */ namespace Magento\Cms\Model\Wysiwyg; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestModuleWysiwygConfig\Model\Config as TestModuleWysiwygConfig; + /** * @magentoAppArea adminhtml */ @@ -13,18 +16,12 @@ class ConfigTest extends \PHPUnit\Framework\TestCase /** * @var \Magento\Cms\Model\Wysiwyg\Config */ - protected $_model; + private $model; protected function setUp() { - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\Config\ScopeInterface::class - )->setCurrentScope( - \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE - ); - $this->_model = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Cms\Model\Wysiwyg\Config::class - ); + $objectManager = Bootstrap::getObjectManager(); + $this->model = $objectManager->create(\Magento\Cms\Model\Wysiwyg\Config::class); } /** @@ -32,7 +29,7 @@ protected function setUp() */ public function testGetConfig() { - $config = $this->_model->getConfig(); + $config = $this->model->getConfig(); $this->assertInstanceOf(\Magento\Framework\DataObject::class, $config); } @@ -41,45 +38,28 @@ public function testGetConfig() */ public function testGetConfigCssUrls() { - $config = $this->_model->getConfig(); + $config = $this->model->getConfig(); $publicPathPattern = 'http://localhost/pub/static/%s/adminhtml/Magento/backend/en_US/mage/%s'; $tinyMce4Config = $config->getData('tinymce4'); $this->assertStringMatchesFormat($publicPathPattern, $tinyMce4Config['content_css']); } /** - * @return array + * Test enabled module is able to modify WYSIWYG config + * @return void + * + * @magentoConfigFixture default/cms/wysiwyg/editor testAdapter */ - public function getConfigNoProcessingDataProvider() + public function testEnabledModuleIsAbleToModifyConfig() { - return [ - [ - [ - 'files_browser_window_url' => 'http://example.com/111/', - 'directives_url' => 'http://example.com/222/', - 'popup_css' => 'http://example.com/333/popup.css', - 'content_css' => 'http://example.com/444/content.css', - 'directives_url_quoted' => 'http://example.com/555/', - ], - ], - [ - [ - 'files_browser_window_url' => '/111/', - 'directives_url' => '/222/', - 'popup_css' => '/333/popup.css', - 'content_css' => '/444/content.css', - 'directives_url_quoted' => '/555/', - ] - ], - [ - [ - 'files_browser_window_url' => '111/', - 'directives_url' => '222/', - 'popup_css' => '333/popup.css', - 'content_css' => '444/content.css', - 'directives_url_quoted' => '555/', - ] - ] - ]; + $objectManager = Bootstrap::getObjectManager(); + $compositeConfigProvider = $objectManager->create(\Magento\Cms\Model\Wysiwyg\CompositeConfigProvider::class); + $model = $objectManager->create( + \Magento\Cms\Model\Wysiwyg\Config::class, + ['configProvider' => $compositeConfigProvider] + ); + $config = $model->getConfig(); + $this->assertEquals(TestModuleWysiwygConfig::CONFIG_HEIGHT, $config['height']); + $this->assertEquals(TestModuleWysiwygConfig::CONFIG_CONTENT_CSS, $config['content_css']); } } diff --git a/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/FieldArray.php b/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/FieldArray.php new file mode 100644 index 0000000000000..53e5db67d0733 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/FieldArray.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Config\Block\System\Config; + +use Magento\Config\Block\System\Config\Form\Field\FieldArray\AbstractFieldArray; + +/** + * Backend system config array field renderer for integration test. + */ +class FieldArray extends AbstractFieldArray +{ + /** + * @inheritdoc + */ + protected function _toHtml() + { + $value = ''; + $element = $this->getElement(); + if ($element->getValue() && is_array($element->getValue())) { + $value = implode('|', $element->getValue()); + } + + return sprintf( + '<input id="%s" name="%s" value="%s" />', + $element->getId(), + $element->getName(), + $value + ); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/FormTest.php b/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/FormTest.php index 032b852f64c33..e78f4831831ac 100644 --- a/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/FormTest.php +++ b/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/FormTest.php @@ -5,7 +5,11 @@ */ namespace Magento\Config\Block\System\Config; +use Magento\Backend\App\Area\FrontNameResolver; use Magento\Framework\App\Cache\State; +use Magento\Framework\Config\ScopeInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\Helper\Xpath; /** * @magentoAppArea adminhtml @@ -16,50 +20,68 @@ class FormTest extends \PHPUnit\Framework\TestCase /** * @var \Magento\Framework\ObjectManagerInterface */ - protected $_objectManager; + private $objectManager; /** * @var \Magento\Framework\Data\FormFactory */ - protected $_formFactory; + private $formFactory; /** * @var \Magento\Config\Model\Config\Structure\Element\Section */ - protected $_section; + private $section; /** * @var \Magento\Config\Model\Config\Structure\Element\Group */ - protected $_group; + private $group; /** * @var \Magento\Config\Model\Config\Structure\Element\Field */ - protected $_field; + private $field; /** * @var array */ - protected $_configData; + private $configData; + + /** @var string Encrypted value stored in config.xml */ + private static $defaultConfigEncrypted = 'Encrypted value'; + + /** @var array Serialized value stored in config.xml */ + private static $defaultConfigSerialized = ['value1', 'value2']; + + /** @var string Serialized value stored in config.xml */ + private static $defaultConfigString = 'test config value'; + + /** @var string Encrypted value stored in DB */ + private static $websiteDbEncrypted = 'DB encrypted value'; + + /** @var array Serialized value stored in DB */ + private static $websiteDbSerialized = ['value3', 'value4']; + + /** @var string String value stored in DB */ + private static $websiteDBString = 'test db value'; protected function setUp() { - $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); - $this->_formFactory = $this->_objectManager->create(\Magento\Framework\Data\FormFactory::class); + $this->objectManager = Bootstrap::getObjectManager(); + $this->formFactory = $this->objectManager->create(\Magento\Framework\Data\FormFactory::class); } public function testDependenceHtml() { /** @var $layout \Magento\Framework\View\LayoutInterface */ - $layout = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( + $layout = Bootstrap::getObjectManager()->create( \Magento\Framework\View\Layout::class, ['area' => 'adminhtml'] ); - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\Config\ScopeInterface::class + Bootstrap::getObjectManager()->get( + ScopeInterface::class )->setCurrentScope( - \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE + FrontNameResolver::AREA_CODE ); /** @var $block \Magento\Config\Block\System\Config\Form */ $block = $layout->createBlock(\Magento\Config\Block\System\Config\Form::class, 'block'); @@ -92,76 +114,76 @@ public function testInitFieldsUseDefaultCheckbox( ) { $this->_setupFieldsInheritCheckbox($fieldId, $isConfigDataEmpty, $configDataValue); - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\Config\ScopeInterface::class + Bootstrap::getObjectManager()->get( + ScopeInterface::class )->setCurrentScope( - \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE + FrontNameResolver::AREA_CODE ); - $form = $this->_formFactory->create(); - $fieldset = $form->addFieldset($this->_section->getId() . '_' . $this->_group->getId(), []); + $form = $this->formFactory->create(); + $fieldset = $form->addFieldset($this->section->getId() . '_' . $this->group->getId(), []); /* @TODO Eliminate stub by proper mock / config fixture usage */ - /** @var $block \Magento\Config\Block\System\Config\FormStub */ - $block = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + /** @var $block FormStub */ + $block = Bootstrap::getObjectManager()->get( \Magento\Framework\View\LayoutInterface::class )->createBlock( - \Magento\Config\Block\System\Config\FormStub::class + FormStub::class ); $block->setScope(\Magento\Config\Block\System\Config\Form::SCOPE_WEBSITES); - $block->setStubConfigData($this->_configData); - $block->initFields($fieldset, $this->_group, $this->_section); + $block->setStubConfigData($this->configData); + $block->initFields($fieldset, $this->group, $this->section); $valueSel = sprintf( '//input[@id="%s_%s_%s"]', - $this->_section->getId(), - $this->_group->getId(), - $this->_field->getId() + $this->section->getId(), + $this->group->getId(), + $this->field->getId() ); $valueDisabledSel = sprintf('%s[@disabled="disabled"]', $valueSel); $useDefaultSel = sprintf( '//input[@id="%s_%s_%s_inherit" and contains(@class,"checkbox")]', - $this->_section->getId(), - $this->_group->getId(), - $this->_field->getId() + $this->section->getId(), + $this->group->getId(), + $this->field->getId() ); $useDefaultCheckedSel = sprintf('%s[@checked="checked"]', $useDefaultSel); $fieldsetHtml = $fieldset->getElementHtml(); $this->assertGreaterThanOrEqual( 1, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath('//fieldset', $fieldsetHtml), + Xpath::getElementsCountForXpath('//fieldset', $fieldsetHtml), 'Fieldset HTML is invalid' ); $this->assertEquals( $valueSelCtr, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath($valueSel, $fieldsetHtml), + Xpath::getElementsCountForXpath($valueSel, $fieldsetHtml), 'Field input should appear ' . $valueSelCtr . ' times in fieldset HTML' ); $this->assertEquals( $valueSelCtr, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath($useDefaultSel, $fieldsetHtml), + Xpath::getElementsCountForXpath($useDefaultSel, $fieldsetHtml), '"Use Default" checkbox should appear' . $valueSelCtr . ' times in fieldset HTML.' ); if ($expectedUseDefault) { $this->assertGreaterThanOrEqual( 1, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath($useDefaultCheckedSel, $fieldsetHtml), + Xpath::getElementsCountForXpath($useDefaultCheckedSel, $fieldsetHtml), '"Use Default" checkbox should be checked' ); $this->assertGreaterThanOrEqual( 1, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath($valueDisabledSel, $fieldsetHtml), + Xpath::getElementsCountForXpath($valueDisabledSel, $fieldsetHtml), 'Field input should be disabled' ); } else { $this->assertEquals( 0, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath($useDefaultCheckedSel, $fieldsetHtml), + Xpath::getElementsCountForXpath($useDefaultCheckedSel, $fieldsetHtml), '"Use Default" checkbox should not be checked' ); $this->assertEquals( 0, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath($valueDisabledSel, $fieldsetHtml), + Xpath::getElementsCountForXpath($valueDisabledSel, $fieldsetHtml), 'Field input should not be disabled' ); } @@ -195,36 +217,36 @@ public function testInitFieldsUseConfigPath($fieldId, $isConfigDataEmpty, $confi { $this->_setupFieldsInheritCheckbox($fieldId, $isConfigDataEmpty, $configDataValue); - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\Config\ScopeInterface::class + Bootstrap::getObjectManager()->get( + ScopeInterface::class )->setCurrentScope( - \Magento\Backend\App\Area\FrontNameResolver::AREA_CODE + FrontNameResolver::AREA_CODE ); - $form = $this->_formFactory->create(); - $fieldset = $form->addFieldset($this->_section->getId() . '_' . $this->_group->getId(), []); + $form = $this->formFactory->create(); + $fieldset = $form->addFieldset($this->section->getId() . '_' . $this->group->getId(), []); /* @TODO Eliminate stub by proper mock / config fixture usage */ - /** @var $block \Magento\Config\Block\System\Config\FormStub */ - $block = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + /** @var $block FormStub */ + $block = Bootstrap::getObjectManager()->get( \Magento\Framework\View\LayoutInterface::class )->createBlock( - \Magento\Config\Block\System\Config\FormStub::class + FormStub::class ); $block->setScope(\Magento\Config\Block\System\Config\Form::SCOPE_DEFAULT); - $block->setStubConfigData($this->_configData); - $block->initFields($fieldset, $this->_group, $this->_section); + $block->setStubConfigData($this->configData); + $block->initFields($fieldset, $this->group, $this->section); $valueSel = sprintf( '//input[@id="%s_%s_%s"]', - $this->_section->getId(), - $this->_group->getId(), - $this->_field->getId() + $this->section->getId(), + $this->group->getId(), + $this->field->getId() ); $fieldsetHtml = $fieldset->getElementHtml(); $this->assertGreaterThanOrEqual( 1, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath( + Xpath::getElementsCountForXpath( '//fieldset', $fieldsetHtml ), @@ -233,7 +255,7 @@ public function testInitFieldsUseConfigPath($fieldId, $isConfigDataEmpty, $confi $this->assertEquals( $valueSelCtr, - \Magento\TestFramework\Helper\Xpath::getElementsCountForXpath( + Xpath::getElementsCountForXpath( $valueSel, $fieldsetHtml ), @@ -256,6 +278,98 @@ public static function initFieldsUseConfigPathDataProvider() ]; } + /** + * Test cases with retrieving config data with backend models for different scopes. + * Config data are stored in config.xml and database. + * + * @param string $fieldId + * @param string $expectedConfigValue + * @param string $currentScope + * @param string $currentScopeCode + * @param bool $isDbOverrideValue whether values should be overridden in the database for the current scope + * + * @dataProvider initFieldsWithBackendModelDataProvider + * @covers \Magento\Config\Block\System\Config\Form::initFields + */ + public function testInitFieldsWithBackendModel( + $fieldId, + $expectedConfigValue, + $currentScope, + $currentScopeCode, + $isDbOverrideValue + ) { + $this->_setupFieldsInheritCheckbox($fieldId, false, $expectedConfigValue); + + if ($isDbOverrideValue) { + $backendModel = $this->field->getAttribute('backend_model') ? : \Magento\Framework\App\Config\Value::class; + $path = $this->section->getId() .'/'. $this->group->getId() . '/' . $this->field->getId(); + $model = Bootstrap::getObjectManager()->create($backendModel); + $model->setPath($path); + $model->setScopeId($currentScopeCode); + $model->setScope($currentScope); + $model->setScopeCode($currentScopeCode); + $model->setValue($expectedConfigValue); + $model->save(); + } + + $this->registerTestConfigXmlMetadata(); + Bootstrap::getObjectManager()->get(\Magento\TestFramework\App\Config::class)->clean(); + + $form = $this->formFactory->create(); + $fieldset = $form->addFieldset($this->section->getId() . '_' . $this->group->getId(), []); + + /** @var $block FormStub */ + $block = Bootstrap::getObjectManager()->get( + \Magento\Framework\View\LayoutInterface::class + )->createBlock( + FormStub::class + ); + + $block->setScope($currentScope); + $block->setScopeCode($currentScopeCode); + $block->setStubConfigData($this->configData); + $block->initFields($fieldset, $this->group, $this->section); + + $fieldsetHtml = $fieldset->getElementHtml(); + + $elementId = $this->section->getId() .'_'. $this->group->getId() . '_' . $this->field->getId(); + if (is_array($expectedConfigValue)) { + $expectedConfigValue = implode('|', $expectedConfigValue); + } + $this->assertEquals( + $expectedConfigValue, + $this->getElementAttributeValueById($fieldsetHtml, $elementId) + ); + } + + /** + * Provides config data variations with different data types and scopes. + * + * @return array + */ + public static function initFieldsWithBackendModelDataProvider() + { + return [ + /** Values stored in config.xml only for default scope, then retrieved for default scope. */ + ['test_field_encrypted', self::$defaultConfigEncrypted, FormStub::SCOPE_DEFAULT, 0, false], + ['test_field_serialized', self::$defaultConfigSerialized, FormStub::SCOPE_DEFAULT, 0, false], + ['test_field', self::$defaultConfigString, FormStub::SCOPE_DEFAULT, 0, false], + + /** Values stored in config.xml only for default scope, then retrieved for website scope. */ + ['test_field_encrypted', self::$defaultConfigEncrypted, FormStub::SCOPE_WEBSITES, 1, false], + ['test_field_serialized', self::$defaultConfigSerialized, FormStub::SCOPE_WEBSITES, 1, false], + ['test_field', self::$defaultConfigString, FormStub::SCOPE_WEBSITES, 1, false], + + /** + * Values stored in config.xml for default scope and in database for website scope, + * then retrieved for website scope. + */ + ['test_field_encrypted', self::$websiteDbEncrypted, FormStub::SCOPE_WEBSITES, 1, true], + ['test_field_serialized', self::$websiteDbSerialized, FormStub::SCOPE_WEBSITES, 1, true], + ['test_field', self::$websiteDBString, FormStub::SCOPE_WEBSITES, 1, true], + ]; + } + /** * @param string $fieldId uses the test_field_use_config field if true * @param bool $isConfigDataEmpty if the config data array should be empty or not @@ -263,28 +377,28 @@ public static function initFieldsUseConfigPathDataProvider() */ protected function _setupFieldsInheritCheckbox($fieldId, $isConfigDataEmpty, $configDataValue) { - \Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize([ + Bootstrap::getInstance()->reinitialize([ State::PARAM_BAN_CACHE => true, ]); - \Magento\TestFramework\Helper\Bootstrap::getObjectManager() - ->get(\Magento\Framework\Config\ScopeInterface::class) - ->setCurrentScope(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE); - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Framework\App\AreaList::class) - ->getArea(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE) + Bootstrap::getObjectManager() + ->get(ScopeInterface::class) + ->setCurrentScope(FrontNameResolver::AREA_CODE); + Bootstrap::getObjectManager()->get(\Magento\Framework\App\AreaList::class) + ->getArea(FrontNameResolver::AREA_CODE) ->load(\Magento\Framework\App\Area::PART_CONFIG); $fileResolverMock = $this->getMockBuilder( \Magento\Framework\App\Config\FileResolver::class )->disableOriginalConstructor()->getMock(); - $fileIteratorFactory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + $fileIteratorFactory = Bootstrap::getObjectManager()->get( \Magento\Framework\Config\FileIteratorFactory::class ); $fileIterator = $fileIteratorFactory->create( - [__DIR__ . '/_files/test_section_config.xml'] + [__DIR__ . '/_files/test_system.xml'] ); $fileResolverMock->expects($this->any())->method('get')->will($this->returnValue($fileIterator)); - $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $objectManager = Bootstrap::getObjectManager(); $structureReader = $objectManager->create( \Magento\Config\Model\Config\Structure\Reader::class, @@ -300,34 +414,34 @@ protected function _setupFieldsInheritCheckbox($fieldId, $isConfigDataEmpty, $co ['structureData' => $structureData] ); - $this->_section = $structure->getElement('test_section'); + $this->section = $structure->getElement('test_section'); - $this->_group = $structure->getElement('test_section/test_group'); + $this->group = $structure->getElement('test_section/test_group'); - $this->_field = $structure->getElement('test_section/test_group/' . $fieldId); + $this->field = $structure->getElement('test_section/test_group/' . $fieldId); - $fieldPath = $this->_field->getConfigPath(); + $fieldPath = $this->field->getConfigPath(); if ($isConfigDataEmpty) { - $this->_configData = []; + $this->configData = []; } else { - $this->_configData = [$fieldPath => $configDataValue]; + $this->configData = [$fieldPath => $configDataValue]; } } public function testInitFormAddsFieldsets() { - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + Bootstrap::getObjectManager()->get( \Magento\Framework\App\ResponseInterface::class )->headersSentThrowsException = false; - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + Bootstrap::getObjectManager()->get( \Magento\Framework\App\RequestInterface::class )->setParam( 'section', 'general' ); /** @var $block \Magento\Config\Block\System\Config\Form */ - $block = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( + $block = Bootstrap::getObjectManager()->get( \Magento\Framework\View\LayoutInterface::class )->createBlock( \Magento\Config\Block\System\Config\Form::class @@ -383,4 +497,100 @@ public function testInitFormAddsFieldsets() } } } + + /** + * Add metadata from test_config.xml to metadataConfigTypeProcessor. + */ + private function registerTestConfigXmlMetadata() + { + /** @var \Magento\Framework\Encryption\EncryptorInterface $encryptor */ + $encryptor = Bootstrap::getObjectManager()->get(\Magento\Framework\Encryption\EncryptorInterface::class); + $this->setEncryptedValue( + $encryptor->encrypt(self::$defaultConfigEncrypted) + ); + + $fileResolver = Bootstrap::getObjectManager()->create(\Magento\Framework\Config\FileResolverInterface::class); + $directories = $fileResolver->get('config.xml', 'global'); + + $property = new \ReflectionProperty($directories, 'paths'); + $property->setAccessible(true); + $property->setValue( + $directories, + array_merge($property->getValue($directories), [__DIR__ . '/_files/test_config.xml']) + ); + + $fileResolverMock = $this->getMockForAbstractClass(\Magento\Framework\Config\FileResolverInterface::class); + $fileResolverMock->method('get')->willReturn($directories); + + $initialReader = Bootstrap::getObjectManager()->create( + \Magento\Framework\App\Config\Initial\Reader::class, + ['fileResolver' => $fileResolverMock] + ); + + $initialConfig = Bootstrap::getObjectManager()->create( + \Magento\Framework\App\Config\Initial::class, + ['reader' => $initialReader] + ); + $metadataConfigTypeProcessor = Bootstrap::getObjectManager()->create( + \Magento\Framework\App\Config\MetadataConfigTypeProcessor::class, + ['initialConfig' => $initialConfig] + ); + + $composite = Bootstrap::getObjectManager()->get('systemConfigPostProcessorComposite'); + $property = new \ReflectionProperty($composite, 'processors'); + $property->setAccessible(true); + $processors = $property->getValue($composite); + $processors['metadata'] = $metadataConfigTypeProcessor; + $property->setValue($composite, $processors); + + Bootstrap::getObjectManager()->get(\Magento\TestFramework\App\State::class) + ->setAreaCode(FrontNameResolver::AREA_CODE); + } + + /** + * Finds element by id and returns value of attribute value property. + * + * @param string $html + * @param string $nodeId + * + * @return string + */ + private function getElementAttributeValueById($html, $nodeId) + { + $domDocument = new \DOMDocument(); + libxml_use_internal_errors(true); + $domDocument->loadHTML($html); + libxml_use_internal_errors(false); + $element = $domDocument->getElementById($nodeId); + + return $element ? $element->attributes->getNamedItem('value')->nodeValue : ''; + } + + /** + * Save encrypted value to test_config.xml + * + * @param string $encryptedValue + */ + private function setEncryptedValue($encryptedValue) + { + $config = simplexml_load_file(__DIR__ . '/_files/test_config.xml'); + $config->default->test_section->test_group->test_field_encrypted = $encryptedValue; + $config->asXml(__DIR__ . '/_files/test_config.xml'); + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + $this->setEncryptedValue('{ENCRYPTED_VALUE}'); + + $configResourceModel = Bootstrap::getObjectManager()->get(\Magento\Config\Model\ResourceModel\Config::class); + foreach (['test_field_encrypted', 'test_field_serialized', 'test_field'] as $field) { + $path = 'test_section/test_group/' . $field; + $configResourceModel->deleteConfig($path, FormStub::SCOPE_WEBSITES, 1); + } + + parent::tearDown(); + } } diff --git a/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/_files/test_config.xml b/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/_files/test_config.xml new file mode 100644 index 0000000000000..2fd972939117b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/_files/test_config.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd"> + <default> + <test_section> + <test_group> + <test_field_encrypted backend_model="Magento\Config\Model\Config\Backend\Encrypted">{ENCRYPTED_VALUE}</test_field_encrypted> + <test_field_serialized>["value1","value2"]</test_field_serialized> + <test_field>test config value</test_field> + </test_group> + </test_section> + </default> +</config> diff --git a/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/_files/test_section_config.xml b/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/_files/test_section_config.xml deleted file mode 100644 index e77c1773cdce5..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/_files/test_section_config.xml +++ /dev/null @@ -1,36 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd"> - <system> - <tab id="Test"> - <label>Test</label> - </tab> - <section id="test_section" translate="label" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="0"> - <label>Test Section</label> - <tab>Test</tab> - - <group id="test_group" translate="label" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="10"> - <label>Test Group</label> - <field id="test_field" translate="label comment" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="20"> - <label>Test Field</label> - <config_path>test_section/test_group/test_field</config_path> - </field> - <field id="test_field_use_config_module_1" translate="label comment" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="20"> - <label>Test Field</label> - <config_path>test_config_section/test_group_config_node/test_field_value</config_path> - <if_module_enabled>Magento_Config</if_module_enabled> - </field> - <field id="test_field_use_config_module_0" translate="label comment" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="20"> - <label>Test Field</label> - <config_path>test_config_section/test_group_config_node/test_field_value</config_path> - <if_module_enabled>Test_Module</if_module_enabled> - </field> - </group> - </section> - </system> -</config> diff --git a/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/_files/test_system.xml b/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/_files/test_system.xml new file mode 100644 index 0000000000000..a0dca39d8fd28 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Config/Block/System/Config/_files/test_system.xml @@ -0,0 +1,47 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd"> + <system> + <tab id="Test"> + <label>Test</label> + </tab> + <section id="test_section" translate="label" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="0"> + <label>Test Section</label> + <tab>Test</tab> + + <group id="test_group" translate="label" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="10"> + <label>Test Group</label> + <field id="test_field_encrypted" translate="label comment" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="20"> + <label>Test Field</label> + <config_path>test_section/test_group/test_field_encrypted</config_path> + <backend_model>Magento\Config\Model\Config\Backend\Encrypted</backend_model> + </field> + <field id="test_field_serialized" translate="label comment" showInDefault="1" showInWebsite="0" showInStore="0" type="text" sortOrder="20"> + <label>Test Field</label> + <config_path>test_section/test_group/test_field_serialized</config_path> + <frontend_model>Magento\Config\Block\System\Config\FieldArray</frontend_model> + <backend_model>Magento\Config\Model\Config\Backend\Serialized</backend_model> + </field> + <field id="test_field" translate="label comment" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="20"> + <label>Test Field</label> + <config_path>test_section/test_group/test_field</config_path> + </field> + <field id="test_field_use_config_module_1" translate="label comment" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="20"> + <label>Test Field</label> + <config_path>test_config_section/test_group_config_node/test_field_value</config_path> + <if_module_enabled>Magento_Config</if_module_enabled> + </field> + <field id="test_field_use_config_module_0" translate="label comment" showInDefault="1" showInWebsite="1" showInStore="1" type="text" sortOrder="20"> + <label>Test Field</label> + <config_path>test_config_section/test_group_config_node/test_field_value</config_path> + <if_module_enabled>Test_Module</if_module_enabled> + </field> + </group> + </section> + </system> +</config> diff --git a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php index 358742ae69ee8..f68f3cf37b079 100644 --- a/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php +++ b/dev/tests/integration/testsuite/Magento/Config/Console/Command/ConfigSetCommandTest.php @@ -142,7 +142,7 @@ private function loadConfig() * @magentoDbIsolation enabled * @dataProvider runLockDataProvider */ - public function testRunLock($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) + public function testRunLockEnv($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null) { $this->inputMock->expects($this->any()) ->method('getArgument') @@ -153,15 +153,15 @@ public function testRunLock($path, $value, $scope = ScopeConfigInterface::SCOPE_ $this->inputMock->expects($this->any()) ->method('getOption') ->willReturnMap([ - [ConfigSetCommand::OPTION_LOCK, true], + [ConfigSetCommand::OPTION_LOCK_ENV, true], [ConfigSetCommand::OPTION_SCOPE, $scope], [ConfigSetCommand::OPTION_SCOPE_CODE, $scopeCode] ]); $this->outputMock->expects($this->exactly(2)) ->method('writeln') ->withConsecutive( - ['<info>Value was saved and locked.</info>'], - ['<info>Value was saved and locked.</info>'] + ['<info>Value was saved in app/etc/env.php and locked.</info>'], + ['<info>Value was saved in app/etc/env.php and locked.</info>'] ); /** @var ConfigSetCommand $command */ @@ -218,7 +218,7 @@ public function testRunExtended( [ConfigSetCommand::OPTION_SCOPE, $scope], [ConfigSetCommand::OPTION_SCOPE_CODE, $scopeCode] ]; - $optionsLock = array_merge($options, [[ConfigSetCommand::OPTION_LOCK, true]]); + $optionsLock = array_merge($options, [[ConfigSetCommand::OPTION_LOCK_ENV, true]]); /** @var ConfigPathResolver $resolver */ $resolver = $this->objectManager->get(ConfigPathResolver::class); @@ -234,8 +234,8 @@ public function testRunExtended( ); $this->assertSame(null, $this->arrayManager->get($configPath, $this->loadConfig())); - $this->runCommand($arguments, $optionsLock, '<info>Value was saved and locked.</info>'); - $this->runCommand($arguments, $optionsLock, '<info>Value was saved and locked.</info>'); + $this->runCommand($arguments, $optionsLock, '<info>Value was saved in app/etc/env.php and locked.</info>'); + $this->runCommand($arguments, $optionsLock, '<info>Value was saved in app/etc/env.php and locked.</info>'); $this->assertSame($value, $this->arrayManager->get($configPath, $this->loadConfig())); } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Api/AddressRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Customer/Api/AddressRepositoryTest.php index ebfbdfb0e7c4d..be2f07ce5de62 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Api/AddressRepositoryTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Api/AddressRepositoryTest.php @@ -200,15 +200,50 @@ public function testSaveNewInvalidAddress() ->setId(null) ->setFirstname(null) ->setLastname(null) - ->setCustomerId(1); + ->setCustomerId(1) + ->setRegionId($invalidRegion = 10354); try { $this->repository->save($address); } catch (InputException $exception) { $this->assertEquals('One or more input exceptions have occurred.', $exception->getMessage()); $errors = $exception->getErrors(); - $this->assertCount(2, $errors); + $this->assertCount(3, $errors); $this->assertEquals('"firstname" is required. Enter and try again.', $errors[0]->getLogMessage()); $this->assertEquals('"lastname" is required. Enter and try again.', $errors[1]->getLogMessage()); + $this->assertEquals( + __( + 'Invalid value of "%value" provided for the %fieldName field.', + ['fieldName' => 'regionId', 'value' => $invalidRegion] + ), + $errors[2]->getLogMessage() + ); + } + + $address->setCountryId($invalidCountry = 'invalid_id'); + try { + $this->repository->save($address); + } catch (InputException $exception) { + $this->assertEquals( + 'One or more input exceptions have occurred.', + $exception->getMessage() + ); + $errors = $exception->getErrors(); + $this->assertCount(3, $errors); + $this->assertEquals( + '"firstname" is required. Enter and try again.', + $errors[0]->getLogMessage() + ); + $this->assertEquals( + '"lastname" is required. Enter and try again.', + $errors[1]->getLogMessage() + ); + $this->assertEquals( + __( + 'Invalid value of "%value" provided for the %fieldName field.', + ['fieldName' => 'countryId', 'value' => $invalidCountry] + ), + $errors[2]->getLogMessage() + ); } } diff --git a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/NewsletterTest.php b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/NewsletterTest.php index b4a00d497f5b6..e28a9602b9377 100644 --- a/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/NewsletterTest.php +++ b/dev/tests/integration/testsuite/Magento/Customer/Block/Adminhtml/Edit/Tab/NewsletterTest.php @@ -65,10 +65,10 @@ public function testRenderingNewsletterBlock() $this->dispatch('backend/customer/index/edit'); $body = $this->getResponse()->getBody(); - $this->assertContains('<span>Newsletter Information<\/span>', $body); - $this->assertContains('<input id=\"_newslettersubscription\"', $body); + $this->assertContains('\u003Cspan\u003ENewsletter Information\u003C\/span\u003E', $body); + $this->assertContains('\u003Cinput id=\"_newslettersubscription\"', $body); $this->assertNotContains('checked="checked"', $body); - $this->assertContains('<span>Subscribed to Newsletter<\/span>', $body); - $this->assertContains('>No Newsletter Found<', $body); + $this->assertContains('\u003Cspan\u003ESubscribed to Newsletter\u003C\/span\u003E', $body); + $this->assertContains('\u003ENo Newsletter Found\u003C', $body); } } diff --git a/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php b/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php index a40a7c8ad2962..3b006b5044337 100644 --- a/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php +++ b/dev/tests/integration/testsuite/Magento/Developer/Model/Logger/Handler/DebugTest.php @@ -112,25 +112,27 @@ private function enableDebugging() ->getMockForAbstractClass(); $this->outputMock = $this->getMockBuilder(OutputInterface::class) ->getMockForAbstractClass(); - $this->inputMock->expects($this->exactly(2)) - ->method('getArgument') - ->withConsecutive([ConfigSetCommand::ARG_PATH], [ConfigSetCommand::ARG_VALUE]) - ->willReturnOnConsecutiveCalls('dev/debug/debug_logging', 1); - $this->inputMock->expects($this->exactly(3)) + $this->inputMock->expects($this->exactly(4)) ->method('getOption') ->withConsecutive( + [ConfigSetCommand::OPTION_LOCK_ENV], + [ConfigSetCommand::OPTION_LOCK_CONFIG], [ConfigSetCommand::OPTION_SCOPE], - [ConfigSetCommand::OPTION_SCOPE_CODE], - [ConfigSetCommand::OPTION_LOCK] + [ConfigSetCommand::OPTION_SCOPE_CODE] ) ->willReturnOnConsecutiveCalls( + true, + false, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, - null, - true + null ); + $this->inputMock->expects($this->exactly(2)) + ->method('getArgument') + ->withConsecutive([ConfigSetCommand::ARG_PATH], [ConfigSetCommand::ARG_VALUE]) + ->willReturnOnConsecutiveCalls('dev/debug/debug_logging', 1); $this->outputMock->expects($this->once()) ->method('writeln') - ->with('<info>Value was saved and locked.</info>'); + ->with('<info>Value was saved in app/etc/env.php and locked.</info>'); $this->assertFalse((bool)$this->configSetCommand->run($this->inputMock, $this->outputMock)); } diff --git a/dev/tests/integration/testsuite/Magento/Downloadable/Controller/Adminhtml/Downloadable/FileTest.php b/dev/tests/integration/testsuite/Magento/Downloadable/Controller/Adminhtml/Downloadable/FileTest.php index 4d19e973556c0..3f13ce7f41ed6 100644 --- a/dev/tests/integration/testsuite/Magento/Downloadable/Controller/Adminhtml/Downloadable/FileTest.php +++ b/dev/tests/integration/testsuite/Magento/Downloadable/Controller/Adminhtml/Downloadable/FileTest.php @@ -1,6 +1,9 @@ <?php namespace Magento\Downloadable\Controller\Adminhtml\Downloadable; +use Magento\Framework\Serialize\Serializer\Json; +use Magento\TestFramework\Helper\Bootstrap; + /** * Magento\Downloadable\Controller\Adminhtml\Downloadable\File * @@ -10,6 +13,17 @@ */ class FileTest extends \Magento\TestFramework\TestCase\AbstractBackendController { + /** + * @inheritdoc + */ + protected function tearDown() + { + $filePath = dirname(__DIR__) . '/_files/sample.tmp'; + if (is_file($filePath)) { + unlink($filePath); + } + } + public function testUploadAction() { copy(dirname(__DIR__) . '/_files/sample.txt', dirname(__DIR__) . '/_files/sample.tmp'); @@ -25,11 +39,53 @@ public function testUploadAction() $this->dispatch('backend/admin/downloadable_file/upload/type/samples'); $body = $this->getResponse()->getBody(); - $result = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\Json\Helper\Data::class - )->jsonDecode( - $body - ); + $result = Bootstrap::getObjectManager()->get(Json::class)->unserialize($body); $this->assertEquals(0, $result['error']); } + + /** + * Checks a case when php files are not allowed to upload. + * + * @param string $fileName + * @dataProvider extensionsDataProvider + */ + public function testUploadProhibitedExtensions($fileName) + { + $path = dirname(__DIR__) . '/_files/'; + copy($path . 'sample.txt', $path . 'sample.tmp'); + + $_FILES = [ + 'samples' => [ + 'name' => $fileName, + 'type' => 'text/plain', + 'tmp_name' => $path . 'sample.tmp', + 'error' => 0, + 'size' => 0, + ], + ]; + + $this->dispatch('backend/admin/downloadable_file/upload/type/samples'); + $body = $this->getResponse()->getBody(); + $result = Bootstrap::getObjectManager()->get(Json::class)->unserialize($body); + + self::assertArrayHasKey('errorcode', $result); + self::assertEquals(0, $result['errorcode']); + self::assertEquals('Disallowed file type.', $result['error']); + } + + /** + * Returns different php file extensions. + * + * @return array + */ + public function extensionsDataProvider() + { + return [ + ['sample.php'], + ['sample.php3'], + ['sample.php4'], + ['sample.php5'], + ['sample.php7'], + ]; + } } diff --git a/dev/tests/integration/testsuite/Magento/Framework/App/Filesystem/DirectoryResolverTest.php b/dev/tests/integration/testsuite/Magento/Framework/App/Filesystem/DirectoryResolverTest.php new file mode 100644 index 0000000000000..278c08fbd2b07 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/App/Filesystem/DirectoryResolverTest.php @@ -0,0 +1,87 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\App\Filesystem; + +use Magento\TestFramework\Helper\Bootstrap; + +/** + * Test class for the \Magento\Framework\App\Filesystem\DirectoryResolver verification. + */ +class DirectoryResolverTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @var \Magento\Framework\App\Filesystem\DirectoryResolver + */ + private $directoryResolver; + + /** + * @var \Magento\Framework\Filesystem\Directory\WriteInterface + */ + private $directory; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->directoryResolver = $this->objectManager + ->create(\Magento\Framework\App\Filesystem\DirectoryResolver::class); + /** @var \Magento\Framework\Filesystem $filesystem */ + $filesystem = $this->objectManager->create(\Magento\Framework\Filesystem::class); + $this->directory = $filesystem->getDirectoryWrite(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA); + } + + /** + * @param string $path + * @param string $directoryConfig + * @param bool $expectation + * @dataProvider validatePathDataProvider + * @magentoAppIsolation enabled + * @return void + */ + public function testValidatePath($path, $directoryConfig, $expectation) + { + $path = $this->directory->getAbsolutePath($path); + $this->assertEquals($expectation, $this->directoryResolver->validatePath($path, $directoryConfig)); + } + + /** + * @expectedException \Magento\Framework\Exception\FileSystemException + * @magentoAppIsolation enabled + * @return void + */ + public function testValidatePathWithException() + { + $path = $this->directory->getAbsolutePath(); + $this->directoryResolver->validatePath($path, 'wrong_dir'); + } + + /** + * @return array + */ + public function validatePathDataProvider() + { + return [ + [ + '/', + DirectoryList::MEDIA, + true, + ], + [ + '/../../pub/', + DirectoryList::MEDIA, + false, + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/ConfigTest.php new file mode 100644 index 0000000000000..228ee9d79d9fe --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/ConfigTest.php @@ -0,0 +1,214 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Test of communication configuration reading and parsing. + * + * @magentoCache config disabled + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class ConfigTest extends \PHPUnit\Framework\TestCase +{ + public function testGetConsumers() + { + $consumers = $this->getConfigData()->getConsumers(); + $expectedParsedConfig = include __DIR__ . '/_files/valid_expected_queue.php'; + $this->assertEquals($expectedParsedConfig['consumers'], $consumers); + } + + public function testGetPublishers() + { + $publishers = $this->getConfigData()->getPublishers(); + $expectedParsedConfig = include __DIR__ . '/_files/valid_expected_queue.php'; + $this->assertEquals($expectedParsedConfig['publishers'], $publishers); + } + + public function testGetBinds() + { + $binds = $this->getConfigData()->getBinds(); + $expectedParsedConfig = include __DIR__ . '/_files/valid_expected_queue.php'; + $this->assertEquals($expectedParsedConfig['binds'], $binds); + } + + public function testGetMaps() + { + $topicName = 'topic.broker.test'; + $queue = $this->getConfigData()->getQueuesByTopic($topicName); + $expectedParsedConfig = include __DIR__ . '/_files/valid_expected_queue.php'; + $this->assertEquals( + $expectedParsedConfig['exchange_topic_to_queues_map']['magento--topic.broker.test'], + $queue + ); + } + + public function testGetTopic() + { + $topicName = 'topic.broker.test'; + $topic = $this->getConfigData()->getTopic($topicName); + $expectedParsedConfig = include __DIR__ . '/_files/valid_expected_queue.php'; + $this->assertEquals($expectedParsedConfig['topics'][$topicName], $topic); + } + + /** + * Return mocked config data + * + * @return \Magento\Framework\MessageQueue\ConfigInterface + */ + private function getConfigData() + { + return $this->getConfigInstance( + [ + __DIR__ . '/_files/valid_new_queue.xml' + ] + ); + } + + /** + * Create config instance initialized with configuration from $configFilePath + * + * @param string|string[] $configFilePath + * @param string|null $envConfigFilePath + * @return \Magento\Framework\MessageQueue\ConfigInterface + */ + protected function getConfigInstance($configFilePath, $envConfigFilePath = null) + { + $content = []; + if (is_array($configFilePath)) { + foreach ($configFilePath as $file) { + $content[] = file_get_contents($file); + } + } else { + $content[] = file_get_contents($configFilePath); + } + $fileResolver = $this->getMockForAbstractClass(\Magento\Framework\Config\FileResolverInterface::class); + $fileResolver->expects($this->any()) + ->method('get') + ->willReturn($content); + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $topicConverter = $objectManager->create( + \Magento\Framework\MessageQueue\Config\Reader\Xml\Converter\TopicConfig::class, + [ + 'communicationConfig' => $this->getCommunicationConfigInstance() + ] + ); + + $converter = $objectManager->create( + \Magento\Framework\MessageQueue\Config\Reader\Xml\CompositeConverter::class, + [ + 'converters' => [ + ['converter' => $topicConverter, 'sortOrder' => 10] + ] + ] + ); + $xmlReader = $objectManager->create( + \Magento\Framework\MessageQueue\Config\Reader\Xml::class, + [ + 'fileResolver' => $fileResolver, + 'converter' => $converter, + ] + ); + $deploymentConfigReader = $this->getMockBuilder(\Magento\Framework\App\DeploymentConfig\Reader::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + $envConfigData = include $envConfigFilePath ?: __DIR__ . '/_files/valid_queue_input.php'; + $deploymentConfigReader->expects($this->any())->method('load')->willReturn($envConfigData); + $deploymentConfig = $objectManager->create( + \Magento\Framework\App\DeploymentConfig::class, + ['reader' => $deploymentConfigReader] + ); + $envReader = $objectManager->create( + \Magento\Framework\MessageQueue\Config\Reader\Env::class, + [ + 'deploymentConfig' => $deploymentConfig + ] + ); + $methodsMap = $objectManager->create(\Magento\Framework\Reflection\MethodsMap::class); + $envValidator = $objectManager->create( + \Magento\Framework\MessageQueue\Config\Reader\Env\Validator::class, + [ + 'methodsMap' => $methodsMap + ] + ); + + $compositeReader = $objectManager->create( + \Magento\Framework\MessageQueue\Config\CompositeReader::class, + [ + 'readers' => [ + ['reader' => $xmlReader, 'sortOrder' => 10], + ['reader' => $envReader, 'sortOrder' => 20] + ], + ] + ); + + /** @var \Magento\Framework\MessageQueue\Config $configData */ + $configData = $objectManager->create( + \Magento\Framework\MessageQueue\Config\Data::class, + [ + 'reader' => $compositeReader, + 'envValidator' => $envValidator + ] + ); + return $objectManager->create( + \Magento\Framework\MessageQueue\ConfigInterface::class, + ['queueConfigData' => $configData] + ); + } + + /** + * Get mocked Communication Config Instance + * + * @return \Magento\Framework\Communication\ConfigInterface + */ + private function getCommunicationConfigInstance() + { + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $fileResolver = $this->getMockForAbstractClass(\Magento\Framework\Config\FileResolverInterface::class); + $fileResolver->expects($this->any()) + ->method('get') + ->willReturn([file_get_contents(__DIR__ . '/_files/communication.xml')]); + + $xmlReader = $objectManager->create( + \Magento\Framework\Communication\Config\Reader\XmlReader::class, + [ + 'fileResolver' => $fileResolver, + ] + ); + + $compositeReader = $objectManager->create( + \Magento\Framework\Communication\Config\CompositeReader::class, + [ + 'readers' => [ + ['reader' => $xmlReader, 'sortOrder' => 10], + [ + 'reader' => $objectManager->create( + \Magento\Framework\Communication\Config\Reader\EnvReader::class + ), + 'sortOrder' => 20 + ] + ], + ] + ); + + /** @var \Magento\Framework\Communication\Config $configData */ + $configData = $objectManager->create( + \Magento\Framework\Communication\Config\Data::class, + [ + 'reader' => $compositeReader + ] + ); + + $config = $objectManager->create( + \Magento\Framework\Communication\ConfigInterface::class, + [ + 'configData' => $configData + ] + ); + return $config; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Consumer/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Consumer/ConfigTest.php new file mode 100644 index 0000000000000..6ff19121e3364 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Consumer/ConfigTest.php @@ -0,0 +1,80 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer; + +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem\Handler\Iterator as HandlerIterator; + +/** + * Test of queue consumer configuration reading and parsing. + * + * @magentoCache config disabled + */ +class ConfigTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + public function testGetConsumers() + { + /** @var \Magento\Framework\MessageQueue\Consumer\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Consumer\ConfigInterface::class); + + $consumers = $config->getConsumers(); + $consumer = $config->getConsumer('consumer1'); + + $this->assertEquals( + $consumer, + $consumers['consumer1'], + 'Consumers received from collection and via getter must be the same' + ); + + $this->assertEquals('consumer1', $consumer->getName()); + $this->assertEquals('queue1', $consumer->getQueue()); + $this->assertEquals('amqp', $consumer->getConnection()); + $this->assertEquals(\Magento\Framework\MessageQueue\BatchConsumer::class, $consumer->getConsumerInstance()); + $this->assertEquals('100', $consumer->getMaxMessages()); + $handlers = $consumer->getHandlers(); + $this->assertInstanceOf(HandlerIterator::class, $handlers); + $this->assertCount(1, $handlers); + $this->assertEquals('handlerMethodOne', $handlers[0]->getMethod()); + $this->assertEquals('Magento\TestModuleMessageQueueConfiguration\HandlerOne', $handlers[0]->getType()); + } + + public function testGetConsumerWithDefaultValues() + { + /** @var \Magento\Framework\MessageQueue\Consumer\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Consumer\ConfigInterface::class); + + $consumer = $config->getConsumer('consumer5'); + + $this->assertEquals('consumer5', $consumer->getName()); + $this->assertEquals('queue5', $consumer->getQueue()); + $this->assertEquals('amqp', $consumer->getConnection()); + $this->assertEquals(\Magento\Framework\MessageQueue\ConsumerInterface::class, $consumer->getConsumerInstance()); + $this->assertEquals(null, $consumer->getMaxMessages()); + $handlers = $consumer->getHandlers(); + $this->assertInstanceOf(HandlerIterator::class, $handlers); + $this->assertCount(0, $handlers); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Consumer 'undeclaredConsumer' is not declared. + */ + public function testGetUndeclaredConsumer() + { + /** @var \Magento\Framework\MessageQueue\Consumer\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Consumer\ConfigInterface::class); + $config->getConsumer('undeclaredConsumer'); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Consumer/DeprecatedConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Consumer/DeprecatedConfigTest.php new file mode 100644 index 0000000000000..7a783cb1da5ce --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Consumer/DeprecatedConfigTest.php @@ -0,0 +1,119 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer; + +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem\Handler\Iterator as HandlerIterator; + +/** + * Test access to consumer configuration declared in deprecated queue.xml configs using Consumer\ConfigInterface. + * + * @magentoCache config disabled + */ +class DeprecatedConfigTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + public function testGetConsumerMultipleHandlersFromCommunicationConfig() + { + /** @var \Magento\Framework\MessageQueue\Consumer\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Consumer\ConfigInterface::class); + $consumer = $config->getConsumer('deprecatedConfigAsyncBoolConsumer'); + + $this->assertEquals('deprecatedConfigAsyncBoolConsumer', $consumer->getName()); + $this->assertEquals('deprecated.config.queue.2', $consumer->getQueue()); + $this->assertEquals('db', $consumer->getConnection()); + $this->assertEquals(\Magento\Framework\MessageQueue\ConsumerInterface::class, $consumer->getConsumerInstance()); + $this->assertEquals(null, $consumer->getMaxMessages()); + + $handlers = $consumer->getHandlers(); + $this->assertInstanceOf(HandlerIterator::class, $handlers); + $this->assertCount(2, $handlers); + $this->assertEquals('methodWithBoolParam', $handlers[0]->getMethod()); + $this->assertEquals(\Magento\TestModuleMessageQueueConfiguration\AsyncHandler::class, $handlers[0]->getType()); + $this->assertEquals('methodWithMixedParam', $handlers[1]->getMethod()); + $this->assertEquals(\Magento\TestModuleMessageQueueConfiguration\AsyncHandler::class, $handlers[1]->getType()); + } + + public function testGetConsumerCustomHandler() + { + /** @var \Magento\Framework\MessageQueue\Consumer\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Consumer\ConfigInterface::class); + $consumer = $config->getConsumer('deprecatedConfigAsyncMixedConsumer'); + + $this->assertEquals('deprecatedConfigAsyncMixedConsumer', $consumer->getName()); + $this->assertEquals('deprecated.config.queue.3', $consumer->getQueue()); + $this->assertEquals('amqp', $consumer->getConnection()); + $this->assertEquals(\Magento\Framework\MessageQueue\ConsumerInterface::class, $consumer->getConsumerInstance()); + $this->assertEquals(null, $consumer->getMaxMessages()); + + $handlers = $consumer->getHandlers(); + $this->assertInstanceOf(HandlerIterator::class, $handlers); + $this->assertCount(1, $handlers); + $this->assertEquals('methodWithMixedParam', $handlers[0]->getMethod()); + $this->assertEquals(\Magento\TestModuleMessageQueueConfiguration\AsyncHandler::class, $handlers[0]->getType()); + } + + public function testGetConsumerCustomConnectionSync() + { + /** @var \Magento\Framework\MessageQueue\Consumer\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Consumer\ConfigInterface::class); + $consumer = $config->getConsumer('deprecatedConfigSyncBoolConsumer'); + + $this->assertEquals('deprecatedConfigSyncBoolConsumer', $consumer->getName()); + $this->assertEquals('deprecated.config.queue.4', $consumer->getQueue()); + $this->assertEquals('amqp', $consumer->getConnection()); + $this->assertEquals(\Magento\Framework\MessageQueue\ConsumerInterface::class, $consumer->getConsumerInstance()); + $this->assertEquals(null, $consumer->getMaxMessages()); + + $handlers = $consumer->getHandlers(); + $this->assertInstanceOf(HandlerIterator::class, $handlers); + $this->assertCount(1, $handlers); + $this->assertEquals('methodWithBoolParam', $handlers[0]->getMethod()); + $this->assertEquals(\Magento\TestModuleMessageQueueConfiguration\SyncHandler::class, $handlers[0]->getType()); + } + + public function testGetConsumerCustomConsumerAndMaxMessages() + { + /** @var \Magento\Framework\MessageQueue\Consumer\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Consumer\ConfigInterface::class); + $consumer = $config->getConsumer('deprecatedConfigAsyncStringConsumer'); + + $this->assertEquals('deprecatedConfigAsyncStringConsumer', $consumer->getName()); + $this->assertEquals('deprecated.config.queue.1', $consumer->getQueue()); + $this->assertEquals('amqp', $consumer->getConnection()); + $this->assertEquals(\Magento\Framework\MessageQueue\BatchConsumer::class, $consumer->getConsumerInstance()); + $this->assertEquals(200, $consumer->getMaxMessages()); + + $handlers = $consumer->getHandlers(); + $this->assertInstanceOf(HandlerIterator::class, $handlers); + $this->assertCount(0, $handlers); + } + + public function testGetOverlapWithQueueConfig() + { + /** @var \Magento\Framework\MessageQueue\Consumer\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Consumer\ConfigInterface::class); + $consumer = $config->getConsumer('overlappingConsumerDeclaration'); + + $this->assertEquals('overlappingConsumerDeclaration', $consumer->getName()); + $this->assertEquals('consumer.config.queue', $consumer->getQueue()); + $this->assertEquals('amqp', $consumer->getConnection()); + $this->assertEquals(\Magento\Framework\MessageQueue\ConsumerInterface::class, $consumer->getConsumerInstance()); + $this->assertEquals(null, $consumer->getMaxMessages()); + + $handlers = $consumer->getHandlers(); + $this->assertInstanceOf(HandlerIterator::class, $handlers); + $this->assertCount(0, $handlers); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/MessageEncoderTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/MessageEncoderTest.php new file mode 100644 index 0000000000000..342f280f6af4d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/MessageEncoderTest.php @@ -0,0 +1,226 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\MessageQueue\MessageEncoder; +use Magento\Framework\Communication\Config; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class MessageEncoderTest extends \PHPUnit\Framework\TestCase +{ + /** @var MessageEncoder */ + protected $encoder; + + /** @var \Magento\Framework\ObjectManagerInterface */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->encoder = $this->objectManager->create(MessageEncoder::class); + $this->setBackwardCompatibleProperty( + $this->encoder, + 'communicationConfig', + $this->getConfig() + ); + parent::setUp(); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_address.php + */ + public function testEncode() + { + /** @var \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository */ + $customerRepository = $this->objectManager->create(\Magento\Customer\Api\CustomerRepositoryInterface::class); + $fixtureCustomerId = 1; + $customer = $customerRepository->getById($fixtureCustomerId); + /** @var \Magento\Customer\Api\Data\CustomerExtensionInterface $customerExtension */ + $customerExtension = $this->objectManager->create(\Magento\Customer\Api\Data\CustomerExtension::class); + $customerExtension->setTestGroupCode('Some Group Code'); + $customer->setExtensionAttributes($customerExtension); + $encodedCustomerData = json_decode($this->encoder->encode('customer.created', $customer), true); + $createdAt = $customer->getCreatedAt(); + $updatedAt = $customer->getUpdatedAt(); + $expectedEncodedCustomerData = json_decode($this->getCustomerDataAsJson($createdAt, $updatedAt), true); + $this->assertEquals($expectedEncodedCustomerData, $encodedCustomerData); + } + + /** + * @magentoDataFixture Magento/Customer/_files/customer.php + * @magentoDataFixture Magento/Customer/_files/customer_address.php + */ + public function testEncodeArrayOfEntities() + { + /** @var \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository */ + $customerRepository = $this->objectManager->create(\Magento\Customer\Api\CustomerRepositoryInterface::class); + $fixtureCustomerId = 1; + $customer = $customerRepository->getById($fixtureCustomerId); + /** @var \Magento\Customer\Api\Data\CustomerExtensionInterface $customerExtension */ + $customerExtension = $this->objectManager->create(\Magento\Customer\Api\Data\CustomerExtension::class); + $customerExtension->setTestGroupCode('Some Group Code'); + $customer->setExtensionAttributes($customerExtension); + $encodedCustomerData = json_decode($this->encoder->encode('customer.list.retrieved', [$customer]), true); + $createdAt = $customer->getCreatedAt(); + $updatedAt = $customer->getUpdatedAt(); + $expectedEncodedCustomerData = json_decode($this->getCustomerDataAsJson($createdAt, $updatedAt), true); + $this->assertEquals($expectedEncodedCustomerData, $encodedCustomerData[0]); + } + + public function testDecode() + { + $encodedMessage = $this->getCustomerDataAsJson('2015-07-22 12:43:36', '2015-07-22 12:45:36'); + /** @var \Magento\Customer\Api\Data\CustomerInterface $decodedCustomerObject */ + $decodedCustomerObject = $this->encoder->decode('customer.created', $encodedMessage); + $this->assertInstanceOf(\Magento\Customer\Api\Data\CustomerInterface::class, $decodedCustomerObject); + $this->assertEquals('customer@example.com', $decodedCustomerObject->getEmail()); + $this->assertEquals(1, $decodedCustomerObject->getGroupId()); + + $this->assertInstanceOf( + \Magento\Customer\Api\Data\CustomerExtensionInterface::class, + $decodedCustomerObject->getExtensionAttributes() + ); + $this->assertEquals('Some Group Code', $decodedCustomerObject->getExtensionAttributes()->getTestGroupCode()); + $addresses = $decodedCustomerObject->getAddresses(); + $this->assertCount(1, $addresses, "Address was not decoded."); + $this->assertInstanceOf( + \Magento\Customer\Api\Data\AddressInterface::class, + $addresses[0] + ); + $this->assertEquals('3468676', $addresses[0]->getTelephone()); + $this->assertEquals(true, $addresses[0]->isDefaultBilling()); + + $this->assertInstanceOf( + \Magento\Customer\Api\Data\RegionInterface::class, + $addresses[0]->getRegion() + ); + $this->assertEquals('AL', $addresses[0]->getRegion()->getRegionCode()); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Error occurred during message decoding + */ + public function testDecodeInvalidMessageFormat() + { + $this->encoder->decode('customer.created', "{"); + } + + /** + * @expectedException \LogicException + */ + public function testDecodeInvalidMessage() + { + $message = 'Property "NotExistingField" does not have accessor method "getNotExistingField" in class ' + . '"Magento\Customer\Api\Data\CustomerInterface".'; + $this->expectExceptionMessage($message); + $this->encoder->decode('customer.created', '{"not_existing_field": "value"}'); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Error occurred during message decoding + */ + public function testDecodeIncorrectMessage() + { + $this->encoder->decode('customer.created', "{"); + } + + /** + * @return \Magento\Framework\MessageQueue\Config + */ + protected function getConfig() + { + $newData = include __DIR__ . '/_files/encoder_communication.php'; + /** @var \Magento\Framework\Communication\Config\Data $configData */ + $configData = $this->objectManager->create(\Magento\Framework\Communication\Config\Data::class); + $configData->reset(); + $configData->merge($newData); + $config = $this->objectManager->create(Config::class, ['configData' => $configData]); + + return $config; + } + + /** + * Get fixture customer data in Json format + * + * @param string $createdAt + * @param string $updatedAt + * @return string + */ + protected function getCustomerDataAsJson($createdAt, $updatedAt) + { + return <<<JSON +{ + "id": 1, + "group_id": 1, + "default_billing": "1", + "default_shipping": "1", + "created_at": "{$createdAt}", + "updated_at": "{$updatedAt}", + "email": "customer@example.com", + "firstname": "John", + "lastname": "Smith", + "middlename": "A", + "prefix": "Mr.", + "suffix": "Esq.", + "gender": 0, + "store_id": 1, + "taxvat": "12", + "website_id": 1, + "addresses": [ + { + "id": 1, + "customer_id": 1, + "region": { + "region_code": "AL", + "region": "Alabama", + "region_id": 1 + }, + "region_id": 1, + "country_id": "US", + "street": [ + "Green str, 67" + ], + "company": "CompanyName", + "telephone": "3468676", + "postcode": "75477", + "city": "CityM", + "firstname": "John", + "lastname": "Smith", + "default_shipping": true, + "default_billing": true + } + ], + "disable_auto_group_change": 0, + "extension_attributes": { + "test_group_code": "Some Group Code" + } +} +JSON; + } + + /** + * Set mocked property + * + * @param object $object + * @param string $propertyName + * @param object $propertyValue + * @return void + */ + public function setBackwardCompatibleProperty($object, $propertyName, $propertyValue) + { + $reflection = new \ReflectionClass(get_class($object)); + $reflectionProperty = $reflection->getProperty($propertyName); + $reflectionProperty->setAccessible(true); + $reflectionProperty->setValue($object, $propertyValue); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Publisher/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Publisher/ConfigTest.php new file mode 100644 index 0000000000000..5dc9889198053 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Publisher/ConfigTest.php @@ -0,0 +1,88 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher; + +/** + * Test of queue publisher configuration reading and parsing. + * + * @magentoCache config disabled + */ +class ConfigTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + public function testGetPublishersWithOneEnabledConnection() + { + /** @var \Magento\Framework\MessageQueue\Publisher\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Publisher\ConfigInterface::class); + + $publishers = $config->getPublishers(); + $publisher = $config->getPublisher('topic.message.queue.config.01'); + $itemFromList = null; + foreach ($publishers as $item) { + if ($item->getTopic() == 'topic.message.queue.config.01') { + $itemFromList = $item; + break; + } + } + + $this->assertEquals($publisher, $itemFromList, 'Inconsistent publisher object'); + + $this->assertEquals('topic.message.queue.config.01', $publisher->getTopic(), 'Incorrect topic name'); + $this->assertFalse($publisher->isDisabled(), 'Incorrect publisher state'); + /** @var \Magento\Framework\MessageQueue\Publisher\Config\PublisherConnectionInterface $connection */ + $connection = $publisher->getConnection(); + $this->assertEquals('amqp', $connection->getName(), 'Incorrect connection name'); + $this->assertEquals('magento2', $connection->getExchange(), 'Incorrect exchange name'); + $this->assertFalse($connection->isDisabled(), 'Incorrect connection status'); + } + + public function testGetPublisherConnectionWithoutConfiguredExchange() + { + /** @var \Magento\Framework\MessageQueue\Publisher\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Publisher\ConfigInterface::class); + + $publisher = $config->getPublisher('topic.message.queue.config.04'); + $connection = $publisher->getConnection(); + $this->assertEquals('magento', $connection->getExchange(), 'Incorrect exchange name'); + } + + public function testGetPublishersWithoutEnabledConnection() + { + /** @var \Magento\Framework\MessageQueue\Publisher\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Publisher\ConfigInterface::class); + + $publisher = $config->getPublisher('topic.message.queue.config.02'); + + $this->assertEquals('topic.message.queue.config.02', $publisher->getTopic(), 'Incorrect topic name'); + $this->assertFalse($publisher->isDisabled(), 'Incorrect publisher state'); + + /** @var \Magento\Framework\MessageQueue\Publisher\Config\PublisherConnectionInterface $connection */ + $connection = $publisher->getConnection(); + $this->assertEquals('amqp', $connection->getName(), 'Incorrect default connection name'); + $this->assertEquals('magento', $connection->getExchange(), 'Incorrect default exchange name'); + $this->assertFalse($connection->isDisabled(), 'Incorrect connection status'); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Publisher 'topic.message.queue.config.03' is not declared. + */ + public function testGetDisabledPublisherThrowsException() + { + /** @var \Magento\Framework\MessageQueue\Publisher\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Publisher\ConfigInterface::class); + $config->getPublisher('topic.message.queue.config.03'); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Publisher/DeprecatedConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Publisher/DeprecatedConfigTest.php new file mode 100644 index 0000000000000..9c2b4c075d890 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Publisher/DeprecatedConfigTest.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher; + +use Magento\Framework\MessageQueue\Publisher\Config\PublisherConnectionInterface; + +/** + * Test access to publisher configuration declared in deprecated queue.xml configs using Publisher\ConfigInterface. + * + * @magentoCache config disabled + */ +class DeprecatedConfigTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + public function testGetPublisher() + { + /** @var \Magento\Framework\MessageQueue\Publisher\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Publisher\ConfigInterface::class); + $publisher = $config->getPublisher('deprecated.config.async.string.topic'); + $this->assertEquals('deprecated.config.async.string.topic', $publisher->getTopic()); + $this->assertEquals(false, $publisher->isDisabled()); + + $connection = $publisher->getConnection(); + $this->assertEquals('amqp', $connection->getName()); + $this->assertEquals('magento', $connection->getExchange()); + $this->assertEquals(false, $connection->isDisabled()); + } + + public function testGetPublisherCustomConnection() + { + /** @var \Magento\Framework\MessageQueue\Publisher\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Publisher\ConfigInterface::class); + $publisher = $config->getPublisher('deprecated.config.sync.bool.topic'); + $this->assertEquals('deprecated.config.sync.bool.topic', $publisher->getTopic()); + $this->assertEquals(false, $publisher->isDisabled()); + + $connection = $publisher->getConnection(); + $this->assertEquals('amqp', $connection->getName()); + $this->assertEquals('customExchange', $connection->getExchange()); + $this->assertEquals(false, $connection->isDisabled()); + } + + public function testGetOverlapWithQueueConfig() + { + /** @var \Magento\Framework\MessageQueue\Publisher\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Publisher\ConfigInterface::class); + $publisher = $config->getPublisher('overlapping.topic.declaration'); + $this->assertEquals('overlapping.topic.declaration', $publisher->getTopic()); + $this->assertEquals(false, $publisher->isDisabled()); + + $connection = $publisher->getConnection(); + $this->assertEquals('amqp', $connection->getName()); + $this->assertEquals('magento', $connection->getExchange()); + $this->assertEquals(false, $connection->isDisabled()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Topology/ConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Topology/ConfigTest.php new file mode 100644 index 0000000000000..a8e55602327f2 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Topology/ConfigTest.php @@ -0,0 +1,91 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology; + +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; + +/** + * Test of queue topology configuration reading and parsing. + * + * @magentoCache config disabled + */ +class ConfigTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + public function testGetExchangeByName() + { + /** @var \Magento\Framework\MessageQueue\Topology\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Topology\ConfigInterface::class); + $exchange = $config->getExchange('magento-topic-based-exchange1', 'amqp'); + $this->assertEquals('magento-topic-based-exchange1', $exchange->getName()); + $this->assertEquals('topic', $exchange->getType()); + $this->assertEquals('amqp', $exchange->getConnection()); + $exchangeArguments = $exchange->getArguments(); + $expectedArguments = ['alternate-exchange' => 'magento-log-exchange']; + $this->assertEquals($expectedArguments, $exchangeArguments); + + /** @var BindingInterface $binding */ + $binding = current($exchange->getBindings()); + $this->assertEquals('topicBasedRouting1', $binding->getId()); + $this->assertEquals('anotherTopic1', $binding->getTopic()); + $this->assertEquals('queue', $binding->getDestinationType()); + $this->assertEquals('topic-queue1', $binding->getDestination()); + $bindingArguments = $binding->getArguments(); + $expectedArguments = ['argument1' => 'value']; + $this->assertEquals($expectedArguments, $bindingArguments); + } + + public function testGetExchangeByNameWithDefaultValues() + { + /** @var \Magento\Framework\MessageQueue\Topology\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Topology\ConfigInterface::class); + $exchange = $config->getExchange('magento-topic-based-exchange2', 'amqp'); + $this->assertEquals('magento-topic-based-exchange2', $exchange->getName()); + $this->assertEquals('topic', $exchange->getType()); + $this->assertEquals('amqp', $exchange->getConnection()); + $exchangeArguments = $exchange->getArguments(); + $expectedArguments = [ + 'alternate-exchange' => 'magento-log-exchange', + 'arrayValue' => [ + 'element01' => '10', + 'element02' => '20', + ] + ]; + $this->assertEquals($expectedArguments, $exchangeArguments); + + /** @var BindingInterface $binding */ + $binding = current($exchange->getBindings()); + $this->assertEquals('topicBasedRouting2', $binding->getId()); + $this->assertEquals('anotherTopic2', $binding->getTopic()); + $this->assertEquals('queue', $binding->getDestinationType()); + $this->assertEquals('topic-queue2', $binding->getDestination()); + $bindingArguments = $binding->getArguments(); + $expectedArguments = ['argument1' => 'value', 'argument2' => true, 'argument3' => 150]; + $this->assertEquals($expectedArguments, $bindingArguments); + } + + public function testGetAllExchanges() + { + /** @var \Magento\Framework\MessageQueue\Topology\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Topology\ConfigInterface::class); + $exchanges = $config->getExchanges(); + $expectedResults = ['magento-topic-based-exchange1', 'magento-topic-based-exchange2']; + $actual = []; + foreach ($exchanges as $exchange) { + $actual[] = $exchange->getName(); + } + $this->assertEmpty(array_diff($expectedResults, $actual)); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Topology/DeprecatedConfigTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Topology/DeprecatedConfigTest.php new file mode 100644 index 0000000000000..30a1c27abf77b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/Topology/DeprecatedConfigTest.php @@ -0,0 +1,117 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology; + +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\Binding\Iterator as BindingIterator; + +/** + * Test access to topology configuration declared in deprecated queue.xml configs using Topology\ConfigInterface. + * + * @magentoCache config disabled + */ +class DeprecatedConfigTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + } + + public function testGetTopology() + { + /** @var \Magento\Framework\MessageQueue\Topology\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Topology\ConfigInterface::class); + $topology = $config->getExchange('deprecatedExchange', 'db'); + $this->assertEquals('deprecatedExchange', $topology->getName()); + $this->assertEquals('topic', $topology->getType()); + $this->assertEquals('db', $topology->getConnection()); + $this->assertEquals(true, $topology->isDurable()); + $this->assertEquals(false, $topology->isAutoDelete()); + $this->assertEquals(false, $topology->isInternal()); + + $arguments = $topology->getArguments(); + $this->assertInternalType('array', $arguments); + $this->assertCount(0, $arguments); + + // Verify bindings + $bindings = $topology->getBindings(); + $this->assertInstanceOf(BindingIterator::class, $bindings); + $this->assertCount(1, $bindings); + + $bindingId = 'queue--deprecated.config.queue.2--deprecated.config.async.bool.topic'; + $this->assertArrayHasKey($bindingId, $bindings); + $binding = $bindings[$bindingId]; + + $this->assertEquals('queue', $binding->getDestinationType()); + $this->assertEquals('deprecated.config.queue.2', $binding->getDestination()); + $this->assertEquals(false, $binding->isDisabled()); + $this->assertEquals('deprecated.config.async.bool.topic', $binding->getTopic()); + $arguments = $binding->getArguments(); + $this->assertInternalType('array', $arguments); + $this->assertCount(0, $arguments); + } + + public function testGetTopologyOverlapWithQueueConfig() + { + /** @var \Magento\Framework\MessageQueue\Topology\ConfigInterface $config */ + $config = $this->objectManager->create(\Magento\Framework\MessageQueue\Topology\ConfigInterface::class); + $topology = $config->getExchange('overlappingDeprecatedExchange', 'amqp'); + $this->assertEquals('overlappingDeprecatedExchange', $topology->getName()); + $this->assertEquals('topic', $topology->getType()); + $this->assertEquals('amqp', $topology->getConnection()); + $this->assertEquals(true, $topology->isDurable()); + $this->assertEquals(false, $topology->isAutoDelete()); + $this->assertEquals(false, $topology->isInternal()); + + $arguments = $topology->getArguments(); + $this->assertInternalType('array', $arguments); + $this->assertCount(0, $arguments); + + // Verify bindings + $bindings = $topology->getBindings(); + $this->assertInstanceOf(BindingIterator::class, $bindings); + $this->assertCount(3, $bindings); + + // Note that connection was changed for this binding during merge with topology config + // since we do not support exchanges with the same names on different connections + $bindingId = 'queue--consumer.config.queue--overlapping.topic.declaration'; + $this->assertArrayHasKey($bindingId, $bindings); + $binding = $bindings[$bindingId]; + $this->assertEquals('queue', $binding->getDestinationType()); + $this->assertEquals('consumer.config.queue', $binding->getDestination()); + $this->assertEquals(false, $binding->isDisabled()); + $this->assertEquals('overlapping.topic.declaration', $binding->getTopic()); + $arguments = $binding->getArguments(); + $this->assertInternalType('array', $arguments); + $this->assertCount(0, $arguments); + + $bindingId = 'binding1'; + $this->assertArrayHasKey($bindingId, $bindings); + $binding = $bindings[$bindingId]; + $this->assertEquals('queue', $binding->getDestinationType()); + $this->assertEquals('topology.config.queue', $binding->getDestination()); + $this->assertEquals(false, $binding->isDisabled()); + $this->assertEquals('overlapping.topic.declaration', $binding->getTopic()); + $arguments = $binding->getArguments(); + $this->assertInternalType('array', $arguments); + $this->assertCount(0, $arguments); + + $bindingId = 'binding2'; + $this->assertArrayHasKey($bindingId, $bindings); + $binding = $bindings[$bindingId]; + $this->assertEquals('queue', $binding->getDestinationType()); + $this->assertEquals('topology.config.queue', $binding->getDestination()); + $this->assertEquals(false, $binding->isDisabled()); + $this->assertEquals('deprecated.config.async.string.topic', $binding->getTopic()); + $arguments = $binding->getArguments(); + $this->assertInternalType('array', $arguments); + $this->assertCount(0, $arguments); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/TopologyTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/TopologyTest.php new file mode 100644 index 0000000000000..189d189d32c97 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/TopologyTest.php @@ -0,0 +1,165 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * @see dev/tests/integration/_files/Magento/TestModuleMessageQueueConfiguration + * @see dev/tests/integration/_files/Magento/TestModuleMessageQueueConfigOverride + */ +class TopologyTest extends \PHPUnit\Framework\TestCase +{ + /** + * List of declared exchanges. + * + * @var array + */ + private $declaredExchanges; + + /** + * @var \Magento\TestFramework\Helper\Amqp + */ + private $helper; + + protected function setUp() + { + $this->helper = new \Magento\TestFramework\Helper\Amqp(); + $this->declaredExchanges = $this->helper->getExchanges(); + } + + /** + * @dataProvider exchangeDataProvider + * @param array $expectedConfig + * @param array $bindingConfig + */ + public function testTopologyInstallation(array $expectedConfig, array $bindingConfig) + { + $name = $expectedConfig['name']; + $this->assertArrayHasKey($name, $this->declaredExchanges); + unset($this->declaredExchanges[$name]['message_stats']); + $this->assertEquals( + $expectedConfig, + $this->declaredExchanges[$name], + 'Invalid exchange configuration: ' . $name + ); + + $bindings = $this->helper->getExchangeBindings($name); + $bindings = array_map(function ($value) { + unset($value['properties_key']); + return $value; + }, $bindings); + $this->assertEquals( + $bindingConfig, + $bindings, + 'Invalid exchange bindings configuration: ' . $name + ); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function exchangeDataProvider() + { + return [ + 'magento-topic-based-exchange1' => [ + 'exchangeConfig' => [ + 'name' => 'magento-topic-based-exchange1', + 'vhost' => '/', + 'type' => 'topic', + 'durable' => true, + 'auto_delete' => false, + 'internal' => false, + 'arguments' => [ + 'alternate-exchange' => 'magento-log-exchange' + ], + ], + 'bindingConfig' => [ + [ + 'source' => 'magento-topic-based-exchange1', + 'vhost' => '/', + 'destination' => 'topic-queue1', + 'destination_type' => 'queue', + 'routing_key' => 'anotherTopic1', + 'arguments' => [ + 'argument1' => 'value' + ], + ], + ] + ], + 'magento-topic-based-exchange2' => [ + 'exchangeConfig' => [ + 'name' => 'magento-topic-based-exchange2', + 'vhost' => '/', + 'type' => 'topic', + 'durable' => true, + 'auto_delete' => false, + 'internal' => false, + 'arguments' => [ + 'alternate-exchange' => 'magento-log-exchange', + 'arrayValue' => ['10', '20'] + ], + ], + 'bindingConfig' => [ + [ + 'source' => 'magento-topic-based-exchange2', + 'vhost' => '/', + 'destination' => 'topic-queue2', + 'destination_type' => 'queue', + 'routing_key' => 'anotherTopic2', + 'arguments' => [ + 'argument1' => 'value', + 'argument2' => true, + 'argument3' => '150', + ], + ], + ] + ], + 'magento-topic-based-exchange3' => [ + 'exchangeConfig' => [ + 'name' => 'magento-topic-based-exchange3', + 'vhost' => '/', + 'type' => 'topic', + 'durable' => false, + 'auto_delete' => true, + 'internal' => true, + 'arguments' => [], + ], + 'bindingConfig' => [], + ], + 'magento-topic-based-exchange4' => [ + 'exchangeConfig' => [ + 'name' => 'magento-topic-based-exchange4', + 'vhost' => '/', + 'type' => 'topic', + 'durable' => true, + 'auto_delete' => false, + 'internal' => false, + 'arguments' => [], + ], + 'bindingConfig' => [ + [ + 'source' => 'magento-topic-based-exchange4', + 'vhost' => '/', + 'destination' => 'topic-queue1', + 'destination_type' => 'queue', + 'routing_key' => '#', + 'arguments' => [ + 'test' => 'one' + ], + ], + [ + 'source' => 'magento-topic-based-exchange4', + 'vhost' => '/', + 'destination' => 'topic-queue2', + 'destination_type' => 'queue', + 'routing_key' => '*.*.*', + 'arguments' => [], + ], + ] + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/AsyncMultipleHandlersTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/AsyncMultipleHandlersTest.php new file mode 100644 index 0000000000000..890a0d01c71f9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/AsyncMultipleHandlersTest.php @@ -0,0 +1,79 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\UseCase; + +use Magento\TestModuleAsyncAmqp\Model\AsyncTestData; + +class AsyncMultipleHandlersTest extends QueueTestCaseAbstract +{ + /** + * @var string + */ + protected $expectedMessages; + + /** + * @var string[] + */ + protected $consumers = [ + 'mtmh.queue.1.consumer', + 'mtmh.queue.2.consumer', + ]; + + /** + * @var string[] + */ + private $topicValueMap = [ + 'mtmh.topic.1' => 'mtmh.topic.1', + 'mtmh.topic.2' => ['mtmh.topic.2-1', 'mtmh.topic.2-2'] + ]; + + /** + * @var string[] + */ + private $expectedValues = [ + 'string-mtmh.topic.1', + 'mixed-mtmh.topic.1', + 'array-mtmh.topic.2-1', + 'array-mtmh.topic.2-2', + 'mixed-mtmh.topic.2-1', + 'mixed-mtmh.topic.2-2' + ]; + + /** + * Verify that Queue Framework supports multiple topics per queue. + * + * Current test is not test of Web API framework itself, + * it just utilizes its infrastructure to test Message Queue. + */ + public function testAsynchronousRpcCommunication() + { + foreach ($this->topicValueMap as $topic => $data) { + $message = null; + if (is_array($data)) { + foreach ($data as $key => $value) { + /** @var AsyncTestData $testObject */ + $testObject = $this->objectManager->create(AsyncTestData::class); + $testObject->setValue($value); + $testObject->setTextFilePath($this->logFilePath); + $message[$key] = $testObject; + } + } else { + $testObject = $this->objectManager->create(AsyncTestData::class); + $testObject->setValue($data); + $testObject->setTextFilePath($this->logFilePath); + $message = $testObject; + } + $this->publisher->publish($topic, $message); + } + + $this->waitForAsynchronousResult(count($this->expectedValues), $this->logFilePath); + + //assertions + foreach ($this->expectedValues as $item) { + $this->assertContains($item, file_get_contents($this->logFilePath)); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/AsyncMultipleTopicsWithEachQueueTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/AsyncMultipleTopicsWithEachQueueTest.php new file mode 100644 index 0000000000000..e1de6423152c7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/AsyncMultipleTopicsWithEachQueueTest.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\UseCase; + +class AsyncMultipleTopicsWithEachQueueTest extends QueueTestCaseAbstract +{ + /** + * @var string[] + */ + protected $uniqueID; + + /** + * @var \Magento\TestModuleAsyncAmqp\Model\AsyncTestData + */ + protected $msgObject; + + /** + * @var string[] + */ + protected $consumers = ['queue.for.multiple.topics.test.y', 'queue.for.multiple.topics.test.z']; + + /** + * @var string[] + */ + private $topics = ['multi.topic.queue.topic.y', 'multi.topic.queue.topic.z']; + + /** + * Verify that Queue Framework processes multiple asynchronous topics sent to the same queue. + * + * Current test is not test of Web API framework itself, it just utilizes its infrastructure to test Message Queue. + */ + public function testAsyncMultipleTopicsPerQueue() + { + $this->msgObject = $this->objectManager->create(\Magento\TestModuleAsyncAmqp\Model\AsyncTestData::class); + + foreach ($this->topics as $topic) { + $this->uniqueID[$topic] = md5(uniqid($topic)); + $this->msgObject->setValue($this->uniqueID[$topic] . "_" . $topic); + $this->msgObject->setTextFilePath($this->logFilePath); + $this->publisher->publish($topic, $this->msgObject); + } + + $this->waitForAsynchronousResult(count($this->uniqueID), $this->logFilePath); + + //assertions + foreach ($this->topics as $item) { + $this->assertContains($this->uniqueID[$item] . "_" . $item, file_get_contents($this->logFilePath)); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/DeprecatedFormat/AsyncMultiTopicsSeparateQueuesTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/DeprecatedFormat/AsyncMultiTopicsSeparateQueuesTest.php new file mode 100644 index 0000000000000..f361f8e4e62fb --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/DeprecatedFormat/AsyncMultiTopicsSeparateQueuesTest.php @@ -0,0 +1,58 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\UseCase\DeprecatedFormat; + +use Magento\Framework\MessageQueue\UseCase\QueueTestCaseAbstract; + +class AsyncMultiTopicsSeparateQueuesTest extends QueueTestCaseAbstract +{ + /** + * @var string[] + */ + protected $uniqueID; + + /** + * @var \Magento\TestModuleAsyncAmqp\Model\AsyncTestData + */ + protected $msgObject; + + /** + * @var string[] + */ + protected $consumers = [ + 'queue.for.multiple.topics.test.c.deprecated', + 'queue.for.multiple.topics.test.d.deprecated' + ]; + + /** + * @var string[] + */ + private $topics = ['multi.topic.queue.topic.c.deprecated', 'multi.topic.queue.topic.d.deprecated']; + + /** + * Verify that Queue Framework processes multiple asynchronous topics sent to the same queue. + * + * Current test is not test of Web API framework itself, it just utilizes its infrastructure to test Message Queue. + */ + public function testAsyncMultipleTopicsPerQueue() + { + $this->msgObject = $this->objectManager->create(\Magento\TestModuleAsyncAmqp\Model\AsyncTestData::class); + + foreach ($this->topics as $topic) { + $this->uniqueID[$topic] = md5(uniqid($topic)); + $this->msgObject->setValue($this->uniqueID[$topic] . "_" . $topic); + $this->msgObject->setTextFilePath($this->logFilePath); + $this->publisher->publish($topic, $this->msgObject); + } + + $this->waitForAsynchronousResult(count($this->uniqueID), $this->logFilePath); + + //assertions + foreach ($this->topics as $item) { + $this->assertContains($this->uniqueID[$item] . "_" . $item, file_get_contents($this->logFilePath)); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/DeprecatedFormat/RpcCommunicationTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/DeprecatedFormat/RpcCommunicationTest.php new file mode 100644 index 0000000000000..2c2b9c94037f4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/DeprecatedFormat/RpcCommunicationTest.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\UseCase\DeprecatedFormat; + +use Magento\Framework\MessageQueue\UseCase\QueueTestCaseAbstract; + +class RpcCommunicationTest extends QueueTestCaseAbstract +{ + /** + * {@inheritdoc} + */ + protected $consumers = ['synchronousRpcTestConsumer.deprecated']; + + /** + * Verify that RPC call based on Rabbit MQ is processed correctly. + * + * Current test is not test of Web API framework itself, it just utilizes its infrastructure to test RPC. + */ + public function testSynchronousRpcCommunication() + { + $input = 'Input value'; + $response = $this->publisher->publish('synchronous.rpc.test.deprecated', $input); + $this->assertEquals($input . ' processed by RPC handler', $response); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/MixSyncAndAsyncSingleQueueTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/MixSyncAndAsyncSingleQueueTest.php new file mode 100644 index 0000000000000..a7987320e90c7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/MixSyncAndAsyncSingleQueueTest.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\UseCase; + +class MixSyncAndAsyncSingleQueueTest extends QueueTestCaseAbstract +{ + /** + * @var \Magento\TestModuleAsyncAmqp\Model\AsyncTestData + */ + protected $msgObject; + + /** + * {@inheritdoc} + */ + protected $consumers = ['mixed.sync.and.async.queue.consumer']; + + /** + * @var string[] + */ + protected $messages = ['message1', 'message2', 'message3']; + + /** + * @var int + */ + protected $maxMessages = 4; + + public function testMixSyncAndAsyncSingleQueue() + { + $this->msgObject = $this->objectManager->create(\Magento\TestModuleAsyncAmqp\Model\AsyncTestData::class); + + // Publish asynchronous messages + foreach ($this->messages as $item) { + $this->msgObject->setValue($item); + $this->msgObject->setTextFilePath($this->logFilePath); + $this->publisher->publish('multi.topic.queue.topic.c', $this->msgObject); + } + + // Publish synchronous message to the same queue + $input = 'Input value'; + $response = $this->publisher->publish('sync.topic.for.mixed.sync.and.async.queue', $input); + $this->assertEquals($input . ' processed by RPC handler', $response); + + $this->waitForAsynchronousResult(count($this->messages), $this->logFilePath); + + // Verify that asynchronous messages were processed + foreach ($this->messages as $item) { + $this->assertContains($item, file_get_contents($this->logFilePath)); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/MultipleTopicsPerQueueTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/MultipleTopicsPerQueueTest.php new file mode 100644 index 0000000000000..edd0fb9d560d5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/MultipleTopicsPerQueueTest.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\UseCase; + +class MultipleTopicsPerQueueTest extends QueueTestCaseAbstract +{ + /** + * {@inheritdoc} + */ + protected $consumers = [ + 'queue.for.multiple.topics.test.a', + 'queue.for.multiple.topics.test.b' + ]; + + /** + * Verify that Queue Framework supports multiple topics per queue. + * + * Current test is not test of Web API framework itself, + * it just utilizes its infrastructure to test Message Queue. + */ + public function testSynchronousRpcCommunication() + { + foreach (['multi.topic.queue.topic.a', 'multi.topic.queue.topic.b'] as $topic) { + $input = "Input value for topic '{$topic}'"; + $response = $this->publisher->publish($topic, $input); + $this->assertEquals($input . ' processed by RPC handler', $response); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/QueueTestCaseAbstract.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/QueueTestCaseAbstract.php new file mode 100644 index 0000000000000..65f7c5681597e --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/QueueTestCaseAbstract.php @@ -0,0 +1,150 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\UseCase; + +use Magento\Framework\ObjectManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\Framework\MessageQueue\PublisherInterface; + +/** + * Base test case for message queue tests. + */ +abstract class QueueTestCaseAbstract extends \PHPUnit\Framework\TestCase +{ + /** + * @var string[] + */ + protected $consumers = []; + + /** + * @var ObjectManagerInterface + */ + protected $objectManager; + + /** + * @var PublisherInterface + */ + protected $publisher; + + /** + * @var string + */ + protected $logFilePath; + + /** + * @var int|null + */ + protected $maxMessages = null; + + protected function setUp() + { + $this->objectManager = Bootstrap::getObjectManager(); + /** @var \Magento\Framework\OsInfo $osInfo */ + $osInfo = $this->objectManager->get(\Magento\Framework\OsInfo::class); + if ($osInfo->isWindows()) { + $this->markTestSkipped("This test relies on *nix shell and should be skipped in Windows environment."); + } + foreach ($this->consumers as $consumer) { + foreach ($this->getConsumerProcessIds($consumer) as $consumerProcessId) { + exec("kill {$consumerProcessId}"); + } + } + foreach ($this->consumers as $consumer) { + if (!$this->getConsumerProcessIds($consumer)) { + exec("{$this->getConsumerStartCommand($consumer, true)} > /dev/null &"); + } + } + + $this->logFilePath = TESTS_TEMP_DIR . "/MessageQueueTestLog.txt"; + if (file_exists($this->logFilePath)) { + // try to remove before failing the test + unlink($this->logFilePath); + if (file_exists($this->logFilePath)) { + $this->fail( + "Precondition failed: test log ({$this->logFilePath}) cannot be deleted before test execution." + ); + } + } + + $this->publisher = $this->objectManager->get(PublisherInterface::class); + } + + protected function tearDown() + { + foreach ($this->consumers as $consumer) { + foreach ($this->getConsumerProcessIds($consumer) as $consumerProcessId) { + exec("kill {$consumerProcessId}"); + } + } + } + + /** + * @param string $consumer + * @return string[] + */ + protected function getConsumerProcessIds($consumer) + { + exec("ps ax | grep -v grep | grep '{$this->getConsumerStartCommand($consumer)}' | awk '{print $1}'", $output); + return $output; + } + + /** + * Get CLI command for starting specified consumer. + * + * @param string $consumer + * @param bool $withEnvVariables + * @return string + */ + protected function getConsumerStartCommand($consumer, $withEnvVariables = false) + { + $binDirectory = realpath(TESTS_TEMP_DIR . '/../bin/'); + $magentoCli = $binDirectory . '/magento'; + $consumerStartCommand = "php {$magentoCli} queue:consumers:start -vvv " . $consumer; + if ($this->maxMessages) { + $consumerStartCommand .= " --max-messages={$this->maxMessages}"; + } + if ($withEnvVariables) { + $params = \Magento\TestFramework\Helper\Bootstrap::getInstance()->getAppInitParams(); + $params['MAGE_DIRS']['base']['path'] = BP; + $params = 'INTEGRATION_TEST_PARAMS="' . urldecode(http_build_query($params)) . '"'; + $consumerStartCommand = $params . ' ' . $consumerStartCommand; + } + return $consumerStartCommand; + } + + /** + * Wait for asynchronous handlers to log data to file. + * + * @param int $expectedLinesCount + * @param string $logFilePath + */ + protected function waitForAsynchronousResult($expectedLinesCount, $logFilePath) + { + $i = 0; + do { + sleep(1); + $actualCount = file_exists($logFilePath) ? count(file($logFilePath)) : 0; + } while (($expectedLinesCount !== $actualCount) && ($i++ < 180)); + + if (!file_exists($logFilePath)) { + $this->fail("No asynchronous messages were processed."); + } + } + + /** + * Workaround for https://bugs.php.net/bug.php?id=72286 + */ + public static function tearDownAfterClass() + { + if (version_compare(phpversion(), '7') == -1) { + $closeConnection = new \ReflectionMethod(\Magento\Amqp\Model\Config::class, 'closeConnection'); + $closeConnection->setAccessible(true); + + $config = Bootstrap::getObjectManager()->get(\Magento\Amqp\Model\Config::class); + $closeConnection->invoke($config); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/RemoteServiceCommunicationTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/RemoteServiceCommunicationTest.php new file mode 100644 index 0000000000000..a7f6845a86640 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/RemoteServiceCommunicationTest.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\UseCase; + +use Magento\TestModuleSynchronousAmqp\Api\ServiceInterface; + +class RemoteServiceCommunicationTest extends QueueTestCaseAbstract +{ + /** + * {@inheritdoc} + */ + protected $consumers = ['RemoteServiceTestConsumer']; + + public function testRemoteServiceCommunication() + { + $input = 'Input value'; + /** @var ServiceInterface $generatedRemoteService */ + $generatedRemoteService = $this->objectManager->get(ServiceInterface::class); + $response = $generatedRemoteService->execute($input); + $this->assertEquals($input . ' processed by RPC handler', $response); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/RpcCommunicationTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/RpcCommunicationTest.php new file mode 100644 index 0000000000000..0acde6fc88457 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/RpcCommunicationTest.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\UseCase; + +class RpcCommunicationTest extends QueueTestCaseAbstract +{ + /** + * {@inheritdoc} + */ + protected $consumers = ['synchronousRpcTestConsumer']; + + /** + * Verify that RPC call based on Rabbit MQ is processed correctly. + * + * Current test is not test of Web API framework itself, it just utilizes its infrastructure to test RPC. + */ + public function testSynchronousRpcCommunication() + { + $input = 'Input value'; + $response = $this->publisher->publish('synchronous.rpc.test', $input); + $this->assertEquals($input . ' processed by RPC handler', $response); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/WildcardTopicTest.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/WildcardTopicTest.php new file mode 100644 index 0000000000000..d8c369334cbb1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/UseCase/WildcardTopicTest.php @@ -0,0 +1,79 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\UseCase; + +use Magento\TestModuleAsyncAmqp\Model\AsyncTestData; + +class WildcardTopicTest extends QueueTestCaseAbstract +{ + /** + * @var string[] + */ + protected $consumers = [ + 'wildcard.queue.one.consumer', + 'wildcard.queue.two.consumer', + 'wildcard.queue.three.consumer', + 'wildcard.queue.four.consumer', + ]; + + /** + * @param string $topic + * @param string[] $matchingQueues + * @param string[] $nonMatchingQueues + * + * @dataProvider wildCardTopicsDataProvider + */ + public function testWildCardMatchingTopic($topic, $matchingQueues, $nonMatchingQueues) + { + $testObject = $this->generateTestObject(); + $this->publisher->publish($topic, $testObject); + + $this->waitForAsynchronousResult(count($matchingQueues), $this->logFilePath); + + $this->assertTrue(file_exists($this->logFilePath), "No handlers invoked (log file was not created)."); + foreach ($nonMatchingQueues as $queueName) { + $this->assertNotContains($queueName, file_get_contents($this->logFilePath)); + } + foreach ($matchingQueues as $queueName) { + $this->assertContains($queueName, file_get_contents($this->logFilePath)); + } + } + + public function wildCardTopicsDataProvider() + { + return [ + 'segment1.segment2.segment3.wildcard' => [ + 'segment1.segment2.segment3.wildcard', + ['wildcard.queue.one', 'wildcard.queue.two', 'wildcard.queue.four'], + ['wildcard.queue.three'] + ], + 'segment2.segment3.wildcard' => [ + 'segment2.segment3.wildcard', + ['wildcard.queue.one', 'wildcard.queue.three', 'wildcard.queue.four'], + ['wildcard.queue.two'] + ] + ]; + } + + public function testWildCardNonMatchingTopic() + { + $testObject = $this->generateTestObject(); + $this->publisher->publish('not.matching.wildcard.topic', $testObject); + sleep(2); + $this->assertFalse(file_exists($this->logFilePath), "No log file must be created for non-matching topic."); + } + + /** + * @return AsyncTestData + */ + private function generateTestObject() + { + $testObject = $this->objectManager->create(AsyncTestData::class); + $testObject->setValue('||Message Contents||'); + $testObject->setTextFilePath($this->logFilePath); + return $testObject; + } +} diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/communication.xml b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/communication.xml new file mode 100644 index 0000000000000..0fc50f0432b93 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/communication.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Communication/etc/communication.xsd"> + <topic name="topic.broker.test" request="string" response="string"> + <handler name="topicBrokerHandler" type="Magento\MysqlMq\Model\Processor" method="processMessage"/> + </topic> +</config> diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/encoder_communication.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/encoder_communication.php new file mode 100644 index 0000000000000..9870e1d234e02 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/encoder_communication.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + 'topics' => [ + 'customer.created' => [ + 'request_type' => 'object_interface', + 'request' => \Magento\Customer\Api\Data\CustomerInterface::class, + 'response' => null, + ], + 'customer.list.retrieved' => [ + 'request_type' => 'object_interface', + 'request' => 'Magento\Customer\Api\Data\CustomerInterface[]', + 'response' => null, + ], + 'customer.updated' => [ + 'request_type' => 'object_interface', + 'request' => \Magento\Customer\Api\Data\CustomerInterface::class, + 'response' => null, + ], + 'customer.deleted' => [ + 'request_type' => 'object_interface', + 'request' => \Magento\Customer\Api\Data\CustomerInterface::class, + 'response' => null, + ], + 'product.created' => [ + 'request_type' => 'object_interface', + 'request' => \Magento\Catalog\Api\Data\ProductInterface::class, + 'response' => null, + ], + ], +]; diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_expected_queue.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_expected_queue.php new file mode 100644 index 0000000000000..b5f5145c32c72 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_expected_queue.php @@ -0,0 +1,90 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + "publishers" => [ + "amqp-magento" => [ + "name" => "amqp-magento", + "connection" => "amqp", + "exchange" => "magento" + ], + 'demo-publisher-1' => [ + 'name' => 'demo-publisher-1', + 'connection' => 'amqp', + "exchange" => "magento" + ], + "test-publisher-5" => [ + "name" => "test-publisher-5", + "connection" => "amqp", + "exchange" => "test-exchange-10" + ] + ], + "topics" => [ + "topic.broker.test" => [ + "name" => "topic.broker.test", + "schema" => [ + "schema_type" => "object", + "schema_value" => "string" + ], + "response_schema" => [ + "schema_type" => "object", + "schema_value" => "string" + ], + "publisher" => "amqp-magento", + 'is_synchronous' => true, + ], + "publisher5.topic" => [ + "name" => "publisher5.topic", + "schema" => [ + "schema_type" => "object", + "schema_value" => '\\' . \Magento\MysqlMq\Model\DataObject::class + ], + "response_schema" => [ + "schema_type" => "object", + "schema_value" => \Magento\Customer\Api\Data\CustomerInterface::class + ], + "publisher" => "test-publisher-5" + ] + ], + "consumers" => [ + "topicBrokerConsumer" => [ + "name" => "topicBrokerConsumer", + "queue" => "demo-queue-1", + "connection" => "amqp", + "consumer_type" => "sync", + "handlers" => [ + "topic.broker.test" => [ + "0" => [ + "type" => \Magento\MysqlMq\Model\Processor::class, + "method" => "processMessage" + ] + ] + ], + "max_messages" => null, + "instance_type" => \Magento\Framework\MessageQueue\ConsumerInterface::class + ] + ], + "binds" => [ + "topic.broker.test--magento--demo-queue-1" => [ + "queue" => "demo-queue-1", + "exchange" => "magento", + "topic" => "topic.broker.test" + ], + "publisher5.topic--test-exchange-10--demo-queue-1" => [ + "queue" => "demo-queue-1", + "exchange" => "test-exchange-10", + "topic" => "publisher5.topic" + ] + ], + "exchange_topic_to_queues_map" => [ + "magento--topic.broker.test" => [ + "demo-queue-1" + ], + "test-exchange-10--publisher5.topic" => [ + "demo-queue-1" + ] + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_new_queue.xml b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_new_queue.xml new file mode 100644 index 0000000000000..f27f0b22f464f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_new_queue.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/queue.xsd"> + <broker topic="topic.broker.test" type="amqp" exchange="magento"> + <queue consumer="topicBrokerConsumer" name="demo-queue-1" /> + </broker> +</config> diff --git a/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_queue_input.php b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_queue_input.php new file mode 100644 index 0000000000000..fdd4a7d3007a7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/MessageQueue/_files/valid_queue_input.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + 'queue' => [ + 'publishers' => [ + 'demo-publisher-1' => [ + 'name' => 'demo-publisher-1', + 'connection' => 'amqp', + "exchange" => "magento" + ], + "test-publisher-5" => [ + "name" => "test-publisher-5", + "connection" => "amqp", + "exchange" => "test-exchange-10" + ] + ], + "topics" => [ + "publisher5.topic" => [ + "name" => "publisher5.topic", + "schema" => [ + "schema_type" => "object", + "schema_value" => "Magento\\MysqlMq\\Model\\DataObject" + ], + "response_schema" => [ + "schema_type" => "object", + "schema_value" => "Magento\\Customer\\Api\\Data\\CustomerInterface" + ], + "publisher" => "test-publisher-5" + ] + ], + "binds" => [ + "publisher5.topic--test-exchange-10--demo-queue-1" => [ + "queue" => "demo-queue-1", + "exchange" => "test-exchange-10", + "topic" => "publisher5.topic" + ] + ], + "exchange_topic_to_queues_map" => [ + "test-exchange-10--publisher5.topic" => [ + "demo-queue-1" + ] + ] + ] +]; diff --git a/dev/tests/integration/testsuite/Magento/Framework/Module/Plugin/DbStatusValidatorTest.php b/dev/tests/integration/testsuite/Magento/Framework/Module/Plugin/DbStatusValidatorTest.php index 4afef47233489..7f00a881ab71d 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Module/Plugin/DbStatusValidatorTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Module/Plugin/DbStatusValidatorTest.php @@ -19,6 +19,7 @@ public function testValidationUpToDateDb() */ public function testValidationOutdatedDb() { + $this->markTestSkipped(); $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); /** @var \Magento\Framework\Module\ModuleListInterface $moduleList */ @@ -31,6 +32,7 @@ public function testValidationOutdatedDb() $moduleNameToTest = $moduleName; break; } + $moduleList->getOne($moduleName); // Prepend '0.' to DB Version, to cause it to be an older version /** @var \Magento\Framework\Module\ResourceInterface $resource */ diff --git a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php index a36da56bb4633..1cfe77b22a69b 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php @@ -9,6 +9,8 @@ } namespace Magento\Framework\Session { + + use Magento\Framework\App\State; // @codingStandardsIgnoreEnd /** @@ -59,6 +61,16 @@ class SessionManagerTest extends \PHPUnit\Framework\TestCase */ protected $objectManager; + /** + * @var \Magento\Framework\App\RequestInterface + */ + private $request; + + /** + * @var State|\PHPUnit_Framework_MockObject_MockObject + */ + private $appState; + protected function setUp() { $this->sessionName = 'frontEndSession'; @@ -69,7 +81,18 @@ protected function setUp() $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); /** @var \Magento\Framework\Session\SidResolverInterface $sidResolver */ - $this->_sidResolver = $this->objectManager->get(\Magento\Framework\Session\SidResolverInterface::class); + $this->appState = $this->getMockBuilder(State::class) + ->setMethods(['getAreaCode']) + ->disableOriginalConstructor() + ->getMock(); + + /** @var \Magento\Framework\Session\SidResolver $sidResolver */ + $this->_sidResolver = $this->objectManager->create( + \Magento\Framework\Session\SidResolver::class, + [ + 'appState' => $this->appState, + ] + ); $this->request = $this->objectManager->get(\Magento\Framework\App\RequestInterface::class); @@ -144,6 +167,9 @@ public function testDestroy() public function testSetSessionId() { $sessionId = $this->_model->getSessionId(); + $this->appState->expects($this->atLeastOnce()) + ->method('getAreaCode') + ->willReturn(\Magento\Framework\App\Area::AREA_FRONTEND); $this->_model->setSessionId($this->_sidResolver->getSid($this->_model)); $this->assertEquals($sessionId, $this->_model->getSessionId()); @@ -156,6 +182,9 @@ public function testSetSessionId() */ public function testSetSessionIdFromParam() { + $this->appState->expects($this->atLeastOnce()) + ->method('getAreaCode') + ->willReturn(\Magento\Framework\App\Area::AREA_FRONTEND); $this->assertNotEquals('test_id', $this->_model->getSessionId()); $this->request->getQuery()->set($this->_sidResolver->getSessionIdQueryParam($this->_model), 'test-id'); $this->_model->setSessionId($this->_sidResolver->getSid($this->_model)); diff --git a/dev/tests/integration/testsuite/Magento/Framework/Session/SidResolverTest.php b/dev/tests/integration/testsuite/Magento/Framework/Session/SidResolverTest.php index 2cfb8b47da7c3..6e043728b073a 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Session/SidResolverTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Session/SidResolverTest.php @@ -5,6 +5,7 @@ */ namespace Magento\Framework\Session; +use Magento\Framework\App\State; use Zend\Stdlib\Parameters; class SidResolverTest extends \PHPUnit\Framework\TestCase @@ -49,6 +50,11 @@ class SidResolverTest extends \PHPUnit\Framework\TestCase */ protected $request; + /** + * @var State|\PHPUnit_Framework_MockObject_MockObject + */ + private $appState; + protected function setUp() { $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); @@ -70,6 +76,11 @@ protected function setUp() $this->request = $objectManager->get(\Magento\Framework\App\RequestInterface::class); + $this->appState = $this->getMockBuilder(State::class) + ->setMethods(['getAreaCode']) + ->disableOriginalConstructor() + ->getMock(); + $this->model = $objectManager->create( \Magento\Framework\Session\SidResolver::class, [ @@ -77,6 +88,7 @@ protected function setUp() 'urlBuilder' => $this->urlBuilder, 'sidNameMap' => [$this->customSessionName => $this->customSessionQueryParam], 'request' => $this->request, + 'appState' => $this->appState, ] ); } @@ -95,6 +107,10 @@ public function tearDown() */ public function testGetSid($sid, $useFrontedSid, $isOwnOriginUrl, $testSid) { + $this->appState->expects($this->atLeastOnce()) + ->method('getAreaCode') + ->willReturn(\Magento\Framework\App\Area::AREA_FRONTEND); + $this->scopeConfig->expects( $this->any() )->method( diff --git a/dev/tests/integration/testsuite/Magento/MessageQueue/Model/Cron/ConsumersRunnerTest.php b/dev/tests/integration/testsuite/Magento/MessageQueue/Model/Cron/ConsumersRunnerTest.php new file mode 100644 index 0000000000000..3d717d6282268 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MessageQueue/Model/Cron/ConsumersRunnerTest.php @@ -0,0 +1,260 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\MessageQueue\Model\Cron; + +use Magento\Framework\MessageQueue\Consumer\ConfigInterface as ConsumerConfigInterface; +use Magento\MessageQueue\Model\Cron\ConsumersRunner\PidConsumerManager; +use Magento\Framework\App\DeploymentConfig\FileReader; +use Magento\Framework\App\DeploymentConfig\Writer; +use Magento\Framework\Config\File\ConfigFilePool; +use Magento\Framework\ShellInterface; +use Magento\Framework\Filesystem; +use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\App\Config\ReinitableConfigInterface; + +/** + * Tests the different cases of consumers running by ConsumersRunner + * + * {@inheritdoc} + */ +class ConsumersRunnerTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * Consumer config provider + * + * @var ConsumerConfigInterface + */ + private $consumerConfig; + + /** + * @var PidConsumerManager + */ + private $pid; + + /** + * @var FileReader + */ + private $reader; + + /** + * @var ConsumersRunner + */ + private $consumersRunner; + + /** + * @var Filesystem + */ + private $filesystem; + + /** + * @var ConfigFilePool + */ + private $configFilePool; + + /** + * @var ReinitableConfigInterface + */ + private $appConfig; + + /** + * @var ShellInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $shellMock; + + /** + * @var array + */ + private $config; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->shellMock = $this->getMockBuilder(ShellInterface::class) + ->getMockForAbstractClass(); + $this->pid = $this->objectManager->get(PidConsumerManager::class); + $this->consumerConfig = $this->objectManager->get(ConsumerConfigInterface::class); + $this->reader = $this->objectManager->get(FileReader::class); + $this->filesystem = $this->objectManager->get(Filesystem::class); + $this->configFilePool = $this->objectManager->get(ConfigFilePool::class); + $this->appConfig = $this->objectManager->get(ReinitableConfigInterface::class); + $this->consumersRunner = $this->objectManager->create( + ConsumersRunner::class, + ['shellBackground' => $this->shellMock] + ); + $this->config = $this->loadConfig(); + + $this->shellMock->expects($this->any()) + ->method('execute') + ->willReturnCallback(function ($command, $arguments) { + $command = vsprintf($command, $arguments); + $params = \Magento\TestFramework\Helper\Bootstrap::getInstance()->getAppInitParams(); + $params['MAGE_DIRS']['base']['path'] = BP; + $params = 'INTEGRATION_TEST_PARAMS="' . urldecode(http_build_query($params)) . '"'; + $command = str_replace('bin/magento', 'dev/tests/integration/bin/magento', $command); + $command = $params . ' ' . $command; + + return exec("{$command} > /dev/null &"); + }); + } + + /** + * Checks that pid files are created + * + * @return void + */ + public function testCheckThatPidFilesWasCreated() + { + $this->consumersRunner->run(); + foreach ($this->consumerConfig->getConsumers() as $consumer) { + $this->waitConsumerPidFile($consumer->getName()); + } + } + + /** + * Tests running of specific consumer and his re-running when it is working + * + * @return void + */ + public function testSpecificConsumerAndRerun() + { + $specificConsumer = 'quoteItemCleaner'; + $pidFilePath = $specificConsumer . ConsumersRunner::PID_FILE_EXT; + $config = $this->config; + $config['cron_consumers_runner'] = ['consumers' => [$specificConsumer], 'max_messages' => 0]; + + $this->writeConfig($config); + $this->reRunConsumersAndCheckPidFiles($specificConsumer); + $pid = $this->pid->getPid($pidFilePath); + $this->reRunConsumersAndCheckPidFiles($specificConsumer); + $this->assertSame($pid, $this->pid->getPid($pidFilePath)); + } + + /** + * @param string $specificConsumer + * @return void + */ + private function reRunConsumersAndCheckPidFiles($specificConsumer) + { + $this->consumersRunner->run(); + + sleep(20); + + foreach ($this->consumerConfig->getConsumers() as $consumer) { + $consumerName = $consumer->getName(); + $pidFileFullPath = $this->getPidFileFullPath($consumerName); + + if ($consumerName === $specificConsumer) { + $this->assertTrue(file_exists($pidFileFullPath)); + } else { + $this->assertFalse(file_exists($pidFileFullPath)); + } + } + } + + /** + * Tests disabling cron job which runs consumers + * + * @return void + */ + public function testCronJobDisabled() + { + $config = $this->config; + $config['cron_consumers_runner'] = ['cron_run' => false]; + + $this->writeConfig($config); + + $this->consumersRunner->run(); + + sleep(20); + + foreach ($this->consumerConfig->getConsumers() as $consumer) { + $pidFileFullPath = $this->getPidFileFullPath($consumer->getName()); + $this->assertFalse(file_exists($pidFileFullPath)); + } + } + + /** + * @param string $consumerName + * @return void + */ + private function waitConsumerPidFile($consumerName) + { + $pidFileFullPath = $this->getPidFileFullPath($consumerName); + $i = 0; + do { + sleep(1); + } while (!file_exists($pidFileFullPath) && ($i++ < 60)); + + if (!file_exists($pidFileFullPath)) { + $this->fail($consumerName . ' pid file does not exist.'); + } + } + + /** + * @return array + */ + private function loadConfig() + { + return $this->reader->load(ConfigFilePool::APP_ENV); + } + + /** + * @param array $config + * @return void + */ + private function writeConfig(array $config) + { + /** @var Writer $writer */ + $writer = $this->objectManager->get(Writer::class); + $writer->saveConfig([ConfigFilePool::APP_ENV => $config]); + } + + /** + * @param string $consumerName + * @return string + */ + private function getPidFileFullPath($consumerName) + { + $directoryList = $this->objectManager->get(DirectoryList::class); + return $directoryList->getPath(DirectoryList::VAR_DIR) . '/' . $consumerName . ConsumersRunner::PID_FILE_EXT; + } + + /** + * @inheritdoc + */ + protected function tearDown() + { + foreach ($this->consumerConfig->getConsumers() as $consumer) { + $consumerName = $consumer->getName(); + $pidFileFullPath = $this->getPidFileFullPath($consumerName); + $pidFilePath = $consumerName . ConsumersRunner::PID_FILE_EXT; + $pid = $this->pid->getPid($pidFilePath); + + if ($pid && $this->pid->isRun($pidFilePath)) { + posix_kill($pid, SIGKILL); + } + + if (file_exists($pidFileFullPath)) { + unlink($pidFileFullPath); + } + } + + $this->filesystem->getDirectoryWrite(DirectoryList::CONFIG)->writeFile( + $this->configFilePool->getPath(ConfigFilePool::APP_ENV), + "<?php\n return array();\n" + ); + $this->writeConfig($this->config); + $this->appConfig->reinit(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/MessageQueue/Model/Plugin/ResourceModel/LockTest.php b/dev/tests/integration/testsuite/Magento/MessageQueue/Model/Plugin/ResourceModel/LockTest.php new file mode 100644 index 0000000000000..960114e35be7f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MessageQueue/Model/Plugin/ResourceModel/LockTest.php @@ -0,0 +1,64 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\MessageQueue\Model\Plugin\ResourceModel; + +use Magento\TestFramework\Event\Magento; + +class LockTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + /** + * @var \Magento\Framework\MessageQueue\LockInterface + */ + protected $lock; + + /** + * @var \Magento\Framework\MessageQueue\Lock\WriterInterface + */ + protected $writer; + + /** + * @var \Magento\Framework\MessageQueue\Lock\ReaderInterface + */ + protected $reader; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $this->lock = $this->objectManager->get(\Magento\Framework\MessageQueue\LockInterface::class); + $this->writer = $this->objectManager->get(\Magento\Framework\MessageQueue\Lock\WriterInterface::class); + $this->reader = $this->objectManager->get(\Magento\Framework\MessageQueue\Lock\ReaderInterface::class); + } + + /** + * Test to ensure Queue Lock Table is cleared when maintenance mode transitions from on to off. + * + * @return void + */ + public function testLockClearedByMaintenanceModeOff() + { + /** @var $maintenanceMode \Magento\Framework\App\MaintenanceMode */ + $maintenanceMode = $this->objectManager->get(\Magento\Framework\App\MaintenanceMode::class); + $code = md5('consumer.name-1'); + $this->lock->setMessageCode($code); + $this->writer->saveLock($this->lock); + $this->reader->read($this->lock, $code); + $id = $this->lock->getId(); + $maintenanceMode->set(true); + $maintenanceMode->set(false); + $this->reader->read($this->lock, $code); + $emptyId = $this->lock->getId(); + + $this->assertGreaterThanOrEqual('1', $id); + $this->assertEmpty($emptyId); + } +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/DataObject.php b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/DataObject.php new file mode 100644 index 0000000000000..31843be00a54b --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/DataObject.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\MysqlMq\Model; + +class DataObject extends \Magento\Framework\Api\AbstractExtensibleObject +{ + /** + * @return string + */ + public function getName() + { + return $this->_get('name'); + } + + /** + * @param string $name + * @return $this + */ + public function setName($name) + { + return $this->setData('name', $name); + } + + /** + * @return int|null + */ + public function getEntityId() + { + return $this->_get('entity_id'); + } + + /** + * @param int $entityId + * @return $this + */ + public function setEntityId($entityId) + { + return $this->setData('entity_id', $entityId); + } +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/DataObjectRepository.php b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/DataObjectRepository.php new file mode 100644 index 0000000000000..879872315ec51 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/DataObjectRepository.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\MysqlMq\Model; + +class DataObjectRepository +{ + /** + * @param DataObject $dataObject + * @param string $requiredParam + * @param int|null $optionalParam + * @return bool + */ + public function delayedOperation( + \Magento\MysqlMq\Model\DataObject $dataObject, + $requiredParam, + $optionalParam = null + ) { + echo "Processed '{$dataObject->getEntityId()}'; " + . "Required param '{$requiredParam}'; Optional param '{$optionalParam}'\n"; + return true; + } +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/Driver/QueueTest.php b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/Driver/QueueTest.php new file mode 100644 index 0000000000000..974d2d78079de --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/Driver/QueueTest.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\MysqlMq\Model\Driver; + +use Magento\MysqlMq\Model\Driver\Queue; + +/** + * Test for MySQL queue driver class. + * + * @magentoDbIsolation disabled + */ +class QueueTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Queue + */ + protected $queue; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + /** @var \Magento\Framework\MessageQueue\Config\Data $queueConfig */ + $queueConfig = $this->objectManager->get(\Magento\Framework\MessageQueue\Config\Data::class); + $queueConfig->reset(); + + $this->queue = $this->objectManager->create( + \Magento\MysqlMq\Model\Driver\Queue::class, + ['queueName' => 'queue2'] + ); + } + + protected function tearDown() + { + /** @var \Magento\Framework\MessageQueue\Config\Data $queueConfig */ + $queueConfig = $this->objectManager->get(\Magento\Framework\MessageQueue\Config\Data::class); + $queueConfig->reset(); + } + + /** + * @magentoDataFixture Magento/MysqlMq/_files/queues.php + */ + public function testPushAndDequeue() + { + /** @var \Magento\Framework\MessageQueue\EnvelopeFactory $envelopFactory */ + $envelopFactory = $this->objectManager->get(\Magento\Framework\MessageQueue\EnvelopeFactory::class); + $messageBody = '{"data": {"body": "Message body"}, "message_id": 1}'; + $topicName = 'some.topic'; + $envelop = $envelopFactory->create(['body' => $messageBody, 'properties' => ['topic_name' => $topicName]]); + + $this->queue->push($envelop); + + $messageFromQueue = $this->queue->dequeue(); + + $this->assertEquals($messageBody, $messageFromQueue->getBody()); + $actualMessageProperties = $messageFromQueue->getProperties(); + $this->assertArrayHasKey('topic_name', $actualMessageProperties); + $this->assertEquals($topicName, $actualMessageProperties['topic_name']); + } +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/ObserverTest.php b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/ObserverTest.php new file mode 100644 index 0000000000000..c22bf2823c10f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/ObserverTest.php @@ -0,0 +1,161 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\MysqlMq\Model; + +class ObserverTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + /** + * @var \Magento\MysqlMq\Model\Observer + */ + private $observer; + + /** + * @var \Magento\MysqlMq\Model\QueueManagement + */ + private $queueManagement; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->observer = $this->objectManager->get(\Magento\MysqlMq\Model\Observer::class); + $this->queueManagement = $this->objectManager->get(\Magento\MysqlMq\Model\QueueManagement::class); + } + + /** + * @magentoDataFixture Magento/MysqlMq/_files/queues.php + * @magentoDataFixture Magento/MysqlMq/_files/messages.php + * @magentoDataFixture Magento/MysqlMq/_files/messages_done_old.php + */ + public function testCleanUpOld() + { + /** @var \Magento\MysqlMq\Model\ResourceModel\MessageStatusCollectionFactory $messageStatusCollectionFactory */ + $messageStatusCollectionFactory = $this->objectManager + ->create(\Magento\MysqlMq\Model\ResourceModel\MessageStatusCollectionFactory::class); + + /** @var \Magento\MysqlMq\Model\ResourceModel\MessageCollectionFactory $messageStatusCollectionFactory */ + $messageCollectionFactory = $this->objectManager + ->create(\Magento\MysqlMq\Model\ResourceModel\MessageCollectionFactory::class); + + //Check how many messages in collection by the beginning of tests + $messageCollection = $messageCollectionFactory->create() + ->addFieldToFilter('topic_name', 'topic.updated.use.just.in.tests'); + $this->assertEquals(1, $messageCollection->getSize()); + $messageId = $messageCollection->getFirstItem()->getId(); + + $messageStatusCollection = $messageStatusCollectionFactory->create() + ->addFieldToFilter('message_id', $messageId); + $this->assertEquals(3, $messageStatusCollection->getSize()); + + //Run clean up once. It should move 3 out of 4 statuses to TO BE DELETED status + $this->observer->cleanupMessages(); + + $messageCollection = $messageCollectionFactory->create() + ->addFieldToFilter('topic_name', 'topic.updated.use.just.in.tests'); + $this->assertEquals(0, $messageCollection->getSize()); + $messageStatusCollection = $messageStatusCollectionFactory->create() + ->addFieldToFilter('message_id', $messageId); + $this->assertEquals(0, $messageStatusCollection->getSize()); + } + + /** + * @magentoDataFixture Magento/MysqlMq/_files/queues.php + * @magentoDataFixture Magento/MysqlMq/_files/messages.php + * @magentoDataFixture Magento/MysqlMq/_files/messages_done_old.php + * @magentoDataFixture Magento/MysqlMq/_files/messages_done_recent.php + */ + public function testCleanupMessages() + { + /** @var \Magento\MysqlMq\Model\ResourceModel\MessageStatusCollectionFactory $messageStatusCollectionFactory */ + $messageStatusCollectionFactory = $this->objectManager + ->create(\Magento\MysqlMq\Model\ResourceModel\MessageStatusCollectionFactory::class); + + /** @var \Magento\MysqlMq\Model\ResourceModel\MessageCollectionFactory $messageStatusCollectionFactory */ + $messageCollectionFactory = $this->objectManager + ->create(\Magento\MysqlMq\Model\ResourceModel\MessageCollectionFactory::class); + + //Check how many messages in collection by the beginning of tests + $messageCollection = $messageCollectionFactory->create() + ->addFieldToFilter('topic_name', 'topic.updated.use.just.in.tests'); + $this->assertEquals(1, $messageCollection->getSize()); + $messageId = $messageCollection->getFirstItem()->getId(); + + $messageStatusCollection = $messageStatusCollectionFactory->create() + ->addFieldToFilter('message_id', $messageId); + $this->assertEquals(4, $messageStatusCollection->getSize()); + + //Run clean up once. It should move 3 out of 4 statuses to TO BE DELETED status + $this->observer->cleanupMessages(); + + $messageCollection = $messageCollectionFactory->create() + ->addFieldToFilter('topic_name', 'topic.updated.use.just.in.tests'); + $this->assertEquals(1, $messageCollection->getSize()); + + $messageStatusCollection = $messageStatusCollectionFactory->create() + ->addFieldToFilter('message_id', $messageId) + ->addFieldToFilter('status', \Magento\MysqlMq\Model\QueueManagement::MESSAGE_STATUS_TO_BE_DELETED); + + $this->assertEquals(3, $messageStatusCollection->getSize()); + + // Change the Updated At in order to make job visible + $lastMessageStatus = $messageStatusCollectionFactory->create() + ->addFieldToFilter('message_id', $messageId) + ->addFieldToFilter('status', \Magento\MysqlMq\Model\QueueManagement::MESSAGE_STATUS_COMPLETE) + ->getFirstItem(); + $lastMessageStatus->setUpdatedAt(time() - 1 - 24 * 7 * 60 * 60) + ->save(); + + $this->observer->cleanupMessages(); + + $messageCollection = $messageCollectionFactory->create() + ->addFieldToFilter('topic_name', 'topic.updated.use.just.in.tests'); + $this->assertEquals(0, $messageCollection->getSize()); + $messageStatusCollection = $messageStatusCollectionFactory->create() + ->addFieldToFilter('message_id', $messageId); + $this->assertEquals(0, $messageStatusCollection->getSize()); + } + + /** + * @magentoDataFixture Magento/MysqlMq/_files/queues.php + * @magentoDataFixture Magento/MysqlMq/_files/messages.php + * @magentoDataFixture Magento/MysqlMq/_files/messages_in_progress.php + */ + public function testCleanupInProgressMessages() + { + /** @var \Magento\MysqlMq\Model\ResourceModel\MessageStatusCollectionFactory $messageStatusCollectionFactory */ + $messageStatusCollectionFactory = $this->objectManager + ->create(\Magento\MysqlMq\Model\ResourceModel\MessageStatusCollectionFactory::class); + + /** @var \Magento\MysqlMq\Model\ResourceModel\MessageCollectionFactory $messageStatusCollectionFactory */ + $messageCollectionFactory = $this->objectManager + ->create(\Magento\MysqlMq\Model\ResourceModel\MessageCollectionFactory::class); + + //Check how many messages in collection by the beginning of tests + $messageCollection = $messageCollectionFactory->create() + ->addFieldToFilter('topic_name', 'topic_second.updated.use.just.in.tests'); + $this->assertEquals(1, $messageCollection->getSize()); + $messageId = $messageCollection->getFirstItem()->getId(); + + $messageStatusCollection = $messageStatusCollectionFactory->create() + ->addFieldToFilter('message_id', $messageId); + $this->assertEquals(2, $messageStatusCollection->getSize()); + + $this->observer->cleanupMessages(); + + $messageCollection = $messageCollectionFactory->create() + ->addFieldToFilter('topic_name', 'topic_second.updated.use.just.in.tests'); + $this->assertEquals(1, $messageCollection->getSize()); + $messageStatusCollection = $messageStatusCollectionFactory->create() + ->addFieldToFilter('message_id', $messageId) + ->addFieldToFilter('status', \Magento\MysqlMq\Model\QueueManagement::MESSAGE_STATUS_RETRY_REQUIRED); + $this->assertEquals(1, $messageStatusCollection->getSize()); + $this->assertEquals(1, $messageStatusCollection->getFirstItem()->getNumberOfTrials()); + } +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/Processor.php b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/Processor.php new file mode 100644 index 0000000000000..3b2a76104a2cd --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/Processor.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\MysqlMq\Model; + +/** + * Test message processor is used by \Magento\MysqlMq\Model\PublisherTest + */ +class Processor +{ + /** + * @param \Magento\MysqlMq\Model\DataObject $message + */ + public function processMessage($message) + { + echo "Processed {$message->getEntityId()}\n"; + } + + /** + * @param \Magento\MysqlMq\Model\DataObject $message + */ + public function processMessageWithException($message) + { + throw new \LogicException("Exception during message processing happened. Entity: {{$message->getEntityId()}}"); + } +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/PublisherConsumerTest.php b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/PublisherConsumerTest.php new file mode 100644 index 0000000000000..f03d03d3a25fd --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/PublisherConsumerTest.php @@ -0,0 +1,200 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\MysqlMq\Model; + +use Magento\Framework\MessageQueue\PublisherInterface; + +/** + * Test for MySQL publisher class. + * + * @magentoDbIsolation disabled + */ +class PublisherConsumerTest extends \PHPUnit\Framework\TestCase +{ + const MAX_NUMBER_OF_TRIALS = 3; + + /** + * @var \Magento\Framework\MessageQueue\PublisherInterface + */ + protected $publisher; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->markTestIncomplete('Should be converted to queue config v2.'); + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $configPath = __DIR__ . '/../etc/queue.xml'; + $fileResolverMock = $this->createMock(\Magento\Framework\Config\FileResolverInterface::class); + $fileResolverMock->expects($this->any()) + ->method('get') + ->willReturn([$configPath => file_get_contents(($configPath))]); + + /** @var \Magento\Framework\MessageQueue\Config\Reader\Xml $xmlReader */ + $xmlReader = $this->objectManager->create( + \Magento\Framework\MessageQueue\Config\Reader\Xml::class, + ['fileResolver' => $fileResolverMock] + ); + + $newData = $xmlReader->read(); + + /** @var \Magento\Framework\MessageQueue\Config\Data $configData */ + $configData = $this->objectManager->get(\Magento\Framework\MessageQueue\Config\Data::class); + $configData->reset(); + $configData->merge($newData); + + $this->publisher = $this->objectManager->create(\Magento\Framework\MessageQueue\PublisherInterface::class); + } + + protected function tearDown() + { + $this->markTestIncomplete('Should be converted to queue config v2.'); + $this->consumeMessages('demoConsumerQueueOne', PHP_INT_MAX); + $this->consumeMessages('demoConsumerQueueTwo', PHP_INT_MAX); + $this->consumeMessages('demoConsumerQueueThree', PHP_INT_MAX); + $this->consumeMessages('demoConsumerQueueFour', PHP_INT_MAX); + $this->consumeMessages('demoConsumerQueueFive', PHP_INT_MAX); + $this->consumeMessages('demoConsumerQueueOneWithException', PHP_INT_MAX); + + $objectManagerConfiguration = [\Magento\Framework\MessageQueue\Config\Reader\Xml::class => [ + 'arguments' => [ + 'fileResolver' => ['instance' => \Magento\Framework\Config\FileResolverInterface::class], + ], + ], + ]; + $this->objectManager->configure($objectManagerConfiguration); + /** @var \Magento\Framework\MessageQueue\Config\Data $queueConfig */ + $queueConfig = $this->objectManager->get(\Magento\Framework\MessageQueue\Config\Data::class); + $queueConfig->reset(); + } + + /** + * @magentoDataFixture Magento/MysqlMq/_files/queues.php + */ + public function testPublishConsumeFlow() + { + /** @var \Magento\MysqlMq\Model\DataObjectFactory $objectFactory */ + $objectFactory = $this->objectManager->create(\Magento\MysqlMq\Model\DataObjectFactory::class); + /** @var \Magento\MysqlMq\Model\DataObject $object */ + $object = $objectFactory->create(); + for ($i = 0; $i < 10; $i++) { + $object->setName('Object name ' . $i)->setEntityId($i); + $this->publisher->publish('demo.object.created', $object); + } + for ($i = 0; $i < 5; $i++) { + $object->setName('Object name ' . $i)->setEntityId($i); + $this->publisher->publish('demo.object.updated', $object); + } + for ($i = 0; $i < 3; $i++) { + $object->setName('Object name ' . $i)->setEntityId($i); + $this->publisher->publish('demo.object.custom.created', $object); + } + + $outputPattern = '/(Processed \d+\s)/'; + /** There are total of 10 messages in the first queue, total expected consumption is 7, 3 then 0 */ + $this->consumeMessages('demoConsumerQueueOne', 7, 7, $outputPattern); + /** Consumer all messages which left in this queue */ + $this->consumeMessages('demoConsumerQueueOne', PHP_INT_MAX, 3, $outputPattern); + $this->consumeMessages('demoConsumerQueueOne', 7, 0, $outputPattern); + + /** Verify that messages were added correctly to second queue for update and create topics */ + $this->consumeMessages('demoConsumerQueueTwo', 20, 15, $outputPattern); + + /** Verify that messages were NOT added to fourth queue */ + $this->consumeMessages('demoConsumerQueueFour', 11, 0, $outputPattern); + + /** Verify that messages were added correctly by '*' pattern in bind config to third queue */ + $this->consumeMessages('demoConsumerQueueThree', 20, 15, $outputPattern); + + /** Verify that messages were added correctly by '#' pattern in bind config to fifth queue */ + $this->consumeMessages('demoConsumerQueueFive', 20, 18, $outputPattern); + } + + /** + * @magentoDataFixture Magento/MysqlMq/_files/queues.php + */ + public function testPublishAndConsumeWithFailedJobs() + { + /** @var \Magento\MysqlMq\Model\DataObjectFactory $objectFactory */ + $objectFactory = $this->objectManager->create(\Magento\MysqlMq\Model\DataObjectFactory::class); + /** @var \Magento\MysqlMq\Model\DataObject $object */ + /** Try consume messages for MAX_NUMBER_OF_TRIALS and then consumer them without exception */ + $object = $objectFactory->create(); + for ($i = 0; $i < 5; $i++) { + $object->setName('Object name ' . $i)->setEntityId($i); + $this->publisher->publish('demo.object.created', $object); + } + $outputPattern = '/(Processed \d+\s)/'; + for ($i = 0; $i < self::MAX_NUMBER_OF_TRIALS; $i++) { + $this->consumeMessages('demoConsumerQueueOneWithException', PHP_INT_MAX, 0, $outputPattern); + } + $this->consumeMessages('demoConsumerQueueOne', PHP_INT_MAX, 0, $outputPattern); + + /** Try consume messages for MAX_NUMBER_OF_TRIALS+1 and then consumer them without exception */ + for ($i = 0; $i < 5; $i++) { + $object->setName('Object name ' . $i)->setEntityId($i); + $this->publisher->publish('demo.object.created', $object); + } + /** Try consume messages for MAX_NUMBER_OF_TRIALS and then consumer them without exception */ + for ($i = 0; $i < self::MAX_NUMBER_OF_TRIALS + 1; $i++) { + $this->consumeMessages('demoConsumerQueueOneWithException', PHP_INT_MAX, 0, $outputPattern); + } + /** Make sure that messages are not accessible anymore after number of trials is exceeded */ + $this->consumeMessages('demoConsumerQueueOne', PHP_INT_MAX, 0, $outputPattern); + } + + /** + * @magentoDataFixture Magento/MysqlMq/_files/queues.php + */ + public function testPublishAndConsumeSchemaDefinedByMethod() + { + /** @var \Magento\MysqlMq\Model\DataObjectFactory $objectFactory */ + $objectFactory = $this->objectManager->create(\Magento\MysqlMq\Model\DataObjectFactory::class); + /** @var \Magento\MysqlMq\Model\DataObject $object */ + $object = $objectFactory->create(); + $id = 33; + $object->setName('Object name ' . $id)->setEntityId($id); + $requiredStringParam = 'Required value'; + $optionalIntParam = 44; + $this->publisher->publish('test.schema.defined.by.method', [$object, $requiredStringParam, $optionalIntParam]); + $outputPattern = "/Processed '{$object->getEntityId()}'; " + . "Required param '{$requiredStringParam}'; Optional param '{$optionalIntParam}'/"; + $this->consumeMessages('delayedOperationConsumer', PHP_INT_MAX, 1, $outputPattern); + } + + /** + * Make sure that consumers consume correct number of messages. + * + * @param string $consumerName + * @param int|null $messagesToProcess + * @param int|null $expectedNumberOfProcessedMessages + * @param string|null $outputPattern + */ + protected function consumeMessages( + $consumerName, + $messagesToProcess, + $expectedNumberOfProcessedMessages = null, + $outputPattern = null + ) { + /** @var \Magento\Framework\MessageQueue\ConsumerFactory $consumerFactory */ + $consumerFactory = $this->objectManager->create(\Magento\Framework\MessageQueue\ConsumerFactory::class); + $consumer = $consumerFactory->get($consumerName); + ob_start(); + $consumer->process($messagesToProcess); + $consumersOutput = ob_get_contents(); + ob_end_clean(); + if ($outputPattern) { + $this->assertEquals( + $expectedNumberOfProcessedMessages, + preg_match_all($outputPattern, $consumersOutput) + ); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/Model/QueueManagementTest.php b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/QueueManagementTest.php new file mode 100644 index 0000000000000..197df29233297 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/Model/QueueManagementTest.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\MysqlMq\Model; + +use Magento\MysqlMq\Model\QueueManagement; + +/** + * Test for Queue Management class. + */ +class QueueManagementTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var QueueManagement + */ + protected $queueManagement; + + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $objectManager; + + protected function setUp() + { + $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $this->queueManagement = $this->objectManager->create(\Magento\MysqlMq\Model\QueueManagement::class); + } + + /** + * @magentoDataFixture Magento/MysqlMq/_files/queues.php + */ + public function testAllFlows() + { + $this->queueManagement->addMessageToQueues('topic1', 'messageBody1', ['queue1', 'queue2']); + $this->queueManagement->addMessageToQueues('topic2', 'messageBody2', ['queue2', 'queue3']); + $this->queueManagement->addMessageToQueues('topic3', 'messageBody3', ['queue1', 'queue3']); + $this->queueManagement->addMessageToQueues('topic4', 'messageBody4', ['queue1', 'queue2', 'queue3']); + $maxMessagesNumber = 2; + $messages = $this->queueManagement->readMessages('queue3', $maxMessagesNumber); + + $this->assertCount($maxMessagesNumber, $messages); + + $firstMessage = array_shift($messages); + $this->assertEquals('topic2', $firstMessage[QueueManagement::MESSAGE_TOPIC]); + $this->assertEquals('messageBody2', $firstMessage[QueueManagement::MESSAGE_BODY]); + $this->assertEquals('queue3', $firstMessage[QueueManagement::MESSAGE_QUEUE_NAME]); + $this->assertEquals( + QueueManagement::MESSAGE_STATUS_IN_PROGRESS, + $firstMessage[QueueManagement::MESSAGE_STATUS] + ); + $this->assertTrue(is_numeric($firstMessage[QueueManagement::MESSAGE_QUEUE_ID])); + $this->assertTrue(is_numeric($firstMessage[QueueManagement::MESSAGE_ID])); + $this->assertTrue(is_numeric($firstMessage[QueueManagement::MESSAGE_QUEUE_RELATION_ID])); + $this->assertEquals(0, $firstMessage[QueueManagement::MESSAGE_NUMBER_OF_TRIALS]); + $this->assertCount(12, date_parse($firstMessage[QueueManagement::MESSAGE_UPDATED_AT])); + + $secondMessage = array_shift($messages); + $this->assertEquals('topic3', $secondMessage[QueueManagement::MESSAGE_TOPIC]); + $this->assertEquals('messageBody3', $secondMessage[QueueManagement::MESSAGE_BODY]); + $this->assertEquals('queue3', $secondMessage[QueueManagement::MESSAGE_QUEUE_NAME]); + $this->assertEquals( + QueueManagement::MESSAGE_STATUS_IN_PROGRESS, + $secondMessage[QueueManagement::MESSAGE_STATUS] + ); + $this->assertTrue(is_numeric($secondMessage[QueueManagement::MESSAGE_QUEUE_ID])); + $this->assertTrue(is_numeric($secondMessage[QueueManagement::MESSAGE_ID])); + $this->assertTrue(is_numeric($secondMessage[QueueManagement::MESSAGE_QUEUE_RELATION_ID])); + $this->assertEquals(0, $secondMessage[QueueManagement::MESSAGE_NUMBER_OF_TRIALS]); + $this->assertCount(12, date_parse($secondMessage[QueueManagement::MESSAGE_UPDATED_AT])); + + /** Mark one message as complete or failed and make sure it is not displayed in the list of read messages */ + $this->queueManagement->changeStatus( + [ + $secondMessage[QueueManagement::MESSAGE_QUEUE_RELATION_ID] + ], + QueueManagement::MESSAGE_STATUS_COMPLETE + ); + $messages = $this->queueManagement->readMessages('queue3', $maxMessagesNumber); + $this->assertCount(1, $messages); + + $this->queueManagement->changeStatus( + [ + $firstMessage[QueueManagement::MESSAGE_QUEUE_RELATION_ID] + ], + QueueManagement::MESSAGE_STATUS_ERROR + ); + $messages = $this->queueManagement->readMessages('queue3', $maxMessagesNumber); + $this->assertCount(0, $messages); + + /** Ensure that message for retry is still accessible when reading messages from the queue */ + $messages = $this->queueManagement->readMessages('queue2', 1); + $message = array_shift($messages); + $messageRelationId = $message[QueueManagement::MESSAGE_QUEUE_RELATION_ID]; + + for ($i = 0; $i < 2; $i++) { + $this->assertEquals($i, $message[QueueManagement::MESSAGE_NUMBER_OF_TRIALS]); + $this->queueManagement->pushToQueueForRetry($message[QueueManagement::MESSAGE_QUEUE_RELATION_ID]); + $messages = $this->queueManagement->readMessages('queue2', 1); + $message = array_shift($messages); + $this->assertEquals($messageRelationId, $message[QueueManagement::MESSAGE_QUEUE_RELATION_ID]); + } + } +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages.php b/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages.php new file mode 100644 index 0000000000000..413ff50f70977 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\MysqlMq\Model\MessageFactory $messageFactory */ +$messageFactory = $objectManager->create(\Magento\MysqlMq\Model\MessageFactory::class); +$message = $messageFactory->create(); + +$message->setTopicName('topic.updated.use.just.in.tests') + ->setBody('{test:test}') + ->save(); + +$message = $messageFactory->create(); + +$message->setTopicName('topic_second.updated.use.just.in.tests') + ->setBody('{test:test}') + ->save(); + +$message = $messageFactory->create(); + +$message->setTopicName('topic_thrird.updated.use.just.in.tests') + ->setBody('{test:test}') + ->save(); diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages_done_old.php b/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages_done_old.php new file mode 100644 index 0000000000000..64d0ffcadde8a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages_done_old.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\MysqlMq\Model\MessageFactory $messageFactory */ +$messageFactory = $objectManager->create(\Magento\MysqlMq\Model\MessageFactory::class); +$message1 = $messageFactory->create() + ->load('topic.updated.use.just.in.tests', 'topic_name'); + +$messageId1 = $message1->getId(); + +/** @var \Magento\MysqlMq\Model\MessageStatusFactory $messageStatusFactory */ +$queueFactory = $objectManager->create(\Magento\MysqlMq\Model\QueueFactory::class); +$queueId1 = $queueFactory->create() + ->load('queue1', Magento\MysqlMq\Model\Queue::KEY_NAME) + ->getId(); +$queueId2 = $queueFactory->create() + ->load('queue2', Magento\MysqlMq\Model\Queue::KEY_NAME) + ->getId(); +$queueId3 = $queueFactory->create() + ->load('queue3', Magento\MysqlMq\Model\Queue::KEY_NAME) + ->getId(); +$queueId4 = $queueFactory->create() + ->load('queue4', Magento\MysqlMq\Model\Queue::KEY_NAME) + ->getId(); + +$plan = [ + [ + $messageId1, + $queueId1, + time() - 1 - 24 * 7 * 60 * 60, Magento\MysqlMq\Model\QueueManagement::MESSAGE_STATUS_COMPLETE + ], + [ + $messageId1, + $queueId2, + time() - 1 - 24 * 7 * 60 * 60, Magento\MysqlMq\Model\QueueManagement::MESSAGE_STATUS_ERROR + ], + [ + $messageId1, + $queueId3, + time() - 1 - 24 * 7 * 60 * 60, Magento\MysqlMq\Model\QueueManagement::MESSAGE_STATUS_COMPLETE + ], +]; + +/** @var \Magento\MysqlMq\Model\MessageStatusFactory $messageStatusFactory */ +$messageStatusFactory = $objectManager->create(\Magento\MysqlMq\Model\MessageStatusFactory::class); +foreach ($plan as $instruction) { + $messageStatus = $messageStatusFactory->create(); + + $messageStatus->setQueueId($instruction[1]) + ->setMessageId($instruction[0]) + ->setUpdatedAt($instruction[2]) + ->setStatus($instruction[3]) + ->save(); +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages_done_recent.php b/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages_done_recent.php new file mode 100644 index 0000000000000..2a0f09b9967ba --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages_done_recent.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\MysqlMq\Model\MessageFactory $messageFactory */ +$messageFactory = $objectManager->create(\Magento\MysqlMq\Model\MessageFactory::class); +$message1 = $messageFactory->create() + ->load('topic.updated.use.just.in.tests', 'topic_name'); + +$messageId1 = $message1->getId(); + +/** @var \Magento\MysqlMq\Model\MessageStatusFactory $messageStatusFactory */ +$queueFactory = $objectManager->create(\Magento\MysqlMq\Model\QueueFactory::class); +$queueId4 = $queueFactory->create() + ->load('queue4', Magento\MysqlMq\Model\Queue::KEY_NAME) + ->getId(); + +$plan = [ + [$messageId1, $queueId4, time(), Magento\MysqlMq\Model\QueueManagement::MESSAGE_STATUS_COMPLETE], +]; + +/** @var \Magento\MysqlMq\Model\MessageStatusFactory $messageStatusFactory */ +$messageStatusFactory = $objectManager->create(\Magento\MysqlMq\Model\MessageStatusFactory::class); +foreach ($plan as $instruction) { + $messageStatus = $messageStatusFactory->create(); + + $messageStatus->setQueueId($instruction[1]) + ->setMessageId($instruction[0]) + ->setUpdatedAt($instruction[2]) + ->setStatus($instruction[3]) + ->save(); +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages_in_progress.php b/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages_in_progress.php new file mode 100644 index 0000000000000..88607060f4fce --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/_files/messages_in_progress.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + +/** @var \Magento\MysqlMq\Model\MessageFactory $messageFactory */ +$messageFactory = $objectManager->create(\Magento\MysqlMq\Model\MessageFactory::class); +$message1 = $messageFactory->create() + ->load('topic_second.updated.use.just.in.tests', 'topic_name'); + +$messageId1 = $message1->getId(); + +/** @var \Magento\MysqlMq\Model\MessageStatusFactory $messageStatusFactory */ +$queueFactory = $objectManager->create(\Magento\MysqlMq\Model\QueueFactory::class); +$queueId1 = $queueFactory->create() + ->load('queue1', Magento\MysqlMq\Model\Queue::KEY_NAME) + ->getId(); +$queueId2 = $queueFactory->create() + ->load('queue2', Magento\MysqlMq\Model\Queue::KEY_NAME) + ->getId(); +$queueId3 = $queueFactory->create() + ->load('queue3', Magento\MysqlMq\Model\Queue::KEY_NAME) + ->getId(); +$queueId4 = $queueFactory->create() + ->load('queue4', Magento\MysqlMq\Model\Queue::KEY_NAME) + ->getId(); + +$plan = [ + [$messageId1, $queueId1, time() - 1 - 24 * 7 * 60 * 60, + Magento\MysqlMq\Model\QueueManagement::MESSAGE_STATUS_IN_PROGRESS], + [$messageId1, $queueId2, time(), Magento\MysqlMq\Model\QueueManagement::MESSAGE_STATUS_IN_PROGRESS], +]; + +/** @var \Magento\MysqlMq\Model\MessageStatusFactory $messageStatusFactory */ +$messageStatusFactory = $objectManager->create(\Magento\MysqlMq\Model\MessageStatusFactory::class); +foreach ($plan as $instruction) { + $messageStatus = $messageStatusFactory->create(); + + $messageStatus->setQueueId($instruction[1]) + ->setMessageId($instruction[0]) + ->setUpdatedAt($instruction[2]) + ->setStatus($instruction[3]) + ->save(); +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/_files/queues.php b/dev/tests/integration/testsuite/Magento/MysqlMq/_files/queues.php new file mode 100644 index 0000000000000..4038ee1bd12d8 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/_files/queues.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +$queues = [ + 'queue1', + 'queue2', + 'queue3', + 'queue4', + 'demo-queue-1', + 'demo-queue-2', + 'demo-queue-3', + 'demo-queue-4', + 'demo-queue-5', + 'demo-queue-6', + 'demo-queue-7', + 'demo-queue-8', + 'demo-queue-9', +]; +foreach ($queues as $queueName) { + /** @var \Magento\MysqlMq\Model\Queue $queue */ + $queue = $objectManager->create(\Magento\MysqlMq\Model\Queue::class); + $queue->load($queueName, 'name'); + if (!$queue->getId()) { + $queue->setName($queueName)->save(); + } +} diff --git a/dev/tests/integration/testsuite/Magento/MysqlMq/etc/queue.xml b/dev/tests/integration/testsuite/Magento/MysqlMq/etc/queue.xml new file mode 100644 index 0000000000000..fd618d504df07 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/MysqlMq/etc/queue.xml @@ -0,0 +1,67 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/queue.xsd"> + <publisher name="demo-publisher-1" connection="db" exchange="magento"/> + <publisher name="demo-publisher-2" connection="db" exchange="magento"/> + + <publisher name="test-publisher-1" connection="amqp" exchange="magento"/> + <publisher name="test-publisher-3" connection="amqp" exchange="test-exchange-1"/> + + <topic name="demo.object.created" schema="Magento\MysqlMq\Model\DataObject" publisher="demo-publisher-1"/> + <topic name="demo.object.updated" schema="Magento\MysqlMq\Model\DataObject" publisher="demo-publisher-2"/> + <topic name="demo.object.custom.created" schema="Magento\MysqlMq\Model\DataObject" publisher="demo-publisher-2"/> + + <topic name="test.schema.defined.by.method" schema="Magento\MysqlMq\Model\DataObjectRepository::delayedOperation" publisher="demo-publisher-2"/> + + <topic name="customer.created" schema="Magento\Customer\Api\Data\CustomerInterface" publisher="test-publisher-1"/> + <topic name="customer.created.one" schema="Magento\Customer\Api\Data\CustomerInterface" publisher="test-publisher-1"/> + <topic name="customer.created.one.two" schema="Magento\Customer\Api\Data\CustomerInterface" publisher="test-publisher-1"/> + <topic name="customer.created.two" schema="Magento\Customer\Api\Data\CustomerInterface" publisher="test-publisher-1"/> + <topic name="customer.updated" schema="Magento\Customer\Api\Data\CustomerInterface" publisher="demo-publisher-2"/> + <topic name="customer.deleted" schema="Magento\Customer\Api\Data\CustomerInterface" publisher="demo-publisher-2"/> + <topic name="cart.created" schema="Magento\Quote\Api\Data\CartInterface" publisher="test-publisher-3"/> + <topic name="cart.created.one" schema="Magento\Quote\Api\Data\CartInterface" publisher="test-publisher-3"/> + + <consumer name="demoConsumerQueueOne" queue="demo-queue-1" connection="db" class="\Magento\MysqlMq\Model\Processor" method="processMessage"/> + <consumer name="demoConsumerQueueOneWithException" queue="demo-queue-1" connection="db" class="\Magento\MysqlMq\Model\Processor" method="processMessageWithException"/> + <consumer name="demoConsumerQueueTwo" queue="demo-queue-2" connection="db" class="\Magento\MysqlMq\Model\Processor" method="processMessage"/> + <consumer name="demoConsumerQueueThree" queue="demo-queue-3" connection="db" class="\Magento\MysqlMq\Model\Processor" method="processMessage"/> + <consumer name="demoConsumerQueueFour" queue="demo-queue-4" connection="db" class="\Magento\MysqlMq\Model\Processor" method="processMessage"/> + <consumer name="demoConsumerQueueFive" queue="demo-queue-5" connection="db" class="\Magento\MysqlMq\Model\Processor" method="processMessage"/> + + <consumer name="customerCreatedListener" queue="test-queue-1" connection="amqp" class="Magento\MysqlMq\Model\Processor" method="processMessage"/> + <consumer name="customerDeletedListener" queue="test-queue-2" connection="db" class="Magento\MysqlMq\Model\Processor" method="processMessage" max_messages="98765"/> + <consumer name="cartCreatedListener" queue="test-queue-3" connection="amqp" class="Magento\MysqlMq\Model\Processor" method="processMessage"/> + + <consumer name="delayedOperationConsumer" queue="demo-queue-6" connection="db" class="Magento\MysqlMq\Model\DataObjectRepository" method="delayedOperation"/> + + <bind queue="demo-queue-1" exchange="magento" topic="demo.object.created"/> + <bind queue="demo-queue-2" exchange="magento" topic="demo.object.created"/> + <bind queue="demo-queue-2" exchange="magento" topic="demo.object.updated"/> + <bind queue="demo-queue-3" exchange="magento" topic="demo.object.*"/> + <bind queue="demo-queue-5" exchange="magento" topic="demo.object.#"/> + + <bind queue="demo-queue-6" exchange="magento" topic="test.schema.defined.by.method"/> + + <bind queue="test-queue-1" exchange="magento" topic="customer.created"/> + <bind queue="test-queue-1" exchange="magento" topic="customer.created.one"/> + <bind queue="test-queue-1" exchange="magento" topic="customer.created.one.two"/> + <bind queue="test-queue-1" exchange="magento" topic="customer.created.two"/> + <bind queue="test-queue-1" exchange="magento" topic="customer.updated"/> + <bind queue="test-queue-1" exchange="test-exchange-1" topic="cart.created"/> + <bind queue="test-queue-2" exchange="magento" topic="customer.created"/> + <bind queue="test-queue-2" exchange="magento" topic="customer.deleted"/> + <bind queue="test-queue-3" exchange="magento" topic="cart.created"/> + <bind queue="test-queue-3" exchange="magento" topic="cart.created.one"/> + <bind queue="test-queue-3" exchange="test-exchange-1" topic="cart.created"/> + <bind queue="test-queue-4" exchange="magento" topic="customer.*"/> + <bind queue="test-queue-5" exchange="magento" topic="customer.#"/> + <bind queue="test-queue-7" exchange="magento" topic="*.created.*"/> + <bind queue="test-queue-8" exchange="magento" topic="*.created.#"/> + <bind queue="test-queue-9" exchange="magento" topic="#"/> +</config> diff --git a/dev/tests/integration/testsuite/Magento/PageCache/Block/System/Config/Form/Field/ExportTest.php b/dev/tests/integration/testsuite/Magento/PageCache/Block/System/Config/Form/Field/ExportTest.php index 8abe1e9711d99..19e6bf450e01c 100644 --- a/dev/tests/integration/testsuite/Magento/PageCache/Block/System/Config/Form/Field/ExportTest.php +++ b/dev/tests/integration/testsuite/Magento/PageCache/Block/System/Config/Form/Field/ExportTest.php @@ -15,6 +15,8 @@ class ExportTest extends \Magento\TestFramework\TestCase\AbstractBackendControll * @covers \Magento\PageCache\Block\System\Config\Form\Field\Export::_getElementHtml * @covers \Magento\PageCache\Block\System\Config\Form\Field\Export\Varnish5::getVarnishVersion * @covers \Magento\PageCache\Block\System\Config\Form\Field\Export\Varnish4::getVarnishVersion + * @magentoAppIsolation enabled + * @magentoDbIsolation enabled */ public function testExportButtons() { diff --git a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php index 3606636d8130f..d59c402e22a71 100644 --- a/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php +++ b/dev/tests/integration/testsuite/Magento/Quote/Model/Quote/AddressTest.php @@ -225,7 +225,7 @@ public function testImportCustomerAddressDataWithCustomer() ->setLastname('Doe') ->setTelephone('123456') ->setPostcode('12345') - ->setCountryId(1) + ->setCountryId('US') ->setCity($city) ->setStreet([$street]); $addressData = $addressRepository->save($addressData); diff --git a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/SaveTest.php b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/SaveTest.php new file mode 100644 index 0000000000000..b9573c99b4493 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/Create/SaveTest.php @@ -0,0 +1,85 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Sales\Controller\Adminhtml\Order\Create; + +use Magento\Backend\Model\Session\Quote; +use Magento\Customer\Api\CustomerRepositoryInterface; +use Magento\Framework\Api\SearchCriteriaBuilder; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Message\MessageInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Sales\Model\Service\OrderService; +use Magento\TestFramework\TestCase\AbstractBackendController; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + +class SaveTest extends AbstractBackendController +{ + /** + * Checks a case when order creation is failed on payment method processing but new customer already created + * in the database and after new controller dispatching the customer should be already loaded in session + * to prevent invalid validation. + * + * @magentoAppArea adminhtml + * @magentoDataFixture Magento/Sales/_files/quote_with_new_customer.php + */ + public function testExecuteWithPaymentOperation() + { + $quote = $this->getQuote('2000000001'); + $session = $this->_objectManager->get(Quote::class); + $session->setQuoteId($quote->getId()); + $session->setCustomerId(0); + + $email = 'john.doe001@test.com'; + $data = [ + 'account' => [ + 'email' => $email + ] + ]; + $this->getRequest()->setPostValue(['order' => $data]); + + /** @var OrderService|MockObject $orderService */ + $orderService = $this->getMockBuilder(OrderService::class) + ->disableOriginalConstructor() + ->getMock(); + $orderService->method('place') + ->willThrowException(new LocalizedException(__('Transaction has been declined.'))); + $this->_objectManager->addSharedInstance($orderService, OrderService::class); + + $this->dispatch('backend/sales/order_create/save'); + $this->assertSessionMessages( + self::equalTo(['Transaction has been declined.']), + MessageInterface::TYPE_ERROR + ); + + /** @var CustomerRepositoryInterface $customerRepository */ + $customerRepository = $this->_objectManager->get(CustomerRepositoryInterface::class); + $customer = $customerRepository->get($email); + + self::assertNotEmpty($session->getCustomerId()); + self::assertEquals($customer->getId(), $session->getCustomerId()); + + $this->_objectManager->removeSharedInstance(OrderService::class); + } + + /** + * Gets quote by reserved order id. + * + * @param string $reservedOrderId + * @return \Magento\Quote\Api\Data\CartInterface + */ + private function getQuote($reservedOrderId) + { + /** @var SearchCriteriaBuilder $searchCriteriaBuilder */ + $searchCriteriaBuilder = $this->_objectManager->get(SearchCriteriaBuilder::class); + $searchCriteria = $searchCriteriaBuilder->addFilter('reserved_order_id', $reservedOrderId) + ->create(); + + /** @var CartRepositoryInterface $quoteRepository */ + $quoteRepository = $this->_objectManager->get(CartRepositoryInterface::class); + $items = $quoteRepository->getList($searchCriteria)->getItems(); + return array_pop($items); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_configurable_product.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_configurable_product.php new file mode 100644 index 0000000000000..65dffd015c809 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_configurable_product.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Sales\Model\Order\Payment; + +// @codingStandardsIgnoreFile + +require __DIR__ . '/../../../Magento/ConfigurableProduct/_files/product_configurable.php'; + +/** @var \Magento\Catalog\Model\Product $product */ +$configurableProduct = $product; + +$addressData = include __DIR__ . '/address_data.php'; + +$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); +/** @var \Magento\Sales\Model\Order\Address $billingAddress */ +$billingAddress = $objectManager->create(\Magento\Sales\Model\Order\Address::class, ['data' => $addressData]); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType('shipping'); + +/** @var Payment $payment */ +$payment = $objectManager->create(Payment::class); +$payment->setMethod('checkmo') + ->setAdditionalInformation([ + 'token_metadata' => [ + 'token' => 'f34vjw', + 'customer_id' => 1, + ], + ]); + +/** @var \Magento\Sales\Model\Order $order */ +$order = $objectManager->create(\Magento\Sales\Model\Order::class); +$order->setIncrementId('100000001') + ->setState(\Magento\Sales\Model\Order::STATE_PENDING_PAYMENT) + ->setStatus($order->getConfig()->getStateDefaultStatus(\Magento\Sales\Model\Order::STATE_PENDING_PAYMENT)) + ->setSubtotal(100) + ->setGrandTotal(100) + ->setBaseSubtotal(100) + ->setBaseGrandTotal(100) + ->setCustomerIsGuest(true) + ->setCustomerEmail('customer@null.com') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->setStoreId($objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->getStore()->getId()) + ->setPayment($payment); +$order->save(); + +$qtyOrdered = 2; +/** @var \Magento\Sales\Model\Order\Item $orderItem */ +$orderConfigurableItem = $objectManager->create(\Magento\Sales\Model\Order\Item::class); +$orderConfigurableItem->setProductId($configurableProduct->getId())->setQtyOrdered($qtyOrdered); +$orderConfigurableItem->setBasePrice($configurableProduct->getPrice()); +$orderConfigurableItem->setPrice($configurableProduct->getPrice()); +$orderConfigurableItem->setRowTotal($configurableProduct->getPrice()); +$orderConfigurableItem->setParentItemId(null); +$orderConfigurableItem->setProductType('configurable'); +$orderConfigurableItem->setOrder($order); +/** @var \Magento\Sales\Api\OrderItemRepositoryInterface $orderItemsRepository */ +$orderItemsRepository = $objectManager->create(\Magento\Sales\Api\OrderItemRepositoryInterface::class); +// Configurable item must be present in database to have its real ID to set parent id of simple product. +$orderItemsRepository->save($orderConfigurableItem); + +if ($configurableProduct->getExtensionAttributes() + && (array)$configurableProduct->getExtensionAttributes()->getConfigurableProductLinks() +) { + $simpleProductId = current($configurableProduct->getExtensionAttributes()->getConfigurableProductLinks()); + /** @var \Magento\Catalog\Api\Data\ProductInterface $simpleProduct */ + $simpleProduct = $productRepository->getById($simpleProductId); + $orderItem = $objectManager->create(\Magento\Sales\Api\Data\OrderItemInterface::class); + $orderItem->setBasePrice($simpleProduct->getPrice()); + $orderItem->setPrice($simpleProduct->getPrice()); + $orderItem->setRowTotal($simpleProduct->getPrice()); + $orderItem->setProductType('simple'); + // duplicate behavior with simple product associated with configurable one that happens during order process. + $orderItem->setProductId($simpleProduct->getId())->setQtyOrdered($qtyOrdered); + $orderItem->setParentItemId($orderConfigurableItem->getId()); + $orderItem->setOrder($order); + $orderItemsRepository->save($orderItem); +} \ No newline at end of file diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_configurable_product_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_configurable_product_rollback.php new file mode 100644 index 0000000000000..e838a8bc7f44a --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_configurable_product_rollback.php @@ -0,0 +1,7 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +require 'order_rollback.php'; diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_new_customer.php b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_new_customer.php new file mode 100644 index 0000000000000..09e0c93107236 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/quote_with_new_customer.php @@ -0,0 +1,74 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Catalog\Api\ProductRepositoryInterface; +use Magento\Catalog\Model\Product; +use Magento\Catalog\Model\Product\Attribute\Source\Status; +use Magento\Catalog\Model\Product\Visibility; +use Magento\CatalogInventory\Api\Data\StockItemInterface; +use Magento\Quote\Api\CartRepositoryInterface; +use Magento\Quote\Model\Quote; +use Magento\Quote\Model\Quote\Address; +use Magento\Store\Model\StoreManagerInterface; +use Magento\TestFramework\Helper\Bootstrap; + +/** @var \Magento\TestFramework\ObjectManager $objectManager */ +$objectManager = Bootstrap::getObjectManager(); + +/** @var Product $product */ +$product = $objectManager->create(Product::class); +$product->setTypeId('simple') + ->setAttributeSetId(4) + ->setName('Simple Product') + ->setSku('simple001') + ->setPrice(10) + ->setQty(100) + ->setVisibility(Visibility::VISIBILITY_BOTH) + ->setStatus(Status::STATUS_ENABLED); + +/** @var StockItemInterface $stockItem */ +$stockItem = $objectManager->create(StockItemInterface::class); +$stockItem->setQty(100) + ->setIsInStock(true); +$extensionAttributes = $product->getExtensionAttributes(); +$extensionAttributes->setStockItem($stockItem); + +/** @var ProductRepositoryInterface $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$product = $productRepository->save($product); + +$addressData = include __DIR__ . '/address_data.php'; +$billingAddress = $objectManager->create(Address::class, ['data' => $addressData]); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null) + ->setAddressType('shipping'); + +/** @var \Magento\Store\Api\Data\StoreInterface $store */ +$store = $objectManager->get(StoreManagerInterface::class) + ->getStore(); + +/** @var Quote $quote */ +$quote = $objectManager->create(Quote::class); +$quote->setCustomerIsGuest(false) + ->setCustomerEmail('john.doe001@test.com') + ->setStoreId($store->getId()) + ->setReservedOrderId('2000000001') + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->addProduct($product); + +$quote->getPayment() + ->setMethod('checkmo'); +$quote->getShippingAddress() + ->setShippingMethod('flatrate_flatrate') + ->setCollectShippingRates(true); +$quote->collectTotals(); + +/** @var CartRepositoryInterface $quoteRepository */ +$quoteRepository = $objectManager->get(CartRepositoryInterface::class); +$quoteRepository->save($quote); diff --git a/dev/tests/integration/testsuite/Magento/Search/Model/SynonymAnalyzerTest.php b/dev/tests/integration/testsuite/Magento/Search/Model/SynonymAnalyzerTest.php index 892ab57080a98..9fc9b10c89fa4 100644 --- a/dev/tests/integration/testsuite/Magento/Search/Model/SynonymAnalyzerTest.php +++ b/dev/tests/integration/testsuite/Magento/Search/Model/SynonymAnalyzerTest.php @@ -42,10 +42,38 @@ public static function loadGetSynonymsForPhraseDataProvider() 'phrase' => 'universe is enormous', 'expectedResult' => [['universe', 'cosmos'], ['is'], ['big', 'huge', 'large', 'enormous']] ], + 'WithCaseMismatch' => [ + 'phrase' => 'GNU\'s Not Unix', + 'expectedResult' => [['GNU\'s'], ['Not'], ['unix', 'linux'],] + ], + 'WithMultiWordPhrase' => [ + 'phrase' => 'Coastline of Great Britain stretches for 11,073 miles', + 'expectedResult' => [ + ['Coastline'], + ['of'], + ['Great Britain', 'United Kingdom'], + ['Britain'], + ['stretches'], + ['for'], + ['11,073'], + ['miles'] + ] + ], + 'PartialSynonymMatching' => [ + 'phrase' => 'Magento Engineering', + 'expectedResult' => [ + ['orange', 'magento'], + ['Engineering', 'Technical Staff'] + ] + ], 'noSynonyms' => [ 'phrase' => 'this sentence has no synonyms', 'expectedResult' => [['this'], ['sentence'], ['has'], ['no'], ['synonyms']] ], + 'multipleSpaces' => [ + 'phrase' => 'GNU\'s Not Unix', + 'expectedResult' => [['GNU\'s'], ['Not'], ['unix', 'linux'],] + ], 'oneMoreTest' => [ 'phrase' => 'schlicht', 'expectedResult' => [['schlicht', 'natürlich']] diff --git a/dev/tests/integration/testsuite/Magento/Search/_files/synonym_reader.php b/dev/tests/integration/testsuite/Magento/Search/_files/synonym_reader.php index f529b61522967..78c30cf458c51 100644 --- a/dev/tests/integration/testsuite/Magento/Search/_files/synonym_reader.php +++ b/dev/tests/integration/testsuite/Magento/Search/_files/synonym_reader.php @@ -24,9 +24,22 @@ $synonymsModel = $objectManager->create(\Magento\Search\Model\SynonymReader::class); $synonymsModel->setSynonyms('hill,mountain,peak')->setWebsiteId(1)->save(); +$synonymsModel = $objectManager->create(\Magento\Search\Model\SynonymReader::class); +$synonymsModel->setSynonyms('Community Engineering,Contributors,Magento Community Engineering')->setWebsiteId(1) + ->save(); + +$synonymsModel = $objectManager->create(\Magento\Search\Model\SynonymReader::class); +$synonymsModel->setSynonyms('Engineering,Technical Staff')->setWebsiteId(1)->save(); + // Synonym groups for "All Store Views" $synonymsModel = $objectManager->create(\Magento\Search\Model\SynonymReader::class); $synonymsModel->setSynonyms('universe,cosmos')->setWebsiteId(0)->save(); +$synonymsModel = $objectManager->create(\Magento\Search\Model\SynonymReader::class); +$synonymsModel->setSynonyms('unix,linux')->setWebsiteId(0)->save(); + +$synonymsModel = $objectManager->create(\Magento\Search\Model\SynonymReader::class); +$synonymsModel->setSynonyms('Great Britain,United Kingdom')->setWebsiteId(0)->save(); + $synonymsModel = $objectManager->create(\Magento\Search\Model\SynonymReader::class); $synonymsModel->setSynonyms('big,huge,large,enormous')->setWebsiteId(0)->save(); diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/etc/module.xml b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/etc/module.xml index d39e09c8f249a..e8e119f1ae48c 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/etc/module.xml +++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/A/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_A" setup_version="2.0.0" /> + <module name="Magento_A" /> </config> diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/etc/module.xml b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/etc/module.xml index e245ec4f4c0d8..9ab558e4147e0 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/etc/module.xml +++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/root/app/code/Magento/B/etc/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_B" setup_version="2.0.0" /> + <module name="Magento_B" /> </config> diff --git a/dev/tests/integration/testsuite/Magento/Setup/Module/DataSetupTest.php b/dev/tests/integration/testsuite/Magento/Setup/Module/DataSetupTest.php index 5abf33d9d5096..425840b44ba0e 100644 --- a/dev/tests/integration/testsuite/Magento/Setup/Module/DataSetupTest.php +++ b/dev/tests/integration/testsuite/Magento/Setup/Module/DataSetupTest.php @@ -38,15 +38,6 @@ public function testUpdateTableRow() ); } - /** - * @expectedException \Zend_Db_Statement_Exception - */ - public function testGetTableRow() - { - $this->assertNotEmpty($this->_model->getTableRow('setup_module', 'module', 'Magento_AdminNotification')); - $this->_model->getTableRow('setup/module', 'module', 'Magento_AdminNotification'); - } - /** * @expectedException \Zend_Db_Statement_Exception */ diff --git a/dev/tests/integration/testsuite/Magento/Ui/Config/ConverterTest.php b/dev/tests/integration/testsuite/Magento/Ui/Config/ConverterTest.php index eedb2c1f9c5f4..3f5766eb3f478 100644 --- a/dev/tests/integration/testsuite/Magento/Ui/Config/ConverterTest.php +++ b/dev/tests/integration/testsuite/Magento/Ui/Config/ConverterTest.php @@ -88,6 +88,7 @@ public function getComponentNameDataProvider() ['form'], ['hidden'], ['htmlContent'], + ['imageUploader'], ['input'], ['insertForm'], ['insertListing'], diff --git a/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/arbitrary/imageUploader.xml b/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/arbitrary/imageUploader.xml new file mode 100644 index 0000000000000..ed1fdd38da26f --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/arbitrary/imageUploader.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<imageUploader xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd"> + <argument name="data" xsi:type="array"> + <item name="config" xsi:type="array"> + <item name="isMultipleFiles" xsi:type="boolean">false</item> + <item name="maxFileSize" xsi:type="number">0</item> + <item name="placeholderType" xsi:type="string">string</item> + <item name="allowedExtensions" xsi:type="string">string</item> + <item name="previewTmpl" xsi:type="string">string</item> + <item name="dropZone" xsi:type="string">string</item> + <item name="uploaderConfig" xsi:type="array"> + <item name="anySimpleType" active="false" xsi:type="string">string</item> + </item> + <item name="openDialogTitle" xsi:type="string" translate="true">string</item> + <item name="visible" xsi:type="boolean">false</item> + <item name="disabled" xsi:type="boolean">false</item> + <item name="labelVisible" xsi:type="boolean">false</item> + <item name="showFallbackReset" xsi:type="boolean">false</item> + <item name="focused" xsi:type="boolean">false</item> + <item name="label" xsi:type="string" translate="true">string</item> + <item name="dataType" xsi:type="string">string</item> + <item name="elementTmpl" xsi:type="string">string</item> + <item name="tooltipTpl" xsi:type="string">string</item> + <item name="fallbackResetTpl" xsi:type="string">string</item> + <item name="placeholder" xsi:type="string" translate="true">text</item> + <item name="validation" xsi:type="array"> + <item name="anySimpleType" active="false" xsi:type="boolean">true</item> + </item> + <item name="notice" xsi:type="string" translate="true">string</item> + <item name="required" xsi:type="boolean">false</item> + <item name="switcherConfig" xsi:type="array"> + <item name="name" xsi:type="string">string</item> + <item name="component" xsi:type="string">string</item> + <item name="target" xsi:type="string">string</item> + <item name="property" xsi:type="string">string</item> + <item name="enabled" xsi:type="boolean">true</item> + <item name="rules" xsi:type="array"> + <item name="string" xsi:type="array"> + <item name="value" xsi:type="string">string</item> + <item name="actions" xsi:type="array"> + <item name="string" xsi:type="array"> + <item name="target" xsi:type="string">string</item> + <item name="callback" xsi:type="string">string</item> + <item name="params" xsi:type="array"> + <item name="string" active="true" xsi:type="string"/> + </item> + </item> + </item> + </item> + </item> + </item> + <item name="tooltip" xsi:type="array"> + <item name="link" xsi:type="string">string</item> + <item name="description" xsi:type="string" translate="true">string</item> + </item> + <item name="additionalClasses" xsi:type="array"> + <item name="string" xsi:type="boolean">false</item> + </item> + <item name="addbefore" xsi:type="string" translate="true">string</item> + <item name="addafter" xsi:type="string" translate="true">string</item> + <item name="provider" xsi:type="string">string</item> + <item name="component" xsi:type="string">string</item> + <item name="template" xsi:type="string">string</item> + <item name="sortOrder" xsi:type="number">0</item> + <item name="displayArea" xsi:type="string">string</item> + <item name="storageConfig" xsi:type="array"> + <item name="provider" xsi:type="string">string</item> + <item name="namespace" xsi:type="string">string</item> + <item name="path" xsi:type="url" path="string"> + <param name="string">string</param> + </item> + </item> + <item name="statefull" xsi:type="array"> + <item name="anySimpleType" xsi:type="boolean">true</item> + </item> + <item name="imports" xsi:type="array"> + <item name="string" xsi:type="string">string</item> + </item> + <item name="exports" xsi:type="array"> + <item name="string" xsi:type="string">string</item> + </item> + <item name="links" xsi:type="array"> + <item name="string" xsi:type="string">string</item> + </item> + <item name="listens" xsi:type="array"> + <item name="string" xsi:type="string">string</item> + </item> + <item name="ns" xsi:type="string">string</item> + <item name="componentType" xsi:type="string">string</item> + <item name="dataScope" xsi:type="string">string</item> + </item> + <item name="js_config" xsi:type="array"> + <item name="deps" xsi:type="array"> + <item name="0" xsi:type="string">string</item> + </item> + </item> + </argument> +</imageUploader> diff --git a/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/expected/imageUploader.php b/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/expected/imageUploader.php new file mode 100644 index 0000000000000..0a9324ddb9284 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/expected/imageUploader.php @@ -0,0 +1,411 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +return [ + 'arguments' => [ + 'data' => [ + 'name' => 'data', + 'xsi:type' => 'array', + 'item' => [ + 'config' => [ + 'name' => 'config', + 'xsi:type' => 'array', + 'item' => [ + 'isMultipleFiles' => [ + 'name' => 'isMultipleFiles', + 'xsi:type' => 'boolean', + 'value' => 'false', + ], + 'maxFileSize' => [ + 'name' => 'maxFileSize', + 'xsi:type' => 'number', + 'value' => '0', + ], + 'placeholderType' => [ + 'name' => 'placeholderType', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'allowedExtensions' => [ + 'name' => 'allowedExtensions', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'previewTmpl' => [ + 'name' => 'previewTmpl', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'dropZone' => [ + 'name' => 'dropZone', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'openDialogTitle' => [ + 'name' => 'openDialogTitle', + 'xsi:type' => 'string', + 'value' => 'string', + 'translate' => 'true' + ], + 'uploaderConfig' => [ + 'name' => 'uploaderConfig', + 'xsi:type' => 'array', + 'item' => [ + 'anySimpleType' => [ + 'name' => 'anySimpleType', + 'xsi:type' => 'string', + 'value' => 'string', + 'active' => 'false', + ], + ], + ], + 'visible' => [ + 'name' => 'visible', + 'xsi:type' => 'boolean', + 'value' => 'false', + ], + 'disabled' => [ + 'name' => 'disabled', + 'xsi:type' => 'boolean', + 'value' => 'false', + ], + 'labelVisible' => [ + 'name' => 'labelVisible', + 'xsi:type' => 'boolean', + 'value' => 'false', + ], + 'showFallbackReset' => [ + 'name' => 'showFallbackReset', + 'xsi:type' => 'boolean', + 'value' => 'false', + ], + 'focused' => [ + 'name' => 'focused', + 'xsi:type' => 'boolean', + 'value' => 'false', + ], + 'label' => [ + 'name' => 'label', + 'translate' => 'true', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'dataType' => [ + 'name' => 'dataType', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'elementTmpl' => [ + 'name' => 'elementTmpl', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'tooltipTpl' => [ + 'name' => 'tooltipTpl', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'fallbackResetTpl' => [ + 'name' => 'fallbackResetTpl', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'placeholder' => [ + 'name' => 'placeholder', + 'xsi:type' => 'string', + 'value' => 'text', + 'translate' => 'true', + ], + 'validation' => [ + 'name' => 'validation', + 'xsi:type' => 'array', + 'item' => [ + 'anySimpleType' => [ + 'name' => 'anySimpleType', + 'xsi:type' => 'boolean', + 'value' => 'true', + 'active' => 'false', + ], + ], + ], + 'notice' => [ + 'name' => 'notice', + 'translate' => 'true', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'required' => [ + 'name' => 'required', + 'xsi:type' => 'boolean', + 'value' => 'false', + ], + 'switcherConfig' => [ + 'name' => 'switcherConfig', + 'xsi:type' => 'array', + 'item' => [ + 'name' => [ + 'name' => 'name', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'component' => [ + 'name' => 'component', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'target' => [ + 'name' => 'target', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'property' => [ + 'name' => 'property', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'enabled' => [ + 'name' => 'enabled', + 'xsi:type' => 'boolean', + 'value' => 'true', + ], + 'rules' => [ + 'name' => 'rules', + 'xsi:type' => 'array', + 'item' => [ + 'string' => [ + 'name' => 'string', + 'xsi:type' => 'array', + 'item' => [ + 'value' => [ + 'name' => 'value', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'actions' => [ + 'name' => 'actions', + 'xsi:type' => 'array', + 'item' => [ + 'string' => [ + 'name' => 'string', + 'xsi:type' => 'array', + 'item' => [ + 'target' => [ + 'name' => 'target', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'callback' => [ + 'name' => 'callback', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'params' => [ + 'name' => 'params', + 'xsi:type' => 'array', + 'item' => [ + 'string' => [ + 'name' => 'string', + 'active' => 'true', + 'xsi:type' => 'string', + ], + ], + ], + ], + ], + ], + ], + ], + ], + ], + ], + ], + ], + 'tooltip' => [ + 'name' => 'tooltip', + 'xsi:type' => 'array', + 'item' => [ + 'link' => [ + 'name' => 'link', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'description' => [ + 'name' => 'description', + 'translate' => 'true', + 'xsi:type' => 'string', + 'value' => 'string', + ], + ], + ], + 'additionalClasses' => [ + 'name' => 'additionalClasses', + 'xsi:type' => 'array', + 'item' => [ + 'string' => [ + 'name' => 'string', + 'xsi:type' => 'boolean', + 'value' => 'false', + ], + ], + ], + 'addbefore' => [ + 'name' => 'addbefore', + 'translate' => 'true', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'addafter' => [ + 'name' => 'addafter', + 'translate' => 'true', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'provider' => [ + 'name' => 'provider', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'component' => [ + 'name' => 'component', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'template' => [ + 'name' => 'template', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'sortOrder' => [ + 'name' => 'sortOrder', + 'xsi:type' => 'number', + 'value' => '0', + ], + 'displayArea' => [ + 'name' => 'displayArea', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'storageConfig' => [ + 'name' => 'storageConfig', + 'xsi:type' => 'array', + 'item' => [ + 'provider' => [ + 'name' => 'provider', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'namespace' => [ + 'name' => 'namespace', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'path' => [ + 'name' => 'path', + 'xsi:type' => 'url', + 'param' => [ + 'string' => [ + 'name' => 'string', + 'value' => 'string', + ], + ], + 'path' => 'string', + ], + ], + ], + 'statefull' => [ + 'name' => 'statefull', + 'xsi:type' => 'array', + 'item' => [ + 'anySimpleType' => [ + 'name' => 'anySimpleType', + 'xsi:type' => 'boolean', + 'value' => 'true', + ], + ], + ], + 'imports' => [ + 'name' => 'imports', + 'xsi:type' => 'array', + 'item' => [ + 'string' => [ + 'name' => 'string', + 'xsi:type' => 'string', + 'value' => 'string', + ], + ], + ], + 'exports' => [ + 'name' => 'exports', + 'xsi:type' => 'array', + 'item' => [ + 'string' => [ + 'name' => 'string', + 'xsi:type' => 'string', + 'value' => 'string', + ], + ], + ], + 'links' => [ + 'name' => 'links', + 'xsi:type' => 'array', + 'item' => [ + 'string' => [ + 'name' => 'string', + 'xsi:type' => 'string', + 'value' => 'string', + ], + ], + ], + 'listens' => [ + 'name' => 'listens', + 'xsi:type' => 'array', + 'item' => [ + 'string' => [ + 'name' => 'string', + 'xsi:type' => 'string', + 'value' => 'string', + ], + ], + ], + 'ns' => [ + 'name' => 'ns', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'componentType' => [ + 'name' => 'componentType', + 'xsi:type' => 'string', + 'value' => 'string', + ], + 'dataScope' => [ + 'name' => 'dataScope', + 'xsi:type' => 'string', + 'value' => 'string', + ], + ], + ], + 'js_config' => [ + 'name' => 'js_config', + 'xsi:type' => 'array', + 'item' => [ + 'deps' => [ + 'name' => 'deps', + 'xsi:type' => 'array', + 'item' => [ + 0 => [ + 'name' => 0, + 'xsi:type' => 'string', + 'value' => 'string', + ], + ], + ], + ], + ], + ], + ], + ], + 'children' => [], + 'uiComponentType' => 'imageUploader', +]; diff --git a/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/mixed/imageUploader.xml b/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/mixed/imageUploader.xml new file mode 100644 index 0000000000000..81fb2bdff70f4 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/mixed/imageUploader.xml @@ -0,0 +1,116 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<imageUploader xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd" + name="string" + template="string" + component="string" + class="string" + provider="string" + sortOrder="0" + displayArea="string"> + <settings> + + <!-- uiElementSettings --> + <statefull> + <property xsi:type="boolean" name="anySimpleType">true</property> + </statefull> + <imports> + <link active="false" name="string">string</link> + </imports> + <exports> + <link active="false" name="string">string</link> + </exports> + <links> + <link active="false" name="string">string</link> + </links> + <listens> + <link active="false" name="string">string</link> + </listens> + <deps> + <dep active="false">string</dep> + </deps> + <ns>string</ns> + <componentType>string</componentType> + <dataScope>string</dataScope> + <storageConfig> + <provider>string</provider> + <namespace>string</namespace> + <path path="string"> + <param name="string">string</param> + </path> + </storageConfig> + <!-- /uiElementSettings --> + + <!-- abstractSettings--> + <additionalClasses> + <class name="string">false</class> + </additionalClasses> + <label translate="false">string</label> + <addBefore translate="false">string</addBefore> + <addAfter translate="false">string</addAfter> + <dataType>string</dataType> + <elementTmpl>string</elementTmpl> + <visible>false</visible> + <disabled>false</disabled> + <notice translate="false">string</notice> + <focused>false</focused> + <tooltipTpl>string</tooltipTpl> + <fallbackResetTpl>string</fallbackResetTpl> + <placeholder translate="true">text</placeholder> + <labelVisible>false</labelVisible> + <showFallbackReset>false</showFallbackReset> + <required>false</required> + <validation> + <rule xsi:type="boolean" active="false" name="anySimpleType">true</rule> + </validation> + <switcherConfig> + <component>string</component> + <name>string</name> + <target>string</target> + <property>string</property> + <enabled>true</enabled> + <argument name="string" xsi:type="array"> + <item name="string" xsi:type="string">string</item> + </argument> + <rules> + <rule name="string"> + <value>string</value> + <actions> + <action name="string"> + <target>string</target> + <callback>string</callback> + <params> + <param name="string" active="true" xsi:type="string"/> + </params> + </action> + </actions> + </rule> + </rules> + </switcherConfig> + <tooltip> + <link>string</link> + <description translate="true">string</description> + </tooltip> + + <!-- /abstractSettings--> + <isMultipleFiles>false</isMultipleFiles> + <maxFileSize>0</maxFileSize> + <placeholderType>string</placeholderType> + <allowedExtensions>string</allowedExtensions> + <previewTmpl>string</previewTmpl> + <dropZone>string</dropZone> + <uploaderConfig> + <param xsi:type="string" active="false" name="anySimpleType"> + string + </param> + </uploaderConfig> + <openDialogTitle>string</openDialogTitle> + + </settings> +</imageUploader> diff --git a/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/semantic/imageUploader.xml b/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/semantic/imageUploader.xml new file mode 100644 index 0000000000000..eee45874a7706 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Ui/_files/view/ui_component/semantic/imageUploader.xml @@ -0,0 +1,117 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<imageUploader xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd" + name="string" + template="string" + component="string" + class="string" + provider="string" + sortOrder="0" + displayArea="string"> + <settings> + + <!-- uiElementSettings --> + <statefull> + <property xsi:type="boolean" name="anySimpleType">true</property> + </statefull> + <imports> + <link active="false" name="string">string</link> + </imports> + <exports> + <link active="false" name="string">string</link> + </exports> + <links> + <link active="false" name="string">string</link> + </links> + <listens> + <link active="false" name="string">string</link> + </listens> + <deps> + <dep active="false">string</dep> + </deps> + <ns>string</ns> + <componentType>string</componentType> + <dataScope>string</dataScope> + <storageConfig> + <provider>string</provider> + <namespace>string</namespace> + <path path="string"> + <param name="string">string</param> + </path> + </storageConfig> + <!-- /uiElementSettings --> + + <!-- abstractSettings--> + <additionalClasses> + <class name="string">false</class> + </additionalClasses> + <label translate="false">string</label> + <addBefore translate="false">string</addBefore> + <addAfter translate="false">string</addAfter> + <dataType>string</dataType> + <elementTmpl>string</elementTmpl> + <visible>false</visible> + <disabled>false</disabled> + <notice translate="false">string</notice> + <focused>false</focused> + <tooltipTpl>string</tooltipTpl> + <fallbackResetTpl>string</fallbackResetTpl> + <placeholder translate="true">text</placeholder> + <labelVisible>false</labelVisible> + <showFallbackReset>false</showFallbackReset> + <required>false</required> + <validation> + <rule xsi:type="boolean" active="false" name="anySimpleType">true</rule> + </validation> + <switcherConfig> + <component>string</component> + <name>string</name> + <target>string</target> + <property>string</property> + <enabled>true</enabled> + <argument name="string" xsi:type="array"> + <item name="string" xsi:type="string">string</item> + </argument> + <rules> + <rule name="string"> + <value>string</value> + <actions> + <action name="string"> + <target>string</target> + <callback>string</callback> + <params> + <param name="string" active="true" xsi:type="string"/> + </params> + </action> + </actions> + </rule> + </rules> + </switcherConfig> + <tooltip> + <link>string</link> + <description translate="true">string</description> + </tooltip> + + <!-- /abstractSettings--> + <isMultipleFiles>false</isMultipleFiles> + <maxFileSize>0</maxFileSize> + <placeholderType>string</placeholderType> + <allowedExtensions>string</allowedExtensions> + <previewTmpl>string</previewTmpl> + <dropZone>string</dropZone> + + <uploaderConfig> + <param xsi:type="string" active="false" name="anySimpleType"> + string + </param> + </uploaderConfig> + + <openDialogTitle>string</openDialogTitle> + </settings> +</imageUploader> diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/components/dynamic-rows-import-custom-options.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/components/dynamic-rows-import-custom-options.test.js index c0d88f2f04ea1..3e904cd63821c 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/components/dynamic-rows-import-custom-options.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/components/dynamic-rows-import-custom-options.test.js @@ -55,7 +55,7 @@ define([ describe('Check processingInsertData', function () { it('Check with empty data.', function () { model.processingInsertData(); - expect(model.cacheGridData).toEqual([]); + expect(JSON.parse(JSON.stringify(model.cacheGridData))).toEqual([]); expect(model.insertData).not.toHaveBeenCalled(); }); @@ -64,21 +64,21 @@ define([ 'options': [] }]; model.processingInsertData(data); - expect(model.cacheGridData).toEqual([]); + expect(JSON.parse(JSON.stringify(model.cacheGridData))).toEqual([]); expect(model.insertData).not.toHaveBeenCalled(); }); it('Check with fake imported custom options data.', function () { model.processingInsertData(data); expect(model.insertData).toHaveBeenCalled(); - expect(model.cacheGridData[0]).toEqual({ + expect(JSON.parse(JSON.stringify(model.cacheGridData[0]))).toEqual({ 'option_type_id': 1, 'position': 1, 'values': [{ 'some_fake_value': 1 }] }); - expect(model.cacheGridData[1]).toEqual({ + expect(JSON.parse(JSON.stringify(model.cacheGridData[1]))).toEqual({ 'option_type_id': 2, 'position': 2, 'values': [{}] diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/image-uploader.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/image-uploader.test.js new file mode 100644 index 0000000000000..5dd3d43383bdb --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Ui/base/js/form/element/image-uploader.test.js @@ -0,0 +1,85 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +/*eslint max-nested-callbacks: 0*/ + +define([ + 'jquery', + 'Magento_Ui/js/form/element/image-uploader', + 'mage/adminhtml/browser' +], function ($, ImageUploader, browser) { + 'use strict'; + + describe('Magento_Ui/js/form/element/image-uploader', function () { + var component; + + beforeEach(function () { + component = new ImageUploader({ + dataScope: 'abstract' + }); + }); + + describe('initConfig method', function () { + it('sets mediaGalleryUid', function () { + component.initConfig(); + expect(component.mediaGalleryUid).toBeDefined(); + }); + }); + + describe('addFileFromMediaGallery method', function () { + it('adds file', function () { + var $el = $('div'); + + spyOn(component, 'addFile'); + + $el.data({ + 'size': 1024, + 'mime-type': 'image/png' + }); + + $el.val('/pub/media/something.png'); + + component.addFileFromMediaGallery(null, { + target: $el + }); + + expect(component.addFile).toHaveBeenCalledWith({ + type: 'image/png', + name: 'something.png', + url: '/pub/media/something.png', + size: 1024 + }); + }); + }); + + describe('openMediaBrowserDialog method', function () { + it('opens browser dialog', function () { + var $el = $('div'); + + $el.attr('id', 'theTargetId'); + + component.mediaGallery = { + openDialogUrl: 'http://example.com/', + openDialogTitle: 'Hello world', + storeId: 3 + }; + + spyOn(browser, 'openDialog'); + + component.openMediaBrowserDialog(null, { + target: $el + }); + + expect(browser.openDialog).toHaveBeenCalledWith( + 'http://example.com/target_element_id/theTargetId/store/3/type/image/' + + 'use_storage_root/1?isAjax=true', + null, + null, + 'Hello world' + ); + }); + }); + }); +}); diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/etc/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/etc/db_schema.xml index 68a0165821403..3eeb141c2e606 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/etc/db_schema.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/etc/db_schema.xml @@ -6,7 +6,7 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="reference_table" resource="sales"> <column xsi:type="tinyint" name="tinyint_ref" padding="7" nullable="false" identity="true" unsigned="false"/> <column xsi:type="tinyint" name="tinyint_without_padding" default="0" nullable="false" unsigned="false"/> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/dry_run_log.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/dry_run_log.php new file mode 100644 index 0000000000000..0ad786b67b825 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/dry_run_log.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +// @codingStandardsIgnoreFile +return ['CREATE TABLE `reference_table` ( +`tinyint_ref` tinyint(7) NOT NULL AUTO_INCREMENT , +`tinyint_without_padding` tinyint(2) NOT NULL DEFAULT 0 , +`bigint_without_padding` bigint(20) NOT NULL DEFAULT 0 , +`smallint_without_padding` smallint(5) NOT NULL DEFAULT 0 , +`integer_without_padding` int(11) NOT NULL DEFAULT 0 , +`smallint_with_big_padding` smallint(254) NOT NULL DEFAULT 0 , +`smallint_without_default` smallint(2) NULL , +`int_without_unsigned` int(2) NULL , +`int_unsigned` int(2) UNSIGNED NULL , +`bigint_default_nullable` bigint(2) UNSIGNED NULL DEFAULT 1 , +`bigint_not_default_not_nullable` bigint(2) UNSIGNED NOT NULL , +CONSTRAINT PRIMARY KEY (`tinyint_ref`) +) ENGINE=innodb + +CREATE TABLE `auto_increment_test` ( +`int_auto_increment_with_nullable` int(12) UNSIGNED NOT NULL AUTO_INCREMENT , +`int_disabled_auto_increment` smallint(12) UNSIGNED NULL DEFAULT 0 , +CONSTRAINT `unique_null_key` UNIQUE KEY (`int_auto_increment_with_nullable`) +) ENGINE=innodb + +CREATE TABLE `test_table` ( +`smallint` smallint(3) NOT NULL AUTO_INCREMENT , +`tinyint` tinyint(7) NULL , +`bigint` bigint(13) NULL DEFAULT 0 , +`float` float(12, 4) NULL DEFAULT 0 , +`double` decimal(14, 6) NULL DEFAULT 11111111.111111 , +`decimal` decimal(15, 4) NULL DEFAULT 0 , +`date` date NULL , +`timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP , +`datetime` datetime NULL DEFAULT 0 , +`longtext` longtext NULL , +`mediumtext` mediumtext NULL , +`varchar` varchar(254) NULL , +`mediumblob` mediumblob NULL , +`blob` blob NULL , +`boolean` BOOLEAN NULL , +CONSTRAINT `some_unique_key` UNIQUE KEY (`smallint`,`bigint`), +CONSTRAINT `some_foreign_key` FOREIGN KEY (`tinyint`) REFERENCES `reference_table` (`tinyint_ref`) ON DELETE NO ACTION, +INDEX `speedup_index` (`tinyint`,`bigint`) +) ENGINE=innodb + +CREATE TABLE `patch_list` ( +`patch_id` int(11) NOT NULL AUTO_INCREMENT COMMENT "Patch Auto Increment", +`patch_name` varchar(1024) NOT NULL COMMENT "Patch Class Name", +CONSTRAINT PRIMARY KEY (`patch_id`) +) ENGINE=innodb COMMENT="List of data/schema patches" + +']; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/dry_run_log_on_upgrade.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/dry_run_log_on_upgrade.php new file mode 100644 index 0000000000000..ccc2d5b792917 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/fixture/dry_run_log_on_upgrade.php @@ -0,0 +1,13 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +// @codingStandardsIgnoreFile +return ['ALTER TABLE `reference_table` MODIFY COLUMN `tinyint_without_padding` tinyint(2) NOT NULL , MODIFY COLUMN `bigint_default_nullable` bigint(2) UNSIGNED NULL DEFAULT 123 , MODIFY COLUMN `bigint_not_default_not_nullable` bigint(20) NOT NULL + +ALTER TABLE `auto_increment_test` MODIFY COLUMN `int_auto_increment_with_nullable` int(15) UNSIGNED NULL + +ALTER TABLE `test_table` MODIFY COLUMN `float` float(12, 10) NULL DEFAULT 0 , MODIFY COLUMN `double` double(245, 10) NULL , MODIFY COLUMN `timestamp` timestamp NULL DEFAULT CURRENT_TIMESTAMP , MODIFY COLUMN `varchar` varchar(100) NULL , MODIFY COLUMN `boolean` BOOLEAN NULL DEFAULT 1 + +']; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/column_modifications/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/column_modifications/db_schema.xml index 59dc94bf5e079..0929fe8db8cd2 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/column_modifications/db_schema.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/column_modifications/db_schema.xml @@ -6,7 +6,7 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="reference_table" resource="sales"> <column xsi:type="tinyint" name="tinyint_ref" padding="7" nullable="false" identity="true" unsigned="false"/> <column xsi:type="tinyint" name="tinyint_without_padding" nullable="false" unsigned="false"/> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/column_removals/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/column_removals/db_schema.xml index fcb3a7b5fa08d..e7361dd28fc0a 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/column_removals/db_schema.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/column_removals/db_schema.xml @@ -6,7 +6,7 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="reference_table" resource="default"> <column xsi:type="tinyint" name="tinyint_ref" padding="7" nullable="false" identity="true" unsigned="false"/> <column xsi:type="tinyint" name="tinyint_without_padding" default="0" nullable="false" unsigned="false"/> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/constraint_modifications/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/constraint_modifications/db_schema.xml index 353760b450af1..97f1862e14028 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/constraint_modifications/db_schema.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/constraint_modifications/db_schema.xml @@ -6,7 +6,7 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="reference_table" resource="default"> <column xsi:type="tinyint" name="tinyint_ref" padding="7" nullable="false" identity="true" unsigned="false"/> <column xsi:type="tinyint" name="tinyint_without_padding" default="0" nullable="false" unsigned="false"/> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/drop_table/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/drop_table/db_schema.xml index 4206ddc16be78..57403cbea3fdc 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/drop_table/db_schema.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/drop_table/db_schema.xml @@ -6,7 +6,7 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="auto_increment_test" resource="default"> <column xsi:type="int" name="int_auto_increment_with_nullable" identity="true" padding="12" unsigned="true" nullable="true"/> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/drop_table/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/drop_table/module.xml index 5d408109ff1ee..a1b48d0ccb7a3 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/drop_table/module.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/drop_table/module.xml @@ -6,5 +6,5 @@ */ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestSetupDeclarationModule1" setup_version="0.0.1"/> + <module name="Magento_TestSetupDeclarationModule1" /> </config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/fail_on_column_declaration/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/fail_on_column_declaration/db_schema.xml index fac0e4011e9b6..b79f9d5beb5c3 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/fail_on_column_declaration/db_schema.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/fail_on_column_declaration/db_schema.xml @@ -6,7 +6,7 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="test_table" resource="sales"> <!--Columns--> <column xsi:type="smallint" name="smallint" default="0" scale="1" padding="3"/> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/fail_on_unique_key_declaration/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/fail_on_unique_key_declaration/db_schema.xml index d98b3c7358df1..787d6d9ce5a38 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/fail_on_unique_key_declaration/db_schema.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/fail_on_unique_key_declaration/db_schema.xml @@ -6,7 +6,7 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="test_table" resource="sales"> <!--Columns--> <column xsi:type="smallint" name="smallint" default="0" padding="3"/> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/foreign_key_interpreter/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/foreign_key_interpreter/db_schema.xml index 5cc5f4af12428..a2895ee56d616 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/foreign_key_interpreter/db_schema.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/foreign_key_interpreter/db_schema.xml @@ -6,7 +6,7 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="reference_table" resource="sales"> <column xsi:type="tinyint" name="tinyint_ref" default="0" padding="7" nullable="true" unsigned="false"/> </table> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/old_diff/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/old_diff/db_schema.xml index f5989c1af9075..97b375d228e0c 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/old_diff/db_schema.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/old_diff/db_schema.xml @@ -6,7 +6,7 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="reference_table" resource="default" comment="Reference table"> <column xsi:type="smallint" name="smallint_ref" padding="6" nullable="false" unsigned="false" identity="true" comment="Smallint"/> <constraint xsi:type="primary" name="tinyint_primary"> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/old_diff_before/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/old_diff_before/db_schema.xml index ab3d5c0f97db7..7598fbd54295f 100644 --- a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/old_diff_before/db_schema.xml +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule1/revisions/old_diff_before/db_schema.xml @@ -6,5 +6,5 @@ */ --> <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> </schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/Setup/InstallData.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/Setup/InstallData.php new file mode 100644 index 0000000000000..9f8dd9e8c1ebc --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/Setup/InstallData.php @@ -0,0 +1,31 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule3\Setup; + +use Magento\Framework\Setup\InstallDataInterface; +use Magento\Framework\Setup\ModuleContextInterface; +use Magento\Framework\Setup\ModuleDataSetupInterface; + +/** + * Class InstallData + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class InstallData implements InstallDataInterface +{ + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $adapter = $setup->getConnection(); + $setup->startSetup(); + $adapter->insertArray('reference_table', ['some_integer'], [7, 2, 3, 5]); + $setup->endSetup(); + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/Setup/UpgradeData.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/Setup/UpgradeData.php new file mode 100644 index 0000000000000..5c1a6b0f4387e --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/Setup/UpgradeData.php @@ -0,0 +1,29 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule3\Setup; + +use Magento\Framework\Setup\ModuleContextInterface; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\UpgradeDataInterface; + +/** + * Class InstallData + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class UpgradeData implements UpgradeDataInterface +{ + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $setup->startSetup(); + $setup->endSetup(); + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/etc/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/etc/db_schema.xml new file mode 100644 index 0000000000000..00b5d6f9bb27d --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/etc/db_schema.xml @@ -0,0 +1,30 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="reference_table" resource="default"> + <column xsi:type="tinyint" name="tinyint_ref" padding="7" nullable="false" identity="true" unsigned="false"/> + <column xsi:type="int" name="some_integer" default="0" nullable="false" unsigned="false"/> + <column xsi:type="varchar" name="for_patch_testing" comment="For patch testing" /> + <constraint xsi:type="primary" name="tinyint_primary"> + <column name="tinyint_ref"/> + </constraint> + </table> + <table name="test_table" resource="default"> + <!--Columns--> + <column xsi:type="smallint" identity="true" name="smallint" padding="3" nullable="true"/> + <column xsi:type="tinyint" name="tinyint" padding="7" nullable="true" unsigned="false"/> + <column xsi:type="varchar" name="varchar" length="254" nullable="true"/> + <column xsi:type="varbinary" name="varbinary" default="10101" /> + <constraint xsi:type="foreign" name="some_foreign_key" column="tinyint" table="test_table" + referenceTable="reference_table" referenceColumn="tinyint_ref" onDelete="CASCADE"/> + <constraint xsi:type="primary" name="PRIMARY"> + <column name="smallint" /> + </constraint> + </table> +</schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/etc/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/etc/module.xml new file mode 100644 index 0000000000000..ed76bd12c9737 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule3" setup_version="0.0.1"/> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/registration.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/registration.php new file mode 100644 index 0000000000000..94ab9f3a90f54 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule3') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule3', __DIR__); +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/all_patches_revision/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/all_patches_revision/module.xml new file mode 100644 index 0000000000000..5b5eec3ecf1bf --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/all_patches_revision/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule3" setup_version="0.0.3"/> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/cyclomatic_and_bic_revision/BicPatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/cyclomatic_and_bic_revision/BicPatch.php new file mode 100644 index 0000000000000..d12e8feda26e9 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/cyclomatic_and_bic_revision/BicPatch.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule3\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchRevertableInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class BicPatch implements + DataPatchInterface, + PatchRevertableInterface, + PatchVersionInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public function getVersion() + { + return '0.0.3'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + /** + * @inheritdoc + */ + public function apply() + { + throw new \Exception("This patch can`t be applied, as it was created to test BIC"); + } + + public function revert() + { + } + + /** + * @return array + */ + public static function getDependencies() + { + return [ + RefBicPatch::class + ]; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/cyclomatic_and_bic_revision/RefBicPatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/cyclomatic_and_bic_revision/RefBicPatch.php new file mode 100644 index 0000000000000..a2db3bc8f4134 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/cyclomatic_and_bic_revision/RefBicPatch.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule3\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchRevertableInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class RefBicPatch implements + DataPatchInterface, + PatchRevertableInterface, + PatchVersionInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public function getVersion() + { + return '0.0.3'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + /** + * @inheritdoc + */ + public function apply() + { + throw new \Exception("This patch can`t be applied, as it was created to test BIC"); + } + + public function revert() + { + } + + /** + * @return array + */ + public static function getDependencies() + { + return [ + BicPatch::class + ]; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/cyclomatic_and_bic_revision/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/cyclomatic_and_bic_revision/module.xml new file mode 100644 index 0000000000000..0beb142b7752a --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/cyclomatic_and_bic_revision/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule3" setup_version="0.0.3" /> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/first_patch_revision/UpgradeData.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/first_patch_revision/UpgradeData.php new file mode 100644 index 0000000000000..dc8a41d24a38f --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/first_patch_revision/UpgradeData.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule3\Setup; + +use Magento\Framework\Setup\ModuleContextInterface; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\UpgradeDataInterface; + +/** + * Class InstallData + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class UpgradeData implements UpgradeDataInterface +{ + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $adapter = $setup->getConnection(); + $setup->startSetup(); + + if (version_compare($context->getVersion(), '0.0.2') < 0) { + $adapter->insertArray('reference_table', ['some_integer'], [6, 12]); + } + + if (version_compare($context->getVersion(), '0.0.3') < 0) { + $adapter->delete('reference_table', 'some_integer = 7'); + } + + $setup->endSetup(); + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/first_patch_revision/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/first_patch_revision/module.xml new file mode 100644 index 0000000000000..5b5eec3ecf1bf --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/first_patch_revision/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule3" setup_version="0.0.3"/> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/old_revision/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/old_revision/module.xml new file mode 100644 index 0000000000000..7bcf829123f5c --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/old_revision/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule3" setup_version="0.0.2"/> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/IncrementalSomeIntegerPatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/IncrementalSomeIntegerPatch.php new file mode 100644 index 0000000000000..b0ddae1a12cbc --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/IncrementalSomeIntegerPatch.php @@ -0,0 +1,91 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule3\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchRevertableInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * Class InstallData + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class IncrementalSomeIntegerPatch implements + DataPatchInterface, + PatchRevertableInterface, + PatchVersionInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public static function getVersion() + { + return '1.0.5'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + /** + * @inheritdoc + */ + public function apply() + { + $adapter = $this->resourceConnection->getConnection(); + $select = $adapter->select()->from('test_table', 'varchar') + ->where('`smallint` = ?', 1); + $refSelect = $adapter->select()->from('reference_table', 'for_patch_testing') + ->where('`tinyint_ref` = ?', 7); + $varchar = $adapter->fetchOne($select); + $varchar2 = $adapter->fetchOne($refSelect); + $adapter->insert('test_table', ['varchar' => $varchar . "_ref", 'varbinary' => 0101010]); + $adapter->insert('test_table', ['varchar' => $varchar2, 'varbinary' => 0]); + } + + public function revert() + { + $adapter = $this->resourceConnection->getConnection(); + $select = $adapter->select()->from('test_table', 'varchar') + ->where('`smallint` = ?', 1); + $varchar = $adapter->fetchOne($select); + $refSelect = $adapter->select()->from('reference_table', 'for_patch_testing') + ->where('`tinyint_ref` = ?', 7); + $varchar2 = $adapter->fetchOne($refSelect); + $adapter->delete('test_table', ['`varchar` = ?' => $varchar . "_ref"]); + $adapter->delete('test_table', ['`varchar` = ?' => $varchar2]); + } + + /** + * @return array + */ + public static function getDependencies() + { + return [ + ReferenceIncrementalSomeIntegerPatch::class, + NextChainPatch::class + ]; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/LlNextChainPatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/LlNextChainPatch.php new file mode 100644 index 0000000000000..341da3bf7f31b --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/LlNextChainPatch.php @@ -0,0 +1,75 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule3\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchRevertableInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class LlNextChainPatch implements + DataPatchInterface, + PatchRevertableInterface, + PatchVersionInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public static function getVersion() + { + return '0.0.5'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + /** + * @inheritdoc + */ + public function apply() + { + $adapter = $this->resourceConnection->getConnection(); + $adapter->insertArray('reference_table', ['for_patch_testing'], ['very_secret_string']); + } + + public function revert() + { + $adapter = $this->resourceConnection->getConnection(); + $adapter->delete('reference_table', ['for_patch_testing = ?' => 'very_secret_string']); + } + + /** + * @return array + */ + public static function getDependencies() + { + return [ + ZFirstPatch::class + ]; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/NextChainPatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/NextChainPatch.php new file mode 100644 index 0000000000000..cdb594d548fe4 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/NextChainPatch.php @@ -0,0 +1,90 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule3\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchRevertableInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class NextChainPatch implements + DataPatchInterface, + PatchRevertableInterface, + PatchVersionInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public static function getVersion() + { + return '0.0.6'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + /** + * @inheritdoc + */ + public function apply() + { + $adapter = $this->resourceConnection->getConnection(); + $refSelect = $adapter->select()->from('reference_table', 'for_patch_testing') + ->where('`tinyint_ref` = ?', 7); + $varchar2 = $adapter->fetchOne($refSelect); + $adapter->update( + 'reference_table', + ['for_patch_testing' => 'changed__' . $varchar2], + ['`tinyint_ref` = ?' => 7] + ); + } + + public function revert() + { + $adapter = $this->resourceConnection->getConnection(); + $refSelect = $adapter->select()->from('reference_table', 'for_patch_testing') + ->where('`tinyint_ref` = ?', 7); + $varchar2 = $adapter->fetchOne($refSelect); + $adapter->update( + 'reference_table', + ['for_patch_testing' => str_replace('changed__', '', $varchar2)], + ['`tinyint_ref` = ?' => 7] + ); + } + + /** + * @return array + */ + public static function getDependencies() + { + return [ + LlNextChainPatch::class, + ZFirstPatch::class + ]; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/ReferenceIncrementalSomeIntegerPatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/ReferenceIncrementalSomeIntegerPatch.php new file mode 100644 index 0000000000000..493cb0375bcf3 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/ReferenceIncrementalSomeIntegerPatch.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule3\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchRevertableInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * Class ReferenceIncrementalSomeIntegerPatch + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class ReferenceIncrementalSomeIntegerPatch implements + DataPatchInterface, + PatchRevertableInterface, + PatchVersionInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public static function getVersion() + { + return '0.0.4'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + /** + * @inheritdoc + */ + public function apply() + { + $adapter = $this->resourceConnection->getConnection(); + $adapter->insert('test_table', ['varchar' => 'Ololo123', 'varbinary' => 0101010]); + } + + public function revert() + { + $adapter = $this->resourceConnection->getConnection(); + $adapter->delete('test_table', ['`smallint` = ?' => 1]); + } + + /** + * @return array + */ + public static function getDependencies() + { + return [ + ZFirstPatch::class + ]; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/ZFirstPatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/ZFirstPatch.php new file mode 100644 index 0000000000000..d26e35879cacc --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule3/revisions/patches_revision/ZFirstPatch.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule3\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Setup\Exception; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchRevertableInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * Class InstallData + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class ZFirstPatch implements + DataPatchInterface, + PatchVersionInterface, + PatchRevertableInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public static function getVersion() + { + return '0.0.3'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + public function revert() + { + } + + /** + * @inheritdoc + */ + public function apply() + { + throw new Exception('This patch should be covered by old script!'); + } + + /** + * @return array + */ + public static function getDependencies() + { + return []; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/etc/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/etc/db_schema.xml new file mode 100644 index 0000000000000..4520cd9e4d406 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/etc/db_schema.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="test_table" resource="default" comment="Test Table"> + <column xsi:type="int" name="page_id" nullable="false" /> + <column xsi:type="varchar" name="email" nullable="false" /> + <column xsi:type="varchar" name="title" /> + <constraint xsi:type="primary" name="PRIMARY"> + <column name="page_id" /> + <column name="email" /> + </constraint> + </table> +</schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/etc/db_schema_whitelist.json b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/etc/db_schema_whitelist.json new file mode 100644 index 0000000000000..4036481252d46 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/etc/db_schema_whitelist.json @@ -0,0 +1,9 @@ +{ + "test_table": { + "column": { + "page_id": true, + "email": true, + "title": true + } + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/etc/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/etc/module.xml new file mode 100644 index 0000000000000..01f7a6d1b0b2c --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule4" setup_version="1.0.0" /> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/fixture/safe_data_provider.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/fixture/safe_data_provider.php new file mode 100644 index 0000000000000..e017996773622 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/fixture/safe_data_provider.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +return [ + [ + 'page_id' => '1', + 'email' => '1@gmail.com', + 'title' => 'Title1' + ], + [ + 'page_id' => '2', + 'email' => '2@gmail.com', + 'title' => 'Title2' + ], + [ + 'page_id' => '3', + 'email' => '3@gmail.com', + 'title' => 'Title3' + ], + [ + 'page_id' => '4', + 'email' => '4@gmail.com', + 'title' => 'Title4' + ] +]; diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/registration.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/registration.php new file mode 100644 index 0000000000000..392171b1f5401 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule4') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule4', __DIR__); +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/revisions/remove_title_column/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/revisions/remove_title_column/db_schema.xml new file mode 100644 index 0000000000000..9d868c0168826 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/revisions/remove_title_column/db_schema.xml @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="test_table" resource="default" comment="Test Table"> + <column xsi:type="int" name="page_id" nullable="false" /> + <column xsi:type="varchar" name="email" nullable="false" /> + <constraint xsi:type="primary" name="PRIMARY"> + <column name="page_id" /> + <column name="email" /> + </constraint> + </table> +</schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/revisions/restore_title_column/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/revisions/restore_title_column/db_schema.xml new file mode 100644 index 0000000000000..4520cd9e4d406 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule4/revisions/restore_title_column/db_schema.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="test_table" resource="default" comment="Test Table"> + <column xsi:type="int" name="page_id" nullable="false" /> + <column xsi:type="varchar" name="email" nullable="false" /> + <column xsi:type="varchar" name="title" /> + <constraint xsi:type="primary" name="PRIMARY"> + <column name="page_id" /> + <column name="email" /> + </constraint> + </table> +</schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/etc/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/etc/db_schema.xml new file mode 100644 index 0000000000000..00b5d6f9bb27d --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/etc/db_schema.xml @@ -0,0 +1,30 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="reference_table" resource="default"> + <column xsi:type="tinyint" name="tinyint_ref" padding="7" nullable="false" identity="true" unsigned="false"/> + <column xsi:type="int" name="some_integer" default="0" nullable="false" unsigned="false"/> + <column xsi:type="varchar" name="for_patch_testing" comment="For patch testing" /> + <constraint xsi:type="primary" name="tinyint_primary"> + <column name="tinyint_ref"/> + </constraint> + </table> + <table name="test_table" resource="default"> + <!--Columns--> + <column xsi:type="smallint" identity="true" name="smallint" padding="3" nullable="true"/> + <column xsi:type="tinyint" name="tinyint" padding="7" nullable="true" unsigned="false"/> + <column xsi:type="varchar" name="varchar" length="254" nullable="true"/> + <column xsi:type="varbinary" name="varbinary" default="10101" /> + <constraint xsi:type="foreign" name="some_foreign_key" column="tinyint" table="test_table" + referenceTable="reference_table" referenceColumn="tinyint_ref" onDelete="CASCADE"/> + <constraint xsi:type="primary" name="PRIMARY"> + <column name="smallint" /> + </constraint> + </table> +</schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/etc/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/etc/module.xml new file mode 100644 index 0000000000000..e383b81bc5c67 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule5" setup_version="1.0.4" /> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/registration.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/registration.php new file mode 100644 index 0000000000000..3bc0eee128e36 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule5') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule5', __DIR__); +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/module-without-version/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/module-without-version/module.xml new file mode 100644 index 0000000000000..d5731572270e4 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/module-without-version/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule5" /> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/old-scripts/UpgradeData.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/old-scripts/UpgradeData.php new file mode 100644 index 0000000000000..5ce7ce9fc8583 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/old-scripts/UpgradeData.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule5\Setup; + +use Magento\Framework\Setup\ModuleContextInterface; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\UpgradeDataInterface; + +/** + * Class InstallData + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class UpgradeData implements UpgradeDataInterface +{ + /** + * {@inheritdoc} + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $adapter = $setup->getConnection(); + $setup->startSetup(); + + if (version_compare($context->getVersion(), '1.0.2') < 0) { + $adapter->insertArray('reference_table', ['some_integer'], [6, 12, 7]); + } + + if (version_compare($context->getVersion(), '1.0.3') < 0) { + $adapter->delete('reference_table', 'some_integer = 7'); + } + + $setup->endSetup(); + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/patches/SomePatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/patches/SomePatch.php new file mode 100644 index 0000000000000..b98e35a01e181 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/patches/SomePatch.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule5\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchRevertableInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * Class SomePatch + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class SomePatch implements + DataPatchInterface, + PatchRevertableInterface, + PatchVersionInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public static function getVersion() + { + return '1.0.5'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + /** + * @inheritdoc + */ + public function apply() + { + $adapter = $this->resourceConnection->getConnection(); + $adapter->insert('test_table', ['varchar' => "_ref", 'varbinary' => 0101010]); + } + + public function revert() + { + } + + /** + * @return array + */ + public static function getDependencies() + { + return []; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/patches/SomeSkippedPatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/patches/SomeSkippedPatch.php new file mode 100644 index 0000000000000..833545ce88ba7 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule5/revisions/patches/SomeSkippedPatch.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule5\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchRevertableInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * Class SomePatch + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class SomeSkippedPatch implements + DataPatchInterface, + PatchRevertableInterface, + PatchVersionInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public static function getVersion() + { + return '1.0.2'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + /** + * @inheritdoc + */ + public function apply() + { + throw new \Exception('This patch should be skipped!'); + } + + public function revert() + { + } + + /** + * @return array + */ + public static function getDependencies() + { + return []; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/etc/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/etc/db_schema.xml new file mode 100644 index 0000000000000..3eeb141c2e606 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/etc/db_schema.xml @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="reference_table" resource="sales"> + <column xsi:type="tinyint" name="tinyint_ref" padding="7" nullable="false" identity="true" unsigned="false"/> + <column xsi:type="tinyint" name="tinyint_without_padding" default="0" nullable="false" unsigned="false"/> + <column xsi:type="bigint" name="bigint_without_padding" default="0" nullable="false" unsigned="false"/> + <column xsi:type="smallint" name="smallint_without_padding" default="0" nullable="false" unsigned="false"/> + <column xsi:type="int" name="integer_without_padding" default="0" nullable="false" unsigned="false"/> + <column xsi:type="smallint" name="smallint_with_big_padding" padding="254" default="0" nullable="false" + unsigned="false"/> + <column xsi:type="smallint" name="smallint_without_default" padding="2" nullable="true" unsigned="false"/> + <column xsi:type="int" name="int_without_unsigned" padding="2" nullable="true"/> + <column xsi:type="int" name="int_unsigned" padding="2" nullable="true" unsigned="true"/> + <column xsi:type="bigint" name="bigint_default_nullable" padding="2" nullable="true" default="1" + unsigned="true"/> + <column xsi:type="bigint" name="bigint_not_default_not_nullable" padding="2" nullable="false" unsigned="true"/> + <constraint xsi:type="primary" name="tinyint_primary"> + <column name="tinyint_ref"/> + </constraint> + </table> + <table name="auto_increment_test" resource="default"> + <column xsi:type="int" name="int_auto_increment_with_nullable" identity="true" padding="12" unsigned="true" + nullable="true"/> + <column xsi:type="smallint" name="int_disabled_auto_increment" default="0" identity="false" padding="12" + unsigned="true" nullable="true"/> + <constraint xsi:type="unique" name="unique_null_key"> + <column name="int_auto_increment_with_nullable"/> + </constraint> + </table> + <table name="test_table" resource="default"> + <!--Columns--> + <column xsi:type="smallint" identity="true" name="smallint" padding="3" nullable="true"/> + <column xsi:type="tinyint" name="tinyint" padding="7" nullable="true" unsigned="false"/> + <column xsi:type="bigint" name="bigint" default="0" padding="13" nullable="true" unsigned="false"/> + <column xsi:type="float" name="float" default="0" scale="4" precision="12"/> + <column xsi:type="decimal" name="double" default="11111111.111111" precision="14" scale="6"/> + <column xsi:type="decimal" name="decimal" default="0" scale="4" precision="15"/> + <column xsi:type="date" name="date"/> + <column xsi:type="timestamp" name="timestamp" default="CURRENT_TIMESTAMP" on_update="true"/> + <column xsi:type="datetime" name="datetime" default="0"/> + <column xsi:type="longtext" name="longtext"/> + <column xsi:type="mediumtext" name="mediumtext"/> + <column xsi:type="varchar" name="varchar" length="254" nullable="true"/> + <column xsi:type="mediumblob" name="mediumblob"/> + <column xsi:type="blob" name="blob"/> + <column xsi:type="boolean" name="boolean"/> + <column xsi:type="varbinary" name="varbinary_rename" default="10101" disabled="true"/> + <!--Constraints--> + <constraint xsi:type="unique" name="some_unique_key"> + <column name="smallint"/> + <column name="bigint"/> + </constraint> + <constraint xsi:type="foreign" name="some_foreign_key" column="tinyint" table="test_table" + referenceTable="reference_table" referenceColumn="tinyint_ref" onDelete="NO ACTION"/> + <!--Indexes--> + <index name="speedup_index" indexType="btree"> + <column name="tinyint"/> + <column name="bigint"/> + </index> + </table> +</schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/etc/db_schema_whitelist.json b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/etc/db_schema_whitelist.json new file mode 100644 index 0000000000000..890fea33106b7 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/etc/db_schema_whitelist.json @@ -0,0 +1,56 @@ +{ + "reference_table": { + "column": { + "tinyint_ref": true, + "tinyint_without_padding": true, + "bigint_without_padding": true, + "integer_without_padding": true, + "smallint_with_big_padding": true, + "smallint_without_default": true, + "int_without_unsigned": true, + "int_unsigned": true, + "bigint_default_nullable": true, + "bigint_not_default_not_nullable": true, + "smallint_without_padding": true + }, + "constraint": { + "tinyint_primary": true + } + }, + "auto_increment_test": { + "column": { + "int_auto_increment_with_nullable": true, + "int_disabled_auto_increment": true + }, + "constraint": { + "unique_null_key": true + } + }, + "test_table": { + "column": { + "smallint": true, + "tinyint": true, + "bigint": true, + "float": true, + "double": true, + "decimal": true, + "date": true, + "timestamp": true, + "datetime": true, + "longtext": true, + "mediumtext": true, + "varchar": true, + "mediumblob": true, + "blob": true, + "boolean": true, + "varbinary_rename": true + }, + "index": { + "speedup_index": true + }, + "constraint": { + "some_unique_key": true, + "some_foreign_key": true + } + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/etc/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/etc/module.xml new file mode 100644 index 0000000000000..af44654afd829 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule6" /> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/registration.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/registration.php new file mode 100644 index 0000000000000..a107dc2498460 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule6/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule6') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule6', __DIR__); +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/Setup/InstallSchema.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/Setup/InstallSchema.php new file mode 100644 index 0000000000000..e7b9b22c5a284 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/Setup/InstallSchema.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\TestSetupDeclarationModule7\Setup; + +use Magento\Framework\Setup\InstallSchemaInterface; +use Magento\Framework\Setup\ModuleContextInterface; +use Magento\Framework\Setup\SchemaSetupInterface; + +/** + * InstallSchema mock class + */ +class InstallSchema implements InstallSchemaInterface +{ + /** + * {@inheritdoc} + */ + public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) + { + $installer = $setup; + $installer->startSetup(); + $installer + ->getConnection() + ->modifyColumn('test_table', 'float', ['type' => 'float', 'default' => 25]); + $installer->endSetup(); + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/Setup/UpgradeData.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/Setup/UpgradeData.php new file mode 100644 index 0000000000000..68016d959bb77 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/Setup/UpgradeData.php @@ -0,0 +1,32 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule7\Setup; + +use Magento\Framework\Setup\ModuleContextInterface; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\UpgradeDataInterface; + +/** + * Class UpgradeData + * @package Magento\TestSetupDeclarationModule7\Setup + */ +class UpgradeData implements UpgradeDataInterface +{ + /** + * {@inheritdoc} + */ + public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $adapter = $setup->getConnection(); + $setup->startSetup(); + + if (version_compare($context->getVersion(), '2.0.0') < 0) { + $adapter->insertArray('reference_table', ['bigint_without_padding'], [6, 12, 7]); + } + + $setup->endSetup(); + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/Setup/UpgradeSchema.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/Setup/UpgradeSchema.php new file mode 100644 index 0000000000000..8381dd3f24537 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/Setup/UpgradeSchema.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\TestSetupDeclarationModule7\Setup; + +use Magento\Framework\Setup\InstallSchemaInterface; +use Magento\Framework\Setup\ModuleContextInterface; +use Magento\Framework\Setup\SchemaSetupInterface; +use Magento\Framework\Setup\UpgradeSchemaInterface; + +/** + * UpgradeSchema mock class + */ +class UpgradeSchema implements UpgradeSchemaInterface +{ + /** + * {@inheritdoc} + */ + public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context) + { + $installer = $setup; + $installer->startSetup(); + + if (version_compare($context->getVersion(), '2.0.1') < 0) { + $installer + ->getConnection() + ->modifyColumn('test_table', 'float', ['type' => 'float', 'default' => 29]); + } + + $installer->endSetup(); + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/etc/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/etc/module.xml new file mode 100644 index 0000000000000..7affd773fd07e --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/etc/module.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule7" setup_version="2.0.1"> + <sequence> + <module name="Magento_TestSetupDeclarationModule6" /> + </sequence> + </module> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/registration.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/registration.php new file mode 100644 index 0000000000000..e357c5171daa3 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule7') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule7', __DIR__); +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/SomePatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/SomePatch.php new file mode 100644 index 0000000000000..9f66308cbab34 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/SomePatch.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule7\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchRevertableInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * Class SomePatch + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class SomePatch implements + DataPatchInterface, + PatchVersionInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public static function getVersion() + { + return '2.0.4'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + /** + * @inheritdoc + */ + public function apply() + { + $adapter = $this->resourceConnection->getConnection(); + $adapter->insert('test_table', ['varchar' => "_ref"]); + } + + /** + * @return array + */ + public static function getDependencies() + { + return []; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/SomeSkippedPatch.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/SomeSkippedPatch.php new file mode 100644 index 0000000000000..7a598905a82f1 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/SomeSkippedPatch.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule7\Setup\Patch\Data; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Patch\DataPatchInterface; +use Magento\Framework\Setup\Patch\PatchVersionInterface; + +/** + * Class SomePatch + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class SomeSkippedPatch implements + DataPatchInterface, + PatchVersionInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * IncrementalSomeIntegerPatch constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @return string + */ + public static function getVersion() + { + return '2.0.2'; + } + + /** + * @return array + */ + public function getAliases() + { + return []; + } + + /** + * @inheritdoc + */ + public function apply() + { + throw new \Exception('This patch should be skipped!'); + } + + /** + * @return array + */ + public static function getDependencies() + { + return []; + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/db_schema.xml new file mode 100644 index 0000000000000..4e4d65baec251 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/db_schema.xml @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="test_table"> + <column xsi:type="float" name="float" default="35" /> + </table> +</schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/module.xml new file mode 100644 index 0000000000000..7affd773fd07e --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/swap_with_declaration/module.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule7" setup_version="2.0.1"> + <sequence> + <module name="Magento_TestSetupDeclarationModule6" /> + </sequence> + </module> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/us_to_us/UpgradeData.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/us_to_us/UpgradeData.php new file mode 100644 index 0000000000000..6dd52909ec2da --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/us_to_us/UpgradeData.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestSetupDeclarationModule7\Setup; + +use Magento\Framework\Setup\ModuleContextInterface; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\UpgradeDataInterface; + +/** + * Class UpgradeData + * @package Magento\TestSetupDeclarationModule3\Setup + */ +class UpgradeData implements UpgradeDataInterface +{ + /** + * {@inheritdoc} + */ + public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + $adapter = $setup->getConnection(); + $setup->startSetup(); + + if (version_compare($context->getVersion(), '2.0.0') < 0) { + $adapter->insertArray('reference_table', ['bigint_without_padding'], [6, 12, 7]); + } + + if (version_compare($context->getVersion(), '2.0.2') < 0) { + $adapter->delete('reference_table', 'bigint_without_padding = 7'); + } + + $setup->endSetup(); + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/us_to_us/UpgradeSchema.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/us_to_us/UpgradeSchema.php new file mode 100644 index 0000000000000..8a91d136a1f10 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/us_to_us/UpgradeSchema.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\TestSetupDeclarationModule7\Setup; + +use Magento\Framework\Setup\InstallSchemaInterface; +use Magento\Framework\Setup\ModuleContextInterface; +use Magento\Framework\Setup\SchemaSetupInterface; +use Magento\Framework\Setup\UpgradeSchemaInterface; + +/** + * UpgradeSchema mock class + */ +class UpgradeSchema implements UpgradeSchemaInterface +{ + /** + * {@inheritdoc} + */ + public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context) + { + $installer = $setup; + $installer->startSetup(); + + if (version_compare($context->getVersion(), '2.0.1') < 0) { + $installer + ->getConnection() + ->modifyColumn('test_table', 'float', ['type' => 'float', 'default' => 29]); + } + //Create table and check, that Magento can`t delete it + if (version_compare($context->getVersion(), '2.0.2') < 0) { + $table = $setup->getConnection()->newTable( + $setup->getTable('custom_table') + )->addColumn( + 'custom_id', + \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, + null, + ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], + 'Custom Id' + )->addColumn( + 'name', + \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 255, + [], + 'Custom Name' + )->setComment( + 'Custom Table' + ); + $setup->getConnection()->createTable($table); + } + + $installer->endSetup(); + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/us_to_us/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/us_to_us/module.xml new file mode 100644 index 0000000000000..b4957234be103 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/us_to_us/module.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule7" setup_version="2.0.2"> + <sequence> + <module name="Magento_TestSetupDeclarationModule6" /> + </sequence> + </module> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/wl_remove_table/db_schema_whitelist.json b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/wl_remove_table/db_schema_whitelist.json new file mode 100644 index 0000000000000..c55475234424c --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule7/revisions/wl_remove_table/db_schema_whitelist.json @@ -0,0 +1,5 @@ +{ + "custom_table": { + "column": {} + } +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/etc/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/etc/module.xml new file mode 100644 index 0000000000000..96a09ad477d41 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/etc/module.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> + <module name="Magento_TestSetupDeclarationModule8" setup_version="1.0.0" /> +</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/registration.php b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/registration.php new file mode 100644 index 0000000000000..cb8e645f1771d --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/registration.php @@ -0,0 +1,12 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use Magento\Framework\Component\ComponentRegistrar; + +$registrar = new ComponentRegistrar(); +if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule8') === null) { + ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestSetupDeclarationModule8', __DIR__); +} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/revisions/incosistence_reference_definition/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/revisions/incosistence_reference_definition/db_schema.xml new file mode 100644 index 0000000000000..e39f0a04bcf5f --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/revisions/incosistence_reference_definition/db_schema.xml @@ -0,0 +1,21 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="test_table" resource="default" comment="Test Table"> + <column xsi:type="int" name="page_id" nullable="false" unsigned="false" identity="true"/> + <constraint xsi:type="primary" name="PRIMARY"> + <column name="page_id"/> + </constraint> + </table> + <table name="dependent" resource="default" comment="Lol"> + <column xsi:type="int" name="page_id_on" nullable="true" unsigned="true"/> + <constraint xsi:type="foreign" name="FOREIGN" table="dependent" column="page_id_on" referenceColumn="page_id" + referenceTable="test_table"/> + </table> +</schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/revisions/invalid_auto_increment/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/revisions/invalid_auto_increment/db_schema.xml new file mode 100644 index 0000000000000..bc889c5fdbefd --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/revisions/invalid_auto_increment/db_schema.xml @@ -0,0 +1,13 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="test_table" resource="default" comment="Test Table"> + <column xsi:type="int" name="page_id" nullable="false" identity="true" /> + </table> +</schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/revisions/invalid_primary_key/db_schema.xml b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/revisions/invalid_primary_key/db_schema.xml new file mode 100644 index 0000000000000..4ecee62286418 --- /dev/null +++ b/dev/tests/setup-integration/_files/Magento/TestSetupDeclarationModule8/revisions/invalid_primary_key/db_schema.xml @@ -0,0 +1,19 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="test_table" resource="default" comment="Test Table"> + <column xsi:type="int" name="page_id" nullable="false" identity="true" /> + <column xsi:type="varchar" name="email" nullable="true" /> + <column xsi:type="varchar" name="title" /> + <constraint xsi:type="primary" name="PRIMARY"> + <column name="page_id" /> + <column name="email" /> + </constraint> + </table> +</schema> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupModule1/Setup/InstallSchema.php b/dev/tests/setup-integration/_files/Magento/TestSetupModule1/Setup/InstallSchema.php deleted file mode 100644 index 32226670cf10d..0000000000000 --- a/dev/tests/setup-integration/_files/Magento/TestSetupModule1/Setup/InstallSchema.php +++ /dev/null @@ -1,169 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\TestSetupModule1\Setup; - -use Magento\Framework\Setup\InstallSchemaInterface; -use Magento\Framework\Setup\ModuleContextInterface; -use Magento\Framework\Setup\SchemaSetupInterface; - -/** - * @codeCoverageIgnore - */ -class InstallSchema implements InstallSchemaInterface -{ - /** - * {@inheritdoc} - * - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) - { - $installer = $setup; - - $installer->startSetup(); - - /** - * Create table 'setup_table1' - */ - $table = $installer->getConnection()->newTable( - $installer->getTable('setup_tests_table1') - )->addColumn( - 'column_with_type_boolean', - \Magento\Framework\DB\Ddl\Table::TYPE_BOOLEAN, - null, - ['nullable' => false, 'default' => 0], - 'Column with type boolean' - )->addColumn( - 'column_with_type_smallint', - \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, - null, - ['unsigned' => true, 'nullable' => false, 'default' => '0'], - 'Column with type smallint' - )->addColumn( - 'column_with_type_integer', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'identity' => true, 'nullable' => false, 'primary' => true], - 'Column with type integer' - )->addColumn( - 'column_with_type_bigint', - \Magento\Framework\DB\Ddl\Table::TYPE_BIGINT, - null, - ['unsigned' => true, 'nullable' => false, 'primary' => true], - 'Column with type bigint' - )->addColumn( - 'column_with_type_float', - \Magento\Framework\DB\Ddl\Table::TYPE_FLOAT, - null, - ['nullable' => true, 'default' => null], - 'Column with type float' - )->addColumn( - 'column_with_type_numeric', - \Magento\Framework\DB\Ddl\Table::TYPE_NUMERIC, - '12,4', - ['unsigned' => true, 'nullable' => true], - 'Column with type numeric' - )->addColumn( - 'column_with_type_decimal', - \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL, - '12,4', - ['unsigned' => true, 'nullable' => true], - 'Column with type decimal' - )->addColumn( - 'column_with_type_datetime', - \Magento\Framework\DB\Ddl\Table::TYPE_DATETIME, - null, - ['nullable' => true, 'default' => null], - 'Column with type datetime' - )->addColumn( - 'column_with_type_timestamp_update', - \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, - null, - ['nullable' => false, 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_UPDATE], - 'Column with type timestamp update' - )->addColumn( - 'column_with_type_date', - \Magento\Framework\DB\Ddl\Table::TYPE_DATE, - null, - ['nullable' => true, 'default' => null], - 'Column with type date' - )->addColumn( - 'column_with_type_text', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - '64k', - [], - 'Column with type text' - )->addColumn( - 'column_with_type_blob', - \Magento\Framework\DB\Ddl\Table::TYPE_BLOB, - 32, - [], - 'Column with type blob' - )->addColumn( - 'column_with_type_verbinary', - \Magento\Framework\DB\Ddl\Table::TYPE_VARBINARY, - '2m', - [], - 'Column with type varbinary' - )->addIndex( - $installer->getIdxName( - 'setup_tests_table1', - ['column_with_type_text'], - \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_FULLTEXT - ), - ['column_with_type_text'], - ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_FULLTEXT] - )->addIndex( - $installer->getIdxName( - 'setup_tests_table1', - 'column_with_type_integer', - \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_INDEX - ), - 'column_with_type_integer', - ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_INDEX] - ); - - $installer->getConnection()->createTable($table); - - $relatedTable = $installer->getConnection()->newTable( - $installer->getTable('setup_tests_table1_related') - )->addColumn( - 'column_with_type_timestamp_init_update', - \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, - null, - ['nullable' => false, 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT_UPDATE], - 'Column with type timestamp init update' - )->addColumn( - 'column_with_type_timestamp_init', - \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, - null, - ['nullable' => false, 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT], - 'Column with type timestamp init' - )->addColumn( - 'column_with_relation', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'nullable' => false], - 'Column with type integer and relation' - )->addForeignKey( - $installer->getFkName( - 'setup_table1_related', - 'column_with_relation', - 'setup_tests_table1', - 'column_with_type_integer' - ), - 'column_with_relation', - $installer->getTable('setup_tests_table1'), - 'column_with_type_integer', - \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE - )->setComment( - 'Related Table' - ); - $installer->getConnection()->createTable($relatedTable); - $installer->endSetup(); - } -} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupModule1/etc/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupModule1/etc/module.xml deleted file mode 100644 index a69c11e3ad489..0000000000000 --- a/dev/tests/setup-integration/_files/Magento/TestSetupModule1/etc/module.xml +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestSetupModule1" setup_version="0.0.1"/> -</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupModule1/registration.php b/dev/tests/setup-integration/_files/Magento/TestSetupModule1/registration.php deleted file mode 100644 index a7e2dcfb5319a..0000000000000 --- a/dev/tests/setup-integration/_files/Magento/TestSetupModule1/registration.php +++ /dev/null @@ -1,12 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -use Magento\Framework\Component\ComponentRegistrar; - -$registrar = new ComponentRegistrar(); -if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestSetupModule1') === null) { - ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestSetupModule1', __DIR__); -} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupModule2/Setup/InstallData.php b/dev/tests/setup-integration/_files/Magento/TestSetupModule2/Setup/InstallData.php deleted file mode 100644 index 7f115c0881abe..0000000000000 --- a/dev/tests/setup-integration/_files/Magento/TestSetupModule2/Setup/InstallData.php +++ /dev/null @@ -1,61 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\TestSetupModule2\Setup; - -use Magento\Framework\Setup\InstallDataInterface; -use Magento\Framework\Setup\ModuleContextInterface; -use Magento\Framework\Setup\ModuleDataSetupInterface; - -/** - * @codeCoverageIgnore - */ -class InstallData implements InstallDataInterface -{ - /** - * {@inheritdoc} - */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - - $setup->getConnection()->insertForce( - $setup->getTable('setup_tests_entity_table'), - [ - 'website_id' => 1, - 'email_field' => 'entity@example.com', - 'created_at' => '2017-10-30 09:41:25', - 'updated_at' => '2017-10-30 09:45:05', - 'created_in' => 'Default Store View', - 'firstname' => 'John', - 'lastname' => 'Doe', - 'dob' => '1973-12-15', - 'default_billing_address_id' => 1, - 'default_shipping_address_id' => 1 - ] - ); - $setup->getConnection()->insertForce( - $setup->getTable('setup_tests_address_entity'), - [ - 'parent_id' => 1, - 'created_at' => '2017-10-30 09:45:05', - 'updated_at' => '2017-10-30 09:45:05', - 'is_active' => 1, - 'city' => 'city', - 'company' => 'Magento', - 'country_id' => 'US', - 'firstname' => 'John', - 'lastname' => 'Doe', - 'postcode' => '90210', - 'region' => 'Alabama', - 'region_id' => 1, - 'street' => 'street1', - 'telephone' => 12345678, - ] - ); - - $setup->endSetup(); - } -} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupModule2/Setup/InstallSchema.php b/dev/tests/setup-integration/_files/Magento/TestSetupModule2/Setup/InstallSchema.php deleted file mode 100644 index 44dccfae087f9..0000000000000 --- a/dev/tests/setup-integration/_files/Magento/TestSetupModule2/Setup/InstallSchema.php +++ /dev/null @@ -1,404 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\TestSetupModule2\Setup; - -use Magento\Framework\Setup\InstallSchemaInterface; -use Magento\Framework\Setup\ModuleContextInterface; -use Magento\Framework\Setup\SchemaSetupInterface; - -/** - * @codeCoverageIgnore - */ -class InstallSchema implements InstallSchemaInterface -{ - /** - * {@inheritdoc} - * - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) - { - $installer = $setup; - $installer->startSetup(); - - /** - * Create table 'entity_table' - */ - $table = $installer->getConnection()->newTable( - $installer->getTable('setup_tests_entity_table') - )->addColumn( - 'entity_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], - 'Entity Id' - )->addColumn( - 'website_id', - \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, - null, - ['unsigned' => true], - 'Website Id' - )->addColumn( - 'email_field', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - [], - 'Email' - )->addColumn( - 'increment_id', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 50, - [], - 'Increment Id' - )->addColumn( - 'created_at', - \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, - null, - ['nullable' => false, 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT], - 'Created At' - )->addColumn( - 'updated_at', - \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, - null, - ['nullable' => false, 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT_UPDATE], - 'Updated At' - )->addColumn( - 'created_in', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - [], - 'Created From' - )->addColumn( - 'firstname', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - [], - 'First Name' - )->addColumn( - 'lastname', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - [], - 'Last Name' - )->addColumn( - 'dob', - \Magento\Framework\DB\Ddl\Table::TYPE_DATE, - null, - [], - 'Date of Birth' - )->addColumn( - 'default_billing_address_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'nullable' => true, 'default' => null], - 'Default Billing Address' - )->addColumn( - 'default_shipping_address_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'nullable' => true, 'default' => null], - 'Default Shipping Address' - )->addIndex( - $installer->getIdxName( - 'setup_tests_entity_table', - ['email_field', 'website_id'], - \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE - ), - ['email_field', 'website_id'], - ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE] - )->addIndex( - $installer->getIdxName('setup_tests_entity_table', ['website_id']), - ['website_id'] - )->addIndex( - $installer->getIdxName('setup_tests_entity_table', ['firstname']), - ['firstname'] - )->addIndex( - $installer->getIdxName('setup_tests_entity_table', ['lastname']), - ['lastname'] - )->addForeignKey( - $installer->getFkName( - 'setup_tests_entity_table', - 'website_id', - 'store_website', - 'website_id' - ), - 'website_id', - $installer->getTable('store_website'), - 'website_id', - \Magento\Framework\DB\Ddl\Table::ACTION_SET_NULL - )->setComment( - 'Entity Table' - ); - $installer->getConnection()->createTable($table); - - /** - * Create table 'address_entity' - */ - $table = $installer->getConnection()->newTable( - $installer->getTable('setup_tests_address_entity') - )->addColumn( - 'entity_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], - 'Entity Id' - )->addColumn( - 'increment_id', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 50, - [], - 'Increment Id' - )->addColumn( - 'parent_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'nullable' => true], - 'Parent Id' - )->addColumn( - 'created_at', - \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, - null, - ['nullable' => false, 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT], - 'Created At' - )->addColumn( - 'updated_at', - \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, - null, - ['nullable' => false, 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT_UPDATE], - 'Updated At' - )->addColumn( - 'is_active', - \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, - null, - ['unsigned' => true, 'nullable' => false, 'default' => '1'], - 'Is Active' - )->addColumn( - 'city', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - ['nullable' => false], - 'City' - )->addColumn( - 'company', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - ['nullable' => true, 'default' => null], - 'Company' - )->addColumn( - 'country_id', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - ['nullable' => false], - 'Country' - )->addColumn( - 'fax', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - ['nullable' => true, 'default' => null], - 'Fax' - )->addColumn( - 'firstname', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - ['nullable' => false], - 'First Name' - )->addColumn( - 'lastname', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - ['nullable' => false], - 'Last Name' - )->addColumn( - 'middlename', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - ['nullable' => true, 'default' => null], - 'Middle Name' - )->addColumn( - 'postcode', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - ['nullable' => true, 'default' => null], - 'Zip/Postal Code' - )->addColumn( - 'prefix', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 40, - ['nullable' => true, 'default' => null], - 'Name Prefix' - )->addColumn( - 'region', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - ['nullable' => true, 'default' => null], - 'State/Province' - )->addColumn( - 'region_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'nullable' => true, 'default' => null], - 'State/Province' - )->addColumn( - 'street', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - null, - ['nullable' => false], - 'Street Address' - )->addColumn( - 'suffix', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 40, - ['nullable' => true, 'default' => null], - 'Name Suffix' - )->addColumn( - 'telephone', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 255, - ['nullable' => false], - 'Phone Number' - )->addIndex( - $installer->getIdxName('address_entity', ['parent_id']), - ['parent_id'] - )->addForeignKey( - $installer->getFkName( - 'setup_tests_address_entity', - 'parent_id', - 'setup_tests_entity_table', - 'entity_id' - ), - 'parent_id', - $installer->getTable('setup_tests_entity_table'), - 'entity_id', - \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE, - \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE - )->setComment( - 'Address Entity' - ); - $installer->getConnection()->createTable($table); - - /** - * Create table 'address_entity_datetime' - */ - $table = $installer->getConnection()->newTable( - $installer->getTable('setup_tests_address_entity_datetime') - )->addColumn( - 'value_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['identity' => true, 'nullable' => false, 'primary' => true], - 'Value Id' - )->addColumn( - 'attribute_id', - \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, - null, - ['unsigned' => true, 'nullable' => false, 'default' => '0'], - 'Attribute Id' - )->addColumn( - 'entity_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'nullable' => false, 'default' => '0'], - 'Entity Id' - )->addColumn( - 'value', - \Magento\Framework\DB\Ddl\Table::TYPE_DATETIME, - null, - ['nullable' => true, 'default' => null], - 'Value' - )->addIndex( - $installer->getIdxName( - 'setup_tests_address_entity_datetime', - ['entity_id', 'attribute_id'], - \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE - ), - ['entity_id', 'attribute_id'], - ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE] - )->addIndex( - $installer->getIdxName('setup_tests_address_entity_datetime', ['attribute_id']), - ['attribute_id'] - )->addIndex( - $installer->getIdxName( - 'setup_tests_address_entity_datetime', - ['entity_id', 'attribute_id', 'value'] - ), - ['entity_id', 'attribute_id', 'value'] - )->addForeignKey( - $installer->getFkName( - 'address_entity_datetime', - 'entity_id', - 'address_entity', - 'entity_id' - ), - 'entity_id', - $installer->getTable('setup_tests_address_entity'), - 'entity_id', - \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE - )->setComment( - 'Address Entity Datetime' - ); - $installer->getConnection()->createTable($table); - - /** - * Create table 'address_entity_decimal' - */ - $table = $installer->getConnection()->newTable( - $installer->getTable('setup_tests_address_entity_decimal') - )->addColumn( - 'value_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['identity' => true, 'nullable' => false, 'primary' => true], - 'Value Id' - )->addColumn( - 'attribute_id', - \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, - null, - ['unsigned' => true, 'nullable' => false, 'default' => '0'], - 'Attribute Id' - )->addColumn( - 'entity_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'nullable' => false, 'default' => '0'], - 'Entity Id' - )->addColumn( - 'value', - \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL, - '12,4', - ['nullable' => false, 'default' => '0.0000'], - 'Value' - )->addIndex( - $installer->getIdxName( - 'setup_tests_address_entity_decimal', - ['entity_id', 'attribute_id'], - \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE - ), - ['entity_id', 'attribute_id'], - ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE] - )->addIndex( - $installer->getIdxName('setup_tests_address_entity_decimal', ['attribute_id']), - ['attribute_id'] - )->addIndex( - $installer->getIdxName('setup_tests_address_entity_decimal', ['entity_id', 'attribute_id', 'value']), - ['entity_id', 'attribute_id', 'value'] - )->addForeignKey( - $installer->getFkName( - 'setup_tests_address_entity_decimal', - 'entity_id', - 'setup_tests_address_entity', - 'entity_id' - ), - 'entity_id', - $installer->getTable('setup_tests_address_entity'), - 'entity_id', - \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE - )->setComment( - 'Address Entity Decimal' - ); - $installer->getConnection()->createTable($table); - } -} diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupModule2/etc/module.xml b/dev/tests/setup-integration/_files/Magento/TestSetupModule2/etc/module.xml deleted file mode 100644 index b6a26d50753fb..0000000000000 --- a/dev/tests/setup-integration/_files/Magento/TestSetupModule2/etc/module.xml +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestSetupModule2" setup_version="0.0.1"/> -</config> diff --git a/dev/tests/setup-integration/_files/Magento/TestSetupModule2/registration.php b/dev/tests/setup-integration/_files/Magento/TestSetupModule2/registration.php deleted file mode 100644 index cdf684229889c..0000000000000 --- a/dev/tests/setup-integration/_files/Magento/TestSetupModule2/registration.php +++ /dev/null @@ -1,12 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -use Magento\Framework\Component\ComponentRegistrar; - -$registrar = new ComponentRegistrar(); -if ($registrar->getPath(ComponentRegistrar::MODULE, 'Magento_TestSetupModule2') === null) { - ComponentRegistrar::register(ComponentRegistrar::MODULE, 'Magento_TestSetupModule2', __DIR__); -} diff --git a/dev/tests/setup-integration/_files/UpgradeScripts/TestSetupModule2/Setup/UpgradeData.php b/dev/tests/setup-integration/_files/UpgradeScripts/TestSetupModule2/Setup/UpgradeData.php deleted file mode 100644 index 871346e10e47e..0000000000000 --- a/dev/tests/setup-integration/_files/UpgradeScripts/TestSetupModule2/Setup/UpgradeData.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\TestSetupModule2\Setup; - -use Magento\Framework\Setup\UpgradeDataInterface; -use Magento\Framework\Setup\ModuleContextInterface; -use Magento\Framework\Setup\ModuleDataSetupInterface; - -/** - * @codeCoverageIgnore - */ -class UpgradeData implements UpgradeDataInterface -{ - - /** - * {@inheritdoc} - */ - public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - - // data update for TestSetupModule2 module < 0.0.2 - if (version_compare($context->getVersion(), '0.0.2', '<')) { - // add one more row to address_entity table - $setup->getConnection()->insertForce( - $setup->getTable('setup_tests_address_entity'), - [ - 'parent_id' => 1, - 'created_at' => '2017-10-30 13:34:19', - 'updated_at' => '2017-10-30 13:34:19', - 'is_active' => 1, - 'city' => 'Austin', - 'company' => 'X.Commerce', - 'country_id' => 'US', - 'firstname' => 'Joan', - 'lastname' => 'Doe', - 'postcode' => '36351', - 'region' => 'Alabama', - 'region_id' => 1, - 'street' => 'New Brockton', - 'telephone' => 12345678, - ] - ); - $setup->getConnection()->update( - $setup->getTable('setup_tests_entity_table'), - [ - 'increment_id'=> 1 - ], - 'increment_id = null' - ); - - $setup->getConnection()->insertForce( - $setup->getTable('setup_tests_entity_passwords'), - [ - 'entity_id' => 1, - 'password_hash' => '139e2ee2785cd9d9eb5714a02aca579bbcc05f9062996389d6e0e329bab9841b', - ] - ); - } - $setup->endSetup(); - } -} diff --git a/dev/tests/setup-integration/_files/UpgradeScripts/TestSetupModule2/Setup/UpgradeSchema.php b/dev/tests/setup-integration/_files/UpgradeScripts/TestSetupModule2/Setup/UpgradeSchema.php deleted file mode 100755 index 084ef15b5f6ee..0000000000000 --- a/dev/tests/setup-integration/_files/UpgradeScripts/TestSetupModule2/Setup/UpgradeSchema.php +++ /dev/null @@ -1,149 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\TestSetupModule2\Setup; - -use Magento\Framework\Setup\ModuleContextInterface; -use Magento\Framework\Setup\SchemaSetupInterface; -use Magento\Framework\Setup\UpgradeSchemaInterface; - -/** - * @codeCoverageIgnore - */ -class UpgradeSchema implements UpgradeSchemaInterface -{ - /** - * {@inheritdoc} - * - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context) - { - $setup->startSetup(); - - if (version_compare($context->getVersion(), '0.0.2') < 0) { - $connection = $setup->getConnection(); - - //add new column - $setup->getConnection()->addColumn( - $setup->getTable('setup_tests_entity_table'), - 'group_id', - [ - 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, - 'unsigned' => true, - 'nullable' => false, - 'default' => '0', - 'comment' => 'Group Id' - ] - ); - $setup->getConnection()->addColumn( - $setup->getTable('setup_tests_entity_table'), - 'store_id', - [ - 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, - 'unsigned' => true, - 'default' => '0', - 'comment' => 'Store Id' - ] - ); - - //add index - $connection->addIndex( - $setup->getTable('setup_tests_entity_table'), - $setup->getIdxName('setup_tests_entity_table', ['store_id']), - ['store_id'] - ); - - //modify existing column with type TEXT/TYPE_TIMESTAMP - $setup->getConnection()->modifyColumn( - $setup->getTable('setup_tests_address_entity'), - 'suffix', - [ - 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 'length' => 100, - ] - )->modifyColumn( - $setup->getTable('setup_tests_entity_table'), - 'created_at', - [ - 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, - 'nullable' => false, - 'default' => \Magento\Framework\DB\Ddl\Table::TIMESTAMP_INIT_UPDATE, - ] - ); - - //addTable - $table = $setup->getConnection() - ->newTable($setup->getTable('setup_tests_entity_passwords')) - ->addColumn( - 'password_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], - 'Password Id' - ) - ->addColumn( - 'entity_id', - \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, - null, - ['unsigned' => true, 'nullable' => false, 'default' => '0'], - 'User Id' - ) - ->addColumn( - 'password_hash', - \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, - 100, - [], - 'Password Hash' - ) - ->addIndex( - $setup->getIdxName('setup_tests_entity_passwords', ['entity_id']), - ['entity_id'] - ) - ->addForeignKey( - $setup->getFkName( - 'setup_tests_entity_passwords', - 'entity_id', - 'setup_tests_entity_table', - 'entity_id' - ), - 'entity_id', - $setup->getTable('setup_tests_entity_table'), - 'entity_id', - \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE - ) - ->setComment('Entity Passwords'); - - $setup->getConnection()->createTable($table); - //remove foreign key - $connection->dropForeignKey( - $setup->getTable('setup_tests_address_entity_decimal'), - $setup->getFkName( - 'setup_tests_address_entity_decimal', - 'entity_id', - 'setup_tests_address_entity', - 'entity_id' - ) - ); - - //remove index - $connection->dropIndex( - $setup->getTable('setup_tests_address_entity_decimal'), - $setup->getIdxName( - $setup->getTable('setup_tests_address_entity_decimal'), - ['entity_id', 'attribute_id'] - ) - ); - //remove column - $connection->dropColumn($setup->getTable('setup_tests_entity_table'), 'dob'); - - //remove table - $connection->dropTable($setup->getTable('setup_tests_address_entity_datetime')); - } - - $setup->endSetup(); - } -} diff --git a/dev/tests/setup-integration/_files/UpgradeScripts/TestSetupModule2/etc/module.xml b/dev/tests/setup-integration/_files/UpgradeScripts/TestSetupModule2/etc/module.xml deleted file mode 100644 index d781d8991cfe5..0000000000000 --- a/dev/tests/setup-integration/_files/UpgradeScripts/TestSetupModule2/etc/module.xml +++ /dev/null @@ -1,10 +0,0 @@ -<?xml version="1.0"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> - <module name="Magento_TestSetupModule2" setup_version="0.0.2"/> -</config> diff --git a/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/CopyModules.php b/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/CopyModules.php index 89d894786b1e3..be503e6de910a 100644 --- a/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/CopyModules.php +++ b/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/CopyModules.php @@ -6,6 +6,8 @@ namespace Magento\TestFramework\Annotation; +use Magento\Framework\Component\ComponentRegistrar; +use Magento\Framework\Filesystem\Io\File; use Magento\TestFramework\Deploy\CliCommand; use Magento\TestFramework\Deploy\TestModuleManager; @@ -44,10 +46,53 @@ public function startTest(\PHPUnit\Framework\TestCase $test) $annotations = $test->getAnnotations(); //This annotation can be declared only on method level if (isset($annotations['method']['moduleName'])) { - $moduleName = $annotations['method']['moduleName'][0]; - $this->cliCommand->introduceModule($moduleName); - $path = MAGENTO_MODULES_PATH . explode("_", $moduleName)[1] . '/registration.php'; - include_once $path; + $moduleNames = $annotations['method']['moduleName']; + + foreach ($moduleNames as $moduleName) { + $this->cliCommand->introduceModule($moduleName); + //Include module`s registration.php to load it + $path = MAGENTO_MODULES_PATH . explode("_", $moduleName)[1] . '/registration.php'; + include $path; + } } } + + /** + * Handler for 'startTest' event + * + * @param \PHPUnit\Framework\TestCase $test + */ + public function endTest(\PHPUnit\Framework\TestCase $test) + { + $annotations = $test->getAnnotations(); + //This annotation can be declared only on method level + if (!empty($annotations['method']['moduleName'])) { + foreach ($annotations['method']['moduleName'] as $moduleName) { + $path = MAGENTO_MODULES_PATH . + //Take only module name from Magento_ModuleName + explode("_", $moduleName)[1]; + File::rmdirRecursive($path); + $this->unsergisterModuleFromComponentRegistrar($moduleName); + } + } + } + + /** + * Unregister module from component registrar. + * The component registrar uses static private variable and does not provide unregister method, + * however unregister is required to remove registered modules after they are deleted from app/code. + * + * @param $moduleName + * + * @return void + */ + private function unsergisterModuleFromComponentRegistrar($moduleName) + { + $reflection = new \ReflectionClass(ComponentRegistrar::class); + $reflectionProperty = $reflection->getProperty('paths'); + $reflectionProperty->setAccessible(true); + $value = $reflectionProperty->getValue(); + unset($value[ComponentRegistrar::MODULE][$moduleName]); + $reflectionProperty->setValue($value); + } } diff --git a/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/ReinstallInstance.php b/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/ReinstallInstance.php index 0bfc7ba969f45..e97ba3f3bcb82 100644 --- a/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/ReinstallInstance.php +++ b/dev/tests/setup-integration/framework/Magento/TestFramework/Annotation/ReinstallInstance.php @@ -6,6 +6,8 @@ namespace Magento\TestFramework\Annotation; +use Magento\Framework\Module\ModuleResource; + /** * Handler for applying reinstallMagento annotation. */ @@ -26,6 +28,11 @@ public function __construct(\Magento\TestFramework\Application $application) $this->application = $application; } + public function startTest() + { + $this->application->reinitialize(); + } + /** * Handler for 'endTest' event. * @@ -34,5 +41,7 @@ public function __construct(\Magento\TestFramework\Application $application) public function endTest() { $this->application->cleanup(); + $this->application->reinitialize(); + ModuleResource::flush(); } } diff --git a/dev/tests/setup-integration/framework/Magento/TestFramework/Bootstrap/SetupDocBlock.php b/dev/tests/setup-integration/framework/Magento/TestFramework/Bootstrap/SetupDocBlock.php index 6732a8de4eb1e..8e212289eb12f 100644 --- a/dev/tests/setup-integration/framework/Magento/TestFramework/Bootstrap/SetupDocBlock.php +++ b/dev/tests/setup-integration/framework/Magento/TestFramework/Bootstrap/SetupDocBlock.php @@ -5,6 +5,8 @@ */ namespace Magento\TestFramework\Bootstrap; +use Magento\TestFramework\Annotation\AppIsolation; + /** * Bootstrap of the custom DocBlock annotations. * diff --git a/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/CliCommand.php b/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/CliCommand.php index 81804a2b8bb8b..a659c82d871d3 100644 --- a/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/CliCommand.php +++ b/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/CliCommand.php @@ -65,21 +65,25 @@ public function enableModule($moduleName) { $initParams = $this->parametersHolder->getInitParams(); $enableModuleCommand = 'php -f ' . BP . '/bin/magento module:enable ' . $moduleName - . ' -n -vvv --magento-init-params=' . $initParams['magento-init-params']; + . ' -n -vvv --magento-init-params="' . $initParams['magento-init-params'] . '"'; return $this->shell->execute($enableModuleCommand); } /** * Execute upgrade magento command. * + * @param array $installParams * @return string */ - public function upgrade() + public function upgrade($installParams = []) { $initParams = $this->parametersHolder->getInitParams(); - $enableModuleCommand = 'php -f ' . BP . '/bin/magento setup:upgrade -vvv -n --magento-init-params=' - . $initParams['magento-init-params']; - return $this->shell->execute($enableModuleCommand); + $upgradeCommand = 'php -f ' . BP . '/bin/magento setup:upgrade -vvv -n --magento-init-params="' + . $initParams['magento-init-params'] . '"'; + $installParams = $this->toCliArguments($installParams); + $upgradeCommand .= ' ' . implode(" ", array_keys($installParams)); + + return $this->shell->execute($upgradeCommand, array_values($installParams)); } /** @@ -147,6 +151,21 @@ public function cacheClean() $this->shell->execute($command); } + /** + * Uninstall module + * + * @param string $moduleName + */ + public function uninstallModule($moduleName) + { + $initParams = $this->parametersHolder->getInitParams(); + $command = 'php -f ' . BP . '/bin/magento module:uninstall ' . $moduleName . ' --remove-data ' . + ' -vvv --non-composer --magento-init-params="' . + $initParams['magento-init-params'] . '"'; + + $this->shell->execute($command); + } + /** * Convert from raw params to CLI arguments, like --admin-username. * diff --git a/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/DescribeTable.php b/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/DescribeTable.php index b3077a49641f3..fe008da2466d1 100644 --- a/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/DescribeTable.php +++ b/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/DescribeTable.php @@ -5,7 +5,7 @@ */ namespace Magento\TestFramework\Deploy; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\DbSchemaReader; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\DbSchemaReader; /** * The purpose of this class is adding test modules files to Magento code base. @@ -24,7 +24,7 @@ class DescribeTable * * @var array */ - private static $ignoredSystemTables = ['cache', 'cache_tag', 'flag', 'session', 'setup_module']; + private static $ignoredSystemTables = ['cache', 'cache_tag', 'flag', 'session', 'setup_module', 'patch_list']; /** * Constructor. diff --git a/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/ParametersHolder.php b/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/ParametersHolder.php index badbddf23fa90..894bab3dfa2e7 100644 --- a/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/ParametersHolder.php +++ b/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/ParametersHolder.php @@ -63,8 +63,10 @@ private function getCustomDirs() { $installDir = TESTS_TEMP_DIR; $path = DirectoryList::PATH; + $var = "{$installDir}/var"; $customDirs = [ DirectoryList::CONFIG => [$path => "{$installDir}/etc"], + DirectoryList::VAR_DIR => [$path => $var], ]; return $customDirs; } diff --git a/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/TableData.php b/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/TableData.php new file mode 100644 index 0000000000000..1d9026acd211a --- /dev/null +++ b/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/TableData.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\TestFramework\Deploy; + +use Magento\Framework\App\ResourceConnection; + +/** + * The purpose of this class is to describe what data is in table + */ +class TableData +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * TableData constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @param string $tableName + * @param string $columnName + * @return array + */ + public function describeTableData($tableName, $columnName = null) + { + $adapter = $this->resourceConnection->getConnection(); + $cols = $columnName ?: '*'; + $select = $adapter + ->select() + ->from($tableName, $cols); + return $columnName ? $adapter->fetchCol($select) : $adapter->fetchAll($select); + } +} diff --git a/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/TestModuleManager.php b/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/TestModuleManager.php index 482fd4abc7592..fcf8695dc8510 100644 --- a/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/TestModuleManager.php +++ b/dev/tests/setup-integration/framework/Magento/TestFramework/Deploy/TestModuleManager.php @@ -5,6 +5,10 @@ */ namespace Magento\TestFramework\Deploy; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Module\ModuleList; +use Magento\Framework\Module\ModuleListInterface; + /** * The purpose of this class is adding test modules files to Magento code base. */ @@ -60,6 +64,27 @@ public function addModuleFiles($moduleName) } } + /** + * Copy revision folder to main module + * + * @param string $moduleName + * @param string $revisionName + * @param string $dir + * @return void + */ + public function addRevision($moduleName, $revisionName, $dir) + { + $modulePath = str_replace("Magento_", "", $moduleName); + $folder = MAGENTO_MODULES_PATH . $modulePath; + $desiredPath = $folder . '/' . $dir; + $revisionPath = $folder . '/revisions/' . $revisionName . '/'; + + if (!is_dir($desiredPath)) { + mkdir($desiredPath, 0777, true); + } + rename($revisionPath, $desiredPath); + } + /** * Update module version. * @@ -76,7 +101,15 @@ public function updateRevision($moduleName, $revisionName, $fileName, $fileDir) $revisionFile = MAGENTO_MODULES_PATH . $modulePath . "/revisions/" . $revisionName . DIRECTORY_SEPARATOR . $fileName; - if (file_exists($oldFile) && file_exists($revisionFile)) { + if (!file_exists($oldFile)) { + $dir = dirname($oldFile); + if (!is_dir($dir)) { + mkdir($dir, 0777, true); + } + touch($oldFile); + } + + if (file_exists($revisionFile)) { unlink($oldFile); copy($revisionFile, $oldFile); } else { @@ -101,6 +134,21 @@ public function removeModuleFiles($moduleName) } } + /** + * There can be situation when config version of module can be cached + * So proposed to clean shared instance of + * @see ModuleList in order to achieve clean installation + */ + public function cleanModuleList() + { + /** + * @var \Magento\TestFramework\ObjectManager $objectManager + */ + $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + $objectManager->removeSharedInstance(ModuleList::class); + $objectManager->removeSharedInstance(ModuleListInterface::class); + } + /** * Update module files. * diff --git a/dev/tests/setup-integration/framework/bootstrap.php b/dev/tests/setup-integration/framework/bootstrap.php index eb2ed02a8ce3d..01f60a3376ff8 100644 --- a/dev/tests/setup-integration/framework/bootstrap.php +++ b/dev/tests/setup-integration/framework/bootstrap.php @@ -79,6 +79,7 @@ $application->createInstallDir(); //We do not want to install anything $application->initialize([]); + $application->cleanup(); \Magento\TestFramework\Helper\Bootstrap::setInstance(new \Magento\TestFramework\Helper\Bootstrap($bootstrap)); diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/BCMultiModuleTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/BCMultiModuleTest.php new file mode 100644 index 0000000000000..6ea79f9628e39 --- /dev/null +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/BCMultiModuleTest.php @@ -0,0 +1,202 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup; + +use Magento\Framework\Module\DbVersionInfo; +use Magento\Framework\Module\ModuleList; +use Magento\Framework\Module\ModuleResource; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaReaderInterface; +use Magento\TestFramework\Deploy\CliCommand; +use Magento\TestFramework\Deploy\TableData; +use Magento\TestFramework\Deploy\TestModuleManager; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\ObjectManager; +use Magento\TestFramework\TestCase\SetupTestCase; + +/** + * The purpose of this test is to check whether whole declarative installation is work + * in mixed mode + */ +class BCMultiModuleTest extends SetupTestCase +{ + /** + * @var TestModuleManager + */ + private $moduleManager; + + /** + * @var CliCommand + */ + private $cliCommand; + + /** + * @var DbVersionInfo + */ + private $dbVersionInfo; + + /** + * @var TableData + */ + private $tableData; + + /** + * @var ModuleResource + */ + private $moduleResource; + + /** + * @var DbSchemaReaderInterface + */ + private $dbSchemaReader; + + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->moduleManager = $objectManager->get(TestModuleManager::class); + $this->cliCommand = $objectManager->get(CliCommand::class); + $this->dbVersionInfo = $objectManager->get(DbVersionInfo::class); + $this->tableData = $objectManager->get(TableData::class); + $this->moduleResource = $objectManager->get(ModuleResource::class); + $this->dbSchemaReader = $objectManager->get(DbSchemaReaderInterface::class); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule6 + * @moduleName Magento_TestSetupDeclarationModule7 + */ + public function testFirstCleanInstall() + { + $this->cliCommand->install([ + 'Magento_TestSetupDeclarationModule6', + 'Magento_TestSetupDeclarationModule7' + ]); + //Check if declaration is applied + $indexes = $this->dbSchemaReader->readIndexes('test_table', 'default'); + self::assertCount(1, $indexes); + self::assertArrayHasKey('speedup_index', $indexes); + //Check UpgradeSchema old format, that modify declaration + $columns = $this->dbSchemaReader->readColumns('test_table', 'default'); + $floatColumn = $columns['float']; + self::assertEquals(29, $floatColumn['default']); + } + + private function doUsToUsRevision() + { + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule7', + 'us_to_us', + 'UpgradeSchema.php', + 'Setup' + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule7', + 'us_to_us', + 'module.xml', + 'etc' + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule7', + 'us_to_us', + 'UpgradeData.php', + 'Setup' + ); + } + + private function doUsToDsRevision() + { + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule7', + 'swap_with_declaration', + 'db_schema.xml', + 'etc' + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule7', + 'swap_with_declaration', + 'SomePatch.php', + 'Setup/Patch/Data' + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule7', + 'swap_with_declaration', + 'SomeSkippedPatch.php', + 'Setup/Patch/Data' + ); + } + + /** + * Assert that data and schema of 2 modules are installed successfully + */ + private function assertUsToUsUpgrade() + { + $usToUsTables = $this->dbSchemaReader->readTables('default'); + self::assertContains('custom_table', $usToUsTables); + self::assertTrue($this->dbVersionInfo->isDataUpToDate('Magento_TestSetupDeclarationModule7')); + self::assertTrue($this->dbVersionInfo->isSchemaUpToDate('Magento_TestSetupDeclarationModule7')); + self::assertEquals( + [6,12], + $this->tableData->describeTableData('reference_table', 'bigint_without_padding') + ); + } + + /** + * Assert that data and schema of 2 modules are installed successfully + */ + private function assertUsToDsUpgrade() + { + //Check UpgradeSchema old format, that modify declaration + $columns = $this->dbSchemaReader->readColumns('test_table', 'default'); + $floatColumn = $columns['float']; + //Check whether declaration will be applied + self::assertEquals(35, $floatColumn['default']); + self::assertTrue($this->dbVersionInfo->isDataUpToDate('Magento_TestSetupDeclarationModule7')); + self::assertTrue($this->dbVersionInfo->isSchemaUpToDate('Magento_TestSetupDeclarationModule7')); + self::assertEquals( + [6,12], + $this->tableData->describeTableData('reference_table', 'bigint_without_padding') + ); + self::assertEquals( + ['_ref'], + $this->tableData->describeTableData('test_table', 'varchar') + ); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule6 + * @moduleName Magento_TestSetupDeclarationModule7 + */ + public function testDSFirstRelease() + { + $this->cliCommand->install([ + 'Magento_TestSetupDeclarationModule6', + 'Magento_TestSetupDeclarationModule7' + ]); + //Check no change upgrade with US + $this->cliCommand->upgrade(); + + $this->doUsToUsRevision(); + //Check US to US upgrade + $this->cliCommand->upgrade(); + $this->assertUsToUsUpgrade(); + + $this->doUsToDsRevision(); + //Check US to declarative schema upgrade + $this->cliCommand->upgrade(); + $this->assertUsToDsUpgrade(); + + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule7', + 'wl_remove_table', + 'db_schema_whitelist.json', + 'etc' + ); + //Check removal case, when we need to remove table with declaration and table was created in old scripts + $this->cliCommand->upgrade(); + $tables = $this->dbSchemaReader->readTables('default'); + self::assertNotContains('custom_table', $tables); + } +} diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/BCPatchTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/BCPatchTest.php new file mode 100644 index 0000000000000..c74f07cd80aea --- /dev/null +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/BCPatchTest.php @@ -0,0 +1,172 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup; + +use Magento\Framework\Module\DbVersionInfo; +use Magento\Framework\Module\ModuleList; +use Magento\Framework\Module\ModuleResource; +use Magento\TestFramework\Deploy\CliCommand; +use Magento\TestFramework\Deploy\TableData; +use Magento\TestFramework\Deploy\TestModuleManager; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\SetupTestCase; + +/** + * The purpose of this test is to check whether patch changes in Magento are backward compatible + */ +class BCPatchTest extends SetupTestCase +{ + /** + * @var TestModuleManager + */ + private $moduleManager; + + /** + * @var CliCommand + */ + private $cliCommand; + + /** + * @var DbVersionInfo + */ + private $dbVersionInfo; + + /** + * @var TableData + */ + private $tableData; + + /** + * @var ModuleResource + */ + private $moduleResource; + + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->moduleManager = $objectManager->get(TestModuleManager::class); + $this->cliCommand = $objectManager->get(CliCommand::class); + $this->dbVersionInfo = $objectManager->get(DbVersionInfo::class); + $this->tableData = $objectManager->get(TableData::class); + $this->moduleResource = $objectManager->get(ModuleResource::class); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule5 + */ + public function testSuccessfullInstall() + { + $this->cliCommand->install(['Magento_TestSetupDeclarationModule5']); + self::assertTrue($this->dbVersionInfo->isDataUpToDate('Magento_TestSetupDeclarationModule5')); + self::assertTrue($this->dbVersionInfo->isSchemaUpToDate('Magento_TestSetupDeclarationModule5')); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule5 + */ + public function testDataMixedMode() + { + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule5', + 'old-scripts', + 'UpgradeData.php', + 'Setup' + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule5', + 'patches', + 'SomePatch.php', + 'Setup/Patch/Data' + ); + + $this->cliCommand->install(['Magento_TestSetupDeclarationModule5']); + self::assertTrue($this->dbVersionInfo->isDataUpToDate('Magento_TestSetupDeclarationModule5')); + self::assertTrue($this->dbVersionInfo->isSchemaUpToDate('Magento_TestSetupDeclarationModule5')); + self::assertEquals( + [6,12], + $this->tableData->describeTableData('reference_table', 'some_integer') + ); + self::assertEquals( + ['_ref'], + $this->tableData->describeTableData('test_table', 'varchar') + ); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule5 + */ + public function testSkippedPatch() + { + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule5', + 'patches', + 'SomePatch.php', + 'Setup/Patch/Data' + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule5', + 'patches', + 'SomeSkippedPatch.php', + 'Setup/Patch/Data' + ); + $this->cliCommand->install(['Magento_TestSetupDeclarationModule5']); + self::assertTrue($this->dbVersionInfo->isDataUpToDate('Magento_TestSetupDeclarationModule5')); + self::assertTrue($this->dbVersionInfo->isSchemaUpToDate('Magento_TestSetupDeclarationModule5')); + self::assertEquals( + ['_ref'], + $this->tableData->describeTableData('test_table', 'varchar') + ); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule5 + */ + public function testDataInstallationWithoutVersion() + { + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule5', + 'module-without-version', + 'module.xml', + 'etc' + ); + $this->cliCommand->install(['Magento_TestSetupDeclarationModule5']); + self::assertTrue($this->dbVersionInfo->isDataUpToDate('Magento_TestSetupDeclarationModule5')); + self::assertTrue($this->dbVersionInfo->isSchemaUpToDate('Magento_TestSetupDeclarationModule5')); + $this->moduleResource->setDataVersion('Magento_TestSetupDeclarationModule5', '1.0.2'); + $this->moduleResource->setDataVersion('Magento_TestSetupDeclarationModule5', '1.0.2'); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule5', + 'old-scripts', + 'UpgradeData.php', + 'Setup' + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule5', + 'patches', + 'SomePatch.php', + 'Setup/Patch/Data' + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule5', + 'patches', + 'SomeSkippedPatch.php', + 'Setup/Patch/Data' + ); + $this->cliCommand->upgrade(); + self::assertTrue($this->dbVersionInfo->isDataUpToDate('Magento_TestSetupDeclarationModule5')); + self::assertTrue($this->dbVersionInfo->isSchemaUpToDate('Magento_TestSetupDeclarationModule5')); + //Old scripts should be skipped because we do not have version + self::assertEquals( + [], + $this->tableData->describeTableData('reference_table', 'some_integer') + ); + self::assertEquals( + ['_ref'], + $this->tableData->describeTableData('test_table', 'varchar') + ); + } +} diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/DataPatchInstallationTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/DataPatchInstallationTest.php new file mode 100644 index 0000000000000..a781972b85887 --- /dev/null +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/DataPatchInstallationTest.php @@ -0,0 +1,238 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup; + +use Magento\Framework\Module\ModuleResource; +use Magento\Framework\Setup\Patch\PatchHistory; +use Magento\TestFramework\Deploy\CliCommand; +use Magento\TestFramework\Deploy\TableData; +use Magento\TestFramework\Deploy\TestModuleManager; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\SetupTestCase; +use Magento\TestSetupDeclarationModule3\Setup\Patch\Data\IncrementalSomeIntegerPatch; +use Magento\TestSetupDeclarationModule3\Setup\Patch\Data\ReferenceIncrementalSomeIntegerPatch; +use Magento\TestSetupDeclarationModule3\Setup\Patch\Data\ZFirstPatch; + +/** + * The purpose of this test is validating schema reader operations. + */ +class DataPatchInstallationTest extends SetupTestCase +{ + /** + * @var TestModuleManager + */ + private $moduleManager; + + /** + * @var CliCommand + */ + private $cliCommad; + + /** + * @var ModuleResource + */ + private $moduleResource; + + /** + * @var PatchHistory + */ + private $patchList; + + /** + * @var TableData + */ + private $tableData; + + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->moduleManager = $objectManager->get(TestModuleManager::class); + $this->cliCommad = $objectManager->get(CliCommand::class); + $this->moduleResource = $objectManager->get(ModuleResource::class); + $this->patchList = $objectManager->get(PatchHistory::class); + $this->tableData = $objectManager->get(TableData::class); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule3 + */ + public function testDataPatchesInstallation() + { + $this->cliCommad->install( + ['Magento_TestSetupDeclarationModule3'] + ); + + self::assertEquals( + '0.0.1', + $this->moduleResource->getDataVersion('Magento_TestSetupDeclarationModule3') + ); + + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule3', + 'first_patch_revision', + 'module.xml', + 'etc' + ); + $this->movePatches(); + ModuleResource::flush(); + $this->cliCommad->upgrade(); + self::assertEquals( + '0.0.3', + $this->moduleResource->getDataVersion('Magento_TestSetupDeclarationModule3') + ); + self::assertTrue($this->patchList->isApplied(IncrementalSomeIntegerPatch::class)); + self::assertTrue($this->patchList->isApplied(ReferenceIncrementalSomeIntegerPatch::class)); + self::assertTrue($this->patchList->isApplied(ZFirstPatch::class)); + $tableData = $this->tableData->describeTableData('test_table'); + self::assertEquals($this->getTestTableData(), $tableData); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule3 + * @expectedException \Magento\Framework\Exception\LocalizedException + */ + public function testCyclomaticDependency() + { + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule3', + 'cyclomatic_and_bic_revision', + 'module.xml', + 'etc' + ); + + $this->movePatches(); + /** + * Test whether installation give the same result as upgrade + */ + $this->cliCommad->install( + ['Magento_TestSetupDeclarationModule3'] + ); + $tableData = $this->tableData->describeTableData('test_table'); + self::assertEquals($this->getTestTableData(), $tableData); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule3', + 'cyclomatic_and_bic_revision', + 'BicPatch.php', + 'Setup/Patch/Data' + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule3', + 'cyclomatic_and_bic_revision', + 'RefBicPatch.php', + 'Setup/Patch/Data' + ); + + $this->cliCommad->upgrade(); + } + + /** + * Move patches + */ + private function movePatches() + { + //Install with patches + $this->moduleManager->addRevision( + 'Magento_TestSetupDeclarationModule3', + 'patches_revision', + 'Setup/Patch/Data' + ); + //Upgrade with UpgradeData + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule3', + 'first_patch_revision', + 'UpgradeData.php', + 'Setup' + ); + + //Upgrade with UpgradeData + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule3', + 'first_patch_revision', + 'module.xml', + 'etc' + ); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule3 + */ + public function testPatchesRevert() + { + $this->movePatches(); + $this->cliCommad->install(['Magento_TestSetupDeclarationModule3']); + $this->cliCommad->uninstallModule('Magento_TestSetupDeclarationModule3'); + $testTableData = $this->tableData->describeTableData('test_table'); + $patchListTableData = $this->tableData->describeTableData('patch_list'); + self::assertEmpty($patchListTableData); + self::assertEmpty($testTableData); + $refTableData = $this->tableData->describeTableData('reference_table'); + self::assertEquals($this->getRefTableData(), $refTableData); + } + + /** + * @return array + */ + private function getTestTableData() + { + return [ + [ + 'smallint' => '1', + 'tinyint' => null, + 'varchar' => 'Ololo123', + 'varbinary' => '33288', + ], + [ + 'smallint' => '2', + 'tinyint' => null, + 'varchar' => 'Ololo123_ref', + 'varbinary' => '33288', + ], + [ + 'smallint' => '3', + 'tinyint' => null, + 'varchar' => 'changed__very_secret_string', + 'varbinary' => '0', + ], + ]; + } + + /** + * Retrieve reference table data + * + * @return array + */ + private function getRefTableData() + { + return [ + [ + 'tinyint_ref' => '2', + 'some_integer' => '2', + 'for_patch_testing' => null, + ], + [ + 'tinyint_ref' => '3', + 'some_integer' => '3', + 'for_patch_testing' => null, + ], + [ + 'tinyint_ref' => '4', + 'some_integer' => '5', + 'for_patch_testing' => null, + ], + [ + 'tinyint_ref' => '5', + 'some_integer' => '6', + 'for_patch_testing' => null, + ], + [ + 'tinyint_ref' => '6', + 'some_integer' => '12', + 'for_patch_testing' => null, + ], + ]; + } +} diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeInstallerTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeInstallerTest.php index 58a50ecc376a2..f0b74670cee21 100644 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeInstallerTest.php +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeInstallerTest.php @@ -7,9 +7,9 @@ namespace Magento\Setup; use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Diff\SchemaDiff; -use Magento\Setup\Model\Declaration\Schema\SchemaConfigInterface; -use Magento\Setup\Model\Declaration\Schema\Sharding; +use Magento\Framework\Setup\Declaration\Schema\Diff\SchemaDiff; +use Magento\Framework\Setup\Declaration\Schema\SchemaConfigInterface; +use Magento\Framework\Setup\Declaration\Schema\Sharding; use Magento\TestFramework\Deploy\CliCommand; use Magento\TestFramework\Deploy\DescribeTable; use Magento\TestFramework\Deploy\TestModuleManager; diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeSchemaBuilderTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeSchemaBuilderTest.php index 4e27f400ebc01..07544c25c45e4 100644 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeSchemaBuilderTest.php +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/DeclarativeSchemaBuilderTest.php @@ -6,16 +6,17 @@ namespace Magento\Setup; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Internal; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; -use Magento\Setup\Model\Declaration\Schema\SchemaConfig; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\SchemaConfig; use Magento\TestFramework\Deploy\CliCommand; use Magento\TestFramework\Deploy\TestModuleManager; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\SetupTestCase; /** + * @magentoAppIsolation enabled * The purpose of this test is verifying initial InstallSchema, InstallData scripts. */ class DeclarativeSchemaBuilderTest extends SetupTestCase @@ -38,7 +39,7 @@ class DeclarativeSchemaBuilderTest extends SetupTestCase public function setUp() { $objectManager = Bootstrap::getObjectManager(); - $this->schemaConfig = $objectManager->get(SchemaConfig::class); + $this->schemaConfig = $objectManager->create(SchemaConfig::class); $this->moduleManager = $objectManager->get(TestModuleManager::class); $this->cliCommad = $objectManager->get(CliCommand::class); } @@ -60,24 +61,24 @@ public function testSchemaBuilder() //Test primary key and renaming $referenceTable = $schemaTables['reference_table']; /** - * @var Internal $primaryKey - */ + * @var Internal $primaryKey + */ $primaryKey = $referenceTable->getPrimaryConstraint(); $columns = $primaryKey->getColumns(); self::assertEquals('tinyint_ref', reset($columns)->getName()); //Test column $testTable = $schemaTables['test_table']; /** - * @var Timestamp $timestampColumn - */ + * @var Timestamp $timestampColumn + */ $timestampColumn = $testTable->getColumnByName('timestamp'); self::assertEquals('CURRENT_TIMESTAMP', $timestampColumn->getOnUpdate()); //Test disabled self::assertArrayNotHasKey('varbinary_rename', $testTable->getColumns()); //Test foreign key /** - * @var Reference $foreignKey - */ + * @var Reference $foreignKey + */ $foreignKey = $testTable->getConstraintByName('some_foreign_key'); self::assertEquals('NO ACTION', $foreignKey->getOnDelete()); self::assertEquals('tinyint_ref', $foreignKey->getReferenceColumn()->getName()); diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/DiffOldSchemaTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/DiffOldSchemaTest.php index 1d428a2cf59d8..3fb117896eaa9 100644 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/DiffOldSchemaTest.php +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/DiffOldSchemaTest.php @@ -6,9 +6,9 @@ namespace Magento\Setup; -use Magento\Setup\Model\Declaration\Schema\Diff\DiffFactory; -use Magento\Setup\Model\Declaration\Schema\Diff\SchemaDiff; -use Magento\Setup\Model\Declaration\Schema\SchemaConfigInterface; +use Magento\Framework\Setup\Declaration\Schema\Diff\DiffFactory; +use Magento\Framework\Setup\Declaration\Schema\Diff\SchemaDiff; +use Magento\Framework\Setup\Declaration\Schema\SchemaConfigInterface; use Magento\TestFramework\Deploy\CliCommand; use Magento\TestFramework\Deploy\TestModuleManager; use Magento\TestFramework\Helper\Bootstrap; diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/DryRunTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/DryRunTest.php new file mode 100644 index 0000000000000..562f88cea75e8 --- /dev/null +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/DryRunTest.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup; + +use Magento\Framework\Setup\Declaration\Schema\DryRunLogger; +use Magento\TestFramework\Deploy\CliCommand; +use Magento\TestFramework\Deploy\TestModuleManager; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\SetupTestCase; + +/** + * The purpose of this test is verifying declarative installation works. + */ +class DryRunTest extends SetupTestCase +{ + /** + * @var TestModuleManager + */ + private $moduleManager; + + /** + * @var CliCommand + */ + private $cliCommad; + + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->moduleManager = $objectManager->get(TestModuleManager::class); + $this->cliCommad = $objectManager->get(CliCommand::class); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule1 + * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/dry_run_log.php + */ + public function testDryRunOnCleanDatabase() + { + $logFileName = TESTS_TEMP_DIR . '/var/log/' . DryRunLogger::FILE_NAME; + $this->cliCommad->install( + ['Magento_TestSetupDeclarationModule1'], + ['dry-run' => true] + ); + self::assertFileExists($logFileName); + $data = file_get_contents($logFileName); + self::assertEquals($data, $this->getData()[0]); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule1 + * @dataProviderFromFile Magento/TestSetupDeclarationModule1/fixture/dry_run_log_on_upgrade.php + */ + public function testDryRunOnUpgrade() + { + $logFileName = TESTS_TEMP_DIR . '/var/log/' . DryRunLogger::FILE_NAME; + $this->cliCommad->install(['Magento_TestSetupDeclarationModule1']); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule1', + 'column_modifications', + 'db_schema.xml', + 'etc' + ); + $this->cliCommad->upgrade(['dry-run' => true]); + self::assertFileExists($logFileName); + $data = file_get_contents($logFileName); + self::assertEquals($data, $this->getData()[0]); + } +} diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/SafeInstallerTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/SafeInstallerTest.php new file mode 100644 index 0000000000000..5b42e6cf43e13 --- /dev/null +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/SafeInstallerTest.php @@ -0,0 +1,90 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\Diff\SchemaDiff; +use Magento\Framework\Setup\Declaration\Schema\SchemaConfigInterface; +use Magento\Framework\Setup\Declaration\Schema\Sharding; +use Magento\TestFramework\Deploy\CliCommand; +use Magento\TestFramework\Deploy\DescribeTable; +use Magento\TestFramework\Deploy\TestModuleManager; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\SetupTestCase; + +/** + * The purpose of this test is verifying safe declarative installation works. + */ +class SafeInstallerTest extends SetupTestCase +{ + /** + * @var TestModuleManager + */ + private $moduleManager; + + /** + * @var CliCommand + */ + private $cliCommad; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->moduleManager = $objectManager->get(TestModuleManager::class); + $this->cliCommad = $objectManager->get(CliCommand::class); + $this->resourceConnection = $objectManager->get(ResourceConnection::class); + } + + /** + * @moduleName Magento_TestSetupDeclarationModule4 + * @dataProviderFromFile Magento/TestSetupDeclarationModule4/fixture/safe_data_provider.php + */ + public function testInstallation() + { + $testTableData = $this->getData(); + $row = reset($testTableData); + $this->cliCommad->install(['Magento_TestSetupDeclarationModule4']); + $adapter = $this->resourceConnection->getConnection(); + $testTableName = $this->resourceConnection->getTableName('test_table'); + $adapter->insertArray( + $this->resourceConnection->getTableName('test_table'), + array_keys($row), + $this->getData() + ); + //Move new db_schema.xml + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule4', + 'remove_title_column', + 'db_schema.xml', + 'etc' + ); + $this->cliCommad->upgrade( + [ + 'safe-mode' => true, + ] + ); + //Move new db_schema.xml with restored title field + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule4', + 'restore_title_column', + 'db_schema.xml', + 'etc' + ); + $this->cliCommad->upgrade( + [ + 'data-restore' => true, + ] + ); + $testTableSelect = $adapter->select()->from($testTableName); + self::assertEquals($testTableData, $adapter->fetchAll($testTableSelect)); + } +} diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/SchemaReaderTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/SchemaReaderTest.php index 86b92ce2720a9..72f910527741c 100644 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/SchemaReaderTest.php +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/SchemaReaderTest.php @@ -6,7 +6,7 @@ namespace Magento\Setup; -use Magento\Setup\Model\Declaration\Schema\Declaration\ReaderComposite; +use Magento\Framework\Setup\Declaration\Schema\Declaration\ReaderComposite; use Magento\TestFramework\Deploy\TestModuleManager; use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\SetupTestCase; @@ -17,7 +17,7 @@ class SchemaReaderTest extends SetupTestCase { /** - * @var \Magento\Setup\Model\Declaration\Schema\FileSystem\XmlReader + * @var \Magento\Framework\Setup\Declaration\Schema\FileSystem\XmlReader */ private $reader; @@ -40,6 +40,7 @@ public function setUp() public function testSuccessfullRead() { $schema = $this->reader->read('all'); + unset($schema['table']['patch_list']); self::assertEquals($this->getData(), $schema); } @@ -78,6 +79,7 @@ public function testForeignKeyInterpreter() { $this->updateRevisionTo('foreign_key_interpreter'); $schema = $this->reader->read('all'); + unset($schema['table']['patch_list']); self::assertEquals($this->getData(), $schema); } } diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/ValidationRulesTest.php b/dev/tests/setup-integration/testsuite/Magento/Setup/ValidationRulesTest.php new file mode 100644 index 0000000000000..a8709b2eee383 --- /dev/null +++ b/dev/tests/setup-integration/testsuite/Magento/Setup/ValidationRulesTest.php @@ -0,0 +1,103 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup; + +use Magento\Framework\Setup\Declaration\Schema\SchemaConfig; +use Magento\TestFramework\Deploy\CliCommand; +use Magento\TestFramework\Deploy\TestModuleManager; +use Magento\TestFramework\Helper\Bootstrap; +use Magento\TestFramework\TestCase\SetupTestCase; + +/** + * The purpose of this test is verifying initial InstallSchema, InstallData scripts. + */ +class ValidationRulesTest extends SetupTestCase +{ + /** + * @var TestModuleManager + */ + private $moduleManager; + + /** + * @var SchemaConfig + */ + private $schemaConfig; + + /** + * @var CliCommand + */ + private $cliCommad; + + public function setUp() + { + $objectManager = Bootstrap::getObjectManager(); + $this->schemaConfig = $objectManager->create(SchemaConfig::class); + $this->moduleManager = $objectManager->get(TestModuleManager::class); + $this->cliCommad = $objectManager->get(CliCommand::class); + } + + /** + * @expectedException \Magento\Framework\Setup\Exception + * @expectedExceptionMessageRegExp + * /Primary key can`t be applied on table "test_table". All columns should be not nullable/ + * @moduleName Magento_TestSetupDeclarationModule8 + */ + public function testFailOnInvalidPrimaryKey() + { + $this->cliCommad->install( + ['Magento_TestSetupDeclarationModule8'] + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule8', + 'invalid_primary_key', + 'db_schema.xml', + 'etc' + ); + + $this->schemaConfig->getDeclarationConfig(); + } + + /** + * @expectedException \Magento\Framework\Setup\Exception + * @expectedExceptionMessageRegExp + * /Column definition "page_id_on" and reference column definition "page_id" + * are different in tables "dependent" and "test_table"/ + * @moduleName Magento_TestSetupDeclarationModule8 + */ + public function testFailOnIncosistentReferenceDefinition() + { + $this->cliCommad->install( + ['Magento_TestSetupDeclarationModule8'] + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule8', + 'incosistence_reference_definition', + 'db_schema.xml', + 'etc' + ); + $this->schemaConfig->getDeclarationConfig(); + } + + /** + * @expectedException \Magento\Framework\Setup\Exception + * @expectedExceptionMessageRegExp /Auto Increment column do not have index. Column - "page_id"/ + * @moduleName Magento_TestSetupDeclarationModule8 + */ + public function testFailOnInvalidAutoIncrementField() + { + $this->cliCommad->install( + ['Magento_TestSetupDeclarationModule8'] + ); + $this->moduleManager->updateRevision( + 'Magento_TestSetupDeclarationModule8', + 'invalid_auto_increment', + 'db_schema.xml', + 'etc' + ); + $this->schemaConfig->getDeclarationConfig(); + } +} diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedData.php b/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedData.php deleted file mode 100644 index 214403fa3d2aa..0000000000000 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedData.php +++ /dev/null @@ -1,46 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -return [ - 'setup_tests_entity_table' => [ - ['entity_id' => '1', - 'website_id' => '1', - 'email_field' => 'entity@example.com', - 'increment_id' => null, - 'created_at' => '2017-10-30 09:41:25', - 'updated_at' => '2017-10-30 09:45:05', - 'created_in' => 'Default Store View', - 'firstname' => 'John', - 'lastname' => 'Doe', - 'default_billing_address_id' => '1', - 'default_shipping_address_id' => '1', - 'dob' => '1973-12-15' - ], - ], - 'setup_tests_address_entity' => [ - [ - 'entity_id' => '1', - 'increment_id' => null, - 'parent_id' => '1', - 'created_at' => '2017-10-30 09:45:05', - 'updated_at' => '2017-10-30 09:45:05', - 'is_active' => '1', - 'city' => 'city', - 'company' => 'Magento', - 'country_id' => 'US', - 'fax' => null, - 'firstname' => 'John', - 'lastname' => 'Doe', - 'middlename' => null, - 'postcode' => '90210', - 'prefix' => null, - 'region' => 'Alabama', - 'region_id' => '1', - 'street' => 'street1', - 'suffix' => null, - 'telephone' => '12345678', - ] - ] -]; diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedDataAfterUpgrade.php b/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedDataAfterUpgrade.php deleted file mode 100644 index 68540dc0939fc..0000000000000 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedDataAfterUpgrade.php +++ /dev/null @@ -1,78 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -return [ - 'setup_tests_entity_table' => [ - [ - 'entity_id' => '1', - 'website_id' => '1', - 'email_field' => 'entity@example.com', - 'increment_id' => null, - 'created_at' => '2017-10-30 09:41:25', - 'updated_at' => '2017-10-30 09:45:05', - 'created_in' => 'Default Store View', - 'firstname' => 'John', - 'lastname' => 'Doe', - 'default_billing_address_id' => '1', - 'default_shipping_address_id' => '1', - 'group_id' => '0', - 'store_id' => '0', - ], - ], - 'setup_tests_address_entity' => [ - [ - 'entity_id' => '1', - 'increment_id' => null, - 'parent_id' => '1', - 'created_at' => '2017-10-30 09:45:05', - 'updated_at' => '2017-10-30 09:45:05', - 'is_active' => '1', - 'city' => 'city', - 'company' => 'Magento', - 'country_id' => 'US', - 'fax' => null, - 'firstname' => 'John', - 'lastname' => 'Doe', - 'middlename' => null, - 'postcode' => '90210', - 'prefix' => null, - 'region' => 'Alabama', - 'region_id' => '1', - 'street' => 'street1', - 'suffix' => null, - 'telephone' => '12345678', - ], - [ - 'entity_id' => '2', - 'increment_id' => null, - 'parent_id' => '1', - 'created_at' => '2017-10-30 13:34:19', - 'updated_at' => '2017-10-30 13:34:19', - 'is_active' => '1', - 'city' => 'Austin', - 'company' => 'X.Commerce', - 'country_id' => 'US', - 'fax' => null, - 'firstname' => 'Joan', - 'lastname' => 'Doe', - 'middlename' => null, - 'postcode' => '36351', - 'prefix' => null, - 'region' => 'Alabama', - 'region_id' => '1', - 'street' => 'New Brockton', - 'suffix' => null, - 'telephone' => '12345678', - - ], - ], - 'setup_tests_entity_passwords' => [ - [ - 'password_id' => '1', - 'entity_id' => '1', - 'password_hash' => '139e2ee2785cd9d9eb5714a02aca579bbcc05f9062996389d6e0e329bab9841b', - ] - ] -]; diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedIndexes.php b/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedIndexes.php deleted file mode 100644 index 76f3479dc53d1..0000000000000 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedIndexes.php +++ /dev/null @@ -1,267 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -return [ - 'setup_tests_table1' => [ - [ - 'COLUMNS_LIST' => [ - 'column_with_type_integer', - 'column_with_type_bigint', - ], - 'INDEX_TYPE' => 'primary', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'primary', - 'fields' => [ - 'column_with_type_integer', - 'column_with_type_bigint', - ], - ], - [ - 'COLUMNS_LIST' => - ['column_with_type_integer',], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => - ['column_with_type_integer',] - ], - [ - 'COLUMNS_LIST' => - ['column_with_type_text',], - 'INDEX_TYPE' => 'fulltext', - 'INDEX_METHOD' => 'FULLTEXT', - 'type' => 'fulltext', - 'fields' => - ['column_with_type_text'], - ], - ], - 'setup_tests_table1_related' => [ - [ - 'COLUMNS_LIST' => [ - 'column_with_relation', - ], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => - ['column_with_relation'], - ], - ], - 'setup_tests_entity_table' => [ - [ - 'COLUMNS_LIST' => [ - 'entity_id', - ], - 'INDEX_TYPE' => 'primary', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'primary', - 'fields' => - ['entity_id'], - ], - [ - 'COLUMNS_LIST' => [ - 'email_field', - 'website_id' - ], - 'INDEX_TYPE' => 'unique', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'unique', - 'fields' => - [ - 'email_field', - 'website_id' - ], - ], - [ - 'COLUMNS_LIST' => [ - 'website_id' - ], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => - [ - 'website_id' - ], - ], - [ - 'COLUMNS_LIST' => [ - 'firstname' - ], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => - [ - 'firstname' - ], - ], - [ - 'COLUMNS_LIST' => [ - 'lastname' - ], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => - [ - 'lastname' - ], - ] - ], - 'setup_tests_address_entity' => [ - [ - 'COLUMNS_LIST' => [ - 'entity_id' - ], - 'INDEX_TYPE' => 'primary', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'primary', - 'fields' => - [ - 'entity_id' - ], - ], - [ - 'COLUMNS_LIST' => [ - 'parent_id' - ], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => [ - 'parent_id' - ], - ] - ], - 'setup_tests_address_entity_datetime' => [ - [ - 'COLUMNS_LIST' => [ - 'value_id' - ], - 'INDEX_TYPE' => 'primary', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'primary', - 'fields' => [ - 'value_id' - ], - ], - [ - 'COLUMNS_LIST' => [ - 'entity_id', - 'attribute_id' - ], - 'INDEX_TYPE' => 'unique', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'unique', - 'fields' => [ - 'entity_id', - 'attribute_id' - ], - ], - [ - 'COLUMNS_LIST' => [ - 'attribute_id' - ], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => [ - 'attribute_id' - ], - ], - [ - 'COLUMNS_LIST' => [ - 'entity_id', - 'attribute_id', - 'value' - ], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => [ - 'entity_id', - 'attribute_id', - 'value' - ], - ], - ], - 'setup_tests_address_entity_decimal' => [ - [ - 'COLUMNS_LIST' => [ - 'value_id' - ], - 'INDEX_TYPE' => 'primary', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'primary', - 'fields' => [ - 'value_id' - ], - ], - [ - 'COLUMNS_LIST' => [ - 'entity_id', - 'attribute_id' - ], - 'INDEX_TYPE' => 'unique', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'unique', - 'fields' => [ - 'entity_id', - 'attribute_id' - ], - ], - [ - 'COLUMNS_LIST' => [ - 'attribute_id' - ], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => [ - 'attribute_id' - ], - ], - [ - 'COLUMNS_LIST' => [ - 'entity_id', - 'attribute_id', - 'value' - ], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => [ - 'entity_id', - 'attribute_id', - 'value' - ], - ], - ], - 'setup_tests_entity_passwords' => [ - [ - 'COLUMNS_LIST' => [ - 'password_id', - ], - 'INDEX_TYPE' => 'primary', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'primary', - 'fields' => [ - 'password_id', - ], - ], - [ - 'COLUMNS_LIST' => [ - 'entity_id', - ], - 'INDEX_TYPE' => 'index', - 'INDEX_METHOD' => 'BTREE', - 'type' => 'index', - 'fields' => [ - 'entity_id', - ], - ], - ] -]; diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedRelations.php b/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedRelations.php deleted file mode 100644 index d4777ec8581f4..0000000000000 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedRelations.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -return [ - 'setup_tests_table1' => [], - 'setup_tests_table1_related' => [ - 'COLUMN_NAME' => 'column_with_relation', - 'REF_COLUMN_NAME' => 'column_with_type_integer', - 'ON_DELETE' => 'CASCADE', - ], - 'setup_tests_entity_table' => [ - 'COLUMN_NAME' => 'website_id', - 'REF_COLUMN_NAME' => 'website_id', - 'ON_DELETE' => 'SET NULL', - ], - 'setup_tests_address_entity' => [ - 'COLUMN_NAME' => 'parent_id', - 'REF_COLUMN_NAME' => 'entity_id', - 'ON_DELETE' => 'CASCADE', - ], - 'setup_tests_address_entity_datetime' => [ - 'COLUMN_NAME' => 'entity_id', - 'REF_COLUMN_NAME' => 'entity_id', - 'ON_DELETE' => 'CASCADE', - ], - 'setup_tests_address_entity_decimal' => [ - 'COLUMN_NAME' => 'entity_id', - 'REF_COLUMN_NAME' => 'entity_id', - 'ON_DELETE' => 'CASCADE', - ], - 'setup_tests_entity_passwords' => [ - 'COLUMN_NAME' => 'entity_id', - 'REF_COLUMN_NAME' => 'entity_id', - 'ON_DELETE' => 'CASCADE', - ] -]; diff --git a/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedSchema.php b/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedSchema.php deleted file mode 100644 index c43291255287b..0000000000000 --- a/dev/tests/setup-integration/testsuite/Magento/Setup/_files/expectedSchema.php +++ /dev/null @@ -1,908 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -return [ - 'setup_tests_table1' => [ - 'column_with_type_boolean' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_boolean', - 'COLUMN_POSITION' => 1, - 'DATA_TYPE' => 'tinyint', - 'DEFAULT' => '0', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_smallint' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_smallint', - 'COLUMN_POSITION' => 2, - 'DATA_TYPE' => 'smallint', - 'DEFAULT' => '0', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_integer' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_integer', - 'COLUMN_POSITION' => 3, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => true, - 'PRIMARY_POSITION' => 1, - 'IDENTITY' => true, - ], - 'column_with_type_bigint' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_bigint', - 'COLUMN_POSITION' => 4, - 'DATA_TYPE' => 'bigint', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => true, - 'PRIMARY_POSITION' => 2, - 'IDENTITY' => false, - ], - 'column_with_type_float' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_float', - 'COLUMN_POSITION' => 5, - 'DATA_TYPE' => 'float', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_numeric' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_numeric', - 'COLUMN_POSITION' => 6, - 'DATA_TYPE' => 'decimal', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => '4', - 'PRECISION' => '12', - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_decimal' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_decimal', - 'COLUMN_POSITION' => 7, - 'DATA_TYPE' => 'decimal', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => '4', - 'PRECISION' => '12', - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_datetime' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_datetime', - 'COLUMN_POSITION' => 8, - 'DATA_TYPE' => 'datetime', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_timestamp_update' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_timestamp_update', - 'COLUMN_POSITION' => 9, - 'DATA_TYPE' => 'timestamp', - 'DEFAULT' => '0000-00-00 00:00:00', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_date' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_date', - 'COLUMN_POSITION' => 10, - 'DATA_TYPE' => 'date', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_text' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_text', - 'COLUMN_POSITION' => 11, - 'DATA_TYPE' => 'text', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_blob' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_blob', - 'COLUMN_POSITION' => 12, - 'DATA_TYPE' => 'varbinary(32)', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_verbinary' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_verbinary', - 'COLUMN_POSITION' => 13, - 'DATA_TYPE' => 'mediumblob', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - ], - 'setup_tests_table1_related' => [ - 'column_with_type_timestamp_init_update' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_timestamp_init_update', - 'COLUMN_POSITION' => 1, - 'DATA_TYPE' => 'timestamp', - 'DEFAULT' => 'CURRENT_TIMESTAMP', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_type_timestamp_init' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_type_timestamp_init', - 'COLUMN_POSITION' => 2, - 'DATA_TYPE' => 'timestamp', - 'DEFAULT' => 'CURRENT_TIMESTAMP', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'column_with_relation' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'column_with_relation', - 'COLUMN_POSITION' => 3, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - ], - 'setup_tests_entity_table' => [ - 'entity_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'entity_id', - 'COLUMN_POSITION' => 1, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => true, - 'PRIMARY_POSITION' => 1, - 'IDENTITY' => true, - ], - 'website_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'website_id', - 'COLUMN_POSITION' => 2, - 'DATA_TYPE' => 'smallint', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'email_field' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'email_field', - 'COLUMN_POSITION' => 3, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'increment_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'increment_id', - 'COLUMN_POSITION' => 4, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '50', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'created_at' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'created_at', - 'COLUMN_POSITION' => 5, - 'DATA_TYPE' => 'timestamp', - 'DEFAULT' => 'CURRENT_TIMESTAMP', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'updated_at' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'updated_at', - 'COLUMN_POSITION' => 6, - 'DATA_TYPE' => 'timestamp', - 'DEFAULT' => 'CURRENT_TIMESTAMP', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'created_in' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'created_in', - 'COLUMN_POSITION' => 7, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'firstname' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'firstname', - 'COLUMN_POSITION' => 8, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'lastname' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'lastname', - 'COLUMN_POSITION' => 9, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'dob' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'dob', - 'COLUMN_POSITION' => 10, - 'DATA_TYPE' => 'date', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'default_billing_address_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'default_billing_address_id', - 'COLUMN_POSITION' => 11, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'default_shipping_address_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'default_shipping_address_id', - 'COLUMN_POSITION' => 12, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - ], - 'setup_tests_address_entity' => [ - 'entity_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'entity_id', - 'COLUMN_POSITION' => 1, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => true, - 'PRIMARY_POSITION' => 1, - 'IDENTITY' => true, - ], - 'increment_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'increment_id', - 'COLUMN_POSITION' => 2, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '50', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'parent_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'parent_id', - 'COLUMN_POSITION' => 3, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'created_at' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'created_at', - 'COLUMN_POSITION' => 4, - 'DATA_TYPE' => 'timestamp', - 'DEFAULT' => 'CURRENT_TIMESTAMP', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'updated_at' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'updated_at', - 'COLUMN_POSITION' => 5, - 'DATA_TYPE' => 'timestamp', - 'DEFAULT' => 'CURRENT_TIMESTAMP', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'is_active' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'is_active', - 'COLUMN_POSITION' => 6, - 'DATA_TYPE' => 'smallint', - 'DEFAULT' => '1', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'city' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'city', - 'COLUMN_POSITION' => 7, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'company' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'company', - 'COLUMN_POSITION' => 8, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'country_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'country_id', - 'COLUMN_POSITION' => 9, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'fax' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'fax', - 'COLUMN_POSITION' => 10, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'firstname' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'firstname', - 'COLUMN_POSITION' => 11, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'lastname' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'lastname', - 'COLUMN_POSITION' => 12, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'middlename' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'middlename', - 'COLUMN_POSITION' => 13, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'postcode' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'postcode', - 'COLUMN_POSITION' => 14, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'prefix' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'prefix', - 'COLUMN_POSITION' => 15, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '40', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'region' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'region', - 'COLUMN_POSITION' => 16, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'region_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'region_id', - 'COLUMN_POSITION' => 17, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'street' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'street', - 'COLUMN_POSITION' => 18, - 'DATA_TYPE' => 'text', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'suffix' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'suffix', - 'COLUMN_POSITION' => 19, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '40', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'telephone' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'telephone', - 'COLUMN_POSITION' => 20, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => '255', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - - ], - 'setup_tests_address_entity_datetime' => [ - 'value_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'value_id', - 'COLUMN_POSITION' => 1, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => true, - 'PRIMARY_POSITION' => 1, - 'IDENTITY' => true, - ], - 'attribute_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'attribute_id', - 'COLUMN_POSITION' => 2, - 'DATA_TYPE' => 'smallint', - 'DEFAULT' => '0', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'entity_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'entity_id', - 'COLUMN_POSITION' => 3, - 'DATA_TYPE' => 'int', - 'DEFAULT' => '0', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'value' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'value', - 'COLUMN_POSITION' => 4, - 'DATA_TYPE' => 'datetime', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - ], - 'setup_tests_address_entity_decimal' => [ - 'value_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'value_id', - 'COLUMN_POSITION' => 1, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => true, - 'PRIMARY_POSITION' => 1, - 'IDENTITY' => true, - ], - 'attribute_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'attribute_id', - 'COLUMN_POSITION' => 2, - 'DATA_TYPE' => 'smallint', - 'DEFAULT' => '0', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'entity_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'entity_id', - 'COLUMN_POSITION' => 3, - 'DATA_TYPE' => 'int', - 'DEFAULT' => '0', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'value' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'value', - 'COLUMN_POSITION' => 4, - 'DATA_TYPE' => 'decimal', - 'DEFAULT' => '0.0000', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => '4', - 'PRECISION' => '12', - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - - ], - 'setup_tests_entity_passwords' => [ - 'password_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'password_id', - 'COLUMN_POSITION' => 1, - 'DATA_TYPE' => 'int', - 'DEFAULT' => null, - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => true, - 'PRIMARY_POSITION' => 1, - 'IDENTITY' => true, - ], - 'entity_id' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'entity_id', - 'COLUMN_POSITION' => 2, - 'DATA_TYPE' => 'int', - 'DEFAULT' => '0', - 'NULLABLE' => false, - 'LENGTH' => null, - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => true, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - 'password_hash' => [ - 'SCHEMA_NAME' => null, - 'COLUMN_NAME' => 'password_hash', - 'COLUMN_POSITION' => 3, - 'DATA_TYPE' => 'varchar', - 'DEFAULT' => null, - 'NULLABLE' => true, - 'LENGTH' => '100', - 'SCALE' => null, - 'PRECISION' => null, - 'UNSIGNED' => null, - 'PRIMARY' => false, - 'PRIMARY_POSITION' => null, - 'IDENTITY' => false, - ], - ] -]; diff --git a/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php b/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php index e240e5037fb3e..2df84c579ccbc 100644 --- a/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php +++ b/dev/tests/static/framework/Magento/TestFramework/Dependency/PhpRule.php @@ -88,39 +88,67 @@ public function getDependencyInfo($currentModule, $fileType, $file, &$contents) return []; } - $pattern = '~\b(?<class>(?<module>(' . implode( - '_|', - Files::init()->getNamespaces() - ) . '[_\\\\])[a-zA-Z0-9]+)[a-zA-Z0-9_\\\\]*)\b~'; + $dependenciesInfo = []; + $dependenciesInfo = $this->considerCaseDependencies( + $dependenciesInfo, + $this->caseClassesAndIdentifiers($currentModule, $file, $contents) + ); + $dependenciesInfo = $this->considerCaseDependencies( + $dependenciesInfo, + $this->_caseGetUrl($currentModule, $contents) + ); + $dependenciesInfo = $this->considerCaseDependencies( + $dependenciesInfo, + $this->_caseLayoutBlock($currentModule, $fileType, $file, $contents) + ); + return $dependenciesInfo; + } + + /** + * Check references to classes and identifiers defined in other modules + * + * @param string $currentModule + * @param string $file + * @param string $contents + * @return array + */ + private function caseClassesAndIdentifiers($currentModule, $file, &$contents) + { + $pattern = '~\b(?<class>(?<module>(' + . implode( + '_|', + Files::init()->getNamespaces() + ) + . '[_\\\\])[a-zA-Z0-9]+)' + . '(?<class_inside_module>[a-zA-Z0-9_\\\\]*))\b(?:::(?<module_scoped_key>[a-z0-9_]+)[\'"])?~'; + + if (!preg_match_all($pattern, $contents, $matches)) { + return []; + } $dependenciesInfo = []; - if (preg_match_all($pattern, $contents, $matches)) { - $matches['module'] = array_unique($matches['module']); - foreach ($matches['module'] as $i => $referenceModule) { - $referenceModule = str_replace('_', '\\', $referenceModule); - if ($currentModule == $referenceModule) { - continue; - } - $dependencyClass = trim($matches['class'][$i]); + $matches['module'] = array_unique($matches['module']); + foreach ($matches['module'] as $i => $referenceModule) { + $referenceModule = str_replace('_', '\\', $referenceModule); + if ($currentModule == $referenceModule) { + continue; + } + + $dependencyClass = trim($matches['class'][$i]); + if (empty($matches['class_inside_module'][$i]) && !empty($matches['module_scoped_key'][$i])) { + $dependencyType = RuleInterface::TYPE_SOFT; + } else { $currentClass = $this->getClassFromFilepath($file, $currentModule); $dependencyType = $this->isPluginDependency($currentClass, $dependencyClass) ? RuleInterface::TYPE_SOFT : RuleInterface::TYPE_HARD; - - $dependenciesInfo[] = [ - 'module' => $referenceModule, - 'type' => $dependencyType, - 'source' => $dependencyClass, - ]; } - } - $result = $this->_caseGetUrl($currentModule, $contents); - if (count($result)) { - $dependenciesInfo = array_merge($dependenciesInfo, $result); - } - $result = $this->_caseLayoutBlock($currentModule, $fileType, $file, $contents); - if (count($result)) { - $dependenciesInfo = array_merge($dependenciesInfo, $result); + + $dependenciesInfo[] = [ + 'module' => $referenceModule, + 'type' => $dependencyType, + 'source' => $dependencyClass, + ]; } return $dependenciesInfo; @@ -366,4 +394,14 @@ protected function _getUniqueDependencies($dependencies = []) } return $result; } + + /** + * @param array $known + * @param array $new + * @return array + */ + private function considerCaseDependencies($known, $new) + { + return array_merge($known, $new); + } } diff --git a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/DeclarativeSchemaRuleTest.php b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/DeclarativeSchemaRuleTest.php index fde892877eff3..269eff8087a91 100644 --- a/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/DeclarativeSchemaRuleTest.php +++ b/dev/tests/static/framework/tests/unit/testsuite/Magento/TestFramework/Dependency/DeclarativeSchemaRuleTest.php @@ -70,7 +70,7 @@ public function getDependencyInfoDataProvider() 'any', '/app/some/path/etc/db_schema.xml', '<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> <table name="some_table"> <constraint xsi:type="foreign" name="FK_NAME" diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php index add61e6722227..87da2f13e1e24 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/ComposerTest.php @@ -35,12 +35,42 @@ class ComposerTest extends \PHPUnit\Framework\TestCase */ private static $objectManager; + /** + * @var string[] + */ + private static $rootComposerModuleBlacklist = []; + + /** + * @var string[] + */ + private static $moduleNameBlacklist; + public static function setUpBeforeClass() { self::$root = BP; self::$rootJson = json_decode(file_get_contents(self::$root . '/composer.json'), true); self::$dependencies = []; self::$objectManager = Bootstrap::create(BP, $_SERVER)->getObjectManager(); + // A block can be whitelisted and thus not be required to be public + self::$rootComposerModuleBlacklist = self::getBlacklist( + __DIR__ . '/_files/blacklist/composer_root_modules*.txt' + ); + self::$moduleNameBlacklist = self::getBlacklist(__DIR__ . '/_files/blacklist/composer_module_names*.txt'); + } + + /** + * Return aggregated blacklist + * + * @param string $pattern + * @return string[] + */ + public static function getBlacklist(string $pattern) + { + $blacklist = []; + foreach (glob($pattern) as $list) { + $blacklist = array_merge($blacklist, file($list, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)); + } + return $blacklist; } public function testValidComposerJson() @@ -222,13 +252,15 @@ private function assertNoMap(\StdClass $json) */ private function assertConsistentModuleName(\SimpleXMLElement $xml, $packageName) { - $moduleName = (string)$xml->module->attributes()->name; - $expectedPackageName = $this->convertModuleToPackageName($moduleName); - $this->assertEquals( - $expectedPackageName, - $packageName, - "For the module '{$moduleName}', the expected package name is '{$expectedPackageName}'" - ); + if (!in_array($packageName, self::$moduleNameBlacklist)) { + $moduleName = (string)$xml->module->attributes()->name; + $expectedPackageName = $this->convertModuleToPackageName($moduleName); + $this->assertEquals( + $expectedPackageName, + $packageName, + "For the module '{$moduleName}', the expected package name is '{$expectedPackageName}'" + ); + } } /** @@ -277,36 +309,48 @@ private function assertPhpVersionInSync($name, $phpVersion) * Make sure requirements of components are reflected in root composer.json * * @param \StdClass $json + * @return void */ private function assertRequireInSync(\StdClass $json) { - $name = $json->name; if (preg_match('/magento\/project-*/', self::$rootJson['name']) == 1) { return; } - if (isset($json->require)) { - $errors = []; - foreach (array_keys((array)$json->require) as $depName) { - if ($depName == 'magento/magento-composer-installer') { - // Magento Composer Installer is not needed for already existing components - continue; - } - if (!isset(self::$rootJson['require-dev'][$depName]) && !isset(self::$rootJson['require'][$depName]) - && !isset(self::$rootJson['replace'][$depName])) { - $errors[] = "'$name' depends on '$depName'"; - } + if (!in_array($json->name, self::$rootComposerModuleBlacklist) && isset($json->require)) { + $this->checkPackageInRootComposer($json); + } + } + + /** + * Check if package is reflected in root composer.json + * + * @param \StdClass $json + * @return void + */ + private function checkPackageInRootComposer(\StdClass $json) + { + $name = $json->name; + $errors = []; + foreach (array_keys((array)$json->require) as $depName) { + if ($depName == 'magento/magento-composer-installer') { + // Magento Composer Installer is not needed for already existing components + continue; } - if (!empty($errors)) { - $this->fail( - "The following dependencies are missing in root 'composer.json'," - . " while declared in child components.\n" - . "Consider adding them to 'require-dev' section (if needed for child components only)," - . " to 'replace' section (if they are present in the project)," - . " to 'require' section (if needed for the skeleton).\n" - . join("\n", $errors) - ); + if (!isset(self::$rootJson['require-dev'][$depName]) && !isset(self::$rootJson['require'][$depName]) + && !isset(self::$rootJson['replace'][$depName])) { + $errors[] = "'$name' depends on '$depName'"; } } + if (!empty($errors)) { + $this->fail( + "The following dependencies are missing in root 'composer.json'," + . " while declared in child components.\n" + . "Consider adding them to 'require-dev' section (if needed for child components only)," + . " to 'replace' section (if they are present in the project)," + . " to 'require' section (if needed for the skeleton).\n" + . join("\n", $errors) + ); + } } /** @@ -401,7 +445,11 @@ private function checkProject() } } sort($dependenciesListed); - $nonDeclaredDependencies = array_diff(self::$dependencies, $dependenciesListed); + $nonDeclaredDependencies = array_diff( + self::$dependencies, + $dependenciesListed, + self::$rootComposerModuleBlacklist + ); $nonexistentDependencies = array_diff($dependenciesListed, self::$dependencies); $this->assertEmpty( $nonDeclaredDependencies, diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/DependencyTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/DependencyTest.php index e2439a4d2d8d6..3e7f7804222e2 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/DependencyTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/DependencyTest.php @@ -423,7 +423,10 @@ public function collectRedundant() { foreach (array_keys(self::$_mapDependencies) as $module) { $declared = $this->_getDependencies($module, self::TYPE_HARD, self::MAP_TYPE_DECLARED); - $found = $this->_getDependencies($module, self::TYPE_HARD, self::MAP_TYPE_FOUND); + $found = array_merge( + $this->_getDependencies($module, self::TYPE_HARD, self::MAP_TYPE_FOUND), + $this->_getDependencies($module, self::TYPE_SOFT, self::MAP_TYPE_FOUND) + ); $found['Magento\Framework'] = 'Magento\Framework'; $this->_setDependencies($module, self::TYPE_HARD, self::MAP_TYPE_REDUNDANT, array_diff($declared, $found)); } diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php index ec255b90a349f..42ef12072a91b 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php @@ -62,6 +62,11 @@ class CompilerTest extends \PHPUnit\Framework\TestCase */ protected $pluginValidator; + /** + * @var string[]|null + */ + private $pluginBlacklist; + protected function setUp() { $this->_shell = new \Magento\Framework\Shell(new \Magento\Framework\Shell\CommandRenderer()); @@ -107,6 +112,31 @@ protected function setUp() $this->pluginValidator = new PluginValidator(new InterfaceValidator()); } + /** + * Return plugin blacklist class names + * + * @return string[] + */ + private function getPluginBlacklist(): array + { + if ($this->pluginBlacklist === null) { + $blacklistFiles = str_replace( + '\\', + '/', + realpath(__DIR__) . '/../_files/blacklist/compiler_plugins*.txt' + ); + $blacklistItems = []; + foreach (glob($blacklistFiles) as $fileName) { + $blacklistItems = array_merge( + $blacklistItems, + file($fileName, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) + ); + } + $this->pluginBlacklist = $blacklistItems; + } + return $this->pluginBlacklist; + } + /** * Validate DI config file * @@ -360,6 +390,7 @@ protected function validatePlugins($plugin, $type) * Get application plugins * * @return array + * @throws \Exception */ protected function pluginDataProvider() { @@ -376,8 +407,10 @@ protected function pluginDataProvider() $type = \Magento\Framework\App\Utility\Classes::resolveVirtualType($type); if ($node->attributes->getNamedItem('type')) { $plugin = $node->attributes->getNamedItem('type')->nodeValue; - $plugin = \Magento\Framework\App\Utility\Classes::resolveVirtualType($plugin); - $plugins[] = ['plugin' => $plugin, 'intercepted type' => $type]; + if (!in_array($plugin, $this->getPluginBlacklist())) { + $plugin = \Magento\Framework\App\Utility\Classes::resolveVirtualType($plugin); + $plugins[] = ['plugin' => $plugin, 'intercepted type' => $type]; + } } } } diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/ControllerAclTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/ControllerAclTest.php index 505d3e5c3270b..175a9aadbeaec 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/ControllerAclTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Backend/ControllerAclTest.php @@ -148,10 +148,10 @@ private function getAclResources() if ($this->aclResources !== null) { return $this->aclResources; } - $aclFiles = array_keys(Files::init()->getConfigFiles('acl.xml', [])); + $aclFiles = Files::init()->getConfigFiles('acl.xml', []); $xmlResources = []; array_map(function ($file) use (&$xmlResources) { - $config = simplexml_load_file($file); + $config = simplexml_load_file($file[0]); $nodes = $config->xpath('.//resource/@id') ?: []; foreach ($nodes as $node) { $xmlResources[(string)$node] = $node; diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Api/_files/ExtensibleInterfacesTest/blacklist_ce.txt b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Api/_files/ExtensibleInterfacesTest/blacklist_ce.txt index 1563abcaf8bd1..0fd245561e6be 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Api/_files/ExtensibleInterfacesTest/blacklist_ce.txt +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Magento/Framework/Api/_files/ExtensibleInterfacesTest/blacklist_ce.txt @@ -1,2 +1,3 @@ module Magento_Payment Model/Info.php -module Magento_Customer Model/Address/AbstractAddress.php \ No newline at end of file +module Magento_Customer Model/Address/AbstractAddress.php +library magento/framework MessageQueue/Rpc/Publisher.php \ No newline at end of file diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/PublicCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/PublicCodeTest.php index 56d00bc725dbd..6dd9d2f2bddfd 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/PublicCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/PublicCodeTest.php @@ -22,33 +22,53 @@ class PublicCodeTest extends \PHPUnit\Framework\TestCase '$this', 'void', 'string', 'int', 'bool', 'boolean', 'integer', 'null' ]; + /** + * @var string[]|null + */ + private $blockWhitelist; + + /** + * Return whitelist class names + * + * @return string[] + */ + private function getWhitelist(): array + { + if ($this->blockWhitelist === null) { + $whiteListFiles = str_replace( + '\\', + '/', + realpath(__DIR__) . '/_files/whitelist/public_code*.txt' + ); + $whiteListItems = []; + foreach (glob($whiteListFiles) as $fileName) { + $whiteListItems = array_merge( + $whiteListItems, + file($fileName, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) + ); + } + $this->blockWhitelist = $whiteListItems; + } + return $this->blockWhitelist; + } + /** * Since blocks can be referenced from templates, they should be stable not to break theme customizations. * So all blocks should be @api annotated. This test checks that all blocks declared in layout files are public * * @param $layoutFile + * @throws \ReflectionException * @dataProvider layoutFilesDataProvider */ public function testAllBlocksReferencedInLayoutArePublic($layoutFile) { - // A block can be whitelisted and thus not be required to be public - $whiteListFiles = str_replace('\\', '/', realpath(__DIR__)) - . '/_files/whitelist/public_code*.txt'; - $whiteListBlocks = []; - foreach (glob($whiteListFiles) as $fileName) { - $whiteListBlocks = array_merge( - $whiteListBlocks, - file($fileName, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) - ); - } - $nonPublishedBlocks = []; $xml = simplexml_load_file($layoutFile); $elements = $xml->xpath('//block | //referenceBlock') ?: []; /** @var $node \SimpleXMLElement */ foreach ($elements as $node) { $class = (string) $node['class']; - if ($class && \class_exists($class) && !in_array($class, $whiteListBlocks)) { + if ($class && \class_exists($class) && !in_array($class, $this->getWhitelist())) { $reflection = (new \ReflectionClass($class)); if (strpos($reflection->getDocComment(), '@api') === false) { $nonPublishedBlocks[] = $class; @@ -58,7 +78,7 @@ public function testAllBlocksReferencedInLayoutArePublic($layoutFile) if (count($nonPublishedBlocks)) { $this->fail( "Layout file '$layoutFile' uses following blocks that are not marked with @api annotation:\n" - . implode(",\n", $nonPublishedBlocks) + . implode(",\n", array_unique($nonPublishedBlocks)) ); } } @@ -67,6 +87,7 @@ public function testAllBlocksReferencedInLayoutArePublic($layoutFile) * Find all layout update files in magento modules and themes. * * @return array + * @throws \Exception */ public function layoutFilesDataProvider() { @@ -79,8 +100,8 @@ public function layoutFilesDataProvider() * This test walks through all public PHP types and makes sure that all their method arguments * and return values are public types. * - * * @param string $class + * @throws \ReflectionException * @dataProvider publicPHPTypesDataProvider */ public function testAllPHPClassesReferencedFromPublicClassesArePublic($class) @@ -113,7 +134,7 @@ public function testAllPHPClassesReferencedFromPublicClassesArePublic($class) if (count($nonPublishedClasses)) { $this->fail( "Public type '" . $class . "' references following non-public types:\n" - . implode("\n", $nonPublishedClasses) + . implode("\n", array_unique($nonPublishedClasses)) ); } } @@ -121,6 +142,7 @@ public function testAllPHPClassesReferencedFromPublicClassesArePublic($class) /** * Retrieve list of all interfaces and classes in Magento codebase that are marked with @api annotation. * @return array + * @throws \Exception */ public function publicPHPTypesDataProvider() { @@ -130,7 +152,9 @@ public function publicPHPTypesDataProvider() $fileContents = \file_get_contents($file); if (strpos($fileContents, '@api') !== false) { foreach ($this->getDeclaredClassesAndInterfaces($file) as $class) { - if (class_exists($class->getName()) || interface_exists($class->getName())) { + if (!in_array($class->getName(), $this->getWhitelist()) + && (class_exists($class->getName()) || interface_exists($class->getName())) + ) { $result[$class->getName()] = [$class->getName()]; } } diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/exception_hierarchy.txt b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/exception_hierarchy.txt index 1c96bbce72454..8eb3392476400 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/exception_hierarchy.txt +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/exception_hierarchy.txt @@ -12,3 +12,4 @@ \Magento\Catalog\Model\Product\Image\NotLoadInfoImageException \Magento\Signifyd\Model\SignifydGateway\GatewayException \Magento\Signifyd\Model\SignifydGateway\ApiCallException +\Magento\Framework\MessageQueue\ConnectionLostException diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/dependency_test/tables_ce.php b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/dependency_test/tables_ce.php index d859cb5b11732..50fe1e3232977 100644 --- a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/dependency_test/tables_ce.php +++ b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/dependency_test/tables_ce.php @@ -300,4 +300,5 @@ 'theme_files' => 'Magento\Theme', 'variable' => 'Magento\Variable', 'variable_value' => 'Magento\Variable', + 'job_queue' => 'Magento\Queue', ]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/InstallUpgradeTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/InstallUpgradeTest.php index 9e9a3418561d1..5c920fb7ad225 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/InstallUpgradeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/InstallUpgradeTest.php @@ -42,6 +42,12 @@ function ($file) { 'InstallSchema objects are obsolete. ' . 'Please use declarative schema approach in module\'s etc/db_schema.xml file' ); + $this->assertStringStartsNotWith( + 'InstallData', + basename($file), + 'InstallData objects are obsolete. ' + . 'Please use data patches approach in module\'s Setup/Patch/Data dir' + ); $this->assertStringStartsNotWith( 'data-install-', basename($file), @@ -59,20 +65,27 @@ function ($file) { 'UpgradeSchema scripts are obsolete. ' . 'Please use declarative schema approach in module\'s etc/db_schema.xml file' ); + $this->assertStringStartsNotWith( + 'UpgradeData', + basename($file), + 'UpgradeSchema scripts are obsolete. ' + . 'Please use data patches approach in module\'s Setup/Patch/Data dir' + ); $this->assertStringStartsNotWith( 'data-upgrade-', basename($file), - 'Upgrade scripts are obsolete. Please create class UpgradeData in module\'s Setup folder' + 'Upgrade scripts are obsolete. ' + . 'Please use data patches approach in module\'s Setup/Patch/Data dir' ); $this->assertStringStartsNotWith( 'recurring', basename($file), 'Recurring scripts are obsolete. Please create class Recurring in module\'s Setup folder' ); - if (preg_match('/.*\/(sql|data)/i', dirname($file))) { + if (preg_match('/.*\/(sql\/|data\/)/', dirname($file))) { $this->fail( "Invalid directory:\n" - . "- Create an UpgradeData class within module's Setup folder for data upgrades.\n" + . "- Create an data patch within module's Setup/Patch/Data folder for data upgrades.\n" . "- Use declarative schema approach in module's etc/db_schema.xml file for schema changes." ); } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/LayoutTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/LayoutTest.php index a7c0385a30cc5..1ee599a04463d 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/LayoutTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/LayoutTest.php @@ -355,7 +355,9 @@ public function getAllowedActionNodeMethods() 'unsetChild', 'unsetChildren', 'updateButton', - 'setIsProductListingContext' + 'setIsProductListingContext', + 'checkCompanyStatus', // MAGETWO-88965 + 'setRendererType', // MAGETWO-88965 ]; } } diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php index 8a00037d2513b..2a6079d619d4c 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php @@ -112,7 +112,7 @@ public function testPhpFiles() $changedFiles = ChangedFiles::getPhpFiles(__DIR__ . '/../_files/changed_files*'); $blacklistFiles = $this->getBlacklistFiles(); foreach ($blacklistFiles as $blacklistFile) { - unset($changedFiles[BP . $blacklistFile]); + unset($changedFiles[$blacklistFile]); } $invoker( function ($file) { @@ -920,7 +920,7 @@ private function processPattern($appPath, $pattern) $fileSet = glob($appPath . DIRECTORY_SEPARATOR . $pattern, GLOB_NOSORT); foreach ($fileSet as $file) { - $files[] = substr($file, $relativePathStart); + $files[] = ltrim(substr($file, $relativePathStart), '/'); } return $files; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/copyright/blacklist.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/copyright/blacklist.php index f80151a41573d..d22c3359f267e 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/copyright/blacklist.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/copyright/blacklist.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ return [ - '/\.(jpe?g|png|gif|ttf|swf|eot|woff|pdf|mp3|pdf|jar|jbf)$/', + '/\.(jpe?g|png|gif|ttf|swf|eot|woff|pdf|mp3|pdf|jar|jbf|php\.dist)$/', '/pub\/opt\/magento\/var/', '/COPYING\.txt/' ]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php index bf107fed0552a..939b98cabc3de 100755 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php @@ -4212,4 +4212,13 @@ ['Magento\Framework\Acl\CacheInterface'], ['Magento\Framework\Acl\Test\Unit\CacheTest'], ['Magento\Eav\Model\Entity\Attribute\Backend\Serialized'], + ['Magento\Fmework\MessageQueue\Config\Reader\Xml\Converter\DeprecatedFormat'], + [ + 'Magento\Framework\MessageQueue\Config\Converter', + 'Magento\Framework\MessageQueue\Config\Reader\Xml\CompositeConverter' + ], + ['Magento\Framework\MessageQueue\Config\Reader', 'Magento\Framework\MessageQueue\Config\Reader\Xml'], + ['Magento\Framework\MessageQueue\PublisherFactory'], + ['Magento\Framework\MessageQueue\PublisherProxy'], + ['Zend_Feed', 'Zend\Feed'], ]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php index 90d4b465d3631..cbf499c8dad38 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php @@ -950,4 +950,8 @@ ], ['TAB_GENERAL_CODE', 'Magento\Eav\Model\ResourceModel\Entity\Attribute\Group'], ['TAB_IMAGE_MANAGEMENT_CODE', 'Magento\Eav\Model\ResourceModel\Entity\Attribute\Group'], + [ + 'CALLBACK', + 'Magento\Framework\MessageQueue\ConsumerConfiguration' + ], ]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php index 3b72ea5e0a4ce..ee91c34002f6c 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_methods.php @@ -2529,4 +2529,42 @@ ['var_dump', ''], ['each', ''], ['create_function', ''], + ['configure', 'Magento\Framework\MessageQueue\BatchConsumer'], + [ + 'getExchangeByTopic', + 'Magento\Framework\MessageQueue\Config\Data', + '\Magento\Framework\MessageQueue\ConfigInterface::getExchangeByTopic' + ], + [ + 'getQueuesByTopic', + 'Magento\Framework\MessageQueue\Config\Data', + '\Magento\Framework\MessageQueue\ConfigInterface::getQueuesByTopic' + ], + [ + 'getConnectionByTopic', + 'Magento\Framework\MessageQueue\Config\Data', + '\Magento\Framework\MessageQueue\ConfigInterface::getConnectionByTopic' + ], + [ + 'getConnectionByConsumer', + 'Magento\Framework\MessageQueue\Config\Data', + '\Magento\Framework\MessageQueue\ConfigInterface::getConnectionByConsumer' + ], + [ + 'getMessageSchemaType', + 'Magento\Framework\MessageQueue\Config\Data', + '\Magento\Framework\MessageQueue\ConfigInterface::getMessageSchemaType' + ], + [ + 'getCallback', + 'Magento\Framework\MessageQueue\ConsumerConfiguration' + ], + [ + 'getCallback', + 'Magento\Framework\MessageQueue\ConsumerConfigurationInterface' + ], + [ + 'configure', + 'Magento\Framework\MessageQueue\ConsumerInterface' + ], ]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php index 169ecd4209883..0d9da334ea3ab 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_namespaces.php @@ -197,5 +197,7 @@ 'Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Super', 'Magento\ConfigurableProduct\Block\Adminhtml\Product\Edit\Tab\Variations', ], - ['Magento\BraintreeTwo', 'Magento\Braintree'] + ['Magento\BraintreeTwo', 'Magento\Braintree'], + ['Magento\MysqlMq\Model\Resource', 'Magento\MysqlMq\Model\ResourceModel'], + ['Magento\BulkOperations', 'Magento\AsynchronousOperations'], ]; diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php index 1c8c2d77ffb90..1c23f8d8ccf8a 100644 --- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php +++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/security/unsecure_php_functions.php @@ -39,7 +39,32 @@ ], 'md5' => [ 'replacement' => '', - 'exclude' => [] + 'exclude' => [ + /* + * Usage of md5 in MessageQueue key generation algorithm + * added to exclude list to avoid backward incompatible changes + */ + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'MessageQueue/Rpc/Publisher.php', + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'MessageQueue/MessageController.php', + ], + [ + 'type' => 'library', + 'name' => 'magento/framework', + 'path' => 'MessageQueue/Publisher.php', + ], + [ + 'type' => 'module', + 'name' => 'Magento_AsynchronousOperations', + 'path' => 'Model/ResourceModel/System/Message/Collection/Synchronized/Plugin.php' + ] + ] ], 'srand' => [ 'replacement' => '', diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt index 0ab8e0216c249..c831239bed42b 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt @@ -199,3 +199,4 @@ Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem IntegrationConfig.php *Test.php setup/performance-toolkit/aggregate-report +Magento/MessageQueue/Setup diff --git a/dev/tools/Magento/Tools/StaticReview/PhpCsFixerReview.php b/dev/tools/Magento/Tools/StaticReview/PhpCsFixerReview.php deleted file mode 100644 index 113b139555dfb..0000000000000 --- a/dev/tools/Magento/Tools/StaticReview/PhpCsFixerReview.php +++ /dev/null @@ -1,66 +0,0 @@ -<?php -/* - * This file is part of StaticReview - * - * Copyright (c) 2014 Samuel Parkinson <@samparkinson_> - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - * - * @see http://github.com/sjparkinson/static-review/blob/master/LICENSE.md - */ -namespace Magento\Tools\StaticReview; - -use StaticReview\File\FileInterface; -use StaticReview\Reporter\ReporterInterface; -use StaticReview\Review\AbstractReview; - -class PhpCsFixerReview extends AbstractReview -{ - /** - * @var array - */ - protected $options; - - /** - * @param array $options - */ - public function __construct($options = []) - { - $this->options = $options; - } - - /** - * Obtained from .php_cs configuration file. - * - * @param FileInterface $file - * @return bool - */ - public function canReview(FileInterface $file) - { - return in_array($file->getExtension(), ['php', 'phtml', 'xml', 'yml']); - } - - /** - * Checks and fixes PHP files using PHP Coding Standards Fixer. - * - * @param ReporterInterface $reporter - * @param FileInterface $file - * @return void - * @SuppressWarnings(PHPMD.UnusedFormalParameter) - */ - public function review(ReporterInterface $reporter, FileInterface $file) - { - $cmd = 'vendor/bin/php-cs-fixer -vvv '; - foreach ($this->options as $key => $value) { - $cmd .= ' --' . $key . '=' . escapeshellarg($value); - } - $cmd .= ' fix ' . escapeshellarg($file->getRelativePath()); - - $process = $this->getProcess($cmd); - $process->run(); - - $process = $this->getProcess('git add ' . escapeshellarg($file->getRelativePath())); - $process->run(); - } -} diff --git a/dev/tools/Magento/Tools/StaticReview/pre-commit b/dev/tools/Magento/Tools/StaticReview/pre-commit deleted file mode 100755 index 0bbb62797f434..0000000000000 --- a/dev/tools/Magento/Tools/StaticReview/pre-commit +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env php -<?php -/* - * This file is part of StaticReview - * - * Copyright (c) 2014 Samuel Parkinson <@samparkinson_> - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - * - * @see https://github.com/sjparkinson/static-review/blob/master/LICENSE - */ -$included = include __DIR__ . '/../../../../../vendor/autoload.php'; -if (!$included) { - echo 'You must set up the project dependencies, run the following commands:' . PHP_EOL - . 'curl -sS https://getcomposer.org/installer | php' . PHP_EOL - . 'php composer.phar install' . PHP_EOL; - - exit(1); -} - -// Installation: -// vendor/bin/static-review.php hook:install dev/tools/Magento/Tools/StaticReview/pre-commit .git/hooks/pre-commit - -// Reference the required classes and the reviews you want to use. -use League\CLImate\CLImate; -use StaticReview\Reporter\Reporter; -use StaticReview\Review\Composer\ComposerLintReview; -use StaticReview\Review\General\LineEndingsReview; -use StaticReview\Review\General\NoCommitTagReview; -use StaticReview\Review\PHP\PhpLeadingLineReview; -use StaticReview\Review\PHP\PhpLintReview; -use Magento\Tools\StaticReview\PhpCsFixerReview; -use StaticReview\StaticReview; -use StaticReview\VersionControl\GitVersionControl; - -$reporter = new Reporter(); -$climate = new CLImate(); -$git = new GitVersionControl(); - -// Apply review which modifies staged files first -$review = new StaticReview($reporter); -$phpCsFixer = new PhpCsFixerReview(); -$review->addReview($phpCsFixer); -$review->review($git->getStagedFiles()); - -// Apply read-only review then -$review = new StaticReview($reporter); -$review->addReview(new LineEndingsReview()) - ->addReview(new PhpLeadingLineReview()) - ->addReview(new NoCommitTagReview()) - ->addReview(new PhpLintReview()) - ->addReview(new ComposerLintReview()); -$review->review($git->getStagedFiles()); - -// Check if any matching issues were found. -if ($reporter->hasIssues()) { - $climate->out('')->out(''); - - foreach ($reporter->getIssues() as $issue) { - $climate->red($issue); - } - - $climate->out('')->red('✘ Please fix the errors above.'); - - exit(1); -} else { - $climate->out('')->green('✔ Looking good.')->white('Have you tested everything?'); - - exit(0); -} diff --git a/lib/internal/Magento/Framework/Amqp/Bulk/Exchange.php b/lib/internal/Magento/Framework/Amqp/Bulk/Exchange.php new file mode 100644 index 0000000000000..3e4b9fdf6709f --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Bulk/Exchange.php @@ -0,0 +1,86 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Bulk; + +use Magento\Framework\MessageQueue\Bulk\ExchangeInterface; +use PhpAmqpLib\Message\AMQPMessage; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfigInterface; +use Magento\Framework\MessageQueue\Publisher\ConfigInterface as PublisherConfig; + +/** + * Used to send messages in bulk in AMQP queue. + */ +class Exchange implements ExchangeInterface +{ + /** + * @var \Magento\Framework\Amqp\Config + */ + private $amqpConfig; + + /** + * @var CommunicationConfigInterface + */ + private $communicationConfig; + + /** + * @var PublisherConfig + */ + private $publisherConfig; + + /** + * @var \Magento\Framework\Amqp\Exchange + */ + private $exchange; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\Amqp\Config $amqpConfig + * @param PublisherConfig $publisherConfig + * @param CommunicationConfigInterface $communicationConfig + * @param \Magento\Framework\Amqp\Exchange $exchange + */ + public function __construct( + \Magento\Framework\Amqp\Config $amqpConfig, + PublisherConfig $publisherConfig, + CommunicationConfigInterface $communicationConfig, + \Magento\Framework\Amqp\Exchange $exchange + ) { + $this->amqpConfig = $amqpConfig; + $this->communicationConfig = $communicationConfig; + $this->publisherConfig = $publisherConfig; + $this->exchange = $exchange; + } + + /** + * @inheritdoc + */ + public function enqueue($topic, array $envelopes) + { + $topicData = $this->communicationConfig->getTopic($topic); + $isSync = $topicData[CommunicationConfigInterface::TOPIC_IS_SYNCHRONOUS]; + + if ($isSync) { + $responses = []; + foreach ($envelopes as $envelope) { + $responses[] = $this->exchange->enqueue($topic, $envelope); + } + return $responses; + } + + $channel = $this->amqpConfig->getChannel(); + $publisher = $this->publisherConfig->getPublisher($topic); + $exchange = $publisher->getConnection()->getExchange(); + + foreach ($envelopes as $envelope) { + $msg = new AMQPMessage($envelope->getBody(), $envelope->getProperties()); + $channel->batch_basic_publish($msg, $exchange, $topic); + } + $channel->publish_batch(); + + return null; + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Config.php b/lib/internal/Magento/Framework/Amqp/Config.php new file mode 100644 index 0000000000000..89f7922daaefd --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Config.php @@ -0,0 +1,221 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp; + +use Magento\Framework\App\DeploymentConfig; +use PhpAmqpLib\Connection\AMQPStreamConnection; +use PhpAmqpLib\Channel\AMQPChannel; +use PhpAmqpLib\Connection\AMQPSSLConnection; + +/** + * Reads the Amqp config in the deployed environment configuration + * + * @api + * @since 100.0.0 + */ +class Config +{ + /** + * Queue config key + */ + const QUEUE_CONFIG = 'queue'; + + /** + * Amqp config key + */ + const AMQP_CONFIG = 'amqp'; + + const HOST = 'host'; + const PORT = 'port'; + const USERNAME = 'user'; + const PASSWORD = 'password'; + const VIRTUALHOST = 'virtualhost'; + const SSL = 'ssl'; + const SSL_OPTIONS = 'ssl_options'; + + /** + * Deployment configuration + * + * @var DeploymentConfig + */ + private $deploymentConfig; + + /** + * @var AMQPStreamConnection + */ + private $connection; + + /** + * @var AMQPChannel + */ + private $channel; + + /** + * Associative array of Amqp configuration + * + * @var array + */ + private $data; + + /** + * AMQP connection name. + * + * @var string + */ + private $connectionName; + + /** + * Initialize dependencies. + * + * Example environment config: + * <code> + * 'queue' => + * [ + * 'amqp' => [ + * 'host' => 'localhost', + * 'port' => 5672, + * 'username' => 'guest', + * 'password' => 'guest', + * 'virtual_host' => '/', + * 'ssl' => false, + * 'ssl_options' => [], + * ], + * ], + * </code> + * + * @param DeploymentConfig $config + * @param string $connectionName + * @since 100.0.0 + */ + public function __construct(DeploymentConfig $config, $connectionName = 'amqp') + { + $this->deploymentConfig = $config; + $this->connectionName = $connectionName; + } + + /** + * Destructor + * + * @return void + * @since 100.0.0 + */ + public function __destruct() + { + $this->closeConnection(); + } + + /** + * Returns the configuration set for the key. + * + * @param string $key + * @return string + * @throws \LogicException + * @since 100.0.0 + */ + public function getValue($key) + { + $this->load(); + return isset($this->data[$key]) ? $this->data[$key] : null; + } + + /** + * Return Amqp channel + * + * @return AMQPChannel + * @throws \LogicException + * @since 100.0.0 + */ + public function getChannel() + { + if (!isset($this->connection) || !isset($this->channel)) { + $this->connection = $this->getValue(self::SSL) ? $this->createSecureConnection() : + $this->createUnsecureConnection(); + + $this->channel = $this->connection->channel(); + } + return $this->channel; + } + + /** + * Load the configuration for Amqp + * + * @return void + * @throws \LogicException + */ + private function load() + { + if (null === $this->data) { + $queueConfig = $this->deploymentConfig->getConfigData(self::QUEUE_CONFIG); + if ($this->connectionName == self::AMQP_CONFIG) { + $this->data = isset($queueConfig[self::AMQP_CONFIG]) ? $queueConfig[self::AMQP_CONFIG] : []; + } else { + $this->data = isset($queueConfig['connections'][$this->connectionName]) + ? $queueConfig['connections'][$this->connectionName] + : []; + } + if (empty($this->data)) { + throw new \LogicException('Unknown connection name ' . $this->connectionName); + } + } + } + + /** + * Close Amqp connection and Channel + * + * @return void + */ + private function closeConnection() + { + if (isset($this->channel)) { + $this->channel->close(); + unset($this->channel); + } + + if (isset($this->connection)) { + $this->connection->close(); + unset($this->connection); + } + } + + /** + * @return AMQPStreamConnection + */ + private function createUnsecureConnection() + { + return new AMQPStreamConnection( + $this->getValue(self::HOST), + $this->getValue(self::PORT), + $this->getValue(self::USERNAME), + $this->getValue(self::PASSWORD), + $this->getValue(self::VIRTUALHOST) + ); + } + + /** + * Create secure connection to AMQP server. + * + * Note: when you are passing empty array of SSL options PHP-AMQPLIB will actually create unsecure connection. + * + * @return AMQPSSLConnection + */ + private function createSecureConnection() + { + $sslOptions = $this->getValue(self::SSL_OPTIONS); + + if (empty($sslOptions)) { + $sslOptions = ['verify_peer' => true]; + } + + return new AMQPSSLConnection( + $this->getValue(self::HOST), + $this->getValue(self::PORT), + $this->getValue(self::USERNAME), + $this->getValue(self::PASSWORD), + $this->getValue(self::VIRTUALHOST), + $sslOptions + ); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/ConfigFactory.php b/lib/internal/Magento/Framework/Amqp/ConfigFactory.php new file mode 100644 index 0000000000000..c1a85541447e1 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/ConfigFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp; + +/** + * Factory class for @see Config + */ +class ConfigFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $_objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + protected $_instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = Config::class + ) { + $this->_objectManager = $objectManager; + $this->_instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return Config + */ + public function create(array $data = []) + { + return $this->_objectManager->create($this->_instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/ConfigPool.php b/lib/internal/Magento/Framework/Amqp/ConfigPool.php new file mode 100644 index 0000000000000..c3d565bc9964f --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/ConfigPool.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp; + +/** + * AMQP connections pool. + */ +class ConfigPool +{ + /** + * @var ConfigFactory + */ + private $configFactory; + + /** + * @var Config[] + */ + private $pool = []; + + /** + * Initialize dependencies. + * + * @param ConfigFactory $configFactory + */ + public function __construct(ConfigFactory $configFactory) + { + $this->configFactory = $configFactory; + } + + /** + * Get connection by name. + * + * @param string $connectionName + * @return Config + */ + public function get($connectionName) + { + if (!isset($this->pool[$connectionName])) { + $this->pool[$connectionName] = $this->configFactory->create(['connectionName' => $connectionName]); + } + return $this->pool[$connectionName]; + } +} diff --git a/lib/internal/Magento/Framework/Amqp/ConnectionTypeResolver.php b/lib/internal/Magento/Framework/Amqp/ConnectionTypeResolver.php new file mode 100644 index 0000000000000..9b600278144f0 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/ConnectionTypeResolver.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp; + +use Magento\Framework\MessageQueue\ConnectionTypeResolverInterface; +use Magento\Framework\App\DeploymentConfig; + +/** + * Amqp connection type resolver. + * + * @api + * @since 100.0.0 + */ +class ConnectionTypeResolver implements ConnectionTypeResolverInterface +{ + /** + * Amqp connection names. + * + * @var string[] + */ + private $amqpConnectionName = []; + + /** + * Initialize dependencies. + * + * @param DeploymentConfig $deploymentConfig + * @since 100.0.0 + */ + public function __construct(DeploymentConfig $deploymentConfig) + { + $queueConfig = $deploymentConfig->getConfigData(Config::QUEUE_CONFIG); + if (isset($queueConfig['connections']) && is_array($queueConfig['connections'])) { + $this->amqpConnectionName = array_keys($queueConfig['connections']); + } + if (isset($queueConfig[Config::AMQP_CONFIG])) { + $this->amqpConnectionName[] = Config::AMQP_CONFIG; + } + } + + /** + * {@inheritdoc} + * @since 100.0.0 + */ + public function getConnectionType($connectionName) + { + return in_array($connectionName, $this->amqpConnectionName) ? 'amqp' : null; + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Exchange.php b/lib/internal/Magento/Framework/Amqp/Exchange.php new file mode 100644 index 0000000000000..e57fa09b83d1b --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Exchange.php @@ -0,0 +1,135 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Amqp; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\MessageQueue\EnvelopeInterface; +use Magento\Framework\MessageQueue\ExchangeInterface; +use PhpAmqpLib\Message\AMQPMessage; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfigInterface; +use Magento\Framework\MessageQueue\Publisher\ConfigInterface as PublisherConfig; +use Magento\Framework\MessageQueue\Rpc\ResponseQueueNameBuilder; + +/** + * Class message exchange. + * + * @api + * @since 100.0.0 + */ +class Exchange implements ExchangeInterface +{ + const RPC_CONNECTION_TIMEOUT = 30; + + /** + * @var Config + */ + private $amqpConfig; + + /** + * @var CommunicationConfigInterface + */ + private $communicationConfig; + + /** + * @var int + */ + private $rpcConnectionTimeout; + + /** + * @var PublisherConfig + */ + private $publisherConfig; + + /** + * @var ResponseQueueNameBuilder + */ + private $responseQueueNameBuilder; + + /** + * Initialize dependencies. + * + * @param Config $amqpConfig + * @param PublisherConfig $publisherConfig + * @param ResponseQueueNameBuilder $responseQueueNameBuilder + * @param CommunicationConfigInterface $communicationConfig + * @param int $rpcConnectionTimeout + * @since 100.0.0 + */ + public function __construct( + Config $amqpConfig, + PublisherConfig $publisherConfig, + ResponseQueueNameBuilder $responseQueueNameBuilder, + CommunicationConfigInterface $communicationConfig, + $rpcConnectionTimeout = self::RPC_CONNECTION_TIMEOUT + ) { + $this->amqpConfig = $amqpConfig; + $this->communicationConfig = $communicationConfig; + $this->rpcConnectionTimeout = $rpcConnectionTimeout; + $this->publisherConfig = $publisherConfig; + $this->responseQueueNameBuilder = $responseQueueNameBuilder; + } + + /** + * {@inheritdoc} + * @since 100.0.0 + */ + public function enqueue($topic, EnvelopeInterface $envelope) + { + $topicData = $this->communicationConfig->getTopic($topic); + $isSync = $topicData[CommunicationConfigInterface::TOPIC_IS_SYNCHRONOUS]; + + $channel = $this->amqpConfig->getChannel(); + $exchange = $this->publisherConfig->getPublisher($topic)->getConnection()->getExchange(); + $responseBody = null; + + $msg = new AMQPMessage($envelope->getBody(), $envelope->getProperties()); + if ($isSync) { + $correlationId = $envelope->getProperties()['correlation_id']; + /** @var AMQPMessage $response */ + $callback = function ($response) use ($correlationId, &$responseBody, $channel) { + if ($response->get('correlation_id') == $correlationId) { + $responseBody = $response->body; + $channel->basic_ack($response->get('delivery_tag')); + } else { + //push message back to the queue + $channel->basic_reject($response->get('delivery_tag'), true); + } + }; + if ($envelope->getProperties()['reply_to']) { + $replyTo = $envelope->getProperties()['reply_to']; + } else { + $replyTo = $this->responseQueueNameBuilder->getQueueName($topic); + } + $channel->basic_consume( + $replyTo, + '', + false, + false, + false, + false, + $callback + ); + $channel->basic_publish($msg, $exchange, $topic); + while ($responseBody === null) { + try { + $channel->wait(null, false, $this->rpcConnectionTimeout); + } catch (\PhpAmqpLib\Exception\AMQPTimeoutException $e) { + throw new LocalizedException( + new \Magento\Framework\Phrase( + "The RPC (Remote Procedure Call) failed. The connection timed out after %time_out. " + . "Please try again later.", + ['time_out' => $this->rpcConnectionTimeout] + ) + ); + } + } + } else { + $channel->basic_publish($msg, $exchange, $topic); + } + return $responseBody; + } +} diff --git a/lib/internal/Magento/Framework/Amqp/ExchangeFactory.php b/lib/internal/Magento/Framework/Amqp/ExchangeFactory.php new file mode 100644 index 0000000000000..5291b3ab59794 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/ExchangeFactory.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp; + +/** + * Factory class for @see \Magento\Framework\Amqp\Exchange + * + * @api + * @since 100.0.0 + */ +class ExchangeFactory implements \Magento\Framework\MessageQueue\ExchangeFactoryInterface +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * @var ConfigPool + */ + private $configPool; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param ConfigPool $configPool + * @param string $instanceName + * @since 100.0.0 + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + ConfigPool $configPool, + $instanceName = \Magento\Framework\Amqp\Exchange::class + ) { + $this->objectManager = $objectManager; + $this->configPool = $configPool; + $this->instanceName = $instanceName; + } + + /** + * {@inheritdoc} + * @since 100.0.0 + */ + public function create($connectionName, array $data = []) + { + $data['amqpConfig'] = $this->configPool->get($connectionName); + return $this->objectManager->create( + $this->instanceName, + $data + ); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Queue.php b/lib/internal/Magento/Framework/Amqp/Queue.php new file mode 100644 index 0000000000000..edd57339b842b --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Queue.php @@ -0,0 +1,190 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp; + +use Magento\Framework\MessageQueue\ConnectionLostException; +use Magento\Framework\MessageQueue\EnvelopeInterface; +use Magento\Framework\MessageQueue\QueueInterface; +use PhpAmqpLib\Exception\AMQPProtocolConnectionException; +use PhpAmqpLib\Message\AMQPMessage; +use Magento\Framework\MessageQueue\EnvelopeFactory; +use Psr\Log\LoggerInterface; + +/** + * Class Queue + * + * @api + * @since 100.0.0 + */ +class Queue implements QueueInterface +{ + /** + * @var Config + */ + private $amqpConfig; + + /** + * @var string + */ + private $queueName; + + /** + * @var EnvelopeFactory + */ + private $envelopeFactory; + + /** + * @var LoggerInterface $logger + */ + private $logger; + + /** + * Initialize dependencies. + * + * @param Config $amqpConfig + * @param EnvelopeFactory $envelopeFactory + * @param string $queueName + * @param LoggerInterface $logger + * @since 100.0.0 + */ + public function __construct( + Config $amqpConfig, + EnvelopeFactory $envelopeFactory, + $queueName, + LoggerInterface $logger + ) { + $this->amqpConfig = $amqpConfig; + $this->queueName = $queueName; + $this->envelopeFactory = $envelopeFactory; + $this->logger = $logger; + } + + /** + * {@inheritdoc} + * @since 100.0.0 + */ + public function dequeue() + { + $envelope = null; + $channel = $this->amqpConfig->getChannel(); + // @codingStandardsIgnoreStart + /** @var AMQPMessage $message */ + try { + $message = $channel->basic_get($this->queueName); + } catch (AMQPProtocolConnectionException $e) { + throw new ConnectionLostException( + $e->getMessage(), + $e->getCode(), + $e + ); + } + + if ($message !== null) { + $properties = array_merge( + $message->get_properties(), + [ + 'topic_name' => $message->delivery_info['routing_key'], + 'delivery_tag' => $message->delivery_info['delivery_tag'], + ] + ); + $envelope = $this->envelopeFactory->create(['body' => $message->body, 'properties' => $properties]); + } + + // @codingStandardsIgnoreEnd + return $envelope; + } + + /** + * {@inheritdoc} + * @since 100.0.0 + */ + public function acknowledge(EnvelopeInterface $envelope) + { + $properties = $envelope->getProperties(); + $channel = $this->amqpConfig->getChannel(); + // @codingStandardsIgnoreStart + try { + $channel->basic_ack($properties['delivery_tag']); + } catch (AMQPProtocolConnectionException $e) { + throw new ConnectionLostException( + $e->getMessage(), + $e->getCode(), + $e + ); + } + // @codingStandardsIgnoreEnd + } + + /** + * {@inheritdoc} + * @since 100.0.0 + */ + public function subscribe($callback) + { + $callbackConverter = function (AMQPMessage $message) use ($callback) { + // @codingStandardsIgnoreStart + $properties = array_merge( + $message->get_properties(), + [ + 'topic_name' => $message->delivery_info['routing_key'], + 'delivery_tag' => $message->delivery_info['delivery_tag'], + ] + ); + // @codingStandardsIgnoreEnd + $envelope = $this->envelopeFactory->create(['body' => $message->body, 'properties' => $properties]); + + if ($callback instanceof \Closure) { + $callback($envelope); + } else { + call_user_func($callback, $envelope); + } + }; + + $channel = $this->amqpConfig->getChannel(); + // @codingStandardsIgnoreStart + $channel->basic_consume($this->queueName, '', false, false, false, false, $callbackConverter); + // @codingStandardsIgnoreEnd + while (count($channel->callbacks)) { + $channel->wait(); + } + } + + /** + * (@inheritdoc) + * @since 100.0.0 + */ + public function reject(EnvelopeInterface $envelope, $requeue = true, $rejectionMessage = null) + { + $properties = $envelope->getProperties(); + + $channel = $this->amqpConfig->getChannel(); + // @codingStandardsIgnoreStart + $channel->basic_reject($properties['delivery_tag'], $requeue); + // @codingStandardsIgnoreEnd + if ($rejectionMessage !== null) { + $this->logger->critical( + new \Magento\Framework\Phrase('Message has been rejected: %message', ['message' => $rejectionMessage]) + ); + } + } + + /** + * (@inheritdoc) + * @since 100.0.0 + */ + public function push(EnvelopeInterface $envelope) + { + $messageProperties = $envelope->getProperties(); + $msg = new AMQPMessage( + $envelope->getBody(), + [ + 'correlation_id' => $messageProperties['correlation_id'], + 'delivery_mode' => 2 + ] + ); + $this->amqpConfig->getChannel()->basic_publish($msg, '', $this->queueName); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/QueueFactory.php b/lib/internal/Magento/Framework/Amqp/QueueFactory.php new file mode 100644 index 0000000000000..9f1635a87977b --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/QueueFactory.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp; + +/** + * Factory class for @see \Magento\Framework\Amqp\Queue + * + * @api + * @since 100.0.0 + */ +class QueueFactory implements \Magento\Framework\MessageQueue\QueueFactoryInterface +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * @var ConfigPool + */ + private $configPool; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param ConfigPool $configPool + * @param string $instanceName + * @since 100.0.0 + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + ConfigPool $configPool, + $instanceName = \Magento\Framework\Amqp\Queue::class + ) { + $this->objectManager = $objectManager; + $this->configPool = $configPool; + $this->instanceName = $instanceName; + } + + /** + * {@inheritdoc} + * @since 100.0.0 + */ + public function create($queueName, $connectionName) + { + return $this->objectManager->create( + $this->instanceName, + [ + 'amqpConfig' => $this->configPool->get($connectionName), + 'queueName' => $queueName + ] + ); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/README.md b/lib/internal/Magento/Framework/Amqp/README.md new file mode 100644 index 0000000000000..0951caead685b --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/README.md @@ -0,0 +1 @@ +AMQP library is designed to provide default implementation for Message Queue Framework. diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/Bulk/ExchangeTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/Bulk/ExchangeTest.php new file mode 100644 index 0000000000000..875d3088af692 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/Bulk/ExchangeTest.php @@ -0,0 +1,129 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Amqp\Test\Unit\Bulk; + +/** + * Unit test for Exchange model. + */ +class ExchangeTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\Amqp\Config|\PHPUnit_Framework_MockObject_MockObject + */ + private $amqpConfig; + + /** + * @var \Magento\Framework\Communication\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $communicationConfig; + + /** + * @var \Magento\Framework\MessageQueue\Publisher\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $publisherConfig; + + /** + * @var \Magento\Framework\Amqp\Exchange|\PHPUnit_Framework_MockObject_MockObject + */ + private $exchange; + + /** + * @var \Magento\Framework\Amqp\Bulk\Exchange + */ + private $bulkExchange; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->amqpConfig = $this->getMockBuilder(\Magento\Framework\Amqp\Config::class) + ->disableOriginalConstructor()->getMock(); + $this->communicationConfig = $this->getMockBuilder(\Magento\Framework\Communication\ConfigInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->publisherConfig = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Publisher\ConfigInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->exchange = $this->getMockBuilder(\Magento\Framework\Amqp\Exchange::class) + ->disableOriginalConstructor()->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->bulkExchange = $objectManager->getObject( + \Magento\Framework\Amqp\Bulk\Exchange::class, + [ + 'amqpConfig' => $this->amqpConfig, + 'communicationConfig' => $this->communicationConfig, + 'publisherConfig' => $this->publisherConfig, + 'exchange' => $this->exchange, + ] + ); + } + + /** + * Test for enqueue method. + * + * @return void + */ + public function testEnqueue() + { + $topicName = 'topic.name'; + $exchangeName = 'exchangeName'; + $envelopeBody = 'envelopeBody'; + $envelopeProperties = ['property_key_1' => 'property_value_1']; + $topicData = [ + \Magento\Framework\Communication\ConfigInterface::TOPIC_IS_SYNCHRONOUS => false + ]; + $this->communicationConfig->expects($this->once()) + ->method('getTopic')->with($topicName)->willReturn($topicData); + $channel = $this->getMockBuilder(\AMQPChannel::class) + ->setMethods(['batch_basic_publish', 'publish_batch']) + ->disableOriginalConstructor()->getMock(); + $this->amqpConfig->expects($this->once())->method('getChannel')->willReturn($channel); + $publisher = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItemInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->publisherConfig->expects($this->once()) + ->method('getPublisher')->with($topicName)->willReturn($publisher); + $connection = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Publisher\Config\PublisherConnectionInterface::class) + ->disableOriginalConstructor()->getMock(); + $publisher->expects($this->once())->method('getConnection')->with()->willReturn($connection); + $connection->expects($this->once())->method('getExchange')->with()->willReturn($exchangeName); + $envelope = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor()->getMock(); + $envelope->expects($this->once())->method('getBody')->willReturn($envelopeBody); + $envelope->expects($this->once())->method('getProperties')->willReturn($envelopeProperties); + $channel->expects($this->once())->method('batch_basic_publish') + ->with($this->isInstanceOf(\PhpAmqpLib\Message\AMQPMessage::class), $exchangeName, $topicName); + $channel->expects($this->once())->method('publish_batch'); + $this->assertNull($this->bulkExchange->enqueue($topicName, [$envelope])); + } + + /** + * Test for enqueue method with synchronous topic. + * + * @return void + */ + public function testEnqueueWithSynchronousTopic() + { + $topicName = 'topic.name'; + $response = 'responseBody'; + $topicData = [ + \Magento\Framework\Communication\ConfigInterface::TOPIC_IS_SYNCHRONOUS => true + ]; + $this->communicationConfig->expects($this->once()) + ->method('getTopic')->with($topicName)->willReturn($topicData); + $envelope = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->exchange->expects($this->once())->method('enqueue')->with($topicName, $envelope)->willReturn($response); + $this->assertEquals([$response], $this->bulkExchange->enqueue($topicName, [$envelope])); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/ConfigPoolTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/ConfigPoolTest.php new file mode 100644 index 0000000000000..5549eb39e54c1 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/ConfigPoolTest.php @@ -0,0 +1,20 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Test\Unit; + +class ConfigPoolTest extends \PHPUnit\Framework\TestCase +{ + public function testGetConnection() + { + $factory = $this->createMock(\Magento\Framework\Amqp\ConfigFactory::class); + $config = $this->createMock(\Magento\Framework\Amqp\Config::class); + $factory->expects($this->once())->method('create')->with(['connectionName' => 'amqp'])->willReturn($config); + $model = new \Magento\Framework\Amqp\ConfigPool($factory); + $this->assertEquals($config, $model->get('amqp')); + //test that object is cached + $this->assertEquals($config, $model->get('amqp')); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/ConfigTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/ConfigTest.php new file mode 100644 index 0000000000000..570a5c416d7ae --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/ConfigTest.php @@ -0,0 +1,147 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Test\Unit; + +use Magento\Framework\Amqp\Config; +use Magento\Framework\App\DeploymentConfig; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +class ConfigTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $deploymentConfigMock; + + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var Config + */ + private $amqpConfig; + + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + $this->deploymentConfigMock = $this->getMockBuilder(\Magento\Framework\App\DeploymentConfig::class) + ->disableOriginalConstructor() + ->setMethods(['getConfigData']) + ->getMock(); + $this->amqpConfig = $this->objectManager->getObject( + \Magento\Framework\Amqp\Config::class, + [ + 'config' => $this->deploymentConfigMock, + ] + ); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Unknown connection name amqp + */ + public function testGetNullConfig() + { + $this->deploymentConfigMock->expects($this->once()) + ->method('getConfigData') + ->with(Config::QUEUE_CONFIG) + ->will($this->returnValue(null)); + + $this->amqpConfig->getValue(Config::HOST); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Unknown connection name amqp + */ + public function testGetEmptyConfig() + { + $this->deploymentConfigMock->expects($this->once()) + ->method('getConfigData') + ->with(Config::QUEUE_CONFIG) + ->will($this->returnValue([])); + + $this->amqpConfig->getValue(Config::HOST); + } + + public function testGetStandardConfig() + { + $expectedHost = 'example.com'; + $expectedPort = 5672; + $expectedUsername = 'guest_username'; + $expectedPassword = 'guest_password'; + $expectedVirtualHost = '/'; + $expectedSsl = false; + $expectedSslOptions = ['some' => 'value']; + + $this->deploymentConfigMock->expects($this->once()) + ->method('getConfigData') + ->with(Config::QUEUE_CONFIG) + ->will($this->returnValue( + [ + Config::AMQP_CONFIG => [ + 'host' => $expectedHost, + 'port' => $expectedPort, + 'user' => $expectedUsername, + 'password' => $expectedPassword, + 'virtualhost' => $expectedVirtualHost, + 'ssl' => $expectedSsl, + 'ssl_options' => $expectedSslOptions, + 'randomKey' => 'randomValue', + ] + ] + )); + + $this->assertEquals($expectedHost, $this->amqpConfig->getValue(Config::HOST)); + $this->assertEquals($expectedPort, $this->amqpConfig->getValue(Config::PORT)); + $this->assertEquals($expectedUsername, $this->amqpConfig->getValue(Config::USERNAME)); + $this->assertEquals($expectedPassword, $this->amqpConfig->getValue(Config::PASSWORD)); + $this->assertEquals($expectedVirtualHost, $this->amqpConfig->getValue(Config::VIRTUALHOST)); + $this->assertEquals($expectedSsl, $this->amqpConfig->getValue(Config::SSL)); + $this->assertEquals($expectedSslOptions, $this->amqpConfig->getValue(Config::SSL_OPTIONS)); + $this->assertEquals('randomValue', $this->amqpConfig->getValue('randomKey')); + } + + public function testGetCustomConfig() + { + $amqpConfig = new \Magento\Framework\Amqp\Config($this->deploymentConfigMock, 'connection-01'); + $expectedHost = 'example.com'; + $expectedPort = 5672; + $expectedUsername = 'guest_username'; + $expectedPassword = 'guest_password'; + $expectedVirtualHost = '/'; + $expectedSsl = ['some' => 'value']; + + $this->deploymentConfigMock->expects($this->once()) + ->method('getConfigData') + ->with(Config::QUEUE_CONFIG) + ->will($this->returnValue( + [ + 'connections' => [ + 'connection-01' => [ + 'host' => $expectedHost, + 'port' => $expectedPort, + 'user' => $expectedUsername, + 'password' => $expectedPassword, + 'virtualhost' => $expectedVirtualHost, + 'ssl' => $expectedSsl, + 'randomKey' => 'randomValue', + ] + ] + ] + )); + + $this->assertEquals($expectedHost, $amqpConfig->getValue(Config::HOST)); + $this->assertEquals($expectedPort, $amqpConfig->getValue(Config::PORT)); + $this->assertEquals($expectedUsername, $amqpConfig->getValue(Config::USERNAME)); + $this->assertEquals($expectedPassword, $amqpConfig->getValue(Config::PASSWORD)); + $this->assertEquals($expectedVirtualHost, $amqpConfig->getValue(Config::VIRTUALHOST)); + $this->assertEquals($expectedSsl, $amqpConfig->getValue(Config::SSL)); + $this->assertEquals('randomValue', $amqpConfig->getValue('randomKey')); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/ConnectionTypeResolverTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/ConnectionTypeResolverTest.php new file mode 100644 index 0000000000000..491e323d6c57f --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/ConnectionTypeResolverTest.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Test\Unit; + +use Magento\Framework\Amqp\ConnectionTypeResolver; +use Magento\Framework\App\DeploymentConfig; + +class ConnectionTypeResolverTest extends \PHPUnit\Framework\TestCase +{ + public function testGetConnectionType() + { + $config = $this->createMock(DeploymentConfig::class); + $config->expects($this->once()) + ->method('getConfigData') + ->with('queue') + ->will($this->returnValue( + [ + 'amqp' => [ + 'host' => '127.0.01', + 'port' => '8989', + 'user' => 'admin', + 'password' => 'admin', + 'virtualhost' => 'root', + 'ssl' => '', + 'randomKey' => 'randomValue', + ], + 'connections' => [ + 'connection-01' => [ + 'host' => 'host', + 'port' => '1515', + 'user' => 'guest', + 'password' => 'guest', + 'virtualhost' => 'localhost', + 'ssl' => '', + 'randomKey' => 'randomValue', + ] + ] + ] + )); + + $model = new ConnectionTypeResolver($config); + $this->assertEquals('amqp', $model->getConnectionType('connection-01')); + $this->assertEquals('amqp', $model->getConnectionType('amqp')); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/BindingInstallerTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/BindingInstallerTest.php new file mode 100644 index 0000000000000..6233e9bf48be3 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/BindingInstallerTest.php @@ -0,0 +1,54 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Test\Unit\Topology; + +use Magento\Framework\Amqp\Topology\BindingInstaller; +use Magento\Framework\Amqp\Topology\BindingInstallerInterface; +use PhpAmqpLib\Channel\AMQPChannel; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; + +class BindingInstallerTest extends \PHPUnit\Framework\TestCase +{ + public function testInstall() + { + $installerOne = $this->createMock(BindingInstallerInterface::class); + $installerTwo = $this->createMock(BindingInstallerInterface::class); + $model = new BindingInstaller( + [ + 'queue' => $installerOne, + 'exchange' => $installerTwo, + ] + ); + $channel = $this->createMock(AMQPChannel::class); + $binding = $this->createMock(BindingInterface::class); + $binding->expects($this->once())->method('getDestinationType')->willReturn('queue'); + $installerOne->expects($this->once())->method('install')->with($channel, $binding, 'magento'); + $installerTwo->expects($this->never())->method('install'); + $model->install($channel, $binding, 'magento'); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Installer type [test] is not configured + */ + public function testInstallInvalidType() + { + $installerOne = $this->createMock(BindingInstallerInterface::class); + $installerTwo = $this->createMock(BindingInstallerInterface::class); + $model = new BindingInstaller( + [ + 'queue' => $installerOne, + 'exchange' => $installerTwo, + ] + ); + $channel = $this->createMock(AMQPChannel::class); + $binding = $this->createMock(BindingInterface::class); + $binding->expects($this->once())->method('getDestinationType')->willReturn('test'); + $installerOne->expects($this->never())->method('install'); + $installerTwo->expects($this->never())->method('install'); + $model->install($channel, $binding, 'magento'); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/BindingInstallerType/ExchangeTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/BindingInstallerType/ExchangeTest.php new file mode 100644 index 0000000000000..ec8176b7016bc --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/BindingInstallerType/ExchangeTest.php @@ -0,0 +1,44 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Test\Unit\Topology\BindingInstallerType; + +use Magento\Framework\Amqp\Topology\BindingInstallerType\Exchange; +use PhpAmqpLib\Channel\AMQPChannel; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; + +class ExchangeTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Exchange + */ + private $model; + + protected function setUp() + { + $this->model = new Exchange(); + } + + public function testInstall() + { + $channel = $this->createMock(AMQPChannel::class); + $binding = $this->createMock(BindingInterface::class); + $binding->expects($this->once())->method('getDestination')->willReturn('queue01'); + $binding->expects($this->once())->method('getTopic')->willReturn('topic01'); + $binding->expects($this->once())->method('getArguments')->willReturn(['some' => 'value']); + + $channel->expects($this->once()) + ->method('exchange_bind') + ->with( + 'queue01', + 'magento', + 'topic01', + false, + ['some' => ['S', 'value']], + null + ); + $this->model->install($channel, $binding, 'magento'); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/BindingInstallerType/QueueTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/BindingInstallerType/QueueTest.php new file mode 100644 index 0000000000000..88a49127109ff --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/BindingInstallerType/QueueTest.php @@ -0,0 +1,44 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Test\Unit\Topology\BindingInstallerType; + +use Magento\Framework\Amqp\Topology\BindingInstallerType\Queue; +use PhpAmqpLib\Channel\AMQPChannel; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; + +class QueueTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Queue + */ + private $model; + + protected function setUp() + { + $this->model = new Queue(); + } + + public function testInstall() + { + $channel = $this->createMock(AMQPChannel::class); + $binding = $this->createMock(BindingInterface::class); + $binding->expects($this->once())->method('getDestination')->willReturn('queue01'); + $binding->expects($this->once())->method('getTopic')->willReturn('topic01'); + $binding->expects($this->once())->method('getArguments')->willReturn(['some' => 'value']); + + $channel->expects($this->once()) + ->method('queue_bind') + ->with( + 'queue01', + 'magento', + 'topic01', + false, + ['some' => ['S', 'value']], + null + ); + $this->model->install($channel, $binding, 'magento'); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/ExchangeInstallerTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/ExchangeInstallerTest.php new file mode 100644 index 0000000000000..ac5faadb29ca8 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/ExchangeInstallerTest.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Test\Unit\Topology; + +use Magento\Framework\Amqp\Topology\ExchangeInstaller; +use Magento\Framework\Amqp\Topology\BindingInstallerInterface; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItemInterface; +use PhpAmqpLib\Channel\AMQPChannel; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; + +class ExchangeInstallerTest extends \PHPUnit\Framework\TestCase +{ + public function testInstall() + { + $bindingInstaller = $this->createMock(BindingInstallerInterface::class); + $model = new ExchangeInstaller($bindingInstaller); + $channel = $this->createMock(AMQPChannel::class); + + $binding = $this->createMock(BindingInterface::class); + + $exchange = $this->createMock(ExchangeConfigItemInterface::class); + $exchange->expects($this->exactly(2))->method('getName')->willReturn('magento'); + $exchange->expects($this->once())->method('getType')->willReturn('topic'); + $exchange->expects($this->once())->method('isDurable')->willReturn(true); + $exchange->expects($this->once())->method('isAutoDelete')->willReturn(false); + $exchange->expects($this->once())->method('isInternal')->willReturn(false); + $exchange->expects($this->once())->method('getArguments')->willReturn(['some' => 'value']); + $exchange->expects($this->once())->method('getBindings')->willReturn(['bind01' => $binding]); + + $channel->expects($this->once()) + ->method('exchange_declare') + ->with('magento', 'topic', false, true, false, false, false, ['some' => ['S', 'value']], null); + $bindingInstaller->expects($this->once())->method('install')->with($channel, $binding, 'magento'); + $model->install($channel, $exchange); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/QueueInstallerTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/QueueInstallerTest.php new file mode 100644 index 0000000000000..f278952b83206 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/Topology/QueueInstallerTest.php @@ -0,0 +1,31 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Test\Unit\Topology; + +use Magento\Framework\Amqp\Topology\QueueInstaller; +use Magento\Framework\MessageQueue\Topology\Config\QueueConfigItemInterface; +use PhpAmqpLib\Channel\AMQPChannel; + +class QueueInstallerTest extends \PHPUnit\Framework\TestCase +{ + public function testInstall() + { + $bindingInstaller = $this->createMock(QueueConfigItemInterface::class); + $model = new QueueInstaller($bindingInstaller); + $channel = $this->createMock(AMQPChannel::class); + + $queue = $this->createMock(QueueConfigItemInterface::class); + $queue->expects($this->once())->method('getName')->willReturn('queue01'); + $queue->expects($this->once())->method('isDurable')->willReturn(true); + $queue->expects($this->once())->method('isAutoDelete')->willReturn(false); + $queue->expects($this->once())->method('getArguments')->willReturn(['some' => 'value']); + + $channel->expects($this->once()) + ->method('queue_declare') + ->with('queue01', false, true, false, false, false, ['some' => ['S', 'value']], null); + $model->install($channel, $queue); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Test/Unit/TopologyInstallerTest.php b/lib/internal/Magento/Framework/Amqp/Test/Unit/TopologyInstallerTest.php new file mode 100644 index 0000000000000..87253a15948e9 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Test/Unit/TopologyInstallerTest.php @@ -0,0 +1,73 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Test\Unit; + +use Magento\Framework\Amqp\TopologyInstaller; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\MessageQueue\Topology\ConfigInterface; +use PhpAmqpLib\Exception\AMQPLogicException; +use Psr\Log\LoggerInterface; + +/** + * Unit tests for @see \Magento\Framework\Amqp\TopologyInstaller + */ +class TopologyInstallerTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\Amqp\TopologyInstaller + */ + private $topologyInstaller; + + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var ConfigInterface | \PHPUnit_Framework_MockObject_MockObject + */ + private $topologyConfigMock; + + /** + * @var LoggerInterface | \PHPUnit_Framework_MockObject_MockObject + */ + private $loggerMock; + + /** + * Initialize topology installer. + */ + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + $this->topologyConfigMock = $this->createMock(ConfigInterface::class); + $this->loggerMock = $this->createMock(LoggerInterface::class); + $this->topologyInstaller = $this->objectManager->getObject( + TopologyInstaller::class, + ['topologyConfig' => $this->topologyConfigMock, 'logger' => $this->loggerMock] + ); + parent::setUp(); + } + + /** + * Make sure that topology creation errors in log contain actual error message. + */ + public function testInstallException() + { + $exceptionMessage = "Exception message"; + + $this->topologyConfigMock + ->expects($this->once()) + ->method('getQueues') + ->willThrowException(new AMQPLogicException($exceptionMessage)); + + $this->loggerMock + ->expects($this->once()) + ->method('error') + ->with($this->stringContains("AMQP topology installation failed: {$exceptionMessage}")); + + $this->topologyInstaller->install(); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Topology/ArgumentProcessor.php b/lib/internal/Magento/Framework/Amqp/Topology/ArgumentProcessor.php new file mode 100644 index 0000000000000..caa5db4e7ef5c --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Topology/ArgumentProcessor.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Topology; + +/** + * @deprecated 100.0.0 + * see: https://github.com/php-amqplib/php-amqplib/issues/405 + */ +trait ArgumentProcessor +{ + /** + * Process arguments + * + * @param array $arguments + * @return array + */ + public function processArguments($arguments) + { + $output = []; + foreach ($arguments as $key => $value) { + if (is_array($value)) { + $output[$key] = ['A', $value]; + } elseif (is_int($value)) { + $output[$key] = ['I', $value]; + } elseif (is_bool($value)) { + $output[$key] = ['t', $value]; + } elseif (is_string($value)) { + $output[$key] = ['S', $value]; + } else { + throw new \InvalidArgumentException('Unknown argument type ' . gettype($value)); + } + } + return $output; + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Topology/BindingInstaller.php b/lib/internal/Magento/Framework/Amqp/Topology/BindingInstaller.php new file mode 100644 index 0000000000000..58e43c0141ea3 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Topology/BindingInstaller.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Topology; + +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; +use PhpAmqpLib\Channel\AMQPChannel; + +/** + * {@inheritdoc} + */ +class BindingInstaller implements BindingInstallerInterface +{ + /** + * @var BindingInstallerInterface[] + */ + private $installers; + + /** + * Initialize dependencies. + * + * @param BindingInstallerInterface[] $installers + */ + public function __construct(array $installers) + { + $this->installers = $installers; + } + + /** + * {@inheritdoc} + */ + public function install(AMQPChannel $channel, BindingInterface $binding, $exchangeName) + { + $this->getInstaller($binding->getDestinationType())->install($channel, $binding, $exchangeName); + } + + /** + * Get binding installer by type. + * + * @param string $type + * @return BindingInstallerInterface + */ + private function getInstaller($type) + { + if (!isset($this->installers[$type])) { + throw new \InvalidArgumentException(sprintf('Installer type [%s] is not configured', $type)); + } + return $this->installers[$type]; + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Topology/BindingInstallerInterface.php b/lib/internal/Magento/Framework/Amqp/Topology/BindingInstallerInterface.php new file mode 100644 index 0000000000000..d18b6b0ad73b9 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Topology/BindingInstallerInterface.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Topology; + +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; +use PhpAmqpLib\Channel\AMQPChannel; + +/** + * Exchange binding installer. + */ +interface BindingInstallerInterface +{ + /** + * Install exchange bindings. + * + * @param AMQPChannel $channel + * @param BindingInterface $binding + * @param string $exchangeName + * @return void + */ + public function install(AMQPChannel $channel, BindingInterface $binding, $exchangeName); +} diff --git a/lib/internal/Magento/Framework/Amqp/Topology/BindingInstallerType/Exchange.php b/lib/internal/Magento/Framework/Amqp/Topology/BindingInstallerType/Exchange.php new file mode 100644 index 0000000000000..9a5a653a2ce7f --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Topology/BindingInstallerType/Exchange.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Topology\BindingInstallerType; + +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; +use Magento\Framework\Amqp\Topology\BindingInstallerInterface; +use PhpAmqpLib\Channel\AMQPChannel; +use Magento\Framework\Amqp\Topology\ArgumentProcessor; + +/** + * {@inheritdoc} + */ +class Exchange implements BindingInstallerInterface +{ + use ArgumentProcessor; + + /** + * {@inheritdoc} + */ + public function install(AMQPChannel $channel, BindingInterface $binding, $exchangeName) + { + $channel->exchange_bind( + $binding->getDestination(), + $exchangeName, + $binding->getTopic(), + false, + $this->processArguments($binding->getArguments()) + ); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Topology/BindingInstallerType/Queue.php b/lib/internal/Magento/Framework/Amqp/Topology/BindingInstallerType/Queue.php new file mode 100644 index 0000000000000..a3ea48e727fcf --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Topology/BindingInstallerType/Queue.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Topology\BindingInstallerType; + +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; +use Magento\Framework\Amqp\Topology\BindingInstallerInterface; +use PhpAmqpLib\Channel\AMQPChannel; +use Magento\Framework\Amqp\Topology\ArgumentProcessor; + +/** + * {@inheritdoc} + */ +class Queue implements BindingInstallerInterface +{ + use ArgumentProcessor; + + /** + * {@inheritdoc} + */ + public function install(AMQPChannel $channel, BindingInterface $binding, $exchangeName) + { + $channel->queue_bind( + $binding->getDestination(), + $exchangeName, + $binding->getTopic(), + false, + $this->processArguments($binding->getArguments()) + ); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Topology/ExchangeInstaller.php b/lib/internal/Magento/Framework/Amqp/Topology/ExchangeInstaller.php new file mode 100644 index 0000000000000..3951c21990097 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Topology/ExchangeInstaller.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Topology; + +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItemInterface; + +/** + * Exchange installer. + */ +class ExchangeInstaller +{ + use ArgumentProcessor; + + /** + * @var BindingInstallerInterface + */ + private $bindingInstaller; + + /** + * Initialize dependencies. + * + * @param BindingInstallerInterface $bindingInstaller + */ + public function __construct(BindingInstallerInterface $bindingInstaller) + { + $this->bindingInstaller = $bindingInstaller; + } + + /** + * Install exchange. + * + * @param \PhpAmqpLib\Channel\AMQPChannel $channel + * @param ExchangeConfigItemInterface $exchange + * @return void + */ + public function install(\PhpAmqpLib\Channel\AMQPChannel $channel, ExchangeConfigItemInterface $exchange) + { + $channel->exchange_declare( + $exchange->getName(), + $exchange->getType(), + false, + $exchange->isDurable(), + $exchange->isAutoDelete(), + $exchange->isInternal(), + false, + $this->processArguments($exchange->getArguments()) + ); + + foreach ($exchange->getBindings() as $binding) { + $this->bindingInstaller->install($channel, $binding, $exchange->getName()); + } + } +} diff --git a/lib/internal/Magento/Framework/Amqp/Topology/QueueInstaller.php b/lib/internal/Magento/Framework/Amqp/Topology/QueueInstaller.php new file mode 100644 index 0000000000000..83816bca9afb3 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/Topology/QueueInstaller.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp\Topology; + +use Magento\Framework\MessageQueue\Topology\Config\QueueConfigItemInterface; + +/** + * Queue installer. + */ +class QueueInstaller +{ + use ArgumentProcessor; + + /** + * Install queue. + * + * @param \PhpAmqpLib\Channel\AMQPChannel $channel + * @param QueueConfigItemInterface $queue + * @return void + */ + public function install(\PhpAmqpLib\Channel\AMQPChannel $channel, QueueConfigItemInterface $queue) + { + $channel->queue_declare( + $queue->getName(), + false, + $queue->isDurable(), + false, + $queue->isAutoDelete(), + false, + $this->processArguments($queue->getArguments()) + ); + } +} diff --git a/lib/internal/Magento/Framework/Amqp/TopologyInstaller.php b/lib/internal/Magento/Framework/Amqp/TopologyInstaller.php new file mode 100644 index 0000000000000..628974442ebcd --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/TopologyInstaller.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Amqp; + +use Magento\Framework\Amqp\Topology\ExchangeInstaller; +use Magento\Framework\Amqp\Topology\QueueInstaller; +use Magento\Framework\MessageQueue\Topology\ConfigInterface; + +/** + * Class Topology creates topology for Amqp messaging + */ +class TopologyInstaller +{ + /** + * @var ConfigInterface + */ + private $topologyConfig; + + /** + * @var \Magento\Framework\Amqp\Topology\ExchangeInstaller + */ + private $exchangeInstaller; + + /** + * @var ConfigPool + */ + private $configPool; + + /** + * @var \Magento\Framework\Amqp\Topology\QueueInstaller + */ + private $queueInstaller; + + /** + * @var ConnectionTypeResolver + */ + private $connectionTypeResolver; + + /** + * @var \Psr\Log\LoggerInterface + */ + protected $logger; + + /** + * Initialize dependencies. + * + * @param ConfigInterface $topologyConfig + * @param ExchangeInstaller $exchangeInstaller + * @param ConfigPool $configPool + * @param QueueInstaller $queueInstaller + * @param ConnectionTypeResolver $connectionTypeResolver + * @param \Psr\Log\LoggerInterface $logger + */ + public function __construct( + ConfigInterface $topologyConfig, + ExchangeInstaller $exchangeInstaller, + ConfigPool $configPool, + QueueInstaller $queueInstaller, + ConnectionTypeResolver $connectionTypeResolver, + \Psr\Log\LoggerInterface $logger + ) { + $this->topologyConfig = $topologyConfig; + $this->exchangeInstaller = $exchangeInstaller; + $this->configPool = $configPool; + $this->queueInstaller = $queueInstaller; + $this->connectionTypeResolver = $connectionTypeResolver; + $this->logger = $logger; + } + + /** + * Install Amqp Exchanges, Queues and bind them + * + * @return void + */ + public function install() + { + try { + foreach ($this->topologyConfig->getQueues() as $queue) { + if ($this->connectionTypeResolver->getConnectionType($queue->getConnection()) != 'amqp') { + continue; + } + $amqpConfig = $this->configPool->get($queue->getConnection()); + $this->queueInstaller->install($amqpConfig->getChannel(), $queue); + } + foreach ($this->topologyConfig->getExchanges() as $exchange) { + if ($this->connectionTypeResolver->getConnectionType($exchange->getConnection()) != 'amqp') { + continue; + } + $amqpConfig = $this->configPool->get($exchange->getConnection()); + $this->exchangeInstaller->install($amqpConfig->getChannel(), $exchange); + } + } catch (\PhpAmqpLib\Exception\AMQPExceptionInterface $e) { + $this->logger->error("AMQP topology installation failed: {$e->getMessage()}\n{$e->getTraceAsString()}"); + } + } +} diff --git a/lib/internal/Magento/Framework/Amqp/composer.json b/lib/internal/Magento/Framework/Amqp/composer.json new file mode 100644 index 0000000000000..7bcd2fe1b8b26 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/composer.json @@ -0,0 +1,26 @@ +{ + "name": "magento/framework-amqp", + "description": "N/A", + "config": { + "sort-packages": true + }, + "type": "magento2-library", + "version": "100.1.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "require": { + "magento/framework": "100.3.*", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "php-amqplib/php-amqplib": "2.5.*" + }, + "autoload": { + "psr-4": { + "Magento\\Framework\\Amqp\\": "" + }, + "files": [ + "registration.php" + ] + } +} diff --git a/lib/internal/Magento/Framework/Amqp/registration.php b/lib/internal/Magento/Framework/Amqp/registration.php new file mode 100644 index 0000000000000..ab14d5aab8e94 --- /dev/null +++ b/lib/internal/Magento/Framework/Amqp/registration.php @@ -0,0 +1,9 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use \Magento\Framework\Component\ComponentRegistrar; + +ComponentRegistrar::register(ComponentRegistrar::LIBRARY, 'magento/framework-amqp', __DIR__); diff --git a/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php b/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php index dab0650fc7f6e..e1a4431783da6 100644 --- a/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php +++ b/lib/internal/Magento/Framework/Api/ExtensionAttributesFactory.php @@ -49,7 +49,7 @@ public function create($extensibleClassName, $data = []) $interfaceReflection = new \ReflectionClass($this->getExtensibleInterfaceName($extensibleClassName)); $methodReflection = $interfaceReflection->getMethod('getExtensionAttributes'); - if ($methodReflection->getDeclaringClass() == self::EXTENSIBLE_INTERFACE_NAME) { + if ($methodReflection->getDeclaringClass()->getName() === self::EXTENSIBLE_INTERFACE_NAME) { throw new \LogicException( "Method 'getExtensionAttributes' must be overridden in the interfaces " . "which extend '" . self::EXTENSIBLE_INTERFACE_NAME . "'. " diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php index 06a66a2b3f873..ff7077213c5c3 100644 --- a/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php +++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php @@ -9,7 +9,9 @@ use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\Exception\FileSystemException; +use Magento\Framework\Exception\RuntimeException; use Magento\Framework\Filesystem\DriverPool; +use Magento\Framework\Phrase; /** * Deployment configuration reader. @@ -87,6 +89,7 @@ public function getFiles() * @param string $fileKey The file key (deprecated) * @return array * @throws FileSystemException If file can not be read + * @throws RuntimeException If file is invalid * @throws \Exception If file key is not correct * @see FileReader */ @@ -99,6 +102,9 @@ public function load($fileKey = null) $filePath = $path . '/' . $this->configFilePool->getPath($fileKey); if ($fileDriver->isExists($filePath)) { $result = include $filePath; + if (!is_array($result)) { + throw new RuntimeException(new Phrase("Invalid configuration file: '%1'", [$filePath])); + } } } else { $configFiles = $this->configFilePool->getPaths(); @@ -108,11 +114,14 @@ public function load($fileKey = null) $configFile = $path . '/' . $this->configFilePool->getPath($fileKey); if ($fileDriver->isExists($configFile)) { $fileData = include $configFile; + if (!is_array($fileData)) { + throw new RuntimeException(new Phrase("Invalid configuration file: '%1'", [$configFile])); + } } else { continue; } $allFilesData[$configFile] = $fileData; - if (is_array($fileData) && count($fileData) > 0) { + if ($fileData) { $result = array_replace_recursive($result, $fileData); } } diff --git a/lib/internal/Magento/Framework/App/Filesystem/DirectoryResolver.php b/lib/internal/Magento/Framework/App/Filesystem/DirectoryResolver.php new file mode 100644 index 0000000000000..4b62476ae8445 --- /dev/null +++ b/lib/internal/Magento/Framework/App/Filesystem/DirectoryResolver.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\App\Filesystem; + +/** + * Magento directories resolver. + */ +class DirectoryResolver +{ + /** + * @var DirectoryList + */ + private $directoryList; + + /** + * @param DirectoryList $directoryList + */ + public function __construct(DirectoryList $directoryList) + { + $this->directoryList = $directoryList; + } + + /** + * Validate path. + * + * Gets real path for directory provided in parameters and compares it with specified root directory. + * Will return TRUE if real path of provided value contains root directory path and FALSE if not. + * Throws the \Magento\Framework\Exception\FileSystemException in case when directory path is absent + * in Directories configuration. + * + * @param string $path + * @param string $directoryConfig + * @return bool + * @throws \Magento\Framework\Exception\FileSystemException + */ + public function validatePath($path, $directoryConfig = DirectoryList::MEDIA) + { + $realPath = realpath($path); + $root = $this->directoryList->getPath($directoryConfig); + + return strpos($realPath, $root) === 0; + } +} diff --git a/lib/internal/Magento/Framework/App/ResourceConnection.php b/lib/internal/Magento/Framework/App/ResourceConnection.php index 55ad76e9113a5..5b9ae925bff27 100644 --- a/lib/internal/Magento/Framework/App/ResourceConnection.php +++ b/lib/internal/Magento/Framework/App/ResourceConnection.php @@ -300,13 +300,14 @@ public function getSchemaName($resourceName) * * @return string */ - private function getTablePrefix() + public function getTablePrefix() { - if (null === $this->tablePrefix) { - $this->tablePrefix = (string)$this->deploymentConfig->get( - ConfigOptionsListConstants::CONFIG_PATH_DB_PREFIX - ); + if ($this->tablePrefix !== null) { + return $this->tablePrefix; } - return $this->tablePrefix; + + return (string) $this->deploymentConfig->get( + ConfigOptionsListConstants::CONFIG_PATH_DB_PREFIX + ); } } diff --git a/lib/internal/Magento/Framework/App/StaticResource.php b/lib/internal/Magento/Framework/App/StaticResource.php index c554e1b49bccc..575074fdb58ac 100644 --- a/lib/internal/Magento/Framework/App/StaticResource.php +++ b/lib/internal/Magento/Framework/App/StaticResource.php @@ -165,9 +165,11 @@ protected function parsePath($path) { $path = ltrim($path, '/'); $parts = explode('/', $path, 6); - if (count($parts) < 5) { + if (count($parts) < 5 || preg_match('/\.\.(\\\|\/)/', $path)) { + //Checking that path contains all required parts and is not above static folder. throw new \InvalidArgumentException("Requested path '$path' is wrong."); } + $result = []; $result['area'] = $parts[0]; $result['theme'] = $parts[1] . '/' . $parts[2]; diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php index 3e3eea322cafd..8f8399263384c 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php @@ -8,26 +8,29 @@ use Magento\Framework\App\DeploymentConfig\Reader; use Magento\Framework\App\Filesystem\DirectoryList; +use Magento\Framework\Config\File\ConfigFilePool; +use Magento\Framework\Filesystem\Driver\File; +use Magento\Framework\Filesystem\DriverPool; class ReaderTest extends \PHPUnit\Framework\TestCase { /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\App\Filesystem\DirectoryList|\PHPUnit_Framework_MockObject_MockObject */ private $dirList; /** - * @var \Magento\Framework\Filesystem\DriverPool|\PHPUnit_Framework_MockObject_MockObject + * @var DriverPool|\PHPUnit_Framework_MockObject_MockObject */ private $driverPool; /** - * @var \Magento\Framework\Filesystem\Driver\File|\PHPUnit_Framework_MockObject_MockObject + * @var File|\PHPUnit_Framework_MockObject_MockObject */ private $fileDriver; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var ConfigFilePool|\PHPUnit_Framework_MockObject_MockObject */ private $configFilePool; @@ -38,7 +41,7 @@ protected function setUp() ->method('getPath') ->with(DirectoryList::CONFIG) ->willReturn(__DIR__ . '/_files'); - $this->fileDriver = $this->createMock(\Magento\Framework\Filesystem\Driver\File::class); + $this->fileDriver = $this->createMock(File::class); $this->fileDriver ->expects($this->any()) ->method('isExists') @@ -51,12 +54,12 @@ protected function setUp() [__DIR__ . '/_files/mergeTwo.php', true], [__DIR__ . '/_files/nonexistent.php', false] ])); - $this->driverPool = $this->createMock(\Magento\Framework\Filesystem\DriverPool::class); + $this->driverPool = $this->createMock(DriverPool::class); $this->driverPool ->expects($this->any()) ->method('getDriver') ->willReturn($this->fileDriver); - $this->configFilePool = $this->createMock(\Magento\Framework\Config\File\ConfigFilePool::class); + $this->configFilePool = $this->createMock(ConfigFilePool::class); $this->configFilePool ->expects($this->any()) ->method('getPaths') @@ -100,13 +103,97 @@ public function testLoad() */ public function testCustomLoad($file, $expected) { - $configFilePool = $this->createMock(\Magento\Framework\Config\File\ConfigFilePool::class); + $configFilePool = $this->createMock(ConfigFilePool::class); $configFilePool->expects($this->any())->method('getPaths')->willReturn([$file]); $configFilePool->expects($this->any())->method('getPath')->willReturn($file); $object = new Reader($this->dirList, $this->driverPool, $configFilePool, $file); $this->assertSame($expected, $object->load($file)); } + /** + * Test Reader::load() will throw exception in case of invalid configuration file(single file). + * + * @expectedException \Magento\Framework\Exception\RuntimeException + * @expectedExceptionMessageRegExp /Invalid configuration file: \'.*\/\_files\/emptyConfig\.php\'/ + * @return void + */ + public function testLoadInvalidConfigurationFileWithFileKey() + { + $fileDriver = $this->getMockBuilder(File::class) + ->disableOriginalConstructor() + ->getMock(); + $fileDriver->expects($this->once()) + ->method('isExists') + ->willReturn(true); + /** @var DriverPool|\PHPUnit_Framework_MockObject_MockObject $driverPool */ + $driverPool = $this->getMockBuilder(DriverPool::class) + ->disableOriginalConstructor() + ->getMock(); + $driverPool + ->expects($this->once()) + ->method('getDriver') + ->willReturn($fileDriver); + /** @var ConfigFilePool|\PHPUnit_Framework_MockObject_MockObject $configFilePool */ + $configFilePool = $this->getMockBuilder(ConfigFilePool::class) + ->disableOriginalConstructor() + ->getMock(); + $configFilePool + ->expects($this->once()) + ->method('getPath') + ->with($this->identicalTo('testConfig')) + ->willReturn('emptyConfig.php'); + $object = new Reader($this->dirList, $driverPool, $configFilePool); + $object->load('testConfig'); + } + + /** + * Test Reader::load() will throw exception in case of invalid configuration file(multiple files). + * + * @expectedException \Magento\Framework\Exception\RuntimeException + * @expectedExceptionMessageRegExp /Invalid configuration file: \'.*\/\_files\/emptyConfig\.php\'/ + * @return void + */ + public function testLoadInvalidConfigurationFile() + { + $fileDriver = $this->getMockBuilder(File::class) + ->disableOriginalConstructor() + ->getMock(); + $fileDriver->expects($this->exactly(2)) + ->method('isExists') + ->willReturn(true); + /** @var DriverPool|\PHPUnit_Framework_MockObject_MockObject $driverPool */ + $driverPool = $this->getMockBuilder(DriverPool::class) + ->disableOriginalConstructor() + ->getMock(); + $driverPool + ->expects($this->once()) + ->method('getDriver') + ->willReturn($fileDriver); + /** @var ConfigFilePool|\PHPUnit_Framework_MockObject_MockObject $configFilePool */ + $configFilePool = $this->getMockBuilder(ConfigFilePool::class) + ->disableOriginalConstructor() + ->getMock(); + $configFilePool->expects($this->exactly(2)) + ->method('getPaths') + ->willReturn( + [ + 'configKeyOne' => 'config.php', + 'testConfig' => 'emptyConfig.php' + ] + ); + $configFilePool->expects($this->exactly(2)) + ->method('getPath') + ->withConsecutive( + [$this->identicalTo('configKeyOne')], + [$this->identicalTo('testConfig')] + )->willReturnOnConsecutiveCalls( + 'config.php', + 'emptyConfig.php' + ); + $object = new Reader($this->dirList, $driverPool, $configFilePool); + $object->load(); + } + /** * @return array */ diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/_files/emptyConfig.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/_files/emptyConfig.php new file mode 100644 index 0000000000000..79549bf674aad --- /dev/null +++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/_files/emptyConfig.php @@ -0,0 +1,6 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +//Example of wrong(empty) configuration file. diff --git a/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php b/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php index 2edd0ffd3b1b5..d69ce4956ce8c 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/StaticResourceTest.php @@ -284,4 +284,22 @@ public function testCatchExceptionDeveloperMode() ->method('sendResponse'); $this->assertTrue($this->object->catchException($bootstrap, $exception)); } + + /** + * @expectedException \InvalidArgumentException + */ + public function testLaunchPathAbove() + { + $path = 'frontend/..\..\folder_above/././Magento_Ui/template/messages.html'; + $this->stateMock->expects($this->once()) + ->method('getMode') + ->will($this->returnValue(State::MODE_DEVELOPER)); + $this->requestMock->expects($this->once()) + ->method('get') + ->with('resource') + ->willReturn('frontend/..\..\folder_above/././Magento_Ui/template/messages.html'); + $this->expectExceptionMessage("Requested path '$path' is wrong."); + + $this->object->launch(); + } } diff --git a/lib/internal/Magento/Framework/App/Utility/Files.php b/lib/internal/Magento/Framework/App/Utility/Files.php index bae2b50a0ea27..7e8d79eead7e1 100644 --- a/lib/internal/Magento/Framework/App/Utility/Files.php +++ b/lib/internal/Magento/Framework/App/Utility/Files.php @@ -162,7 +162,8 @@ public static function composeDataSets(array $files) { $result = []; foreach ($files as $file) { - $result[$file] = [$file]; + $key = str_replace(BP . '/', '', $file); + $result[$key] = [$file]; } return $result; } diff --git a/lib/internal/Magento/Framework/Bulk/BulkManagementInterface.php b/lib/internal/Magento/Framework/Bulk/BulkManagementInterface.php new file mode 100644 index 0000000000000..9cfb2b1c97a4d --- /dev/null +++ b/lib/internal/Magento/Framework/Bulk/BulkManagementInterface.php @@ -0,0 +1,35 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Bulk; + +/** + * Interface BulkManagementInterface + * @api + * @since 100.2.0 + */ +interface BulkManagementInterface +{ + /** + * Schedule new bulk + * + * @param string $bulkUuid + * @param OperationInterface[] $operations + * @param string $description + * @param int $userId + * @return boolean + * @since 100.2.0 + */ + public function scheduleBulk($bulkUuid, array $operations, $description, $userId = null); + + /** + * Delete bulk + * + * @param string $bulkId + * @return boolean + * @since 100.2.0 + */ + public function deleteBulk($bulkId); +} diff --git a/lib/internal/Magento/Framework/Bulk/BulkStatusInterface.php b/lib/internal/Magento/Framework/Bulk/BulkStatusInterface.php new file mode 100644 index 0000000000000..0f1deb0ceeeaf --- /dev/null +++ b/lib/internal/Magento/Framework/Bulk/BulkStatusInterface.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Bulk; + +/** + * Interface BulkStatusInterface + * @api + * @since 100.2.0 + */ +interface BulkStatusInterface +{ + /** + * Get failed operations by bulk uuid + * + * @param string $bulkUuid + * @param int|null $failureType + * @return \Magento\Framework\Bulk\OperationInterface[] + * @since 100.2.0 + */ + public function getFailedOperationsByBulkId($bulkUuid, $failureType = null); + + /** + * Get operations count by bulk uuid and status. + * + * @param string $bulkUuid + * @param int $status + * @return int + * @since 100.2.0 + */ + public function getOperationsCountByBulkIdAndStatus($bulkUuid, $status); + + /** + * Get all bulks created by user + * + * @param int $userId + * @return BulkSummaryInterface[] + * @since 100.2.0 + */ + public function getBulksByUser($userId); + + /** + * Computational status based on statuses of belonging operations + * + * FINISHED_SUCCESFULLY - all operations are handled succesfully + * FINISHED_WITH_FAILURE - some operations are handled with failure + * + * @param string $bulkUuid + * @return int NOT_STARTED | IN_PROGRESS | FINISHED_SUCCESFULLY | FINISHED_WITH_FAILURE + * @since 100.2.0 + */ + public function getBulkStatus($bulkUuid); +} diff --git a/lib/internal/Magento/Framework/Bulk/BulkSummaryInterface.php b/lib/internal/Magento/Framework/Bulk/BulkSummaryInterface.php new file mode 100644 index 0000000000000..69e9b71ca00c3 --- /dev/null +++ b/lib/internal/Magento/Framework/Bulk/BulkSummaryInterface.php @@ -0,0 +1,118 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Bulk; + +/** + * Interface BulkSummaryInterface + * @api + * @since 100.2.0 + */ +interface BulkSummaryInterface +{ + /**#@+ + * Constants for keys of data array. Identical to the name of the getter in snake case + */ + const BULK_ID = 'uuid'; + const DESCRIPTION = 'description'; + const START_TIME = 'start_time'; + const USER_ID = 'user_id'; + const OPERATION_COUNT = 'operation_count'; + /**#@-*/ + + /**#@+ + * Bulk statuses constants + */ + const NOT_STARTED = 0; + const IN_PROGRESS = 1; + const FINISHED_SUCCESSFULLY = 2; + const FINISHED_WITH_FAILURE = 3; + /**#@-*/ + + /** + * Get bulk uuid + * + * @return string + * @since 100.2.0 + */ + public function getBulkId(); + + /** + * Set bulk uuid + * + * @param string $bulkUuid + * @return $this + * @since 100.2.0 + */ + public function setBulkId($bulkUuid); + + /** + * Get bulk description + * + * @return string + * @since 100.2.0 + */ + public function getDescription(); + + /** + * Set bulk description + * + * @param string $description + * @return $this + * @since 100.2.0 + */ + public function setDescription($description); + + /** + * Get bulk scheduled time + * + * @return string + * @since 100.2.0 + */ + public function getStartTime(); + + /** + * Set bulk scheduled time + * + * @param string $timestamp + * @return $this + * @since 100.2.0 + */ + public function setStartTime($timestamp); + + /** + * Get user id + * + * @return int + * @since 100.2.0 + */ + public function getUserId(); + + /** + * Set user id + * + * @param int $userId + * @return $this + * @since 100.2.0 + */ + public function setUserId($userId); + + /** + * Get total number of operations scheduled in scope of this bulk + * + * @return int + * @since 100.2.0 + */ + public function getOperationCount(); + + /** + * Set total number of operations scheduled in scope of this bulk + * + * @param int $operationCount + * @return $this + * @since 100.2.0 + */ + public function setOperationCount($operationCount); +} diff --git a/lib/internal/Magento/Framework/Bulk/OperationInterface.php b/lib/internal/Magento/Framework/Bulk/OperationInterface.php new file mode 100644 index 0000000000000..c6d714b0363bd --- /dev/null +++ b/lib/internal/Magento/Framework/Bulk/OperationInterface.php @@ -0,0 +1,156 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Bulk; + +/** + * Interface OperationInterface + * @api + * @since 100.2.0 + */ +interface OperationInterface +{ + /**#@+ + * Constants for keys of data array. Identical to the name of the getter in snake case + */ + const ID = 'id'; + const BULK_ID = 'bulk_uuid'; + const TOPIC_NAME = 'topic_name'; + const SERIALIZED_DATA = 'serialized_data'; + const STATUS = 'status'; + const RESULT_MESSAGE = 'result_message'; + const ERROR_CODE = 'error_code'; + /**#@-*/ + + /**#@+ + * Status types + */ + const STATUS_TYPE_COMPLETE = 1; + const STATUS_TYPE_RETRIABLY_FAILED = 2; + const STATUS_TYPE_NOT_RETRIABLY_FAILED = 3; + const STATUS_TYPE_OPEN = 4; + /**#@-*/ + + /** + * Operation id + * + * @return int + * @since 100.2.0 + */ + public function getId(); + + /** + * Set operation id + * + * @param int $id + * @return $this + * @since 100.2.0 + */ + public function setId($id); + + /** + * Get bulk uuid + * + * @return string + * @since 100.2.0 + */ + public function getBulkUuid(); + + /** + * Set bulk uuid + * + * @param string $bulkId + * @return $this + * @since 100.2.0 + */ + public function setBulkUuid($bulkId); + + /** + * Message Queue Topic + * + * @return string + * @since 100.2.0 + */ + public function getTopicName(); + + /** + * Set message queue topic + * + * @param string $topic + * @return $this + * @since 100.2.0 + */ + public function setTopicName($topic); + + /** + * Serialized Data + * + * @return string + * @since 100.2.0 + */ + public function getSerializedData(); + + /** + * Set serialized data + * + * @param string $serializedData + * @return $this + * @since 100.2.0 + */ + public function setSerializedData($serializedData); + + /** + * Get operation status + * + * OPEN | COMPLETE | RETRIABLY_FAILED | NOT_RETRIABLY_FAILED + * + * @return int + * @since 100.2.0 + */ + public function getStatus(); + + /** + * Set status + * + * @param int $status + * @return $this + * @since 100.2.0 + */ + public function setStatus($status); + + /** + * Get result message + * + * @return string + * @since 100.2.0 + */ + public function getResultMessage(); + + /** + * Set result message + * + * @param string $resultMessage + * @return $this + * @since 100.2.0 + */ + public function setResultMessage($resultMessage); + + /** + * Get error code + * + * @return int + * @since 100.2.0 + */ + public function getErrorCode(); + + /** + * Set error code + * + * @param int $errorCode + * @return $this + * @since 100.2.0 + */ + public function setErrorCode($errorCode); +} diff --git a/lib/internal/Magento/Framework/Bulk/OperationManagementInterface.php b/lib/internal/Magento/Framework/Bulk/OperationManagementInterface.php new file mode 100644 index 0000000000000..e86d3ca8c1624 --- /dev/null +++ b/lib/internal/Magento/Framework/Bulk/OperationManagementInterface.php @@ -0,0 +1,28 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Bulk; + +/** + * Interface OperationManagementInterface + * @api + * @since 100.2.0 + */ +interface OperationManagementInterface +{ + /** + * Used by consumer to change status after processing operation + * + * @param int $operationId + * @param int $status + * @param int|null $errorCode + * @param string|null $message property to update Result Message + * @param string|null $data serialized data object of failed message + * @return boolean + * @since 100.2.0 + */ + public function changeOperationStatus($operationId, $status, $errorCode = null, $message = null, $data = null); +} diff --git a/lib/internal/Magento/Framework/Bulk/README.md b/lib/internal/Magento/Framework/Bulk/README.md new file mode 100644 index 0000000000000..8ddbc686147ff --- /dev/null +++ b/lib/internal/Magento/Framework/Bulk/README.md @@ -0,0 +1 @@ + This component is designed to provide Bulk Operations Framework. \ No newline at end of file diff --git a/lib/internal/Magento/Framework/Bulk/composer.json b/lib/internal/Magento/Framework/Bulk/composer.json new file mode 100644 index 0000000000000..8cb9139ca0d52 --- /dev/null +++ b/lib/internal/Magento/Framework/Bulk/composer.json @@ -0,0 +1,25 @@ +{ + "name": "magento/framework-bulk", + "description": "N/A", + "config": { + "sort-packages": true + }, + "type": "magento2-library", + "version": "100.3.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "require": { + "magento/framework": "100.3.*", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "autoload": { + "psr-4": { + "Magento\\Framework\\Bulk\\": "" + }, + "files": [ + "registration.php" + ] + } +} diff --git a/lib/internal/Magento/Framework/Bulk/registration.php b/lib/internal/Magento/Framework/Bulk/registration.php new file mode 100644 index 0000000000000..f9f5606b76841 --- /dev/null +++ b/lib/internal/Magento/Framework/Bulk/registration.php @@ -0,0 +1,9 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use \Magento\Framework\Component\ComponentRegistrar; + +ComponentRegistrar::register(ComponentRegistrar::LIBRARY, 'magento/framework-bulk', __DIR__); diff --git a/lib/internal/Magento/Framework/Code/Reader/ClassReader.php b/lib/internal/Magento/Framework/Code/Reader/ClassReader.php index 1bc71a342eb25..fe96e9cc742aa 100644 --- a/lib/internal/Magento/Framework/Code/Reader/ClassReader.php +++ b/lib/internal/Magento/Framework/Code/Reader/ClassReader.php @@ -27,10 +27,8 @@ public function getConstructor($className) $result[] = [ $parameter->getName(), $parameter->getClass() !== null ? $parameter->getClass()->getName() : null, - !$parameter->isOptional(), - $parameter->isOptional() - ? ($parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null) - : null, + !$parameter->isOptional() && !$parameter->isDefaultValueAvailable(), + $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null, ]; } catch (\ReflectionException $e) { $message = $e->getMessage(); diff --git a/lib/internal/Magento/Framework/Config/Data/ConfigDataFactory.php b/lib/internal/Magento/Framework/Config/Data/ConfigDataFactory.php new file mode 100644 index 0000000000000..655e624ff0637 --- /dev/null +++ b/lib/internal/Magento/Framework/Config/Data/ConfigDataFactory.php @@ -0,0 +1,42 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Config\Data; + +use Magento\Framework\App\ObjectManager; +use Magento\Framework\ObjectManagerInterface; + +/** + * Factory for ConfigData. + */ +class ConfigDataFactory +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * Factory constructor. + * + * @param ObjectManagerInterface $objectManager + */ + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * Returns a new instance of ConfigData on every call. + * + * @param string $fileKey + * @return ConfigData + */ + public function create($fileKey) + { + return $this->objectManager->create(ConfigData::class, ['fileKey' => $fileKey]); + } +} diff --git a/lib/internal/Magento/Framework/Config/FileResolverByModule.php b/lib/internal/Magento/Framework/Config/FileResolverByModule.php index bd8a61e0ec234..efd84823dfbc9 100644 --- a/lib/internal/Magento/Framework/Config/FileResolverByModule.php +++ b/lib/internal/Magento/Framework/Config/FileResolverByModule.php @@ -6,7 +6,9 @@ namespace Magento\Framework\Config; use Magento\Framework\Component\ComponentRegistrar; +use Magento\Framework\Filesystem\DriverInterface; use Magento\Framework\Module\Dir; +use Magento\Framework\Oauth\Exception; /** * Application config file resolver. @@ -23,6 +25,11 @@ class FileResolverByModule extends \Magento\Framework\App\Config\FileResolver */ private $componentRegistrar; + /** + * @var DriverInterface + */ + private $driver; + /** * Constructor. * @@ -30,15 +37,18 @@ class FileResolverByModule extends \Magento\Framework\App\Config\FileResolver * @param \Magento\Framework\Filesystem $filesystem * @param FileIteratorFactory $iteratorFactory * @param ComponentRegistrar $componentRegistrar + * @param \Magento\Framework\Filesystem\Driver\File $driver */ public function __construct( \Magento\Framework\Module\Dir\Reader $moduleReader, \Magento\Framework\Filesystem $filesystem, \Magento\Framework\Config\FileIteratorFactory $iteratorFactory, - ComponentRegistrar $componentRegistrar + ComponentRegistrar $componentRegistrar, + \Magento\Framework\Filesystem\Driver\File $driver ) { parent::__construct($moduleReader, $filesystem, $iteratorFactory); $this->componentRegistrar = $componentRegistrar; + $this->driver = $driver; } /** @@ -51,10 +61,15 @@ public function get($filename, $scope) $iterator = $this->_moduleReader->getConfigurationFiles($filename)->toArray(); if ($scope !== self::ALL_MODULES) { $path = $this->componentRegistrar->getPath('module', $scope); - $path .= DIRECTORY_SEPARATOR . Dir::MODULE_ETC_DIR . DIRECTORY_SEPARATOR . $filename; + $path .= '/' . Dir::MODULE_ETC_DIR . '/'. $filename; $iterator = isset($iterator[$path]) ? [$path => $iterator[$path]] : []; } - + $primaryFile = parent::get($filename, 'primary')->toArray(); + if (!$this->driver->isFile(key($primaryFile))) { + throw new \Exception("Primary db_schema file doesn`t exists"); + } + /** Load primary configurations */ + $iterator += $primaryFile; return $iterator; } } diff --git a/lib/internal/Magento/Framework/Config/Test/Unit/Dom/UrnResolverTest.php b/lib/internal/Magento/Framework/Config/Test/Unit/Dom/UrnResolverTest.php index 79f9333a3b6db..d497cef8ee70a 100644 --- a/lib/internal/Magento/Framework/Config/Test/Unit/Dom/UrnResolverTest.php +++ b/lib/internal/Magento/Framework/Config/Test/Unit/Dom/UrnResolverTest.php @@ -36,7 +36,7 @@ public function testGetRealPathNoUrn() public function testGetRealPathWithFrameworkUrn() { $xsdUrn = 'urn:magento:framework:Config/Test/Unit/_files/sample.xsd'; - $xsdPath = realpath(dirname(__DIR__)) . '/_files/sample.xsd'; + $xsdPath = str_replace('\\', '/', realpath(dirname(__DIR__)) . '/_files/sample.xsd'); $result = $this->urnResolver->getRealPath($xsdUrn); $this->assertSame($xsdPath, $result, 'XSD paths does not match.'); } @@ -54,10 +54,10 @@ public function testGetRealPathWithModuleUrn() public function testGetRealPathWithSetupUrn() { - $xsdUrn = 'urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd'; + $xsdUrn = 'urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd'; $componentRegistrar = new ComponentRegistrar(); - $xsdPath = $componentRegistrar->getPath(ComponentRegistrar::SETUP, 'magento/setup') - . '/Model/Declaration/Schema/etc/schema.xsd'; + $xsdPath = $componentRegistrar->getPath(ComponentRegistrar::LIBRARY, 'magento/framework') + . '/Setup/Declaration/Schema/etc/schema.xsd'; $result = $this->urnResolver->getRealPath($xsdUrn); $this->assertSame($xsdPath, $result, 'XSD paths does not match.'); diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Editor.php b/lib/internal/Magento/Framework/Data/Form/Element/Editor.php index f2368beadc51a..39a0479f7540e 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Editor.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Editor.php @@ -67,7 +67,7 @@ protected function getButtonTranslations() * @return bool|string * @throws \InvalidArgumentException */ - private function getJsonConfig() + protected function getJsonConfig() { if (is_object($this->getConfig()) && method_exists($this->getConfig(), 'toJson')) { return $this->getConfig()->toJson(); diff --git a/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php b/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php index 9462579422548..03daa6c08fff4 100644 --- a/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php +++ b/lib/internal/Magento/Framework/Data/Form/Element/Multiselect.php @@ -61,6 +61,10 @@ public function getElementHtml() <input type="hidden" id="' . $this->getHtmlId() . '_hidden" name="' . parent::getName() . '" value="" /> '; } + if (!empty($this->_data['disabled'])) { + $html .= '<input type="hidden" name="' . parent::getName() . '_disabled" value="" />'; + } + $html .= '<select id="' . $this->getHtmlId() . '" name="' . $this->getName() . '" ' . $this->serialize( $this->getHtmlAttributes() ) . $this->_getUiId() . ' multiple="multiple">' . "\n"; diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php index 84dfdf4085a48..47eae73d8cd8c 100644 --- a/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php +++ b/lib/internal/Magento/Framework/Data/Test/Unit/Form/Element/MultiselectTest.php @@ -20,9 +20,10 @@ protected function setUp() } /** - * Verify that hidden input is present in multiselect + * Verify that hidden input is present in multiselect. * * @covers \Magento\Framework\Data\Form\Element\Multiselect::getElementHtml + * @return void */ public function testHiddenFieldPresentInMultiSelect() { @@ -39,7 +40,38 @@ public function testHiddenFieldPresentInMultiSelect() } /** - * Verify that js element is added + * Verify that hidden input is present in multiselect when multiselect is disabled. + * + * @return void + */ + public function testHiddenDisabledFieldPresentInMultiSelect() + { + $fieldName = 'fieldName'; + $this->_model->setDisabled(true); + $this->_model->setName($fieldName); + $elementHtml = $this->_model->getElementHtml(); + $this->assertContains('<input type="hidden" name="' . $fieldName . '_disabled"', $elementHtml); + } + + /** + * Verify that hidden input is not present in multiselect when multiselect is not disabled. + * + * @covers \Magento\Framework\Data\Form\Element\Multiselect::getElementHtml + * @return void + */ + public function testHiddenDisabledFieldNotPresentInMultiSelect() + { + $fieldName = 'fieldName'; + $this->_model->setDisabled(false); + $this->_model->setName($fieldName); + $elementHtml = $this->_model->getElementHtml(); + $this->assertNotContains('<input type="hidden" name="' . $fieldName . '_disabled"', $elementHtml); + } + + /** + * Verify that js element is added. + * + * @return void */ public function testGetAfterElementJs() { diff --git a/lib/internal/Magento/Framework/Event/ObserverInterface.php b/lib/internal/Magento/Framework/Event/ObserverInterface.php index 09358e0966216..e7c9b770ea1f5 100644 --- a/lib/internal/Magento/Framework/Event/ObserverInterface.php +++ b/lib/internal/Magento/Framework/Event/ObserverInterface.php @@ -10,6 +10,7 @@ /** * Interface \Magento\Framework\Event\ObserverInterface * + * @api */ interface ObserverInterface { diff --git a/lib/internal/Magento/Framework/Filesystem/DirectoryList.php b/lib/internal/Magento/Framework/Filesystem/DirectoryList.php index 2685ca13ac4ba..20874f60791c1 100644 --- a/lib/internal/Magento/Framework/Filesystem/DirectoryList.php +++ b/lib/internal/Magento/Framework/Filesystem/DirectoryList.php @@ -202,6 +202,7 @@ public function getRoot() * * @param string $code * @return string + * @throws \Magento\Framework\Exception\FileSystemException */ public function getPath($code) { diff --git a/lib/internal/Magento/Framework/Filter/RemoveTags.php b/lib/internal/Magento/Framework/Filter/RemoveTags.php index 63528dd4234c3..ca581176de368 100644 --- a/lib/internal/Magento/Framework/Filter/RemoveTags.php +++ b/lib/internal/Magento/Framework/Filter/RemoveTags.php @@ -34,7 +34,8 @@ public function filter($value) [$this, '_convertEntities'], $value ); - $value = strip_tags($value); - return htmlspecialchars_decode($value); + $value = htmlspecialchars_decode($value); + + return strip_tags($value); } } diff --git a/lib/internal/Magento/Framework/Filter/Test/Unit/RemoveTagsTest.php b/lib/internal/Magento/Framework/Filter/Test/Unit/RemoveTagsTest.php index 7ac9a7fe583c4..8fc9685aa7c42 100644 --- a/lib/internal/Magento/Framework/Filter/Test/Unit/RemoveTagsTest.php +++ b/lib/internal/Magento/Framework/Filter/Test/Unit/RemoveTagsTest.php @@ -5,6 +5,9 @@ */ namespace Magento\Framework\Filter\Test\Unit; +/** + * Test for \Magento\Framework\Filter\RemoveTags + */ class RemoveTagsTest extends \PHPUnit\Framework\TestCase { /** @@ -19,4 +22,13 @@ public function testRemoveTags() $expected = '10 < 11 > 10'; $this->assertSame($expected, $actual); } + + public function testFilterEncodedValue() + { + $input = '"><script>alert("website")</script><br a="'; + $removeTags = new \Magento\Framework\Filter\RemoveTags(); + $actual = $removeTags->filter($input); + $expected = '">alert("website")'; + $this->assertSame($expected, $actual); + } } diff --git a/lib/internal/Magento/Framework/MessageQueue/BatchConsumer.php b/lib/internal/Magento/Framework/MessageQueue/BatchConsumer.php new file mode 100644 index 0000000000000..e7dc12be40e6d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/BatchConsumer.php @@ -0,0 +1,305 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\MessageQueue\ConfigInterface as MessageQueueConfig; +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\MessageQueue\Consumer\ConfigInterface as ConsumerConfig; + +/** + * Class BatchConsumer + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class BatchConsumer implements ConsumerInterface +{ + /** + * @var ConsumerConfigurationInterface + */ + private $configuration; + + /** + * @var MessageEncoder + */ + private $messageEncoder; + + /** + * @var QueueRepository + */ + private $queueRepository; + + /** + * @var MergerFactory + */ + private $mergerFactory; + + /** + * @var int + */ + private $interval; + + /** + * @var int + */ + private $batchSize; + + /** + * @var MessageProcessorLoader + */ + private $messageProcessorLoader; + + /** + * @var Resource + */ + private $resource; + + /** + * @var MessageController + */ + private $messageController; + + /** + * @var ConsumerConfig + */ + private $consumerConfig; + + /** + * @param ConfigInterface $messageQueueConfig + * @param MessageEncoder $messageEncoder + * @param QueueRepository $queueRepository + * @param MergerFactory $mergerFactory + * @param ResourceConnection $resource + * @param ConsumerConfigurationInterface $configuration + * @param int $interval [optional] + * @param int $batchSize [optional] + * @param MessageProcessorLoader $messageProcessorLoader [optional] + * @param MessageController $messageController [optional] + * @param ConsumerConfig $consumerConfig [optional] + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __construct( + MessageQueueConfig $messageQueueConfig, + MessageEncoder $messageEncoder, + QueueRepository $queueRepository, + MergerFactory $mergerFactory, + ResourceConnection $resource, + ConsumerConfigurationInterface $configuration, + $interval = 5, + $batchSize = 0, + MessageProcessorLoader $messageProcessorLoader = null + ) { + $this->messageEncoder = $messageEncoder; + $this->queueRepository = $queueRepository; + $this->mergerFactory = $mergerFactory; + $this->interval = $interval; + $this->batchSize = $batchSize; + $this->resource = $resource; + $this->configuration = $configuration; + $this->messageProcessorLoader = $messageProcessorLoader + ?: \Magento\Framework\App\ObjectManager::getInstance()->get(MessageProcessorLoader::class); + } + + /** + * {@inheritdoc} + */ + public function process($maxNumberOfMessages = null) + { + $queueName = $this->configuration->getQueueName(); + $consumerName = $this->configuration->getConsumerName(); + $connectionName = $this->getConsumerConfig()->getConsumer($consumerName)->getConnection(); + + $queue = $this->queueRepository->get($connectionName, $queueName); + $merger = $this->mergerFactory->create($consumerName); + + if (!isset($maxNumberOfMessages)) { + $this->runDaemonMode($queue, $merger); + } else { + $this->run($queue, $merger, $maxNumberOfMessages); + } + } + + /** + * Run process in a daemon mode. + * + * @param QueueInterface $queue + * @param MergerInterface $merger + * @return void + */ + private function runDaemonMode(QueueInterface $queue, MergerInterface $merger) + { + $transactionCallback = $this->getTransactionCallback($queue, $merger); + + while (true) { + $messages = $this->batchSize > 0 + ? $this->getMessages($queue, $this->batchSize) + : $this->getAllMessages($queue); + $transactionCallback($messages); + sleep($this->interval); + } + } + + /** + * Run short running process. + * + * @param QueueInterface $queue + * @param MergerInterface $merger + * @param int $maxNumberOfMessages + * @return void + */ + private function run(QueueInterface $queue, MergerInterface $merger, $maxNumberOfMessages) + { + $count = $maxNumberOfMessages + ? $maxNumberOfMessages + : $this->configuration->getMaxMessages() ?: 1; + $transactionCallback = $this->getTransactionCallback($queue, $merger); + + if ($this->batchSize) { + while ($count > 0) { + $messages = $this->getMessages($queue, $count > $this->batchSize ? $this->batchSize : $count); + $transactionCallback($messages); + $count -= $this->batchSize; + } + } else { + $messages = $this->getMessages($queue, $count); + $transactionCallback($messages); + } + } + + /** + * Get all messages from a queue. + * + * @param QueueInterface $queue + * @return EnvelopeInterface[] + */ + private function getAllMessages(QueueInterface $queue) + { + $messages = []; + while ($message = $queue->dequeue()) { + $messages[] = $message; + } + + return $messages; + } + + /** + * Get $count messages from a queue. + * + * @param QueueInterface $queue + * @param int $count + * @return EnvelopeInterface[] + */ + private function getMessages(QueueInterface $queue, $count) + { + $messages = []; + for ($i = $count; $i > 0; $i--) { + $message = $queue->dequeue(); + if ($message === null) { + break; + } + $messages[] = $message; + } + + return $messages; + } + + /** + * Decode provided messages. + * + * @param EnvelopeInterface[] $messages + * @return object[] + */ + private function decodeMessages(array $messages) + { + $decodedMessages = []; + foreach ($messages as $messageId => $message) { + $properties = $message->getProperties(); + $topicName = $properties['topic_name']; + $decodedMessages[$topicName][$messageId] = $this->messageEncoder->decode($topicName, $message->getBody()); + } + + return $decodedMessages; + } + + /** + * Get transaction callback. + * + * @param QueueInterface $queue + * @param MergerInterface $merger + * @return \Closure + */ + private function getTransactionCallback(QueueInterface $queue, MergerInterface $merger) + { + return function (array $messages) use ($queue, $merger) { + list($messages, $messagesToAcknowledge) = $this->lockMessages($messages); + $decodedMessages = $this->decodeMessages($messages); + $mergedMessages = $merger->merge($decodedMessages); + $messageProcessor = $this->messageProcessorLoader->load($mergedMessages); + $messageProcessor->process( + $queue, + $this->configuration, + $messages, + $messagesToAcknowledge, + $mergedMessages + ); + }; + } + + /** + * Create lock for the messages. + * + * @param array $messages + * @return array + */ + private function lockMessages(array $messages) + { + $toProcess = []; + $toAcknowledge = []; + foreach ($messages as $message) { + try { + $this->getMessageController()->lock($message, $this->configuration->getConsumerName()); + $toProcess[] = $message; + } catch (MessageLockException $exception) { + $toAcknowledge[] = $message; + } + } + return [$toProcess, $toAcknowledge]; + } + + /** + * Get consumer config. + * + * This getter serves as a workaround to add this dependency to this class without breaking constructor structure + * + * @return ConsumerConfig + * + * @deprecated 100.2.0 + */ + private function getConsumerConfig() + { + if ($this->consumerConfig === null) { + $this->consumerConfig = \Magento\Framework\App\ObjectManager::getInstance()->get(ConsumerConfig::class); + } + return $this->consumerConfig; + } + + /** + * Get message controller. + * + * This getter serves as a workaround to add this dependency to this class without breaking constructor structure + * + * @return MessageController + * + * @deprecated 100.1.0 + */ + private function getMessageController() + { + if ($this->messageController === null) { + $this->messageController = \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\MessageQueue\MessageController::class); + } + return $this->messageController; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeFactory.php b/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeFactory.php new file mode 100644 index 0000000000000..47775ac857b07 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeFactory.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Bulk; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\ExchangeInterface + * + * @api + * @since 100.2.0 + */ +class ExchangeFactory implements ExchangeFactoryInterface +{ + /** + * @var ExchangeFactoryInterface[] + */ + private $exchangeFactories; + + /** + * @var \Magento\Framework\MessageQueue\ConnectionTypeResolver + */ + private $connectionTypeResolver; + + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + * @since 100.2.0 + */ + protected $objectManager = null; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\MessageQueue\ConnectionTypeResolver $connectionTypeResolver + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param ExchangeFactoryInterface[] $exchangeFactories + * @since 100.2.0 + */ + public function __construct( + \Magento\Framework\MessageQueue\ConnectionTypeResolver $connectionTypeResolver, + \Magento\Framework\ObjectManagerInterface $objectManager, + array $exchangeFactories = [] + ) { + $this->objectManager = $objectManager; + $this->exchangeFactories = $exchangeFactories; + $this->connectionTypeResolver = $connectionTypeResolver; + } + + /** + * @inheritdoc + * @since 100.2.0 + */ + public function create($connectionName, array $data = []) + { + $connectionType = $this->connectionTypeResolver->getConnectionType($connectionName); + + if (!isset($this->exchangeFactories[$connectionType])) { + throw new \LogicException("Not found exchange for connection name '{$connectionName}' in config"); + } + + $factory = $this->exchangeFactories[$connectionType]; + $exchange = $factory->create($connectionName, $data); + + if (!$exchange instanceof ExchangeInterface) { + $exchangeInterface = \Magento\Framework\MessageQueue\Bulk\ExchangeInterface::class; + throw new \LogicException( + "Exchange for connection name '{$connectionName}' " . + "does not implement interface '{$exchangeInterface}'" + ); + } + return $exchange; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeFactoryInterface.php b/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeFactoryInterface.php new file mode 100644 index 0000000000000..dc691e632c9ed --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeFactoryInterface.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Bulk; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\Bulk\ExchangeInterface + * + * @api + * @since 100.2.0 + */ +interface ExchangeFactoryInterface +{ + /** + * Create exchange instance. + * + * @param string $connectionName + * @param array $data + * @return ExchangeInterface + * @throws \LogicException If exchange is not defined for the specified connection type + * or it doesn't implement ExchangeInterface + * @since 100.2.0 + */ + public function create($connectionName, array $data = []); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeInterface.php b/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeInterface.php new file mode 100644 index 0000000000000..08b64689c2940 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeInterface.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Bulk; + +/** + * Interface for bulk exchange. + * + * @api + * @since 100.2.0 + */ +interface ExchangeInterface +{ + /** + * Send messages in bulk to the queue. + * + * @param string $topic + * @param \Magento\Framework\MessageQueue\EnvelopeInterface[] $envelopes + * @return mixed + * @since 100.2.0 + */ + public function enqueue($topic, array $envelopes); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeRepository.php b/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeRepository.php new file mode 100644 index 0000000000000..dee0ba72c39e2 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Bulk/ExchangeRepository.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Bulk; + +/** + * Used to get exchange instance from the pool. + */ +class ExchangeRepository +{ + /** + * @var ExchangeFactoryInterface + */ + private $exchangeFactory; + + /** + * Pool of exchange instances. + * + * @var ExchangeInterface[] + */ + private $exchangePool = []; + + /** + * @param ExchangeFactoryInterface $exchangeFactory + */ + public function __construct(ExchangeFactoryInterface $exchangeFactory) + { + $this->exchangeFactory = $exchangeFactory; + } + + /** + * Get exchange from the pool for the specified connection type. + * + * @param string $connectionName + * @return ExchangeInterface + * @throws \LogicException + */ + public function getByConnectionName($connectionName) + { + if (!isset($this->exchangePool[$connectionName])) { + $exchange = $this->exchangeFactory->create($connectionName); + $this->exchangePool[$connectionName] = $exchange; + } + return $this->exchangePool[$connectionName]; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Bulk/Publisher.php b/lib/internal/Magento/Framework/MessageQueue/Bulk/Publisher.php new file mode 100644 index 0000000000000..7b71cc451b800 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Bulk/Publisher.php @@ -0,0 +1,98 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Bulk; + +use Magento\Framework\MessageQueue\EnvelopeFactory; +use Magento\Framework\MessageQueue\PublisherInterface; +use Magento\Framework\MessageQueue\MessageEncoder; +use Magento\Framework\MessageQueue\MessageValidator; +use Magento\Framework\MessageQueue\Publisher\ConfigInterface as PublisherConfig; + +/** + * A MessageQueue Publisher to handle publishing messages in bulk. + */ +class Publisher implements PublisherInterface +{ + /** + * @var ExchangeRepository + */ + private $exchangeRepository; + + /** + * @var EnvelopeFactory + */ + private $envelopeFactory; + + /** + * @var MessageEncoder + */ + private $messageEncoder; + + /** + * @var MessageValidator + */ + private $messageValidator; + + /** + * @var PublisherConfig + */ + private $publisherConfig; + + /** + * @var \Magento\Framework\MessageQueue\MessageIdGeneratorInterface + */ + private $messageIdGenerator; + + /** + * @param ExchangeRepository $exchangeRepository + * @param EnvelopeFactory $envelopeFactory + * @param MessageEncoder $messageEncoder + * @param MessageValidator $messageValidator + * @param PublisherConfig $publisherConfig + * @param \Magento\Framework\MessageQueue\MessageIdGeneratorInterface $messageIdGenerator + */ + public function __construct( + ExchangeRepository $exchangeRepository, + EnvelopeFactory $envelopeFactory, + MessageEncoder $messageEncoder, + MessageValidator $messageValidator, + PublisherConfig $publisherConfig, + \Magento\Framework\MessageQueue\MessageIdGeneratorInterface $messageIdGenerator + ) { + $this->exchangeRepository = $exchangeRepository; + $this->envelopeFactory = $envelopeFactory; + $this->messageEncoder = $messageEncoder; + $this->messageValidator = $messageValidator; + $this->publisherConfig = $publisherConfig; + $this->messageIdGenerator = $messageIdGenerator; + } + + /** + * @inheritdoc + */ + public function publish($topicName, $data) + { + $envelopes = []; + foreach ($data as $message) { + $this->messageValidator->validate($topicName, $message); + $message = $this->messageEncoder->encode($topicName, $message); + $envelopes[] = $this->envelopeFactory->create( + [ + 'body' => $message, + 'properties' => [ + 'delivery_mode' => 2, + 'message_id' => $this->messageIdGenerator->generate($topicName), + ] + ] + ); + } + $publisher = $this->publisherConfig->getPublisher($topicName); + $connectionName = $publisher->getConnection()->getName(); + $exchange = $this->exchangeRepository->getByConnectionName($connectionName); + $exchange->enqueue($topicName, $envelopes); + return null; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Bulk/Rpc/Publisher.php b/lib/internal/Magento/Framework/MessageQueue/Bulk/Rpc/Publisher.php new file mode 100644 index 0000000000000..d7570c26bfad9 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Bulk/Rpc/Publisher.php @@ -0,0 +1,112 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Bulk\Rpc; + +use Magento\Framework\MessageQueue\PublisherInterface; +use Magento\Framework\MessageQueue\EnvelopeFactory; +use Magento\Framework\MessageQueue\Bulk\ExchangeRepository; +use PhpAmqpLib\Message\AMQPMessage; +use Magento\Framework\MessageQueue\MessageEncoder; +use Magento\Framework\MessageQueue\MessageValidator; +use Magento\Framework\MessageQueue\Publisher\ConfigInterface as PublisherConfig; +use Magento\Framework\MessageQueue\Rpc\ResponseQueueNameBuilder; + +/** + * A MessageQueue Publisher to handle publishing a message. + */ +class Publisher implements PublisherInterface +{ + /** + * @var ExchangeRepository + */ + private $exchangeRepository; + + /** + * @var EnvelopeFactory + */ + private $envelopeFactory; + + /** + * @var MessageEncoder + */ + private $messageEncoder; + + /** + * @var MessageValidator + */ + private $messageValidator; + + /** + * @var ResponseQueueNameBuilder + */ + private $responseQueueNameBuilder; + + /** + * @var PublisherConfig + */ + private $publisherConfig; + + /** + * @var \Magento\Framework\MessageQueue\MessageIdGeneratorInterface + */ + private $messageIdGenerator; + + /** + * @param ExchangeRepository $exchangeRepository + * @param EnvelopeFactory $envelopeFactory + * @param MessageEncoder $messageEncoder + * @param MessageValidator $messageValidator + * @param ResponseQueueNameBuilder $responseQueueNameBuilder + * @param PublisherConfig $publisherConfig + * @param \Magento\Framework\MessageQueue\MessageIdGeneratorInterface $messageIdGenerator + */ + public function __construct( + ExchangeRepository $exchangeRepository, + EnvelopeFactory $envelopeFactory, + MessageEncoder $messageEncoder, + MessageValidator $messageValidator, + ResponseQueueNameBuilder $responseQueueNameBuilder, + PublisherConfig $publisherConfig, + \Magento\Framework\MessageQueue\MessageIdGeneratorInterface $messageIdGenerator + ) { + $this->exchangeRepository = $exchangeRepository; + $this->envelopeFactory = $envelopeFactory; + $this->messageEncoder = $messageEncoder; + $this->messageValidator = $messageValidator; + $this->responseQueueNameBuilder = $responseQueueNameBuilder; + $this->publisherConfig = $publisherConfig; + $this->messageIdGenerator = $messageIdGenerator; + } + + /** + * @inheritdoc + */ + public function publish($topicName, $data) + { + $envelopes = []; + $replyTo = $this->responseQueueNameBuilder->getQueueName($topicName); + foreach ($data as $message) { + $this->messageValidator->validate($topicName, $message); + $message = $this->messageEncoder->encode($topicName, $message); + $envelope = $this->envelopeFactory->create( + [ + 'body' => $message, + 'properties' => [ + 'reply_to' => $replyTo, + 'delivery_mode' => 2, + 'correlation_id' => rand(), + 'message_id' => $this->messageIdGenerator->generate($topicName), + ] + ] + ); + $envelopes[] = $envelope; + } + $publisher = $this->publisherConfig->getPublisher($topicName); + $connectionName = $publisher->getConnection()->getName(); + $exchange = $this->exchangeRepository->getByConnectionName($connectionName); + return $exchange->enqueue($topicName, $envelopes); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/BulkPublisherInterface.php b/lib/internal/Magento/Framework/MessageQueue/BulkPublisherInterface.php new file mode 100644 index 0000000000000..459966b2c91b8 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/BulkPublisherInterface.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Producer to publish messages in bulk via a specific transport to a specific queue or exchange. + */ +interface BulkPublisherInterface +{ + /** + * Publishes messages in bulk to a specific queue or exchange. + * + * @param string $topicName + * @param array|object $data + * @return null|mixed + */ + public function publish($topicName, $data); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/CallbackInvoker.php b/lib/internal/Magento/Framework/MessageQueue/CallbackInvoker.php new file mode 100644 index 0000000000000..cb80bc4becaec --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/CallbackInvoker.php @@ -0,0 +1,31 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue; + +/** + * Class CallbackInvoker to invoke callbacks for consumer classes + */ +class CallbackInvoker +{ + /** + * Run short running process + * + * @param QueueInterface $queue + * @param int $maxNumberOfMessages + * @param \Closure $callback + * @return void + */ + public function invoke(QueueInterface $queue, $maxNumberOfMessages, $callback) + { + for ($i = $maxNumberOfMessages; $i > 0; $i--) { + do { + $message = $queue->dequeue(); + } while ($message === null && (sleep(1) === 0)); + $callback($message); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Code/Generator/Config/RemoteServiceReader/Communication.php b/lib/internal/Magento/Framework/MessageQueue/Code/Generator/Config/RemoteServiceReader/Communication.php new file mode 100644 index 0000000000000..6219dbf29b14c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Code/Generator/Config/RemoteServiceReader/Communication.php @@ -0,0 +1,106 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Code\Generator\Config\RemoteServiceReader; + +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; +use Magento\Framework\ObjectManager\ConfigInterface as ObjectManagerConfig; +use Magento\Framework\Communication\Config\ReflectionGenerator; +use Magento\Framework\Reflection\MethodsMap as ServiceMethodsMap; +use Magento\Framework\MessageQueue\Code\Generator\RemoteServiceGenerator; + +/** + * Remote service configuration reader. + */ +class Communication implements \Magento\Framework\Config\ReaderInterface +{ + /** + * @var ObjectManagerConfig + */ + private $objectManagerConfig; + + /** + * @var ReflectionGenerator + */ + private $dataGenerator; + + /** + * @var ServiceMethodsMap + */ + private $serviceMethodsMap; + + /** + * Initialize dependencies. + * + * @param ObjectManagerConfig $objectManagerConfig + * @param ReflectionGenerator $dataGenerator + * @param ServiceMethodsMap $serviceMethodsMap + */ + public function __construct( + ObjectManagerConfig $objectManagerConfig, + ReflectionGenerator $dataGenerator, + ServiceMethodsMap $serviceMethodsMap + ) { + $this->objectManagerConfig = $objectManagerConfig; + $this->dataGenerator = $dataGenerator; + $this->serviceMethodsMap = $serviceMethodsMap; + } + + /** + * Generate communication configuration based on remote services declarations in di.xml + * + * @param string|null $scope + * @return array + * @throws \LogicException + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + */ + public function read($scope = null) + { + $preferences = $this->objectManagerConfig->getPreferences(); + $remoteServices = []; + foreach ($preferences as $type => $preference) { + if ($preference == $type . RemoteServiceGenerator::REMOTE_SERVICE_SUFFIX) { + $remoteServices[$type] = $preference; + } + } + $result = []; + foreach ($remoteServices as $serviceInterface => $remoteImplementation) { + try { + $methodsMap = $this->serviceMethodsMap->getMethodsMap($serviceInterface); + } catch (\Exception $e) { + throw new \LogicException(sprintf('Service interface was expected, "%s" given', $serviceInterface)); + } + foreach ($methodsMap as $methodName => $returnType) { + $topicName = $this->dataGenerator->generateTopicName($serviceInterface, $methodName); + $result[$topicName] = $this->dataGenerator->generateTopicConfigForServiceMethod( + $topicName, + $serviceInterface, + $methodName + ); + $result[$topicName][CommunicationConfig::TOPIC_HANDLERS] = []; + } + } + return [CommunicationConfig::TOPICS => $result]; + } + + /** + * Generate topic name based on service type and method name. + * + * Perform the following conversion: + * \Magento\Customer\Api\RepositoryInterface + getById => magento.customer.api.repositoryInterface.getById + * + * @param string $typeName + * @param string $methodName + * @return string + * + * @deprecated 100.2.0 + * @see \Magento\Framework\Communication\Config\ReflectionGenerator::generateTopicName + */ + public function generateTopicName($typeName, $methodName) + { + return $this->dataGenerator->generateTopicName($typeName, $methodName); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Code/Generator/Config/RemoteServiceReader/MessageQueue.php b/lib/internal/Magento/Framework/MessageQueue/Code/Generator/Config/RemoteServiceReader/MessageQueue.php new file mode 100644 index 0000000000000..9412e1c2384f0 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Code/Generator/Config/RemoteServiceReader/MessageQueue.php @@ -0,0 +1,90 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Code\Generator\Config\RemoteServiceReader; + +use Magento\Framework\MessageQueue\ConfigInterface as QueueConfig; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; + +/** + * Remote service configuration reader. + * + * @deprecated 100.2.0 + */ +class MessageQueue implements \Magento\Framework\Config\ReaderInterface +{ + const DEFAULT_PUBLISHER = 'default'; + const DEFAULT_CONNECTION = 'amqp'; + const DEFAULT_EXCHANGE = 'magento'; + + /** + * @var Communication + */ + private $communicationReader; + + /** + * Initialize dependencies. + * + * @param Communication $communicationReader + */ + public function __construct( + Communication $communicationReader + ) { + $this->communicationReader = $communicationReader; + } + + /** + * Generate communication configuration based on remote services declarations in di.xml + * + * @param string|null $scope + * @return array + */ + public function read($scope = null) + { + $remoteServiceTopics = $this->communicationReader->read($scope); + $queueTopics = []; + $queueBinds = []; + $queueExchangeTopicToQueueMap = []; + foreach ($remoteServiceTopics[CommunicationConfig::TOPICS] as $topicName => $communicationConfig) { + $queueTopics[$topicName] = [ + QueueConfig::TOPIC_NAME => $topicName, + QueueConfig::TOPIC_SCHEMA => [ + QueueConfig::TOPIC_SCHEMA_TYPE => QueueConfig::TOPIC_SCHEMA_TYPE_METHOD, + QueueConfig::TOPIC_SCHEMA_VALUE => $communicationConfig[CommunicationConfig::TOPIC_REQUEST] + ], + QueueConfig::TOPIC_RESPONSE_SCHEMA => [ + QueueConfig::TOPIC_SCHEMA_TYPE => isset($communicationConfig[CommunicationConfig::TOPIC_RESPONSE]) + ? QueueConfig::TOPIC_SCHEMA_TYPE_OBJECT + : null, + QueueConfig::TOPIC_SCHEMA_VALUE => $communicationConfig[CommunicationConfig::TOPIC_RESPONSE] + ], + QueueConfig::TOPIC_PUBLISHER => self::DEFAULT_PUBLISHER + ]; + + $queueName = 'queue.' . $topicName; + $queueBinds[$topicName . '--' . self::DEFAULT_EXCHANGE . '--' . $queueName] = [ + QueueConfig::BIND_TOPIC => $topicName, + QueueConfig::BIND_EXCHANGE => self::DEFAULT_EXCHANGE, + QueueConfig::BIND_QUEUE => $queueName, + ]; + + $queueExchangeTopicToQueueMap[self::DEFAULT_EXCHANGE . '--' . $topicName] = [$queueName]; + } + $queuePublishers = [ + self::DEFAULT_PUBLISHER => [ + QueueConfig::PUBLISHER_NAME => self::DEFAULT_PUBLISHER, + QueueConfig::PUBLISHER_CONNECTION => self::DEFAULT_CONNECTION, + QueueConfig::PUBLISHER_EXCHANGE => self::DEFAULT_EXCHANGE + ] + ]; + return [ + QueueConfig::PUBLISHERS => $queuePublishers, + QueueConfig::TOPICS => $queueTopics, + QueueConfig::CONSUMERS => [], + QueueConfig::BINDS => $queueBinds, + QueueConfig::EXCHANGE_TOPIC_TO_QUEUES_MAP => $queueExchangeTopicToQueueMap, + ]; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Code/Generator/RemoteServiceGenerator.php b/lib/internal/Magento/Framework/MessageQueue/Code/Generator/RemoteServiceGenerator.php new file mode 100644 index 0000000000000..0cd62963c547c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Code/Generator/RemoteServiceGenerator.php @@ -0,0 +1,231 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Code\Generator; + +use Magento\Framework\Code\Generator\DefinedClasses; +use Magento\Framework\Code\Generator\Io; +use Magento\Framework\Communication\Config\ReflectionGenerator; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; +use Magento\Framework\MessageQueue\Code\Generator\Config\RemoteServiceReader\Communication as RemoteServiceReader; +use Magento\Framework\Reflection\MethodsMap as ServiceMethodsMap; +use Zend\Code\Reflection\MethodReflection; + +/** + * Code generator for remote services. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class RemoteServiceGenerator extends \Magento\Framework\Code\Generator\EntityAbstract +{ + const ENTITY_TYPE = 'remote'; + const REMOTE_SERVICE_SUFFIX = 'Remote'; + + /** + * @var CommunicationConfig + */ + protected $communicationConfig; + + /** + * @var ServiceMethodsMap + */ + private $serviceMethodsMap; + + /** + * @var ReflectionGenerator + */ + private $reflectionGenerator; + + /** + * Initialize dependencies. + * + * @param CommunicationConfig $communicationConfig + * @param ServiceMethodsMap $serviceMethodsMap + * @param RemoteServiceReader $communicationRemoteServiceReader + * @param string|null $sourceClassName + * @param string|null $resultClassName + * @param Io $ioObject + * @param \Magento\Framework\Code\Generator\CodeGeneratorInterface $classGenerator + * @param DefinedClasses $definedClasses + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __construct( + CommunicationConfig $communicationConfig, + ServiceMethodsMap $serviceMethodsMap, + RemoteServiceReader $communicationRemoteServiceReader, + $sourceClassName = null, + $resultClassName = null, + Io $ioObject = null, + \Magento\Framework\Code\Generator\CodeGeneratorInterface $classGenerator = null, + DefinedClasses $definedClasses = null + ) { + $this->communicationConfig = $communicationConfig; + $this->serviceMethodsMap = $serviceMethodsMap; + parent::__construct( + $sourceClassName, + $resultClassName, + $ioObject, + $classGenerator, + $definedClasses + ); + } + + /** + * {@inheritdoc} + */ + protected function _getDefaultConstructorDefinition() + { + return [ + 'name' => '__construct', + 'parameters' => [ + ['name' => 'publisher', 'type' => '\\' . \Magento\Framework\MessageQueue\PublisherInterface::class], + ], + 'body' => "\$this->publisher = \$publisher;", + 'docblock' => [ + 'shortDescription' => 'Initialize dependencies.', + 'tags' => [ + [ + 'name' => 'param', + 'description' => '\Magento\Framework\MessageQueue\PublisherInterface $publisher', + ], + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + protected function _getClassProperties() + { + return [ + [ + 'name' => 'publisher', + 'visibility' => 'protected', + 'docblock' => [ + 'shortDescription' => 'Publisher', + 'tags' => [ + [ + 'name' => 'var', + 'description' => '\\' . \Magento\Framework\MessageQueue\PublisherInterface::class, + ], + ], + ], + ], + ]; + } + + /** + * {@inheritdoc} + */ + protected function _getClassMethods() + { + $methods = [$this->_getDefaultConstructorDefinition()]; + $interfaceMethodsMap = $this->serviceMethodsMap->getMethodsMap($this->getSourceClassName()); + foreach (array_keys($interfaceMethodsMap) as $methodName) { + // Uses Zend Reflection instead MethodsMap service, because second does not support features of PHP 7.x + $methodReflection = new MethodReflection($this->getSourceClassName(), $methodName); + $sourceMethodParameters = $methodReflection->getParameters(); + $methodParameters = []; + $topicParameters = []; + /** @var \Zend\Code\Reflection\ParameterReflection $methodParameter */ + foreach ($sourceMethodParameters as $methodParameter) { + $parameterName = $methodParameter->getName(); + $parameter = [ + 'name' => $parameterName, + 'type' => $methodParameter->getType(), + ]; + if ($methodParameter->isDefaultValueAvailable()) { + $parameter['defaultValue'] = $methodParameter->getDefaultValue() !== null + ? $methodParameter->getDefaultValue() : $this->_getNullDefaultValue(); + } + $methodParameters[] = $parameter; + $topicParameters[] = "'{$parameterName}' => \${$parameterName}"; + } + $topicName = $this->getReflectionGenerator()->generateTopicName($this->getSourceClassName(), $methodName); + $topicConfig = $this->communicationConfig->getTopic($topicName); + $methodBody = $topicConfig[CommunicationConfig::TOPIC_IS_SYNCHRONOUS] ? 'return ' : ''; + $methodBody .= "\$this->publisher->publish(\n" + . " '{$topicName}',\n" + . " [" . implode(', ', $topicParameters) . "]\n" + . ");"; + $annotations = [['name' => 'inheritdoc']]; + $method = [ + 'name' => $methodName, + 'returnType' => $methodReflection->getReturnType(), + 'parameters' => $methodParameters, + 'body' => $methodBody, + 'docblock' => ['tags' => $annotations], + ]; + $methods[] = $method; + } + return $methods; + } + + /** + * {@inheritdoc} + */ + protected function _validateData() + { + $classNameValidationResults = $this->validateResultClassName(); + return parent::_validateData() && $classNameValidationResults; + } + + /** + * {@inheritdoc} + */ + protected function _generateCode() + { + $this->_classGenerator->setImplementedInterfaces([$this->getSourceClassName()]); + return parent::_generateCode(); + } + + /** + * Ensure that result class name corresponds to the source class name. + * + * @return bool + */ + protected function validateResultClassName() + { + $result = true; + $sourceClassName = $this->getSourceClassName(); + $resultClassName = $this->_getResultClassName(); + $interfaceSuffix = 'Interface'; + if (substr($sourceClassName, -strlen($interfaceSuffix)) !== $interfaceSuffix) { + $this->_addError( + sprintf( + 'Remote service class "%s" should be set as preference for an interface, "%s" given', + $resultClassName, + $sourceClassName + ) + ); + } + $expectedResultClassName = $sourceClassName . self::REMOTE_SERVICE_SUFFIX; + if ($resultClassName !== $expectedResultClassName) { + $this->_addError( + 'Invalid remote service class name [' . $resultClassName . ']. Use ' . $expectedResultClassName + ); + $result = false; + } + return $result; + } + + /** + * Get reflection generator. + * + * @return ReflectionGenerator + * + * @deprecated 100.2.0 + */ + private function getReflectionGenerator() + { + if ($this->reflectionGenerator === null) { + $this->reflectionGenerator = \Magento\Framework\App\ObjectManager::getInstance() + ->get(ReflectionGenerator::class); + } + return $this->reflectionGenerator; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config.php b/lib/internal/Magento/Framework/MessageQueue/Config.php new file mode 100644 index 0000000000000..e29b5d06bee6c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config.php @@ -0,0 +1,207 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; + +/** + * Queue configuration. + * + * @deprecated 100.2.0 + */ +class Config implements ConfigInterface +{ + /** + * @var \Magento\Framework\MessageQueue\Config\Data + */ + protected $queueConfigData; + + /** + * @param Config\Data $queueConfigData + */ + public function __construct(Config\Data $queueConfigData) + { + $this->queueConfigData = $queueConfigData; + } + + /** + * {@inheritdoc} + */ + public function getExchangeByTopic($topicName) + { + $publisherConfig = $this->getPublisherConfigByTopic($topicName); + return isset($publisherConfig[ConfigInterface::PUBLISHER_EXCHANGE]) + ? $publisherConfig[ConfigInterface::PUBLISHER_EXCHANGE] + : null; + } + + /** + * {@inheritdoc} + */ + public function getQueuesByTopic($topic) + { + $publisherConfig = $this->getPublisherConfigByTopic($topic); + $exchange = isset($publisherConfig[ConfigInterface::PUBLISHER_NAME]) + ? $publisherConfig[ConfigInterface::PUBLISHER_NAME] + : null; + /** + * Exchange should be taken into account here to avoid retrieving queues, related to another exchange, + * which is not currently associated with topic, but is configured in binds + */ + $bindKey = $exchange . '--' . $topic; + $output = $this->queueConfigData->get(ConfigInterface::EXCHANGE_TOPIC_TO_QUEUES_MAP . '/' . $bindKey); + if (!$output) { + throw new LocalizedException( + new Phrase( + 'No bindings configured for the "%topic" topic at "%exchange" exchange.', + ['topic' => $topic, 'exchange' => $exchange] + ) + ); + } + return $output; + } + + /** + * {@inheritdoc} + */ + public function getConnectionByTopic($topic) + { + try { + $publisherConfig = $this->getPublisherConfigByTopic($topic); + } catch (\Magento\Framework\Exception\LocalizedException $e) { + return null; + } + return isset($publisherConfig[ConfigInterface::PUBLISHER_CONNECTION]) + ? $publisherConfig[ConfigInterface::PUBLISHER_CONNECTION] + : null; + } + + /** + * {@inheritdoc} + */ + public function getConnectionByConsumer($consumer) + { + $connection = $this->queueConfigData->get( + ConfigInterface::CONSUMERS . '/'. $consumer . '/'. ConfigInterface::CONSUMER_CONNECTION + ); + if (!$connection) { + throw new LocalizedException( + new Phrase('Consumer "%consumer" has not connection.', ['consumer' => $consumer]) + ); + } + return $connection; + } + + /** + * {@inheritdoc} + */ + public function getMessageSchemaType($topic) + { + return $this->queueConfigData->get( + ConfigInterface::TOPICS . '/' . + $topic . '/' . ConfigInterface::TOPIC_SCHEMA . '/' . ConfigInterface::TOPIC_SCHEMA_TYPE + ); + } + + /** + * {@inheritdoc} + */ + public function getConsumerNames() + { + $queueConfig = $this->queueConfigData->get(ConfigInterface::CONSUMERS, []); + return array_keys($queueConfig); + } + + /** + * {@inheritdoc} + */ + public function getConsumer($name) + { + + return $this->queueConfigData->get(ConfigInterface::CONSUMERS . '/' . $name); + } + + /** + * {@inheritdoc} + */ + public function getBinds() + { + return $this->queueConfigData->get(ConfigInterface::BINDS, []); + } + + /** + * {@inheritdoc} + */ + public function getPublishers() + { + return $this->queueConfigData->get(ConfigInterface::PUBLISHERS, []); + } + + /** + * {@inheritdoc} + */ + public function getConsumers() + { + return $this->queueConfigData->get(ConfigInterface::CONSUMERS, []); + } + + /** + * {@inheritdoc} + */ + public function getTopic($name) + { + return $this->queueConfigData->get(ConfigInterface::TOPICS . '/' . $name); + } + + /** + * {@inheritdoc} + */ + public function getPublisher($name) + { + return $this->queueConfigData->get(ConfigInterface::PUBLISHERS . '/' . $name); + } + + /** + * {@inheritdoc} + */ + public function getResponseQueueName($topicName) + { + return ConfigInterface::RESPONSE_QUEUE_PREFIX . str_replace('-', '_', $topicName); + } + + /** + * Get publisher config by topic + * + * @param string $topicName + * @return array|mixed|null + * @throws LocalizedException + */ + protected function getPublisherConfigByTopic($topicName) + { + $publisherName = $this->queueConfigData->get( + ConfigInterface::TOPICS . '/' . $topicName . '/' . ConfigInterface::TOPIC_PUBLISHER + ); + + if (!$publisherName) { + throw new LocalizedException( + new Phrase('Message queue topic "%topic" is not configured.', ['topic' => $topicName]) + ); + } + + $publisherConfig = $this->queueConfigData->get(ConfigInterface::PUBLISHERS . '/' . $publisherName); + if (!$publisherConfig) { + throw new LocalizedException( + new Phrase( + 'Message queue publisher "%publisher" is not configured.', + ['publisher' => $publisherName] + ) + ); + } + return $publisherConfig; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/CompositeReader.php b/lib/internal/Magento/Framework/MessageQueue/Config/CompositeReader.php new file mode 100644 index 0000000000000..370096172865b --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/CompositeReader.php @@ -0,0 +1,87 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Config; + +use Magento\Framework\Config\ReaderInterface; +use Magento\Framework\Phrase; + +/** + * Composite reader for communication config. + */ +class CompositeReader implements ReaderInterface +{ + /** + * @var ReaderInterface[] + */ + private $readers; + + /** + * Initialize dependencies. + * + * @param array $readers + */ + public function __construct(array $readers) + { + $this->readers = []; + $readers = $this->sortReaders($readers); + foreach ($readers as $name => $readerInfo) { + if (!isset($readerInfo['reader']) || !($readerInfo['reader'] instanceof ReaderInterface)) { + throw new \InvalidArgumentException( + new Phrase( + 'Reader [%name] must implement Magento\Framework\Config\ReaderInterface', + ['name' => $name] + ) + ); + } + $this->readers[] = $readerInfo['reader']; + } + } + + /** + * Read config. + * + * @param string|null $scope + * @return array + */ + public function read($scope = null) + { + $result = []; + foreach ($this->readers as $reader) { + $result = array_replace_recursive($result, $reader->read($scope)); + } + return $result; + } + + /** + * Sort readers according to param 'sortOrder' + * + * @param array $readers + * @return array + */ + private function sortReaders(array $readers) + { + usort( + $readers, + function ($firstItem, $secondItem) { + $firstValue = 0; + $secondValue = 0; + if (isset($firstItem['sortOrder'])) { + $firstValue = intval($firstItem['sortOrder']); + } + + if (isset($secondItem['sortOrder'])) { + $secondValue = intval($secondItem['sortOrder']); + } + + if ($firstValue == $secondValue) { + return 0; + } + return $firstValue < $secondValue ? -1 : 1; + } + ); + return $readers; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Consumer/ConfigReaderPlugin.php b/lib/internal/Magento/Framework/MessageQueue/Config/Consumer/ConfigReaderPlugin.php new file mode 100644 index 0000000000000..c791baf4deb66 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Consumer/ConfigReaderPlugin.php @@ -0,0 +1,77 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Config\Consumer; + +use Magento\Framework\MessageQueue\ConfigInterface; +use Magento\Framework\MessageQueue\Consumer\Config\CompositeReader as ConsumerConfigCompositeReader; + +/** + * Plugin which provides access to consumers declared in queue config using consumer config interface. + * + * @deprecated 100.2.0 + */ +class ConfigReaderPlugin +{ + /** + * @var ConfigInterface + */ + private $config; + + /** + * @param ConfigInterface $config + */ + public function __construct(ConfigInterface $config) + { + $this->config = $config; + } + + /** + * Read values from queue config and make them available via consumer config. + * + * @param ConsumerConfigCompositeReader $subject + * @param array $result + * @param string|null $scope + * @return array + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterRead(ConsumerConfigCompositeReader $subject, $result, $scope = null) + { + return array_merge($this->getConsumerConfigDataFromQueueConfig(), $result); + } + + /** + * Get data from queue config in format compatible with consumer config data internal structure. + * + * @return array + */ + private function getConsumerConfigDataFromQueueConfig() + { + $result = []; + + foreach ($this->config->getConsumers() as $consumerData) { + $consumerName = $consumerData['name']; + $handlers = []; + + foreach ($consumerData['handlers'] as $topicHandlers) { + foreach ($topicHandlers as $handlerConfig) { + $handlers[] = $handlerConfig; + } + } + + $result[$consumerName] = [ + 'name' => $consumerName, + 'queue' => $consumerData['queue'], + 'consumerInstance' => $consumerData['instance_type'], + 'handlers' => $handlers, + 'connection' => $consumerData['connection'], + 'maxMessages' => $consumerData['max_messages'] + ]; + } + + return $result; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Data.php b/lib/internal/Magento/Framework/MessageQueue/Config/Data.php new file mode 100644 index 0000000000000..03e01eda5ecd9 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Data.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Config; + +use Magento\Framework\Serialize\SerializerInterface; + +/** + * Class for access to MessageQueue configuration data. + */ +class Data extends \Magento\Framework\Config\Data +{ + /** + * Data constructor + * + * @param CompositeReader $reader + * @param \Magento\Framework\Config\CacheInterface $cache + * @param Reader\Env $envReader + * @param Reader\Env\Validator $envValidator + * @param string|null $cacheId + * @param SerializerInterface|null $serializer + */ + public function __construct( + \Magento\Framework\MessageQueue\Config\CompositeReader $reader, + \Magento\Framework\Config\CacheInterface $cache, + \Magento\Framework\MessageQueue\Config\Reader\Env $envReader, + \Magento\Framework\MessageQueue\Config\Reader\Env\Validator $envValidator, + $cacheId = 'message_queue_config_cache', + SerializerInterface $serializer = null + ) { + parent::__construct($reader, $cache, $cacheId, $serializer); + $envValidator->validate($envReader->read(), $this->get()); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Publisher/ConfigReaderPlugin.php b/lib/internal/Magento/Framework/MessageQueue/Config/Publisher/ConfigReaderPlugin.php new file mode 100644 index 0000000000000..78b82a67069bf --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Publisher/ConfigReaderPlugin.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Config\Publisher; + +use Magento\Framework\MessageQueue\ConfigInterface; +use Magento\Framework\MessageQueue\Publisher\Config\CompositeReader as PublisherConfigCompositeReader; + +/** + * Plugin which provides access to publishers declared in queue config using publisher config interface. + * + * @deprecated 100.2.0 + */ +class ConfigReaderPlugin +{ + /** + * @var ConfigInterface + */ + private $config; + + /** + * @param ConfigInterface $config + */ + public function __construct(ConfigInterface $config) + { + $this->config = $config; + } + + /** + * Read values from queue config and make them available via publisher config + * + * @param PublisherConfigCompositeReader $subject + * @param array $result + * @param string|null $scope + * @return array + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterRead(PublisherConfigCompositeReader $subject, $result, $scope = null) + { + return array_merge($this->getPublisherConfigDataFromQueueConfig(), $result); + } + + /** + * Get data from queue config in format compatible with publisher config data internal structure + * + * @return array + */ + private function getPublisherConfigDataFromQueueConfig() + { + $result = []; + + foreach ($this->config->getBinds() as $bindingConfig) { + $topic = $bindingConfig['topic']; + $result[$topic] = [ + 'topic' => $topic, + 'connection' => [ + 'name' => $this->config->getConnectionByTopic($topic), + 'exchange' => $bindingConfig['exchange'], + 'disabled' => false + ], + 'disabled' => false + ]; + } + + return $result; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Env.php b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Env.php new file mode 100644 index 0000000000000..52e97e80e9dff --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Env.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Config\Reader; + +use Magento\Framework\App\DeploymentConfig; +use Magento\Framework\MessageQueue\Config\Reader\Env\Converter\Publisher as PublisherConverter; +use Magento\Framework\App\ObjectManager; + +/** + * Communication configuration reader. Reads data from env.php. + */ +class Env implements \Magento\Framework\Config\ReaderInterface +{ + const ENV_QUEUE = 'queue'; + const ENV_PUBLISHERS = 'publishers'; + const ENV_TOPICS = 'topics'; + const ENV_CONSUMERS = 'consumers'; + const ENV_CONSUMER_CONNECTION = 'connection'; + const ENV_CONSUMER_MAX_MESSAGES = 'max_messages'; + + /** + * @var DeploymentConfig + */ + private $deploymentConfig; + + /** + * @var PublisherConverter + */ + private $publisherConverter; + + /** + * @param DeploymentConfig $deploymentConfig + * @param PublisherConverter|null $publisherConverter + */ + public function __construct( + DeploymentConfig $deploymentConfig, + PublisherConverter $publisherConverter = null + ) { + $this->deploymentConfig = $deploymentConfig; + $this->publisherConverter = $publisherConverter ?: ObjectManager::getInstance()->get(PublisherConverter::class); + } + + /** + * Read communication configuration from env.php + * + * @param string|null $scope + * @return array + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function read($scope = null) + { + $configData = $this->deploymentConfig->getConfigData(self::ENV_QUEUE) ?: []; + if (isset($configData['config'])) { + $configData = $this->publisherConverter->convert($configData = $configData['config']); + } + return $configData; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Env/Converter/Publisher.php b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Env/Converter/Publisher.php new file mode 100644 index 0000000000000..3ea96bd577ef3 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Env/Converter/Publisher.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Config\Reader\Env\Converter; + +/** + * Converts publisher related data from env.php to MessageQueue config array + */ +class Publisher implements \Magento\Framework\Config\ConverterInterface +{ + /** + * Mapping between connection name and default exchange value + * @var array + */ + private $connectionToExchangeMap; + + /** + * @param array $connectionToExchangeMap + */ + public function __construct( + $connectionToExchangeMap = [] + ) { + $this->connectionToExchangeMap = $connectionToExchangeMap; + } + + /** + * {@inheritDoc} + */ + public function convert($source) + { + $publishersConfig = isset($source[\Magento\Framework\MessageQueue\Config\Reader\Env::ENV_PUBLISHERS]) + ? $source[\Magento\Framework\MessageQueue\Config\Reader\Env::ENV_PUBLISHERS] + : []; + $connections = []; + if (!empty($publishersConfig)) { + foreach ($publishersConfig as $configuration) { + if (isset($configuration['connections'])) { + $publisherData = []; + foreach ($configuration['connections'] as $connectionName => $config) { + if (isset($this->connectionToExchangeMap[$connectionName])) { + $publisherName = $connectionName . '-' . $this->connectionToExchangeMap[$connectionName]; + $config['connection'] = $config['name']; + $config['name'] = $publisherName; + $publisherData[$publisherName] = $config; + $connections = array_replace_recursive($connections, $publisherData); + } + } + } + } + $source[\Magento\Framework\MessageQueue\Config\Reader\Env::ENV_PUBLISHERS] = $connections; + } + return $source; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Env/Validator.php b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Env/Validator.php new file mode 100644 index 0000000000000..43f788343fa88 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Env/Validator.php @@ -0,0 +1,122 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Config\Reader\Env; + +use Magento\Framework\MessageQueue\ConfigInterface as QueueConfig; +use Magento\Framework\MessageQueue\Config\Validator as ConfigValidator; +use Magento\Framework\Reflection\MethodsMap; +use Magento\Framework\Reflection\TypeProcessor; + +/** + * Communication configuration validator. Validates data, that have been read from env.php. + */ +class Validator extends ConfigValidator +{ + /** + * @var MethodsMap + */ + private $methodsMap; + + /** + * Initialize dependencies + * + * @param TypeProcessor $typeProcessor + * @param MethodsMap $methodsMap + */ + public function __construct( + TypeProcessor $typeProcessor, + MethodsMap $methodsMap + ) { + $this->methodsMap = $methodsMap; + parent::__construct($typeProcessor, $methodsMap); + } + + /** + * Validate config data + * + * @param array $configData + * @param array|null $xmlConfigData + * @return void + */ + public function validate($configData, array $xmlConfigData = []) + { + if (isset($configData[QueueConfig::TOPICS])) { + foreach ($configData[QueueConfig::TOPICS] as $topicName => $configDataItem) { + $schemaType = $configDataItem[QueueConfig::TOPIC_SCHEMA][QueueConfig::TOPIC_SCHEMA_VALUE]; + $responseSchemaType = + $configDataItem[QueueConfig::TOPIC_RESPONSE_SCHEMA][QueueConfig::TOPIC_SCHEMA_VALUE]; + $publisherName = $configDataItem[QueueConfig::TOPIC_PUBLISHER]; + $this->validateSchemaType($schemaType, $topicName); + $this->validateResponseSchemaType($responseSchemaType, $topicName); + $this->validateTopicPublisher( + $this->getAvailablePublishers($configData, $xmlConfigData), + $publisherName, + $topicName + ); + } + } + if (isset($configData[QueueConfig::CONSUMERS])) { + foreach ($configData[QueueConfig::CONSUMERS] as $consumerName => $configDataItem) { + $handlers = isset($configDataItem[QueueConfig::CONSUMER_HANDLERS]) + ? $configDataItem[QueueConfig::CONSUMER_HANDLERS] : []; + foreach ($handlers as $handler) { + $this->validateHandlerType( + $handler[QueueConfig::CONSUMER_CLASS], + $handler[QueueConfig::CONSUMER_METHOD], + $consumerName + ); + } + } + } + if (isset($configData[QueueConfig::BINDS])) { + foreach ($configData[QueueConfig::BINDS] as $configDataItem) { + $this->validateBindTopic( + $this->getAvailableTopics($configData, $xmlConfigData), + $configDataItem[QueueConfig::BIND_TOPIC] + ); + } + } + } + + /** + * Return all available publishers from xml and env configs + * + * @param array $configData + * @param array $xmlConfigData + * @return array + */ + private function getAvailablePublishers($configData, $xmlConfigData) + { + $envConfigPublishers = isset($configData[QueueConfig::PUBLISHERS]) ? $configData[QueueConfig::PUBLISHERS] : []; + $xmlConfigPublishers = isset($xmlConfigData[QueueConfig::PUBLISHERS]) + ? $xmlConfigData[QueueConfig::PUBLISHERS] : []; + return array_unique( + array_merge( + array_keys($xmlConfigPublishers), + array_keys($envConfigPublishers) + ) + ); + } + + /** + * Return all available topics from xml and env configs + * + * @param array $configData + * @param array $xmlConfigData + * @return array + */ + private function getAvailableTopics($configData, $xmlConfigData) + { + $envConfigTopics = isset($configData[QueueConfig::TOPICS]) ? $configData[QueueConfig::TOPICS] : []; + $xmlConfigTopics = isset($xmlConfigData[QueueConfig::TOPICS]) ? $xmlConfigData[QueueConfig::TOPICS] : []; + return array_unique( + array_merge( + array_keys($xmlConfigTopics), + array_keys($envConfigTopics) + ) + ); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml.php b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml.php new file mode 100644 index 0000000000000..16efacf628d57 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml.php @@ -0,0 +1,61 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Config\Reader; + +/** + * MessageQueue configuration filesystem loader. Loads all publisher configuration from XML file + * + * @deprecated 100.2.0 + */ +class Xml extends \Magento\Framework\Config\Reader\Filesystem +{ + /** + * List of id attributes for merge + * + * @var array + */ + protected $_idAttributes = [ + '/config/publisher' => 'name', + '/config/consumer' => 'name', + '/config/topic' => 'name', + '/config/bind' => ['queue', 'exchange', 'topic'], + '/config/broker' => 'topic', + '/config/broker/consumer' => 'name' + ]; + + /** + * @param \Magento\Framework\Config\FileResolverInterface $fileResolver + * @param \Magento\Framework\MessageQueue\Config\Reader\Xml\CompositeConverter $converter + * @param \Magento\Framework\MessageQueue\Config\Reader\Xml\SchemaLocator $schemaLocator + * @param \Magento\Framework\Config\ValidationStateInterface $validationState + * @param string $fileName + * @param array $idAttributes + * @param string $domDocumentClass + * @param string $defaultScope + */ + public function __construct( + \Magento\Framework\Config\FileResolverInterface $fileResolver, + \Magento\Framework\MessageQueue\Config\Reader\Xml\CompositeConverter $converter, + \Magento\Framework\MessageQueue\Config\Reader\Xml\SchemaLocator $schemaLocator, + \Magento\Framework\Config\ValidationStateInterface $validationState, + $fileName = 'queue.xml', + $idAttributes = [], + $domDocumentClass = \Magento\Framework\Config\Dom::class, + $defaultScope = 'global' + ) { + parent::__construct( + $fileResolver, + $converter, + $schemaLocator, + $validationState, + $fileName, + $idAttributes, + $domDocumentClass, + $defaultScope + ); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml/CompositeConverter.php b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml/CompositeConverter.php new file mode 100644 index 0000000000000..be375c1ac817d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml/CompositeConverter.php @@ -0,0 +1,86 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Config\Reader\Xml; + +use Magento\Framework\Config\ConverterInterface; +use Magento\Framework\Phrase; + +/** + * Converts MessageQueue config from \DOMDocument to array + * + * @deprecated 100.2.0 + */ +class CompositeConverter implements ConverterInterface +{ + /** + * @var ConverterInterface[] + */ + private $converters; + + /** + * Initialize dependencies. + * + * @param array $converters + */ + public function __construct(array $converters) + { + $this->converters = []; + $converters = $this->sortConverters($converters); + foreach ($converters as $name => $converterInfo) { + if (!isset($converterInfo['converter']) || !($converterInfo['converter'] instanceof ConverterInterface)) { + throw new \InvalidArgumentException( + new Phrase( + 'Converter [%name] must implement Magento\Framework\Config\ConverterInterface', + ['name' => $name] + ) + ); + } + $this->converters[] = $converterInfo['converter']; + } + } + + /** + * {@inheritdoc} + */ + public function convert($source) + { + $result = []; + foreach ($this->converters as $converter) { + $result = array_replace_recursive($result, $converter->convert($source)); + } + return $result; + } + + /** + * Sort converters according to param 'sortOrder' + * + * @param array $converters + * @return array + */ + private function sortConverters(array $converters) + { + usort( + $converters, + function ($firstItem, $secondItem) { + $firstValue = 0; + $secondValue = 0; + if (isset($firstItem['sortOrder'])) { + $firstValue = intval($firstItem['sortOrder']); + } + + if (isset($secondItem['sortOrder'])) { + $secondValue = intval($secondItem['sortOrder']); + } + + if ($firstValue == $secondValue) { + return 0; + } + return $firstValue < $secondValue ? -1 : 1; + } + ); + return $converters; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml/Converter/TopicConfig.php b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml/Converter/TopicConfig.php new file mode 100644 index 0000000000000..e33d6ab5b1fb8 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml/Converter/TopicConfig.php @@ -0,0 +1,313 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Config\Reader\Xml\Converter; + +use Magento\Framework\MessageQueue\ConfigInterface; +use Magento\Framework\MessageQueue\Config\Validator; +use Magento\Framework\Reflection\MethodsMap; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; +use Magento\Framework\MessageQueue\ConfigInterface as QueueConfig; +use Magento\Framework\MessageQueue\ConsumerInterface; + +/** + * Converts MessageQueue config from \DOMDocument to array + * + * @deprecated 100.2.0 + */ +class TopicConfig implements \Magento\Framework\Config\ConverterInterface +{ + const DEFAULT_TYPE = 'amqp'; + const DEFAULT_EXCHANGE = 'magento'; + const DEFAULT_INSTANCE = ConsumerInterface::class; + + /** + * @var Validator + */ + private $xmlValidator; + + /** + * @var MethodsMap + */ + private $methodsMap; + + /** + * @var CommunicationConfig + */ + private $communicationConfig; + + /** + * Initialize dependencies. + * + * @param MethodsMap $methodsMap + * @param Validator $xmlValidator + * @param CommunicationConfig $communicationConfig + */ + public function __construct( + MethodsMap $methodsMap, + Validator $xmlValidator, + CommunicationConfig $communicationConfig + ) { + $this->methodsMap = $methodsMap; + $this->xmlValidator = $xmlValidator; + $this->communicationConfig = $communicationConfig; + } + + /** + * {@inheritDoc} + */ + public function convert($source) + { + $topics = $this->extractTopics($source); + $topics = $this->processWildcard($topics); + $publishers = $this->buildPublishers($topics); + $binds = $this->buildBinds($topics); + $map = $this->buildExchangeTopicToQueue($topics); + $consumers = $this->buildConsumers($topics); + return [ + ConfigInterface::TOPICS => $this->buildTopicsConfiguration($topics), + ConfigInterface::PUBLISHERS => $publishers, + ConfigInterface::BINDS => $binds, + ConfigInterface::CONSUMERS => $consumers, + ConfigInterface::EXCHANGE_TOPIC_TO_QUEUES_MAP => $map, + ]; + } + + /** + * Generate list of topics. + * + * @param array $topics + * @return array + */ + private function buildTopicsConfiguration($topics) + { + $output = []; + foreach ($topics as $topicName => $topicConfig) { + $topicDefinition = $this->communicationConfig->getTopic($topicName); + $schemaType = + $topicDefinition['request_type'] == CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS + ? QueueConfig::TOPIC_SCHEMA_TYPE_OBJECT + : QueueConfig::TOPIC_SCHEMA_TYPE_METHOD; + $schemaValue = $topicDefinition[CommunicationConfig::TOPIC_REQUEST]; + $output[$topicName] = [ + 'name' => $topicName, + 'schema' => [ + 'schema_type' => $schemaType, + 'schema_value' => $schemaValue + ], + 'response_schema' => [ + 'schema_type' => isset($topicDefinition['response']) ? QueueConfig::TOPIC_SCHEMA_TYPE_OBJECT : null, + 'schema_value' => $topicDefinition['response'] + ], + 'is_synchronous' => $topicDefinition[CommunicationConfig::TOPIC_IS_SYNCHRONOUS], + 'publisher' => $topicConfig['type'] . '-' . $topicConfig['exchange'] + ]; + } + return $output; + } + + /** + * Generate consumers. + * + * @param array $topics + * @return array + */ + private function buildConsumers($topics) + { + $output = []; + foreach ($topics as $topicName => $topicConfig) { + $topic = $this->communicationConfig->getTopic($topicName); + foreach ($topicConfig['queues'] as $queueName => $queueConfig) { + $handlers = []; + foreach ($queueConfig['handlers'] as $handler) { + if (!isset($handler[QueueConfig::CONSUMER_CLASS])) { + $handlerExploded = explode('::', $handler); + unset($handler); + $handler[QueueConfig::CONSUMER_CLASS] = $handlerExploded[0]; + $handler[QueueConfig::CONSUMER_METHOD] = $handlerExploded[1]; + } + $handlers[] = $handler; + } + $queueConfig['handlers'] = $handlers; + + $output[$queueConfig['consumer']] = [ + 'name' => $queueConfig['consumer'], + 'queue' => $queueName, + 'handlers' => [$topicName => $queueConfig['handlers']], + 'instance_type' => $queueConfig['consumerInstance'] != null + ? $queueConfig['consumerInstance'] : self::DEFAULT_INSTANCE, + 'consumer_type' => $topic[CommunicationConfig::TOPIC_IS_SYNCHRONOUS] ? 'sync' : 'async', + 'max_messages' => $queueConfig['maxMessages'], + 'connection' => $topicConfig['type'] + ]; + } + } + return $output; + } + + /** + * Generate topics list based on wildcards. + * + * @param array $topics + * @return array + */ + private function processWildcard($topics) + { + $topicDefinitions = $this->communicationConfig->getTopics(); + $wildcardKeys = []; + $topicNames = array_keys($topics); + foreach ($topicNames as $topicName) { + if (strpos($topicName, '*') !== false || strpos($topicName, '#') !== false) { + $wildcardKeys[] = $topicName; + } + } + foreach (array_unique($wildcardKeys) as $wildcardKey) { + $pattern = $this->xmlValidator->buildWildcardPattern($wildcardKey); + foreach (array_keys($topicDefinitions) as $topicName) { + if (preg_match($pattern, $topicName)) { + if (isset($topics[$topicName])) { + $topics[$topicName] = array_merge($topics[$topicName], $topics[$wildcardKey]); + } else { + $topics[$topicName] = $topics[$wildcardKey]; + } + } + } + unset($topics[$wildcardKey]); + } + return $topics; + } + + /** + * Generate publishers + * + * @param array $topics + * @return array + */ + private function buildPublishers($topics) + { + $output = []; + foreach ($topics as $topicConfig) { + $publisherName = $topicConfig['type'] . '-' . $topicConfig['exchange']; + $output[$publisherName] = [ + 'name' => $publisherName, + 'connection' => $topicConfig['type'], + 'exchange' => $topicConfig['exchange'] + ]; + } + return $output; + } + + /** + * Generate binds + * + * @param array $topics + * @return array + */ + private function buildBinds($topics) + { + $output = []; + foreach ($topics as $topicName => $topicConfig) { + $queueNames = array_keys($topicConfig['queues']); + foreach ($queueNames as $queueName) { + $name = $topicName . '--' . $topicConfig['exchange']. '--' .$queueName; + $output[$name] = [ + 'queue' => $queueName, + 'exchange' => $topicConfig['exchange'], + 'topic' => $topicName, + ]; + } + } + return $output; + } + + /** + * Generate topic-to-queues map. + * + * @param array $topics + * @return array + */ + private function buildExchangeTopicToQueue($topics) + { + $output = []; + foreach ($topics as $topicName => $topicConfig) { + $key = $topicConfig['type'] . '-' . $topicConfig['exchange'] . '--' . $topicName; + $queueNames = array_keys($topicConfig['queues']); + foreach ($queueNames as $queueName) { + $output[$key][] = $queueName; + $output[$key] = array_unique($output[$key]); + } + } + return $output; + } + + /** + * Extract topics configuration. + * + * @param \DOMDocument $config + * @return array + */ + private function extractTopics($config) + { + $output = []; + /** @var $brokerNode \DOMElement */ + foreach ($config->getElementsByTagName('broker') as $brokerNode) { + $topicName = $this->getAttributeValue($brokerNode, 'topic'); + $output[$topicName] = [ + ConfigInterface::TOPIC_NAME => $topicName, + 'type' => $this->getAttributeValue($brokerNode, 'type', self::DEFAULT_TYPE), + 'exchange' => $this->getAttributeValue($brokerNode, 'exchange', self::DEFAULT_EXCHANGE), + 'consumerInstance' => $this->getAttributeValue($brokerNode, 'consumerInstance'), + 'maxMessages' => $this->getAttributeValue($brokerNode, 'maxMessages'), + 'queues' => $this->extractQueuesFromBroker($brokerNode, $topicName) + ]; + } + return $output; + } + + /** + * Extract queues configuration from the topic node. + * + * @param \DOMElement $brokerNode + * @param string $topicName + * @return array + */ + protected function extractQueuesFromBroker(\DOMElement $brokerNode, $topicName) + { + $queues = []; + $topicConfig = $this->communicationConfig->getTopic($topicName); + /** @var $queueNode \DOMElement */ + foreach ($brokerNode->getElementsByTagName('queue') as $queueNode) { + $handler = $this->getAttributeValue($queueNode, 'handler'); + $queueName = $this->getAttributeValue($queueNode, 'name'); + $queue = [ + 'name'=> $queueName, + 'handlerName' => $this->getAttributeValue($queueNode, 'handlerName'), + 'handlers' => $handler ? ['default' => $handler] : $topicConfig['handlers'], + 'exchange' => $this->getAttributeValue($queueNode, 'exchange'), + 'consumer' => $this->getAttributeValue($queueNode, 'consumer'), + 'consumerInstance' => $this->getAttributeValue($queueNode, 'consumerInstance'), + 'maxMessages' => $this->getAttributeValue($queueNode, 'maxMessages', null), + 'type' => $this->getAttributeValue($queueNode, 'type') + + ]; + $queues[$queueName] = $queue; + } + return $queues; + } + + /** + * Get attribute value of the given node + * + * @param \DOMNode $node + * @param string $attributeName + * @param mixed $default + * @return string|null + */ + protected function getAttributeValue(\DOMNode $node, $attributeName, $default = null) + { + $item = $node->attributes->getNamedItem($attributeName); + return $item ? $item->nodeValue : $default; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml/SchemaLocator.php b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml/SchemaLocator.php new file mode 100644 index 0000000000000..613d564942e2f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Reader/Xml/SchemaLocator.php @@ -0,0 +1,60 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Config\Reader\Xml; + +/** + * Schema locator for Publishers + * + * @deprecated 100.2.0 + */ +class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface +{ + /** + * Path to corresponding XSD file with validation rules for merged config + * + * @var string + */ + protected $schema; + + /** + * Path to corresponding XSD file with validation rules for separate config files + * + * @var string + */ + protected $perFileSchema; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\Config\Dom\UrnResolver $urnResolver + */ + public function __construct(\Magento\Framework\Config\Dom\UrnResolver $urnResolver) + { + $this->schema = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/queue_merged.xsd'); + $this->perFileSchema = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/queue.xsd'); + } + + /** + * Get path to merged config schema + * + * @return string|null + */ + public function getSchema() + { + return $this->schema; + } + + /** + * Get path to per file validation schema + * + * @return string|null + */ + public function getPerFileSchema() + { + return $this->perFileSchema; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Topology/ConfigReaderPlugin.php b/lib/internal/Magento/Framework/MessageQueue/Config/Topology/ConfigReaderPlugin.php new file mode 100644 index 0000000000000..b5f8d179961c6 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Topology/ConfigReaderPlugin.php @@ -0,0 +1,102 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Config\Topology; + +use Magento\Framework\MessageQueue\ConfigInterface as QueueConfig; + +/** + * Plugin which provides access to topology declared in queue config using topology config interface. + * + * @deprecated 100.2.0 + */ +class ConfigReaderPlugin +{ + /** + * @var QueueConfig + */ + private $queueConfig; + + /** + * Initialize dependencies. + * + * @param QueueConfig $queueConfig + */ + public function __construct(QueueConfig $queueConfig) + { + $this->queueConfig = $queueConfig; + } + + /** + * Read values from queue config and make them available via topology config. + * + * @param \Magento\Framework\MessageQueue\Topology\Config\CompositeReader $subject + * @param array $result + * @param string|null $scope + * @return array + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function afterRead( + \Magento\Framework\MessageQueue\Topology\Config\CompositeReader $subject, + array $result, + $scope = null + ) { + $topologyConfigDataFromQueueConfig = $this->getTopologyConfigDataFromQueueConfig(); + foreach ($topologyConfigDataFromQueueConfig as $exchangeKey => $exchangeConfig) { + if (isset($result[$exchangeKey])) { + $result[$exchangeKey]['bindings'] = array_merge( + $exchangeConfig['bindings'], + $result[$exchangeKey]['bindings'] + ); + } else { + $result[$exchangeKey] = $exchangeConfig; + } + } + return $result; + } + + /** + * Get data from queue config in format compatible with topology config data internal structure. + * + * @return array + */ + private function getTopologyConfigDataFromQueueConfig() + { + $result = []; + foreach ($this->queueConfig->getBinds() as $queueConfigBinding) { + $topic = $queueConfigBinding['topic']; + $destinationType = 'queue'; + $destination = $queueConfigBinding['queue']; + $bindingId = $destinationType . '--' . $destination . '--' . $topic; + $bindingData = [ + 'id' => $bindingId, + 'destinationType' => $destinationType, + 'destination' => $destination, + 'disabled' => false, + 'topic' => $topic, + 'arguments' => [] + ]; + + $exchangeName = $queueConfigBinding['exchange']; + $connection = $this->queueConfig->getConnectionByTopic($topic); + if (isset($result[$exchangeName . '--' . $connection])) { + $result[$exchangeName . '--' . $connection]['bindings'][$bindingId] = $bindingData; + } else { + $result[$exchangeName . '--' . $connection] = [ + 'name' => $exchangeName, + 'type' => 'topic', + 'connection' => $connection, + 'durable' => true, + 'autoDelete' => false, + 'internal' => false, + 'bindings' => [$bindingId => $bindingData], + 'arguments' => [], + ]; + } + } + return $result; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Config/Validator.php b/lib/internal/Magento/Framework/MessageQueue/Config/Validator.php new file mode 100644 index 0000000000000..47a2a4b8eed0a --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Config/Validator.php @@ -0,0 +1,227 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Config; + +use Magento\Framework\Reflection\MethodsMap; +use Magento\Framework\Reflection\TypeProcessor; + +/** + * Communication configuration validator. + */ +class Validator +{ + /** + * @var MethodsMap + */ + private $methodsMap; + + /** + * @var TypeProcessor + */ + private $typeProcessor; + + /** + * Initialize dependencies. + * + * @param TypeProcessor $typeProcessor + * @param MethodsMap $methodsMap + */ + public function __construct( + TypeProcessor $typeProcessor, + MethodsMap $methodsMap + ) { + $this->typeProcessor = $typeProcessor; + $this->methodsMap = $methodsMap; + } + + /** + * Validate schema Method Type + * + * @param string $schemaType + * @param string $schemaMethod + * @param string $topicName + * @return void + * @throws \LogicException + */ + public function validateSchemaMethodType($schemaType, $schemaMethod, $topicName) + { + try { + $this->methodsMap->getMethodParams($schemaType, $schemaMethod); + } catch (\Exception $e) { + throw new \LogicException( + sprintf( + 'Service method specified for topic "%s" is not available. Given "%s"', + $topicName, + $schemaType . '::' . $schemaMethod + ) + ); + } + } + + /** + * Validate handler type + * + * @param string $serviceName + * @param string $methodName + * @param string $consumerName + * @return void + * @throws \LogicException + */ + public function validateHandlerType($serviceName, $methodName, $consumerName) + { + try { + $this->methodsMap->getMethodParams($serviceName, $methodName); + } catch (\Exception $e) { + throw new \LogicException( + sprintf( + 'Service method specified in handler for consumer "%s"' + . ' is not available. Given "%s"', + $consumerName, + $serviceName . '::' . $methodName + ) + ); + } + } + + /** + * Validate topic in a bind + * + * @param string[] $topics + * @param string $topicName + * @return void + * @throws \LogicException + */ + public function validateBindTopic($topics, $topicName) + { + $isDefined = false; + if (strpos($topicName, '#') === false && strpos($topicName, '*') === false) { + if (in_array($topicName, $topics)) { + $isDefined = true; + } + } else { + $pattern = $this->buildWildcardPattern($topicName); + if (count(preg_grep($pattern, $topics))) { + $isDefined = true; + } + } + if (!$isDefined) { + throw new \LogicException( + sprintf('Topic "%s" declared in binds must be defined in topics', $topicName) + ); + } + } + + /** + * Construct perl regexp pattern for matching topic names from wildcard key. + * + * @param string $wildcardKey + * @return string + */ + public function buildWildcardPattern($wildcardKey) + { + $pattern = '/^' . str_replace('.', '\.', $wildcardKey); + $pattern = str_replace('#', '.+', $pattern); + $pattern = str_replace('*', '[^\.]+', $pattern); + if (strpos($wildcardKey, '#') === strlen($wildcardKey)) { + $pattern .= '/'; + } else { + $pattern .= '$/'; + } + + return $pattern; + } + + /** + * Validate publisher in the topic + * + * @param string[] $publishers + * @param string $publisherName + * @param string $topicName + * @return void + * @throws \LogicException + */ + public function validateTopicPublisher($publishers, $publisherName, $topicName) + { + if (!in_array($publisherName, $publishers)) { + throw new \LogicException( + sprintf( + 'Publisher "%s", specified in env.php for topic "%s" is not declared.', + $publisherName, + $topicName + ) + ); + } + } + + /** + * Validate response schema type + * + * @param string $responseSchema + * @param string $topicName + * @return void + * @throws \LogicException + */ + public function validateResponseSchemaType($responseSchema, $topicName) + { + try { + $this->validateType($responseSchema); + } catch (\Exception $e) { + throw new \LogicException( + sprintf( + 'Response schema definition for topic "%s" should reference existing type or service class. ' + . 'Given "%s"', + $topicName, + $responseSchema + ) + ); + } + } + + /** + * Validate schema type + * + * @param string $schema + * @param string $topicName + * @return void + * @throws \LogicException + */ + public function validateSchemaType($schema, $topicName) + { + try { + $this->validateType($schema); + } catch (\Exception $e) { + throw new \LogicException( + sprintf( + 'Schema definition for topic "%s" should reference existing type or service class. ' + . 'Given "%s"', + $topicName, + $schema + ) + ); + } + } + + /** + * Ensure that specified type is either a simple type or a valid service data type. + * + * @param string $typeName + * @return $this + * @throws \Exception In case when type is invalid + */ + protected function validateType($typeName) + { + if ($this->typeProcessor->isTypeSimple($typeName)) { + return $this; + } + if ($this->typeProcessor->isArrayType($typeName)) { + $arrayItemType = $this->typeProcessor->getArrayItemType($typeName); + $this->methodsMap->getMethodsMap($arrayItemType); + } else { + $this->methodsMap->getMethodsMap($typeName); + } + return $this; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ConfigInterface.php b/lib/internal/Magento/Framework/MessageQueue/ConfigInterface.php new file mode 100644 index 0000000000000..a88b5dedbd269 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ConfigInterface.php @@ -0,0 +1,187 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\Exception\LocalizedException; + +/** + * @deprecated 100.2.0 + */ +interface ConfigInterface +{ + const PUBLISHERS = 'publishers'; + const PUBLISHER_NAME = 'name'; + const PUBLISHER_CONNECTION = 'connection'; + const PUBLISHER_EXCHANGE = 'exchange'; + + const TOPICS = 'topics'; + const TOPIC_NAME = 'name'; + const TOPIC_PUBLISHER = 'publisher'; + const TOPIC_SCHEMA = 'schema'; + const TOPIC_RESPONSE_SCHEMA = 'response_schema'; + const TOPIC_SCHEMA_TYPE = 'schema_type'; + const TOPIC_SCHEMA_VALUE = 'schema_value'; + + const TOPIC_SCHEMA_TYPE_OBJECT = 'object'; + const TOPIC_SCHEMA_TYPE_METHOD = 'method_arguments'; + + const SCHEMA_METHOD_PARAM_NAME = 'param_name'; + const SCHEMA_METHOD_PARAM_POSITION = 'param_position'; + const SCHEMA_METHOD_PARAM_TYPE = 'param_type'; + const SCHEMA_METHOD_PARAM_IS_REQUIRED = 'is_required'; + + const CONSUMERS = 'consumers'; + const CONSUMER_NAME = 'name'; + const CONSUMER_QUEUE = 'queue'; + const CONSUMER_CONNECTION = 'connection'; + const CONSUMER_INSTANCE_TYPE = 'instance_type'; + const CONSUMER_CLASS = 'type'; + const CONSUMER_METHOD = 'method'; + const CONSUMER_MAX_MESSAGES = 'max_messages'; + const CONSUMER_HANDLERS = 'handlers'; + const CONSUMER_HANDLER_TYPE = 'type'; + const CONSUMER_HANDLER_METHOD = 'method'; + const CONSUMER_TYPE = 'consumer_type'; + const CONSUMER_TYPE_SYNC = 'sync'; + const CONSUMER_TYPE_ASYNC = 'async'; + + const RESPONSE_QUEUE_PREFIX = 'responseQueue.'; + + const BINDS = 'binds'; + const BIND_QUEUE = 'queue'; + const BIND_EXCHANGE = 'exchange'; + const BIND_TOPIC = 'topic'; + + const BROKER_TOPIC = 'topic'; + const BROKER_TYPE = 'type'; + const BROKER_EXCHANGE = 'exchange'; + const BROKER_CONSUMERS = 'consumers'; + const BROKER_CONSUMER_NAME = 'name'; + const BROKER_CONSUMER_QUEUE = 'queue'; + const BROKER_CONSUMER_INSTANCE_TYPE = 'instance_type'; + const BROKER_CONSUMER_MAX_MESSAGES = 'max_messages'; + const BROKERS = 'brokers'; + + /** + * Map which allows optimized search of queues corresponding to the specified exchange and topic pair. + */ + const EXCHANGE_TOPIC_TO_QUEUES_MAP = 'exchange_topic_to_queues_map'; + + /** + * Identify configured exchange for the provided topic. + * + * @param string $topicName + * @return string + * @throws LocalizedException + * @see \Magento\Framework\MessageQueue\Publisher\ConfigInterface::getPublisher + */ + public function getExchangeByTopic($topicName); + + /** + * Identify a list of all queue names corresponding to the specified topic (and implicitly exchange). + * + * @param string $topic + * @return string[] + * @throws LocalizedException + * @see \Magento\Framework\MessageQueue\Topology\ConfigInterface::getQueues + */ + public function getQueuesByTopic($topic); + + /** + * @param string $topic + * @return string + * @throws LocalizedException + * @see \Magento\Framework\MessageQueue\Publisher\ConfigInterface::getPublisher + */ + public function getConnectionByTopic($topic); + + /** + * @param string $consumer + * @return string + * @throws LocalizedException + * @see \Magento\Framework\MessageQueue\Consumer\ConfigInterface::getConsumer + */ + public function getConnectionByConsumer($consumer); + + /** + * Identify which option is used to define message schema: data interface or service method params + * + * @param string $topic + * @return string + * @see \Magento\Framework\Communication\ConfigInterface::getTopic + */ + public function getMessageSchemaType($topic); + + /** + * Get all consumer names + * + * @return string[] + * @see \Magento\Framework\MessageQueue\Consumer\ConfigInterface::getConsumers + */ + public function getConsumerNames(); + + /** + * Get consumer configuration + * + * @param string $name + * @return array|null + * @see \Magento\Framework\MessageQueue\Consumer\ConfigInterface::getConsumer + */ + public function getConsumer($name); + + /** + * Get queue binds + * + * @return array + * @see \Magento\Framework\MessageQueue\Topology\ConfigInterface::getExchanges + */ + public function getBinds(); + + /** + * Get publishers + * + * @return array + * @see \Magento\Framework\MessageQueue\Publisher\ConfigInterface::getPublishers + */ + public function getPublishers(); + + /** + * Get consumers + * + * @return array + * @see \Magento\Framework\MessageQueue\Consumer\ConfigInterface::getConsumers + */ + public function getConsumers(); + + /** + * Get topic config + * + * @param string $name + * @return array + * @see \Magento\Framework\Communication\ConfigInterface::getTopic + * @see \Magento\Framework\MessageQueue\Publisher\ConfigInterface::getPublisher + */ + public function getTopic($name); + + /** + * Get published config + * @param string $name + * + * @return array + * @see \Magento\Framework\MessageQueue\Publisher\ConfigInterface::getPublisher + */ + public function getPublisher($name); + + /** + * Get queue name for response + * + * @param string $topicName + * @return string + * @see \Magento\Framework\MessageQueue\Rpc\ResponseQueueNameBuilder::getQueueName + */ + public function getResponseQueueName($topicName); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ConnectionLostException.php b/lib/internal/Magento/Framework/MessageQueue/ConnectionLostException.php new file mode 100644 index 0000000000000..e22ac3184ae6b --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ConnectionLostException.php @@ -0,0 +1,13 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Class ConnectionLostException + */ +class ConnectionLostException extends \Exception +{ +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ConnectionTypeResolver.php b/lib/internal/Magento/Framework/MessageQueue/ConnectionTypeResolver.php new file mode 100644 index 0000000000000..7d9756c92988b --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ConnectionTypeResolver.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * {@inheritdoc} + */ +class ConnectionTypeResolver +{ + /** + * @var ConnectionTypeResolverInterface[] + */ + private $resolvers; + + /** + * Initialize dependencies. + * + * @param ConnectionTypeResolverInterface[] $resolvers + */ + public function __construct($resolvers) + { + $this->resolvers = $resolvers; + } + + /** + * {@inheritdoc} + */ + public function getConnectionType($connectionName) + { + $type = null; + + foreach ($this->resolvers as $resolver) { + $type = $resolver->getConnectionType($connectionName); + if ($type != null) { + break; + } + } + + if ($type === null) { + throw new \LogicException('Unknown connection name ' . $connectionName); + } + return $type; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ConnectionTypeResolverInterface.php b/lib/internal/Magento/Framework/MessageQueue/ConnectionTypeResolverInterface.php new file mode 100644 index 0000000000000..20c1a8ebffe03 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ConnectionTypeResolverInterface.php @@ -0,0 +1,20 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Message Queue connection type resolver. + */ +interface ConnectionTypeResolverInterface +{ + /** + * Get connection type by connection name. + * + * @param string $connectionName + * @return string|null + */ + public function getConnectionType($connectionName); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer.php b/lib/internal/Magento/Framework/MessageQueue/Consumer.php new file mode 100644 index 0000000000000..9bdacfbc1ff6c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer.php @@ -0,0 +1,331 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; +use Magento\Framework\MessageQueue\Consumer\ConfigInterface as ConsumerConfig; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; +use Magento\Framework\MessageQueue\QueueRepository; +use Psr\Log\LoggerInterface; + +/** + * Class Consumer used to process a single message, unlike batch consumer. + * + * This could be used for both synchronous and asynchronous processing, depending on topic. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class Consumer implements ConsumerInterface +{ + /** + * @var ConsumerConfigurationInterface + */ + private $configuration; + + /** + * @var ResourceConnection + */ + private $resource; + + /** + * @var MessageEncoder + */ + private $messageEncoder; + + /** + * @var CallbackInvoker + */ + private $invoker; + + /** + * @var MessageController + */ + private $messageController; + + /** + * @var QueueRepository + */ + private $queueRepository; + + /** + * @var EnvelopeFactory + */ + private $envelopeFactory; + + /** + * @var MessageValidator + */ + private $messageValidator; + + /** + * @var ConsumerConfig + */ + private $consumerConfig; + + /** + * @var CommunicationConfig + */ + private $communicationConfig; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * Initialize dependencies. + * + * @param CallbackInvoker $invoker + * @param MessageEncoder $messageEncoder + * @param ResourceConnection $resource + * @param ConsumerConfigurationInterface $configuration + * @param LoggerInterface $logger + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __construct( + CallbackInvoker $invoker, + MessageEncoder $messageEncoder, + ResourceConnection $resource, + ConsumerConfigurationInterface $configuration, + LoggerInterface $logger = null + ) { + $this->invoker = $invoker; + $this->messageEncoder = $messageEncoder; + $this->resource = $resource; + $this->configuration = $configuration; + $this->logger = $logger ?: \Magento\Framework\App\ObjectManager::getInstance()->get(LoggerInterface::class); + } + + /** + * {@inheritdoc} + */ + public function process($maxNumberOfMessages = null) + { + $queue = $this->configuration->getQueue(); + + if (!isset($maxNumberOfMessages)) { + $queue->subscribe($this->getTransactionCallback($queue)); + } else { + $this->invoker->invoke($queue, $maxNumberOfMessages, $this->getTransactionCallback($queue)); + } + } + + /** + * Decode message and invoke callback method, return reply back for sync processing. + * + * @param EnvelopeInterface $message + * @param boolean $isSync + * @return string|null + * @throws LocalizedException + */ + private function dispatchMessage(EnvelopeInterface $message, $isSync = false) + { + $properties = $message->getProperties(); + $topicName = $properties['topic_name']; + $handlers = $this->configuration->getHandlers($topicName); + $decodedMessage = $this->messageEncoder->decode($topicName, $message->getBody()); + + if (isset($decodedMessage)) { + $messageSchemaType = $this->configuration->getMessageSchemaType($topicName); + if ($messageSchemaType == CommunicationConfig::TOPIC_REQUEST_TYPE_METHOD) { + foreach ($handlers as $callback) { + $result = call_user_func_array($callback, $decodedMessage); + return $this->processSyncResponse($topicName, $result); + } + } else { + foreach ($handlers as $callback) { + $result = call_user_func($callback, $decodedMessage); + if ($isSync) { + return $this->processSyncResponse($topicName, $result); + } + } + } + } + return null; + } + + /** + * Validate and encode synchronous handler output. + * + * @param string $topicName + * @param mixed $result + * @return string + * @throws LocalizedException + */ + private function processSyncResponse($topicName, $result) + { + if (isset($result)) { + $this->getMessageValidator()->validate($topicName, $result, false); + return $this->messageEncoder->encode($topicName, $result, false); + } else { + throw new LocalizedException(new Phrase('No reply message resulted in RPC.')); + } + } + + /** + * Send RPC response message. + * + * @param EnvelopeInterface $envelope + * @return void + */ + private function sendResponse(EnvelopeInterface $envelope) + { + $messageProperties = $envelope->getProperties(); + $connectionName = $this->getConsumerConfig() + ->getConsumer($this->configuration->getConsumerName())->getConnection(); + $queue = $this->getQueueRepository()->get($connectionName, $messageProperties['reply_to']); + $queue->push($envelope); + } + + /** + * Get transaction callback. This handles the case of both sync and async. + * + * @param QueueInterface $queue + * @return \Closure + */ + private function getTransactionCallback(QueueInterface $queue) + { + return function (EnvelopeInterface $message) use ($queue) { + /** @var LockInterface $lock */ + $lock = null; + try { + $topicName = $message->getProperties()['topic_name']; + $topicConfig = $this->getCommunicationConfig()->getTopic($topicName); + $lock = $this->getMessageController()->lock($message, $this->configuration->getConsumerName()); + + if ($topicConfig[CommunicationConfig::TOPIC_IS_SYNCHRONOUS]) { + $responseBody = $this->dispatchMessage($message, true); + $responseMessage = $this->getEnvelopeFactory()->create( + ['body' => $responseBody, 'properties' => $message->getProperties()] + ); + $this->sendResponse($responseMessage); + } else { + $allowedTopics = $this->configuration->getTopicNames(); + if (in_array($topicName, $allowedTopics)) { + $this->dispatchMessage($message); + } else { + $queue->reject($message); + return; + } + } + $queue->acknowledge($message); + } catch (MessageLockException $exception) { + $queue->acknowledge($message); + } catch (\Magento\Framework\MessageQueue\ConnectionLostException $e) { + if ($lock) { + $this->resource->getConnection() + ->delete($this->resource->getTableName('queue_lock'), ['id = ?' => $lock->getId()]); + } + } catch (\Magento\Framework\Exception\NotFoundException $e) { + $queue->acknowledge($message); + $this->logger->warning($e->getMessage()); + } catch (\Exception $e) { + $queue->reject($message, false, $e->getMessage()); + if ($lock) { + $this->resource->getConnection() + ->delete($this->resource->getTableName('queue_lock'), ['id = ?' => $lock->getId()]); + } + } + }; + } + + /** + * Get consumer config. + * + * @return ConsumerConfig + * + * @deprecated 100.2.0 + */ + private function getConsumerConfig() + { + if ($this->consumerConfig === null) { + $this->consumerConfig = \Magento\Framework\App\ObjectManager::getInstance()->get(ConsumerConfig::class); + } + return $this->consumerConfig; + } + + /** + * Get communication config. + * + * @return CommunicationConfig + * + * @deprecated 100.2.0 + */ + private function getCommunicationConfig() + { + if ($this->communicationConfig === null) { + $this->communicationConfig = \Magento\Framework\App\ObjectManager::getInstance() + ->get(CommunicationConfig::class); + } + return $this->communicationConfig; + } + + /** + * Get queue repository. + * + * @return QueueRepository + * + * @deprecated 100.2.0 + */ + private function getQueueRepository() + { + if ($this->queueRepository === null) { + $this->queueRepository = \Magento\Framework\App\ObjectManager::getInstance()->get(QueueRepository::class); + } + return $this->queueRepository; + } + + /** + * Get message controller. + * + * @return MessageController + * + * @deprecated 100.1.0 + */ + private function getMessageController() + { + if ($this->messageController === null) { + $this->messageController = \Magento\Framework\App\ObjectManager::getInstance() + ->get(MessageController::class); + } + return $this->messageController; + } + + /** + * Get message validator. + * + * @return MessageValidator + * + * @deprecated 100.2.0 + */ + private function getMessageValidator() + { + if ($this->messageValidator === null) { + $this->messageValidator = \Magento\Framework\App\ObjectManager::getInstance() + ->get(MessageValidator::class); + } + return $this->messageValidator; + } + + /** + * Get envelope factory. + * + * @return EnvelopeFactory + * + * @deprecated 100.2.0 + */ + private function getEnvelopeFactory() + { + if ($this->envelopeFactory === null) { + $this->envelopeFactory = \Magento\Framework\App\ObjectManager::getInstance() + ->get(EnvelopeFactory::class); + } + return $this->envelopeFactory; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config.php new file mode 100644 index 0000000000000..4b97943bcc929 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem\Iterator; +use Magento\Framework\Phrase; + +/** + * {@inheritdoc} + */ +class Config implements ConfigInterface +{ + /** + * Item iterator. + * + * @var Iterator + */ + private $iterator; + + /** + * Initialize dependencies. + * + * @param Iterator $iterator + */ + public function __construct(Iterator $iterator) + { + $this->iterator = $iterator; + } + + /** + * {@inheritdoc} + */ + public function getConsumer($name) + { + $consumer = $this->iterator[$name]; + if (!$consumer) { + throw new LocalizedException(new Phrase("Consumer '%consumer' is not declared.", ['consumer' => $name])); + } + return $consumer; + } + + /** + * {@inheritdoc} + */ + public function getConsumers() + { + return $this->iterator; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/CompositeReader.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/CompositeReader.php new file mode 100644 index 0000000000000..fc2878cafd454 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/CompositeReader.php @@ -0,0 +1,54 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config; + +use Magento\Framework\MessageQueue\Consumer\Config\ReaderInterface; +use Magento\Framework\Phrase; +use Magento\Framework\MessageQueue\Consumer\Config\ValidatorInterface; + +/** + * Composite reader for consumer config. + */ +class CompositeReader implements ReaderInterface +{ + /** + * @var ValidatorInterface + */ + private $validator; + + /** + * @var ReaderInterface[] + */ + private $readers; + + /** + * Initialize dependencies. + * + * @param ValidatorInterface $validator + * @param ReaderInterface[] $readers + */ + public function __construct(ValidatorInterface $validator, array $readers) + { + $this->validator = $validator; + $this->readers = $readers; + } + + /** + * Read config. + * + * @param string|null $scope + * @return array + */ + public function read($scope = null) + { + $result = []; + foreach ($this->readers as $reader) { + $result = array_replace_recursive($result, $reader->read($scope)); + } + $this->validator->validate($result); + return $result; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/CompositeValidator.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/CompositeValidator.php new file mode 100644 index 0000000000000..c673b16110722 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/CompositeValidator.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config; + +use Magento\Framework\MessageQueue\Consumer\Config\ValidatorInterface; +use Magento\Framework\Phrase; + +/** + * Composite validator for consumer config. + */ +class CompositeValidator implements ValidatorInterface +{ + /** + * @var ValidatorInterface[] + */ + private $validators; + + /** + * Initialize dependencies. + * + * @param ValidatorInterface[] $validators + */ + public function __construct(array $validators) + { + $this->validators = $validators; + } + + /** + * {@inheritdoc} + */ + public function validate($configData) + { + foreach ($this->validators as $validator) { + $validator->validate($configData); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem.php new file mode 100644 index 0000000000000..92242698a5ba5 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem.php @@ -0,0 +1,116 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config; + +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem\Handler\Iterator as HandlerIterator; +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem\Handler\IteratorFactory as HandlerIteratorFactory; + +/** + * {@inheritdoc} + */ +class ConsumerConfigItem implements ConsumerConfigItemInterface +{ + /** + * @var string + */ + private $name; + + /** + * @var string + */ + private $connection; + + /** + * @var string + */ + private $queue; + + /** + * @var string + */ + private $consumerInstance; + + /** + * @var HandlerIterator + */ + private $handlers; + + /** + * @var string + */ + private $maxMessages; + + /** + * Initialize dependencies. + * + * @param HandlerIteratorFactory $handlerIteratorFactory + */ + public function __construct(HandlerIteratorFactory $handlerIteratorFactory) + { + $this->handlers = $handlerIteratorFactory->create(); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function getConnection() + { + return $this->connection; + } + + /** + * {@inheritdoc} + */ + public function getQueue() + { + return $this->queue; + } + + /** + * {@inheritdoc} + */ + public function getConsumerInstance() + { + return $this->consumerInstance; + } + + /** + * {@inheritdoc} + */ + public function getHandlers() + { + return $this->handlers; + } + + /** + * {@inheritdoc} + */ + public function getMaxMessages() + { + return $this->maxMessages; + } + + /** + * {@inheritdoc} + */ + public function setData(array $data) + { + $this->name = $data['name']; + $this->connection = $data['connection']; + $this->queue = $data['queue']; + $this->consumerInstance = $data['consumerInstance']; + $this->maxMessages = $data['maxMessages']; + $this->handlers->setData($data['handlers']); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Handler.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Handler.php new file mode 100644 index 0000000000000..1226fb79d38d4 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Handler.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem; + +/** + * {@inheritdoc} + */ +class Handler implements HandlerInterface +{ + /** + * @var string + */ + private $type; + + /** + * @var string + */ + private $method; + + /** + * {@inheritdoc} + */ + public function getType() + { + return $this->type; + } + + /** + * {@inheritdoc} + */ + public function getMethod() + { + return $this->method; + } + + /** + * {@inheritdoc} + */ + public function setData(array $data) + { + $this->type = $data['type']; + $this->method = $data['method']; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Handler/Iterator.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Handler/Iterator.php new file mode 100644 index 0000000000000..94a36ef0f0ba9 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Handler/Iterator.php @@ -0,0 +1,147 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem\Handler; + +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem\Handler; +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem\HandlerFactory; + +/** + * Consumer handler config iterator. + */ +class Iterator implements \Iterator, \ArrayAccess +{ + /** + * Consumer config handler item. + * + * @var Handler + */ + private $object; + + /** + * Config data. + * + * @var array + */ + private $data; + + /** + * Initialize dependencies. + * + * @param HandlerFactory $itemFactory + */ + public function __construct(HandlerFactory $itemFactory) + { + $this->object = $itemFactory->create(); + } + + /** + * Set data. + * + * @param array $data + * @return void + */ + public function setData(array $data) + { + $this->data = $data; + $this->rewind(); + } + + /** + * Get current item. + * + * @return Handler + */ + public function current() + { + return $this->object; + } + + /** + * {@inheritdoc} + */ + public function next() + { + next($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + } + } + + /** + * Initialize object. + * + * @param array $data + * @return void + */ + private function initObject(array $data) + { + $this->object->setData($data); + } + + /** + * {@inheritdoc} + */ + public function key() + { + key($this->data); + } + + /** + * {@inheritdoc} + */ + public function valid() + { + return (bool)current($this->data); + } + + /** + * {@inheritdoc} + */ + public function rewind() + { + reset($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + } + } + + /** + * {@inheritdoc} + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->data); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($offset) + { + if (!$this->offsetExists($offset)) { + return null; + } + $item = clone $this->object; + $item->setData($this->data[$offset]); + return $item; + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Handler/IteratorFactory.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Handler/IteratorFactory.php new file mode 100644 index 0000000000000..b17f7deb417b2 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Handler/IteratorFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem\Handler; + +/** + * Factory class for @see Iterator + */ +class IteratorFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = Iterator::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return Iterator + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/HandlerFactory.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/HandlerFactory.php new file mode 100644 index 0000000000000..9028ea9d2ad39 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/HandlerFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem; + +/** + * Factory type for @see Handler + */ +class HandlerFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = Handler::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create type instance with specified parameters + * + * @param array $data + * @return Handler + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/HandlerInterface.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/HandlerInterface.php new file mode 100644 index 0000000000000..2cbcb19ff74fd --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/HandlerInterface.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem; + +/** + * Representation of message queue handler configuration. + */ +interface HandlerInterface +{ + /** + * Get handler type name. + * + * @return string + */ + public function getType(); + + /** + * Get handler method name. + * + * @return string + */ + public function getMethod(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Iterator.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Iterator.php new file mode 100644 index 0000000000000..d60b54a689791 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItem/Iterator.php @@ -0,0 +1,139 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem; + +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem; +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItemFactory; +use Magento\Framework\MessageQueue\Consumer\Config\Data; + +/** + * Consumer config item iterator. + */ +class Iterator implements \Iterator, \ArrayAccess +{ + /** + * Consumer config item. + * + * @var ConsumerConfigItem + */ + private $object; + + /** + * Config data. + * + * @var array + */ + private $data; + + /** + * Initialize dependencies. + * + * @param Data $configData + * @param ConsumerConfigItemFactory $itemFactory + */ + public function __construct(Data $configData, ConsumerConfigItemFactory $itemFactory) + { + $this->data = $configData->get(); + $this->object = $itemFactory->create(); + $this->rewind(); + } + + /** + * Get current item. + * + * @return ConsumerConfigItem + */ + public function current() + { + return $this->object; + } + + /** + * {@inheritdoc} + */ + public function next() + { + next($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + } + } + + /** + * Initialize object. + * + * @param array $data + * @return void + */ + private function initObject(array $data) + { + $this->object->setData($data); + } + + /** + * {@inheritdoc} + */ + public function key() + { + key($this->data); + } + + /** + * {@inheritdoc} + */ + public function valid() + { + return (bool)current($this->data); + } + + /** + * {@inheritdoc} + */ + public function rewind() + { + reset($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + } + } + + /** + * {@inheritdoc} + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->data); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($offset) + { + if (!$this->offsetExists($offset)) { + return null; + } + $item = clone $this->object; + $item->setData($this->data[$offset]); + return $item; + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItemFactory.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItemFactory.php new file mode 100644 index 0000000000000..47711b4fb7e79 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItemFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config; + +/** + * Factory class for @see ConsumerConfigItem + */ +class ConsumerConfigItemFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = ConsumerConfigItem::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return ConsumerConfigItem + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItemInterface.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItemInterface.php new file mode 100644 index 0000000000000..0896b7789e1f1 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ConsumerConfigItemInterface.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config; + +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem\HandlerInterface; + +/** + * Items of this class represent config items declared in etc/queue_consumer.xsd + */ +interface ConsumerConfigItemInterface +{ + /** + * Get consumer name. + * + * @return string + */ + public function getName(); + + /** + * Get connection name. + * + * @return string + */ + public function getConnection(); + + /** + * Get name of the queue current consumer is listening to. + * + * @return string + */ + public function getQueue(); + + /** + * Get consumer class name. + * + * @return string + */ + public function getConsumerInstance(); + + /** + * Get information about custom handlers to be used by current consumer. + * + * @return HandlerInterface[] + */ + public function getHandlers(); + + /** + * Get maximum number of messages to be consumed from queue before terminating consumer. + * + * @return int + */ + public function getMaxMessages(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Data.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Data.php new file mode 100644 index 0000000000000..d94f5bd4a64da --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Data.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config; + +use Magento\Framework\Serialize\SerializerInterface; + +/** + * Consumer config data storage. Caches merged config. + */ +class Data extends \Magento\Framework\Config\Data +{ + /** + * {@inheritdoc} + */ + public function __construct( + \Magento\Framework\MessageQueue\Consumer\Config\ReaderInterface $reader, + \Magento\Framework\Config\CacheInterface $cache, + $cacheId = 'message_queue_consumer_config_cache', + SerializerInterface $serializer = null + ) { + parent::__construct($reader, $cache, $cacheId, $serializer); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Env/Reader.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Env/Reader.php new file mode 100644 index 0000000000000..aa318ba5f19cf --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Env/Reader.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Consumer\Config\Env; + +/** + * Communication configuration reader. Reads data from env.php. + */ +class Reader implements \Magento\Framework\Config\ReaderInterface +{ + /** + * @var \Magento\Framework\MessageQueue\Config\Reader\Env + */ + private $envConfig; + + /** + * @param \Magento\Framework\MessageQueue\Config\Reader\Env $envConfig + */ + public function __construct(\Magento\Framework\MessageQueue\Config\Reader\Env $envConfig) + { + $this->envConfig = $envConfig; + } + + /** + * Read consumers configuration from env.php + * + * @param string|null $scope + * @return array + */ + public function read($scope = null) + { + $configData = $this->envConfig->read($scope); + return isset($configData[\Magento\Framework\MessageQueue\Config\Reader\Env::ENV_CONSUMERS]) + ? $configData[\Magento\Framework\MessageQueue\Config\Reader\Env::ENV_CONSUMERS] + : []; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ReaderInterface.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ReaderInterface.php new file mode 100644 index 0000000000000..c56b14c3f6745 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ReaderInterface.php @@ -0,0 +1,14 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config; + +/** + * Queue consumer config reader interface. + */ +interface ReaderInterface extends \Magento\Framework\Config\ReaderInterface +{ + +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/ConsumerInstance.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/ConsumerInstance.php new file mode 100644 index 0000000000000..5d38fddc8f607 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/ConsumerInstance.php @@ -0,0 +1,63 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\Validator; + +use Magento\Framework\MessageQueue\Consumer; +use Magento\Framework\MessageQueue\Consumer\Config\ValidatorInterface; +use Magento\Framework\MessageQueue\ConsumerInterface; + +/** + * Consumer config data validator for consumer instance. + */ +class ConsumerInstance implements ValidatorInterface +{ + /** + * {@inheritdoc} + */ + public function validate($configData) + { + foreach ($configData as $consumerConfig) { + $this->validateConsumerInstance($consumerConfig); + } + } + + /** + * Make sure that specified consumer instance is valid. + * + * @param array $consumerConfig + * @return void + * @throws \LogicException + */ + private function validateConsumerInstance($consumerConfig) + { + $consumerInstance = $consumerConfig['consumerInstance']; + if ($consumerInstance == ConsumerInterface::class) { + return; + } + if (!class_exists($consumerInstance)) { + throw new \LogicException( + sprintf( + "'%s' does not exist and thus cannot be used as 'consumerInstance' for '%s' consumer.", + $consumerInstance, + $consumerConfig['name'], + ConsumerInterface::class + ) + ); + } + $implementedInterfaces = class_implements($consumerInstance); + if (!in_array(ConsumerInterface::class, $implementedInterfaces)) { + throw new \LogicException( + sprintf( + "'%s' cannot be specified as 'consumerInstance' for '%s' consumer," + . " unless it implements '%s' interface", + $consumerInstance, + $consumerConfig['name'], + ConsumerInterface::class + ) + ); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/FieldsTypes.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/FieldsTypes.php new file mode 100644 index 0000000000000..d1409dec026de --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/FieldsTypes.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\Validator; + +use Magento\Framework\MessageQueue\Consumer\Config\ValidatorInterface; + +/** + * Consumer config data validator for fields types. + */ +class FieldsTypes implements ValidatorInterface +{ + /** + * {@inheritdoc} + */ + public function validate($configData) + { + foreach ($configData as $consumerName => $consumerConfig) { + $this->validateConsumerFieldsTypes($consumerName, $consumerConfig); + } + } + + /** + * Make sure types of all fields in the consumer item config are correct. + * + * @param string $consumerName + * @param array $consumerConfig + * @return void + * @throws \LogicException + */ + private function validateConsumerFieldsTypes($consumerName, $consumerConfig) + { + $fields = [ + 'name' => 'string', + 'queue' => 'string', + 'handlers' => 'array', + 'consumerInstance' => 'string', + 'connection' => 'string' + ]; + foreach ($fields as $fieldName => $expectedType) { + $actualType = gettype($consumerConfig[$fieldName]); + if ($actualType !== $expectedType) { + throw new \LogicException( + sprintf( + "Type of '%s' field specified in configuration of '%s' consumer is invalid. " + . "Given '%s', '%s' was expected.", + $fieldName, + $consumerName, + $actualType, + $expectedType + ) + ); + } + } + if (null !== $consumerConfig['maxMessages'] && !is_numeric($consumerConfig['maxMessages'])) { + throw new \LogicException( + sprintf( + "Type of 'maxMessages' field specified in configuration of '%s' consumer is invalid. " + . "Given '%s', '%s' was expected.", + $consumerName, + gettype($consumerConfig['maxMessages']), + 'int|null' + ) + ); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/Handlers.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/Handlers.php new file mode 100644 index 0000000000000..fa6586d81b177 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/Handlers.php @@ -0,0 +1,83 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\Validator; + +use Magento\Framework\MessageQueue\Consumer\Config\ValidatorInterface; +use Magento\Framework\Reflection\MethodsMap; + +/** + * Consumer config data validator for handlers. + */ +class Handlers implements ValidatorInterface +{ + /** + * @var MethodsMap + */ + private $methodsMap; + + /** + * Initialize dependencies. + * + * @param MethodsMap $methodsMap + */ + public function __construct(MethodsMap $methodsMap) + { + $this->methodsMap = $methodsMap; + } + + /** + * {@inheritdoc} + */ + public function validate($configData) + { + foreach ($configData as $consumerConfig) { + $consumerName = $consumerConfig['name']; + if (!is_array($consumerConfig['handlers'])) { + throw new \LogicException( + sprintf( + "'handlers' element must be an array for consumer '%s'", + $consumerName + ) + ); + } + foreach ($consumerConfig['handlers'] as $handler) { + $this->validateHandler($handler, $consumerName); + } + } + } + + /** + * Validate handler configuration. + * + * @param array $handler + * @param string $consumerName + * @return void + * @throws \LogicException + */ + private function validateHandler($handler, $consumerName) + { + if (!isset($handler['type']) || !isset($handler['method'])) { + throw new \LogicException( + sprintf( + "'%s' consumer declaration is invalid. " + . "Every handler element must be an array. It must contain 'type' and 'method' elements.", + $consumerName + ) + ); + } + try { + $this->methodsMap->getMethodParams($handler['type'], $handler['method']); + } catch (\Exception $e) { + throw new \LogicException( + sprintf( + 'Service method specified as handler for of consumer "%s" is not available. Given "%s"', + $consumerName, + $handler['type'] . '::' . $handler['method'] + ) + ); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/RequiredFields.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/RequiredFields.php new file mode 100644 index 0000000000000..87de2233381e2 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Validator/RequiredFields.php @@ -0,0 +1,31 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\Validator; + +use Magento\Framework\MessageQueue\Consumer\Config\ValidatorInterface; + +/** + * Consumer config data validator for required fields. + */ +class RequiredFields implements ValidatorInterface +{ + /** + * {@inheritdoc} + */ + public function validate($configData) + { + foreach ($configData as $consumerName => $consumerConfig) { + $requiredFields = ['name', 'queue', 'handlers', 'consumerInstance', 'connection', 'maxMessages']; + foreach ($requiredFields as $fieldName) { + if (!array_key_exists($fieldName, $consumerConfig)) { + throw new \LogicException( + sprintf("'%s' field must be specified for consumer '%s'", $fieldName, $consumerName) + ); + } + } + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ValidatorInterface.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ValidatorInterface.php new file mode 100644 index 0000000000000..70cad49728347 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/ValidatorInterface.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config; + +/** + * Queue consumer config validator interface. + */ +interface ValidatorInterface +{ + /** + * Validate merged consumer config data. + * + * @param array $configData + * @return void + * @throws \LogicException + */ + public function validate($configData); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Xml/Converter.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Xml/Converter.php new file mode 100644 index 0000000000000..352bc53e94e90 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Xml/Converter.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\Xml; + +use Magento\Framework\MessageQueue\DefaultValueProvider; +use Magento\Framework\MessageQueue\ConsumerInterface; +use Magento\Framework\Communication\Config\ConfigParser; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; + +/** + * Converts MessageQueue consumers config from \DOMDocument to array + */ +class Converter implements \Magento\Framework\Config\ConverterInterface +{ + /** + * @var string + */ + private static $defaultInstance = ConsumerInterface::class; + + /** + * @var ConfigParser + */ + private $configParser; + + /** + * Default value provider. + * + * @var DefaultValueProvider + */ + private $defaultValueProvider; + + /** + * Initialize dependencies. + * + * @param ConfigParser $configParser + * @param DefaultValueProvider $defaultValueProvider + */ + public function __construct(ConfigParser $configParser, DefaultValueProvider $defaultValueProvider) + { + $this->configParser = $configParser; + $this->defaultValueProvider = $defaultValueProvider; + } + + /** + * {@inheritDoc} + */ + public function convert($source) + { + $result = []; + /** @var $consumerNode \DOMElement */ + foreach ($source->getElementsByTagName('consumer') as $consumerNode) { + $consumerName = $this->getAttributeValue($consumerNode, 'name'); + $handler = $this->getAttributeValue($consumerNode, 'handler'); + $result[$consumerName] = [ + 'name' => $consumerName, + 'queue' => $this->getAttributeValue($consumerNode, 'queue'), + 'consumerInstance' => $this->getAttributeValue( + $consumerNode, + 'consumerInstance', + self::$defaultInstance + ), + 'handlers' => $handler ? [$this->parseHandler($handler)] : [], + 'connection' => $this->getAttributeValue( + $consumerNode, + 'connection', + $this->defaultValueProvider->getConnection() + ), + 'maxMessages' => $this->getAttributeValue($consumerNode, 'maxMessages') + ]; + } + return $result; + } + + /** + * Get attribute value of the given node + * + * @param \DOMNode $node + * @param string $attributeName + * @param mixed $default + * @return string|null + */ + private function getAttributeValue(\DOMNode $node, $attributeName, $default = null) + { + $item = $node->attributes->getNamedItem($attributeName); + return $item ? $item->nodeValue : $default; + } + + /** + * Parse service method callback to become compatible with handlers format. + * + * @param array $handler + * @return array + */ + private function parseHandler($handler) + { + $parseServiceMethod = $this->configParser->parseServiceMethod($handler); + return [ + CommunicationConfig::HANDLER_TYPE => $parseServiceMethod[ConfigParser::TYPE_NAME], + CommunicationConfig::HANDLER_METHOD => $parseServiceMethod[ConfigParser::METHOD_NAME] + ]; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Xml/Reader.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Xml/Reader.php new file mode 100644 index 0000000000000..52502e8f13940 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Xml/Reader.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\Xml; + +use Magento\Framework\MessageQueue\Consumer\Config\ReaderInterface; + +/** + * Reader for etc/queue_consumer.xml configs. + */ +class Reader extends \Magento\Framework\Config\Reader\Filesystem implements ReaderInterface +{ + /** + * {@inheritdoc} + */ + protected $_idAttributes = [ + '/config/consumer' => 'name' + ]; + + /** + * {@inheritdoc} + */ + public function __construct( + \Magento\Framework\Config\FileResolverInterface $fileResolver, + \Magento\Framework\MessageQueue\Consumer\Config\Xml\Converter $converter, + \Magento\Framework\MessageQueue\Consumer\Config\Xml\SchemaLocator $schemaLocator, + \Magento\Framework\Config\ValidationStateInterface $validationState, + $fileName = 'queue_consumer.xml', + $idAttributes = [], + $domDocumentClass = \Magento\Framework\Config\Dom::class, + $defaultScope = 'global' + ) { + parent::__construct( + $fileResolver, + $converter, + $schemaLocator, + $validationState, + $fileName, + $idAttributes, + $domDocumentClass, + $defaultScope + ); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Xml/SchemaLocator.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Xml/SchemaLocator.php new file mode 100644 index 0000000000000..3ddbc143f3b0a --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/Config/Xml/SchemaLocator.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer\Config\Xml; + +/** + * Schema locator for etc/queue_consumer.xml + */ +class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface +{ + /** + * Path to corresponding XSD file with validation rules for merged config + * + * @var string + */ + protected $schema; + + /** + * Path to corresponding XSD file with validation rules for separate config files + * + * @var string + */ + protected $perFileSchema; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\Config\Dom\UrnResolver $urnResolver + */ + public function __construct(\Magento\Framework\Config\Dom\UrnResolver $urnResolver) + { + $this->schema = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/consumer.xsd'); + $this->perFileSchema = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/consumer.xsd'); + } + + /** + * Get path to merged config schema + * + * @return string|null + */ + public function getSchema() + { + return $this->schema; + } + + /** + * Get path to per file validation schema + * + * @return string|null + */ + public function getPerFileSchema() + { + return $this->perFileSchema; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Consumer/ConfigInterface.php b/lib/internal/Magento/Framework/MessageQueue/Consumer/ConfigInterface.php new file mode 100644 index 0000000000000..344b5ef1d580c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Consumer/ConfigInterface.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Consumer; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItemInterface; + +/** + * Consumer config interface provides access data declared in etc/queue_consumer.xml + * + * @api + * @since 100.2.0 + */ +interface ConfigInterface +{ + /** + * Get consumer configuration by consumer name. + * + * @param string $name + * @return ConsumerConfigItemInterface + * @throws LocalizedException + * @throws \LogicException + * @since 100.2.0 + */ + public function getConsumer($name); + + /** + * Get list of all consumers declared in the system. + * + * @return ConsumerConfigItemInterface[] + * @throws \LogicException + * @since 100.2.0 + */ + public function getConsumers(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ConsumerConfiguration.php b/lib/internal/Magento/Framework/MessageQueue/ConsumerConfiguration.php new file mode 100644 index 0000000000000..09cd5dcb8d909 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ConsumerConfiguration.php @@ -0,0 +1,202 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\MessageQueue\ConfigInterface as MessageQueueConfig; +use Magento\Framework\MessageQueue\Consumer\ConfigInterface as ConsumerConfig; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; + +/** + * Value class which stores the configuration + */ +class ConsumerConfiguration implements ConsumerConfigurationInterface +{ + /** + * @deprecated + * @see ConsumerConfigurationInterface::TOPIC_TYPE + */ + const CONSUMER_TYPE = "consumer_type"; + + /** + * @deprecated + * @see ConsumerConfigurationInterface::TOPIC_HANDLERS + */ + const HANDLERS = 'handlers'; + + /** + * @var array + */ + private $data; + + /** + * @var QueueRepository + */ + private $queueRepository; + + /** + * @var ConsumerConfig + */ + private $consumerConfig; + + /** + * @var CommunicationConfig + */ + private $communicationConfig; + + /** + * Initialize dependencies. + * + * @param QueueRepository $queueRepository + * @param MessageQueueConfig $messageQueueConfig + * @param array $data configuration data + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __construct(QueueRepository $queueRepository, MessageQueueConfig $messageQueueConfig, $data = []) + { + $this->data = $data; + $this->queueRepository = $queueRepository; + } + + /** + * {@inheritdoc} + */ + public function getConsumerName() + { + return $this->getData(self::CONSUMER_NAME); + } + + /** + * {@inheritdoc} + */ + public function getMaxMessages() + { + return $this->getData(self::MAX_MESSAGES); + } + + /** + * {@inheritdoc} + */ + public function getQueueName() + { + return $this->getData(self::QUEUE_NAME); + } + + /** + * {@inheritdoc} + */ + public function getType() + { + $topics = $this->getData(self::TOPICS); + if (count($topics) > 1) { + throw new \LogicException( + 'Current method is deprecated and does not support more than 1 topic declarations for consumer. ' + . 'Use \Magento\Framework\MessageQueue\ConsumerConfiguration::getConsumerType instead. ' + . "Multiple topics declared for consumer '{$this->getConsumerName()}'" + ); + } elseif (count($topics) < 1) { + throw new \LogicException( + "There must be at least one topic declared for consumer '{$this->getConsumerName()}'." + ); + } + // Get the only topic and read consumer type from its declaration. Necessary for backward compatibility + $topicConfig = reset($topics); + return $topicConfig[self::TOPIC_TYPE]; + } + + /** + * {@inheritdoc} + */ + public function getHandlers($topicName) + { + return $this->getTopicConfig($topicName)[self::TOPIC_HANDLERS]; + } + + /** + * {@inheritdoc} + */ + public function getTopicNames() + { + $topics = $this->getData(self::TOPICS); + return is_array($topics) && count($topics) ? array_keys($topics) : []; + } + + /** + * {@inheritdoc} + */ + public function getQueue() + { + $connectionName = $this->getConsumerConfig()->getConsumer($this->getConsumerName())->getConnection(); + return $this->queueRepository->get($connectionName, $this->getQueueName()); + } + + /** + * {@inheritdoc} + */ + public function getMessageSchemaType($topicName) + { + return $this->getCommunicationConfig()->getTopic($topicName)[CommunicationConfig::TOPIC_REQUEST_TYPE]; + } + + /** + * Get topic configuration for current consumer. + * @param string $topicName + * @return array + * @throws \LogicException + */ + private function getTopicConfig($topicName) + { + if (!isset($this->getData(self::TOPICS)[$topicName])) { + throw new \LogicException("Consumer configuration for {$topicName} topic not found."); + } + return $this->getData(self::TOPICS)[$topicName]; + } + + /** + * Get specified data item. + * + * @param string $key + * @return string|null + */ + private function getData($key) + { + if (!isset($this->data[$key])) { + return null; + } + return $this->data[$key]; + } + + /** + * Get consumer config. + * + * @return ConsumerConfig + * + * @deprecated 100.2.0 + */ + private function getConsumerConfig() + { + if ($this->consumerConfig === null) { + $this->consumerConfig = \Magento\Framework\App\ObjectManager::getInstance()->get(ConsumerConfig::class); + } + return $this->consumerConfig; + } + + /** + * Get communication config. + * + * @return CommunicationConfig + * + * @deprecated 100.2.0 + */ + private function getCommunicationConfig() + { + if ($this->communicationConfig === null) { + $this->communicationConfig = \Magento\Framework\App\ObjectManager::getInstance() + ->get(CommunicationConfig::class); + } + return $this->communicationConfig; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ConsumerConfigurationInterface.php b/lib/internal/Magento/Framework/MessageQueue/ConsumerConfigurationInterface.php new file mode 100644 index 0000000000000..b825949ddb019 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ConsumerConfigurationInterface.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Configuration for the consumer. + */ +interface ConsumerConfigurationInterface +{ + const CONSUMER_NAME = "consumer_name"; + + const QUEUE_NAME = "queue_name"; + const MAX_MESSAGES = "max_messages"; + const SCHEMA_TYPE = "schema_type"; + const TOPICS = 'topics'; + const TOPIC_TYPE = 'consumer_type'; + const TOPIC_HANDLERS = 'handlers'; + + const TYPE_SYNC = 'sync'; + const TYPE_ASYNC = 'async'; + const INSTANCE_TYPE_BATCH = 'batch'; + const INSTANCE_TYPE_SINGULAR = 'singular'; + + /** + * Get consumer name. + * + * @return string + */ + public function getConsumerName(); + + /** + * Get the name of queue which consumer will read from. + * + * @return string + */ + public function getQueueName(); + + /** + * Get consumer type sync|async. + * + * @return string + * @deprecated 100.2.0 + * @see \Magento\Framework\Communication\ConfigInterface::getTopic + * @throws \LogicException + */ + public function getType(); + + /** + * Get maximum number of message, which will be read by consumer before termination of the process. + * + * @return int|null + */ + public function getMaxMessages(); + + /** + * Get handlers by topic type. + * + * @param string $topicName + * @return callback[] + * @throws \LogicException + */ + public function getHandlers($topicName); + + /** + * Get topics. + * + * @return string[] + */ + public function getTopicNames(); + + /** + * @param string $topicName + * @return string + */ + public function getMessageSchemaType($topicName); + + /** + * @return QueueInterface + */ + public function getQueue(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ConsumerFactory.php b/lib/internal/Magento/Framework/MessageQueue/ConsumerFactory.php new file mode 100644 index 0000000000000..7d9f210b4a698 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ConsumerFactory.php @@ -0,0 +1,169 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\MessageQueue\ConfigInterface as QueueConfig; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Phrase; +use Magento\Framework\MessageQueue\ConsumerInterface; +use Magento\Framework\MessageQueue\Consumer\ConfigInterface as ConsumerConfig; +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItemInterface; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; + +/** + * Class which creates Consumers + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class ConsumerFactory +{ + /** + * Object Manager instance + * + * @var ObjectManagerInterface + */ + private $objectManager = null; + + /** + * @var ConsumerConfig + */ + private $consumerConfig; + + /** + * @var CommunicationConfig + */ + private $communicationConfig; + + /** + * Initialize dependencies. + * + * @param QueueConfig $queueConfig + * @param ObjectManagerInterface $objectManager + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __construct( + QueueConfig $queueConfig, + ObjectManagerInterface $objectManager + ) { + $this->objectManager = $objectManager; + } + + /** + * Return the actual Consumer implementation for the given consumer name. + * + * @param string $consumerName + * @param int $batchSize [optional] + * @return ConsumerInterface + * @throws LocalizedException + */ + public function get($consumerName, $batchSize = 0) + { + $consumerConfig = $this->getConsumerConfig()->getConsumer($consumerName); + if ($consumerConfig === null) { + throw new LocalizedException( + new Phrase('Specified consumer "%consumer" is not declared.', ['consumer' => $consumerName]) + ); + } + + return $this->objectManager->create( + $consumerConfig->getConsumerInstance(), + [ + 'configuration' => $this->createConsumerConfiguration($consumerConfig), + 'batchSize' => $batchSize, + ] + ); + } + + /** + * Creates the objects necessary for the ConsumerConfigurationInterface to configure a Consumer. + * + * @param ConsumerConfigItemInterface $consumerConfigItem + * @return ConsumerConfigurationInterface + */ + private function createConsumerConfiguration($consumerConfigItem) + { + $customConsumerHandlers = []; + foreach ($consumerConfigItem->getHandlers() as $handlerConfig) { + $customConsumerHandlers[] = [ + $this->objectManager->create($handlerConfig->getType()), + $handlerConfig->getMethod() + ]; + } + $topics = []; + foreach ($this->getCommunicationConfig()->getTopics() as $topicConfig) { + $topicName = $topicConfig[CommunicationConfig::TOPIC_NAME]; + $topics[$topicName] = [ + ConsumerConfigurationInterface::TOPIC_HANDLERS => $customConsumerHandlers + ?: $this->getHandlersFromCommunicationConfig($topicName), + ConsumerConfigurationInterface::TOPIC_TYPE => $topicConfig[CommunicationConfig::TOPIC_IS_SYNCHRONOUS] + ? ConsumerConfiguration::TYPE_SYNC + : ConsumerConfiguration::TYPE_ASYNC + ]; + } + $configData = [ + ConsumerConfigurationInterface::CONSUMER_NAME => $consumerConfigItem->getName(), + ConsumerConfigurationInterface::QUEUE_NAME => $consumerConfigItem->getQueue(), + ConsumerConfigurationInterface::TOPICS => $topics, + ConsumerConfigurationInterface::MAX_MESSAGES => $consumerConfigItem->getMaxMessages(), + ]; + + return $this->objectManager->create( + \Magento\Framework\MessageQueue\ConsumerConfiguration::class, + ['data' => $configData] + ); + } + + /** + * Get consumer config. + * + * @return ConsumerConfig + * + * @deprecated 100.2.0 + */ + private function getConsumerConfig() + { + if ($this->consumerConfig === null) { + $this->consumerConfig = \Magento\Framework\App\ObjectManager::getInstance()->get(ConsumerConfig::class); + } + return $this->consumerConfig; + } + + /** + * Get communication config. + * + * @return CommunicationConfig + * + * @deprecated 100.2.0 + */ + private function getCommunicationConfig() + { + if ($this->communicationConfig === null) { + $this->communicationConfig = \Magento\Framework\App\ObjectManager::getInstance() + ->get(CommunicationConfig::class); + } + return $this->communicationConfig; + } + + /** + * Get handlers by topic based on communication config. + * + * @param string $topicName + * @return array + */ + private function getHandlersFromCommunicationConfig($topicName) + { + $topicConfig = $this->getCommunicationConfig()->getTopic($topicName); + $handlers = []; + foreach ($topicConfig[CommunicationConfig::TOPIC_HANDLERS] as $handlerConfig) { + $handlers[] = [ + $this->objectManager->create($handlerConfig[CommunicationConfig::HANDLER_TYPE]), + $handlerConfig[CommunicationConfig::HANDLER_METHOD] + ]; + } + return $handlers; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ConsumerInterface.php b/lib/internal/Magento/Framework/MessageQueue/ConsumerInterface.php new file mode 100644 index 0000000000000..ca45da7eca8ff --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ConsumerInterface.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Consumers will connect to a queue, read messages, and invoke a method to process the message contents. + * + * @api + */ +interface ConsumerInterface +{ + /** + * Connects to a queue, consumes a message on the queue, and invoke a method to process the message contents. + * + * @param int|null $maxNumberOfMessages if not specified - process all queued incoming messages and terminate, + * otherwise terminate execution after processing the specified number of messages + * @return void + */ + public function process($maxNumberOfMessages = null); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/DefaultValueProvider.php b/lib/internal/Magento/Framework/MessageQueue/DefaultValueProvider.php new file mode 100644 index 0000000000000..592581a0259f9 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/DefaultValueProvider.php @@ -0,0 +1,58 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Message Queue default config value provider. + */ +class DefaultValueProvider +{ + /** + * Default connection name. + * + * @var string + */ + private $connection; + + /** + * Default exchange name. + * + * @var string + */ + private $exchange; + + /** + * Initialize dependencies. + * + * @param string $connection + * @param string $exchange + */ + public function __construct($connection = 'amqp', $exchange = 'magento') + { + $this->connection = $connection; + $this->exchange = $exchange; + } + + /** + * Get default connection name. + * + * @return string + */ + public function getConnection() + { + return $this->connection; + } + + /** + * Get default exchange name. + * + * @return string + */ + public function getExchange() + { + return $this->exchange; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Envelope.php b/lib/internal/Magento/Framework/MessageQueue/Envelope.php new file mode 100644 index 0000000000000..07dd45efbf1bc --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Envelope.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\MessageQueue\EnvelopeInterface; + +class Envelope implements EnvelopeInterface +{ + /** + * @var array + */ + private $properties; + + /** + * @var string + */ + private $body; + + /** + * @param string $body + * @param array $properties + */ + public function __construct($body, array $properties = []) + { + $this->body = $body; + $this->properties = $properties; + } + + /** + * {@inheritdoc} + */ + public function getBody() + { + return $this->body; + } + + /** + * {@inheritdoc} + */ + public function getProperties() + { + return $this->properties; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/EnvelopeFactory.php b/lib/internal/Magento/Framework/MessageQueue/EnvelopeFactory.php new file mode 100644 index 0000000000000..0ffcc988bf405 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/EnvelopeFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\Envelope + */ +class EnvelopeFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + protected $_objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + protected $_instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = \Magento\Framework\MessageQueue\Envelope::class + ) { + $this->_objectManager = $objectManager; + $this->_instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return \Magento\Framework\MessageQueue\Envelope + */ + public function create(array $data = []) + { + return $this->_objectManager->create($this->_instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/EnvelopeInterface.php b/lib/internal/Magento/Framework/MessageQueue/EnvelopeInterface.php new file mode 100644 index 0000000000000..07f12d1856317 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/EnvelopeInterface.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * @api + */ +interface EnvelopeInterface +{ + /** + * Binary representation of message + * + * @return string + */ + public function getBody(); + + /** + * Message metadata + * + * @return array + */ + public function getProperties(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ExchangeFactory.php b/lib/internal/Magento/Framework/MessageQueue/ExchangeFactory.php new file mode 100644 index 0000000000000..ca1ef769af90f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ExchangeFactory.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\ExchangeInterface + * + * @api + * @since 100.2.0 + */ +class ExchangeFactory implements ExchangeFactoryInterface +{ + /** + * @var ExchangeFactoryInterface[] + */ + private $exchangeFactories; + + /** + * @var ConnectionTypeResolver + */ + private $connectionTypeResolver; + + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + * @since 100.2.0 + */ + protected $objectManager = null; + + /** + * Initialize dependencies. + * + * @param ConnectionTypeResolver $connectionTypeResolver + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param ExchangeFactoryInterface[] $exchangeFactories + * @since 100.2.0 + */ + public function __construct( + ConnectionTypeResolver $connectionTypeResolver, + \Magento\Framework\ObjectManagerInterface $objectManager, + array $exchangeFactories = [] + ) { + $this->objectManager = $objectManager; + $this->exchangeFactories = $exchangeFactories; + $this->connectionTypeResolver = $connectionTypeResolver; + } + + /** + * {@inheritdoc} + * @since 100.2.0 + */ + public function create($connectionName, array $data = []) + { + $connectionType = $this->connectionTypeResolver->getConnectionType($connectionName); + + if (!isset($this->exchangeFactories[$connectionType])) { + throw new \LogicException("Not found exchange for connection name '{$connectionName}' in config"); + } + + $factory = $this->exchangeFactories[$connectionType]; + $exchange = $factory->create($connectionName, $data); + + if (!$exchange instanceof ExchangeInterface) { + $exchangeInterface = \Magento\Framework\MessageQueue\ExchangeInterface::class; + throw new \LogicException( + "Exchange for connection name '{$connectionName}' " . + "does not implement interface '{$exchangeInterface}'" + ); + } + return $exchange; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ExchangeFactoryInterface.php b/lib/internal/Magento/Framework/MessageQueue/ExchangeFactoryInterface.php new file mode 100644 index 0000000000000..1e70b0266fc4f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ExchangeFactoryInterface.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\ExchangeInterface + * + * @api + * @since 100.2.0 + */ +interface ExchangeFactoryInterface +{ + /** + * Create exchange instance. + * + * @param string $connectionName + * @param array $data + * @return ExchangeInterface + * @since 100.2.0 + */ + public function create($connectionName, array $data = []); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ExchangeInterface.php b/lib/internal/Magento/Framework/MessageQueue/ExchangeInterface.php new file mode 100644 index 0000000000000..bb36332ae25b1 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ExchangeInterface.php @@ -0,0 +1,23 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Interface message Exchange + * + * @api + */ +interface ExchangeInterface +{ + /** + * Send message + * + * @param string $topic + * @param EnvelopeInterface $envelope + * @return mixed + */ + public function enqueue($topic, EnvelopeInterface $envelope); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/ExchangeRepository.php b/lib/internal/Magento/Framework/MessageQueue/ExchangeRepository.php new file mode 100644 index 0000000000000..1f26e5d785c1a --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/ExchangeRepository.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +class ExchangeRepository +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @var ExchangeFactoryInterface + */ + private $exchangeFactory; + + /** + * Pool of exchange instances. + * + * @var ExchangeInterface[] + */ + private $exchangePool = []; + + /** + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string[] $exchanges + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager, array $exchanges = []) + { + $this->objectManager = $objectManager; + } + + /** + * @param string $connectionName + * @return ExchangeInterface + * @throws \LogicException + */ + public function getByConnectionName($connectionName) + { + if (!isset($this->exchangePool[$connectionName])) { + $exchange = $this->getExchangeFactory()->create($connectionName); + $this->exchangePool[$connectionName] = $exchange; + } + return $this->exchangePool[$connectionName]; + } + + /** + * Get exchange factory. + * + * @return ExchangeFactoryInterface + * @deprecated 100.2.0 + */ + private function getExchangeFactory() + { + if ($this->exchangeFactory === null) { + $this->exchangeFactory = $this->objectManager->get(ExchangeFactoryInterface::class); + } + return $this->exchangeFactory; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Lock.php b/lib/internal/Magento/Framework/MessageQueue/Lock.php new file mode 100644 index 0000000000000..15a9530d05483 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Lock.php @@ -0,0 +1,60 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Class Lock to handle message lock transactions. + */ +class Lock extends \Magento\Framework\DataObject implements LockInterface +{ + /** + * @inheritDoc + */ + public function getId() + { + return $this->getData('id'); + } + + /** + * @inheritDoc + */ + public function setId($value) + { + $this->setData('id', $value); + } + + /** + * @inheritDoc + */ + public function getMessageCode() + { + return $this->getData('message_code'); + } + + /** + * @inheritDoc + */ + public function setMessageCode($value) + { + $this->setData('message_code', $value); + } + + /** + * @inheritDoc + */ + public function getCreatedAt() + { + return $this->getData('created_at'); + } + + /** + * @inheritDoc + */ + public function setCreatedAt($value) + { + $this->setData('created_at', $value); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Lock/ReaderInterface.php b/lib/internal/Magento/Framework/MessageQueue/Lock/ReaderInterface.php new file mode 100644 index 0000000000000..33490f5137491 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Lock/ReaderInterface.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Lock; + +/** + * Message lock reader interface + */ +interface ReaderInterface +{ + /** + * Get lock from storage + * + * @param \Magento\Framework\MessageQueue\LockInterface $lock + * @param string $code + * @return void + */ + public function read(\Magento\Framework\MessageQueue\LockInterface $lock, $code); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Lock/WriterInterface.php b/lib/internal/Magento/Framework/MessageQueue/Lock/WriterInterface.php new file mode 100644 index 0000000000000..3d446f283c1ce --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Lock/WriterInterface.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Lock; + +/** + * Message lock writer + */ +interface WriterInterface +{ + /** + * Save lock + * + * @param \Magento\Framework\MessageQueue\LockInterface $lock + * @return void + */ + public function saveLock(\Magento\Framework\MessageQueue\LockInterface $lock); + + /** + * Remove outdated locks + * + * @return void + */ + public function releaseOutdatedLocks(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/LockInterface.php b/lib/internal/Magento/Framework/MessageQueue/LockInterface.php new file mode 100644 index 0000000000000..1f3d4fd50c3f4 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/LockInterface.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Class Lock to handle message lock transactions. + */ +interface LockInterface +{ + /** + * Get lock id + * + * @return int + */ + public function getId(); + + /** + * Set lock id + * + * @param int $value + * @return void + */ + public function setId($value); + + /** + * Get message code + * + * @return string + */ + public function getMessageCode(); + + /** + * Set message code + * + * @param string $value + * @return void + */ + public function setMessageCode($value); + + /** + * Get lock date + * + * @return string + */ + public function getCreatedAt(); + + /** + * Set lock date + * + * @param string $value + * @return void + */ + public function setCreatedAt($value); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MergedMessage.php b/lib/internal/Magento/Framework/MessageQueue/MergedMessage.php new file mode 100644 index 0000000000000..31dfc423f7471 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MergedMessage.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Provides mapping between merged message and appropriate original messages ids. + */ +class MergedMessage implements MergedMessageInterface +{ + /** + * @var mixed + */ + private $mergedMessage; + + /** + * @var array + */ + private $originalMessagesIds; + + /** + * @param mixed $mergedMessage + * @param array $originalMessagesIds + */ + public function __construct($mergedMessage, array $originalMessagesIds) + { + $this->mergedMessage = $mergedMessage; + $this->originalMessagesIds = $originalMessagesIds; + } + + /** + * @inheritdoc + */ + public function getMergedMessage() + { + return $this->mergedMessage; + } + + /** + * @inheritdoc + */ + public function getOriginalMessagesIds() + { + return $this->originalMessagesIds; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MergedMessageInterface.php b/lib/internal/Magento/Framework/MessageQueue/MergedMessageInterface.php new file mode 100644 index 0000000000000..ff291a7cdb970 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MergedMessageInterface.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Interface for mapping between original and merged messages. + */ +interface MergedMessageInterface +{ + /** + * Get merged message instance. + * + * @return mixed + */ + public function getMergedMessage(); + + /** + * Get original messages ids connected with the merged message. + * + * @return array + */ + public function getOriginalMessagesIds(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MergedMessageProcessor.php b/lib/internal/Magento/Framework/MessageQueue/MergedMessageProcessor.php new file mode 100644 index 0000000000000..eb37214aabc9c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MergedMessageProcessor.php @@ -0,0 +1,98 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Processing messages implementing MergedMessageInterface. + */ +class MergedMessageProcessor implements MessageProcessorInterface +{ + /** + * @var \Magento\Framework\MessageQueue\MessageStatusProcessor + */ + private $messageStatusProcessor; + + /** + * @param MessageStatusProcessor $messageStatusProcessor + */ + public function __construct(MessageStatusProcessor $messageStatusProcessor) + { + $this->messageStatusProcessor = $messageStatusProcessor; + } + + /** + * @inheritdoc + */ + public function process( + QueueInterface $queue, + ConsumerConfigurationInterface $configuration, + array $messages, + array $messagesToAcknowledge, + array $mergedMessages + ) { + $this->messageStatusProcessor->acknowledgeMessages($queue, $messagesToAcknowledge); + $this->dispatchMessages($queue, $configuration, $mergedMessages, $messages); + } + + /** + * Processing decoded messages, invoking callbacks, changing statuses for messages. + * + * @param QueueInterface $queue + * @param ConsumerConfigurationInterface $configuration + * @param array $messageList + * @param array $originalMessages + */ + private function dispatchMessages( + QueueInterface $queue, + ConsumerConfigurationInterface $configuration, + array $messageList, + array $originalMessages + ) { + $originalMessagesIds = []; + + try { + foreach ($messageList as $topicName => $messages) { + foreach ($messages as $message) { + /** + * @var \Magento\Framework\MessageQueue\MergedMessageInterface $message + */ + $callbacks = $configuration->getHandlers($topicName); + $originalMessagesIds = $message->getOriginalMessagesIds(); + + foreach ($callbacks as $callback) { + call_user_func($callback, $message->getMergedMessage()); + } + + $originalMessages = $this->getOriginalMessages($originalMessages, $originalMessagesIds); + $this->messageStatusProcessor->acknowledgeMessages($queue, $originalMessages); + } + } + } catch (\Exception $e) { + $originalMessages = $this->getOriginalMessages($originalMessages, $originalMessagesIds); + $this->messageStatusProcessor->rejectMessages($queue, $originalMessages); + } + } + + /** + * Get original messages by messages ids. + * + * @param array $messages + * @param array $messagesIds + * @return array + */ + private function getOriginalMessages(array $messages, array $messagesIds) + { + $originalMessages = []; + + foreach ($messagesIds as $messageId) { + if (isset($messages[$messageId])) { + $originalMessages[] = $messages[$messageId]; + } + } + + return $originalMessages; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MergerFactory.php b/lib/internal/Magento/Framework/MessageQueue/MergerFactory.php new file mode 100644 index 0000000000000..0647279258ae2 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MergerFactory.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\ObjectManagerInterface; + +class MergerFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string[] + */ + private $mergers; + + /** + * MergerFactory constructor. + * @param ObjectManagerInterface $objectManager + * @param string[] $mergers + */ + public function __construct(ObjectManagerInterface $objectManager, $mergers = []) + { + $this->objectManager = $objectManager; + $this->mergers = $mergers; + } + + /** + * @param string $consumerName + * @return MergerInterface + * @throws \LogicException + */ + public function create($consumerName) + { + if (!isset($this->mergers[$consumerName])) { + throw new \LogicException("Not found merger for consumer name '{$consumerName}'"); + } + + $mergerClassName = $this->mergers[$consumerName]; + $merger = $this->objectManager->get($mergerClassName); + + if (!$merger instanceof MergerInterface) { + $mergerInterfaceName = \Magento\Framework\MessageQueue\MergerInterface::class; + throw new \LogicException( + "Merger '{$mergerClassName}' for consumer name '{$consumerName}' " . + "does not implement interface '{$mergerInterfaceName}'" + ); + } + + return $merger; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MergerInterface.php b/lib/internal/Magento/Framework/MessageQueue/MergerInterface.php new file mode 100644 index 0000000000000..a922cbf894d16 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MergerInterface.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Interface for merging decoded queue messages. + */ +interface MergerInterface +{ + /** + * Merges or/and converts decoded queue messages. + * + * MergedMessage object contains array with ids of original queue messages + * + * @param object[] $messages + * @return object[]|MergedMessageInterface[] + */ + public function merge(array $messages); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MessageController.php b/lib/internal/Magento/Framework/MessageQueue/MessageController.php new file mode 100644 index 0000000000000..16853501e1d65 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MessageController.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\Exception\NotFoundException; +use Magento\Framework\Phrase; + +class MessageController +{ + /** + * @var \Magento\Framework\MessageQueue\LockInterfaceFactory + */ + private $lockFactory; + + /** + * @var \Magento\Framework\MessageQueue\Lock\ReaderInterface + */ + private $reader; + + /** + * @var \Magento\Framework\MessageQueue\Lock\WriterInterface + */ + private $writer; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\MessageQueue\LockInterfaceFactory $lockFactory + * @param Lock\ReaderInterface $reader + * @param Lock\WriterInterface $writer + */ + public function __construct( + \Magento\Framework\MessageQueue\LockInterfaceFactory $lockFactory, + \Magento\Framework\MessageQueue\Lock\ReaderInterface $reader, + \Magento\Framework\MessageQueue\Lock\WriterInterface $writer + ) { + $this->lockFactory = $lockFactory; + $this->reader = $reader; + $this->writer = $writer; + } + + /** + * Create lock corresponding to the provided message. Throw MessageLockException if lock is already created. + * + * @param EnvelopeInterface $envelope + * @param string $consumerName + * @return LockInterface + * @throws MessageLockException + * @throws NotFoundException + */ + public function lock(EnvelopeInterface $envelope, $consumerName) + { + $lock = $this->lockFactory->create(); + $properties = $envelope->getProperties(); + if (empty($properties['message_id'])) { + throw new NotFoundException(new Phrase("Property 'message_id' not found in properties.")); + } + $code = $consumerName . '-' . $properties['message_id']; + $code = md5($code); + $this->reader->read($lock, $code); + if ($lock->getId()) { + throw new MessageLockException(new Phrase('The "%1" message code was already processed.', [$code])); + } + $this->writer->saveLock($lock); + return $lock; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MessageEncoder.php b/lib/internal/Magento/Framework/MessageQueue/MessageEncoder.php new file mode 100644 index 0000000000000..91ad24eaeb978 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MessageEncoder.php @@ -0,0 +1,232 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\MessageQueue\ConfigInterface as QueueConfig; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; +use Magento\Framework\Webapi\ServicePayloadConverterInterface; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; + +/** + * Class which provides encoding and decoding capabilities for MessageQueue messages. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class MessageEncoder +{ + const DIRECTION_ENCODE = 'encode'; + const DIRECTION_DECODE = 'decode'; + + /** + * @var \Magento\Framework\Webapi\ServiceOutputProcessor + */ + private $dataObjectEncoder; + + /** + * @var \Magento\Framework\Webapi\ServiceInputProcessor + */ + private $dataObjectDecoder; + + /** + * @var \Magento\Framework\Json\EncoderInterface + */ + private $jsonEncoder; + + /** + * @var \Magento\Framework\Json\DecoderInterface + */ + private $jsonDecoder; + + /** + * @var CommunicationConfig + */ + private $communicationConfig; + + /** + * Initialize dependencies. + * + * @param QueueConfig $queueConfig + * @param \Magento\Framework\Json\EncoderInterface $jsonEncoder + * @param \Magento\Framework\Json\DecoderInterface $jsonDecoder + * @param \Magento\Framework\Webapi\ServiceOutputProcessor $dataObjectEncoder + * @param \Magento\Framework\Webapi\ServiceInputProcessor $dataObjectDecoder + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __construct( + QueueConfig $queueConfig, + \Magento\Framework\Json\EncoderInterface $jsonEncoder, + \Magento\Framework\Json\DecoderInterface $jsonDecoder, + \Magento\Framework\Webapi\ServiceOutputProcessor $dataObjectEncoder, + \Magento\Framework\Webapi\ServiceInputProcessor $dataObjectDecoder + ) { + $this->dataObjectEncoder = $dataObjectEncoder; + $this->dataObjectDecoder = $dataObjectDecoder; + $this->jsonEncoder = $jsonEncoder; + $this->jsonDecoder = $jsonDecoder; + } + + /** + * Encode message content based on current topic. + * + * @param string $topic + * @param mixed $message + * @param bool $requestType + * @return string + * @throws LocalizedException + */ + public function encode($topic, $message, $requestType = true) + { + $convertedMessage = $this->convertMessage($topic, $message, self::DIRECTION_ENCODE, $requestType); + return $this->jsonEncoder->encode($convertedMessage); + } + + /** + * Decode message content based on current topic. + * + * @param string $topic + * @param string $message + * @param bool $requestType + * @return mixed + * @throws LocalizedException + */ + public function decode($topic, $message, $requestType = true) + { + try { + $decodedMessage = $this->jsonDecoder->decode($message); + } catch (\Exception $e) { + throw new LocalizedException(new Phrase("Error occurred during message decoding.")); + } + return $this->convertMessage($topic, $decodedMessage, self::DIRECTION_DECODE, $requestType); + } + + /** + * Identify message data schema by topic. + * + * @param string $topic + * @param bool $requestType + * @return array + * @throws LocalizedException + */ + protected function getTopicSchema($topic, $requestType) + { + $topicConfig = $this->getCommunicationConfig()->getTopic($topic); + if ($topicConfig === null) { + throw new LocalizedException(new Phrase('Specified topic "%topic" is not declared.', ['topic' => $topic])); + } + if ($requestType) { + return [ + 'schema_type' => $topicConfig[CommunicationConfig::TOPIC_REQUEST_TYPE], + 'schema_value' => $topicConfig[CommunicationConfig::TOPIC_REQUEST] + ]; + } else { + return [ + 'schema_type' => isset($topicConfig[CommunicationConfig::TOPIC_RESPONSE]) + ? CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS + : null, + 'schema_value' => $topicConfig[CommunicationConfig::TOPIC_RESPONSE] + ]; + } + } + + /** + * Convert message according to the format associated with its topic using provided converter. + * + * @param string $topic + * @param mixed $message + * @param string $direction + * @param bool $requestType + * @return mixed + * @throws LocalizedException + */ + protected function convertMessage($topic, $message, $direction, $requestType) + { + $topicSchema = $this->getTopicSchema($topic, $requestType); + if ($topicSchema['schema_type'] == CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS) { + /** Convert message according to the data interface associated with the message topic */ + $messageDataType = $topicSchema[QueueConfig::TOPIC_SCHEMA_VALUE]; + try { + $convertedMessage = $this->getConverter($direction)->convertValue($message, $messageDataType); + } catch (LocalizedException $e) { + throw new LocalizedException( + new Phrase( + 'Message with topic "%topic" must be an instance of "%class".', + ['topic' => $topic, 'class' => $messageDataType] + ) + ); + } + } else { + /** Convert message according to the method signature associated with the message topic */ + $message = (array)$message; + $isIndexedArray = array_keys($message) === range(0, count($message) - 1); + $convertedMessage = []; + /** Message schema type is defined by method signature */ + foreach ($topicSchema['schema_value'] as $methodParameterMeta) { + $paramName = $methodParameterMeta[CommunicationConfig::SCHEMA_METHOD_PARAM_NAME]; + $paramType = $methodParameterMeta[CommunicationConfig::SCHEMA_METHOD_PARAM_TYPE]; + if ($isIndexedArray) { + /** Encode parameters according to their positions in method signature */ + $paramPosition = $methodParameterMeta[CommunicationConfig::SCHEMA_METHOD_PARAM_POSITION]; + if (isset($message[$paramPosition])) { + $convertedMessage[$paramName] = $this->getConverter($direction) + ->convertValue($message[$paramPosition], $paramType); + } + } else { + /** Encode parameters according to their names in method signature */ + if (isset($message[$paramName])) { + $convertedMessage[$paramName] = $this->getConverter($direction) + ->convertValue($message[$paramName], $paramType); + } + } + + /** Ensure that all required params were passed */ + if ($methodParameterMeta[CommunicationConfig::SCHEMA_METHOD_PARAM_IS_REQUIRED] + && !isset($convertedMessage[$paramName]) + ) { + throw new LocalizedException( + new Phrase( + 'Data item corresponding to "%param" must be specified ' + . 'in the message with topic "%topic".', + [ + 'topic' => $topic, + 'param' => $paramName + ] + ) + ); + } + } + } + return $convertedMessage; + } + + /** + * Get value converter based on conversion direction. + * + * @param string $direction + * @return ServicePayloadConverterInterface + */ + protected function getConverter($direction) + { + return ($direction == self::DIRECTION_ENCODE) ? $this->dataObjectEncoder : $this->dataObjectDecoder; + } + + /** + * Get communication config. + * + * @return CommunicationConfig + * + * @deprecated 100.2.0 + */ + private function getCommunicationConfig() + { + if ($this->communicationConfig === null) { + $this->communicationConfig = \Magento\Framework\App\ObjectManager::getInstance() + ->get(CommunicationConfig::class); + } + return $this->communicationConfig; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MessageIdGenerator.php b/lib/internal/Magento/Framework/MessageQueue/MessageIdGenerator.php new file mode 100644 index 0000000000000..7f8196e1a5972 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MessageIdGenerator.php @@ -0,0 +1,36 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Generate unique id for queue message. + */ +class MessageIdGenerator implements MessageIdGeneratorInterface +{ + /** + * @var \Magento\Framework\Encryption\EncryptorInterface + */ + private $encryptor; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\Encryption\EncryptorInterface $encryptor + */ + public function __construct( + \Magento\Framework\Encryption\EncryptorInterface $encryptor + ) { + $this->encryptor = $encryptor; + } + + /** + * {@inheritdoc} + */ + public function generate($topicName) + { + return $this->encryptor->hash(uniqid($topicName)); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MessageIdGeneratorInterface.php b/lib/internal/Magento/Framework/MessageQueue/MessageIdGeneratorInterface.php new file mode 100644 index 0000000000000..727db7d34761a --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MessageIdGeneratorInterface.php @@ -0,0 +1,24 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Used to generate unique id for queue message. + * + * @api + * @since 100.2.0 + */ +interface MessageIdGeneratorInterface +{ + /** + * Generate unique message id based on topic name. + * + * @param string $topicName + * @return string + * @since 100.2.0 + */ + public function generate($topicName); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MessageLockException.php b/lib/internal/Magento/Framework/MessageQueue/MessageLockException.php new file mode 100644 index 0000000000000..4ea462f7e1a8e --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MessageLockException.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\Exception\LocalizedException; + +/** + * Class MessageLockException to be thrown when a message being processed is already in the lock table. + * + * @api + * @since 100.1.0 + */ +class MessageLockException extends LocalizedException +{ + +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MessageProcessor.php b/lib/internal/Magento/Framework/MessageQueue/MessageProcessor.php new file mode 100644 index 0000000000000..d71a527c9cbb1 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MessageProcessor.php @@ -0,0 +1,78 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\App\ResourceConnection; + +/** + * Processes any type of messages except messages implementing MergedMessageInterface. + */ +class MessageProcessor implements MessageProcessorInterface +{ + /** + * @var \Magento\Framework\MessageQueue\MessageStatusProcessor + */ + private $messageStatusProcessor; + + /** + * @var \Magento\Framework\App\ResourceConnection + */ + private $resource; + + /** + * @param MessageStatusProcessor $messageStatusProcessor + * @param ResourceConnection $resource + */ + public function __construct( + MessageStatusProcessor $messageStatusProcessor, + ResourceConnection $resource + ) { + $this->messageStatusProcessor = $messageStatusProcessor; + $this->resource = $resource; + } + + /** + * @inheritdoc + */ + public function process( + QueueInterface $queue, + ConsumerConfigurationInterface $configuration, + array $messages, + array $messagesToAcknowledge, + array $mergedMessages + ) { + try { + $this->resource->getConnection()->beginTransaction(); + $this->messageStatusProcessor->acknowledgeMessages($queue, $messagesToAcknowledge); + $this->dispatchMessages($configuration, $mergedMessages); + $this->resource->getConnection()->commit(); + $this->messageStatusProcessor->acknowledgeMessages($queue, $messages); + } catch (ConnectionLostException $e) { + $this->resource->getConnection()->rollBack(); + } catch (\Exception $e) { + $this->resource->getConnection()->rollBack(); + $this->messageStatusProcessor->rejectMessages($queue, $messages); + } + } + + /** + * Processes decoded messages, invokes callbacks, changes statuses for messages. + * + * @param ConsumerConfigurationInterface $configuration + * @param array $messageList + */ + private function dispatchMessages(ConsumerConfigurationInterface $configuration, array $messageList) + { + foreach ($messageList as $topicName => $messages) { + foreach ($messages as $message) { + $callbacks = $configuration->getHandlers($topicName); + foreach ($callbacks as $callback) { + call_user_func($callback, $message); + } + } + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MessageProcessorInterface.php b/lib/internal/Magento/Framework/MessageQueue/MessageProcessorInterface.php new file mode 100644 index 0000000000000..c78485b7748e8 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MessageProcessorInterface.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Interface for processing queue messages. + */ +interface MessageProcessorInterface +{ + /** + * Processing decoded messages, invoking callbacks, changing statuses for messages. + * + * @param QueueInterface $queue + * @param ConsumerConfigurationInterface $configuration + * @param array $messages + * @param array $messagesToAcknowledge + * @param array $mergedMessages + * @return void + */ + public function process( + QueueInterface $queue, + ConsumerConfigurationInterface $configuration, + array $messages, + array $messagesToAcknowledge, + array $mergedMessages + ); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MessageProcessorLoader.php b/lib/internal/Magento/Framework/MessageQueue/MessageProcessorLoader.php new file mode 100644 index 0000000000000..ae6072e39cfec --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MessageProcessorLoader.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Loads message processor depending on the message type. + */ +class MessageProcessorLoader +{ + /** + * @var \Magento\Framework\MessageQueue\MessageProcessorInterface + */ + private $mergedMessageProcessor; + + /** + * @var \Magento\Framework\MessageQueue\MessageProcessorInterface + */ + private $defaultMessageProcessor; + + /** + * @param MessageProcessorInterface $mergedMessageProcessor + * @param MessageProcessorInterface $defaultMessageProcessor + */ + public function __construct( + MessageProcessorInterface $mergedMessageProcessor, + MessageProcessorInterface $defaultMessageProcessor + ) { + $this->mergedMessageProcessor = $mergedMessageProcessor; + $this->defaultMessageProcessor = $defaultMessageProcessor; + } + + /** + * Loads message processor depending on the message type. + * + * @param array $messages + * @return MessageProcessorInterface + */ + public function load(array $messages) + { + $message = $this->getMergedMessage($messages); + + return ($message instanceof MergedMessageInterface) + ? $this->mergedMessageProcessor : $this->defaultMessageProcessor; + } + + /** + * Get first message from the list of merged messages. + * + * @param array $messages + * @return mixed|null + */ + private function getMergedMessage(array $messages) + { + $message = null; + + if ($messages) { + $topicMessages = array_shift($messages); + + if ($topicMessages) { + $message = array_shift($topicMessages); + } + } + + return $message; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MessageStatusProcessor.php b/lib/internal/Magento/Framework/MessageQueue/MessageStatusProcessor.php new file mode 100644 index 0000000000000..a6d97dd1e5114 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MessageStatusProcessor.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Changes messages status. + */ +class MessageStatusProcessor +{ + /** + * Acknowledge all provided messages. + * + * @param QueueInterface $queue + * @param array $messages + * @return void + */ + public function acknowledgeMessages(QueueInterface $queue, array $messages) + { + foreach ($messages as $message) { + $queue->acknowledge($message); + } + } + + /** + * Reject all provided messages. + * + * @param QueueInterface $queue + * @param array $messages + * @return void + */ + public function rejectMessages(QueueInterface $queue, array $messages) + { + foreach ($messages as $message) { + $queue->reject($message); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/MessageValidator.php b/lib/internal/Magento/Framework/MessageQueue/MessageValidator.php new file mode 100644 index 0000000000000..9bc519fc87efc --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/MessageValidator.php @@ -0,0 +1,195 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Doctrine\Instantiator\Exception\InvalidArgumentException; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; + +/** + * Class MessageValidator to validate message with topic schema + * + */ +class MessageValidator +{ + /** + * @var CommunicationConfig + */ + private $communicationConfig; + + /** + * Identify message data schema by topic. + * + * @param string $topic + * @param bool $requestType + * @return array + * @throws LocalizedException + */ + protected function getTopicSchema($topic, $requestType) + { + $topicConfig = $this->getCommunicationConfig()->getTopic($topic); + if ($topicConfig === null) { + throw new LocalizedException(new Phrase('Specified topic "%topic" is not declared.', ['topic' => $topic])); + } + if ($requestType) { + return [ + 'schema_type' => $topicConfig[CommunicationConfig::TOPIC_REQUEST_TYPE], + 'schema_value' => $topicConfig[CommunicationConfig::TOPIC_REQUEST] + ]; + } else { + return [ + 'schema_type' => isset($topicConfig[CommunicationConfig::TOPIC_RESPONSE]) + ? CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS + : null, + 'schema_value' => $topicConfig[CommunicationConfig::TOPIC_RESPONSE] + ]; + } + } + + /** + * Validate message according to the format associated with its topic + * + * @param string $topic + * @param mixed $message + * @param bool $requestType + * @return void + * @throws InvalidArgumentException + */ + public function validate($topic, $message, $requestType = true) + { + $topicSchema = $this->getTopicSchema($topic, $requestType); + if ($topicSchema['schema_type'] == CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS) { + $messageDataType = $topicSchema['schema_value']; + $this->validateMessage($message, $messageDataType, $topic); + } else { + /** Validate message according to the method signature associated with the message topic */ + $message = (array)$message; + $isIndexedArray = array_keys($message) === range(0, count($message) - 1); + foreach ($topicSchema['schema_value'] as $methodParameterMeta) { + $paramName = $methodParameterMeta[CommunicationConfig::SCHEMA_METHOD_PARAM_NAME]; + $paramType = $methodParameterMeta[CommunicationConfig::SCHEMA_METHOD_PARAM_TYPE]; + if ($isIndexedArray) { + $paramPosition = $methodParameterMeta[CommunicationConfig::SCHEMA_METHOD_PARAM_POSITION]; + if (isset($message[$paramPosition])) { + $this->validateMessage($message[$paramPosition], $paramType, $topic); + } + } else { + if (isset($message[$paramName])) { + if (isset($message[$paramName])) { + $this->validateMessage($message[$paramName], $paramType, $topic); + } + } + } + } + } + } + + /** + * @param string $message + * @param string $messageType + * @param string $topic + * @return void + */ + protected function validateMessage($message, $messageType, $topic) + { + if (preg_match_all("/\\\\/", $messageType)) { + $this->validateClassType($message, $messageType, $topic); + } else { + $this->validatePrimitiveType($message, $messageType, $topic); + } + } + + /** + * @param string $message + * @param string $messageType + * @param string $topic + * @return void + */ + protected function validatePrimitiveType($message, $messageType, $topic) + { + $compareType = $messageType; + $realType = $this->getRealType($message); + if ($realType == 'array' && count($message) == 0) { + return; + } elseif ($realType == 'array' && count($message) > 0) { + $realType = $this->getRealType($message[0]); + $compareType = preg_replace('/\[\]/', '', $messageType); + } + if ($realType !== $compareType) { + throw new InvalidArgumentException( + new Phrase( + 'Data in topic "%topic" must be of type "%expectedType". ' + . '"%actualType" given.', + [ + 'topic' => $topic, + 'expectedType' => $messageType, + 'actualType' => $this->getRealType($message) + ] + ) + ); + } + } + + /** + * @param string $message + * @param string $messageType + * @param string $topic + * @return void + */ + protected function validateClassType($message, $messageType, $topic) + { + $origMessage = $message; + $compareType = $messageType; + $realType = $this->getRealType($message); + if ($realType == 'array' && count($message) == 0) { + return; + } elseif ($realType == 'array' && count($message) > 0) { + $message = $message[0]; + $compareType = preg_replace('/\[\]/', '', $messageType); + } + if (!($message instanceof $compareType)) { + throw new InvalidArgumentException( + new Phrase( + 'Data in topic "%topic" must be of type "%expectedType". ' + . '"%actualType" given.', + [ + 'topic' => $topic, + 'expectedType' => $messageType, + 'actualType' => $this->getRealType($origMessage) + ] + ) + ); + } + } + + /** + * @param string $message + * @return string + */ + private function getRealType($message) + { + $type = is_object($message) ? get_class($message) : gettype($message); + return $type == "integer" ? "int" : $type; + } + + /** + * Get communication config. + * + * @return CommunicationConfig + * + * @deprecated 100.2.0 + */ + private function getCommunicationConfig() + { + if ($this->communicationConfig === null) { + $this->communicationConfig = \Magento\Framework\App\ObjectManager::getInstance()->get( + CommunicationConfig::class + ); + } + return $this->communicationConfig; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher.php b/lib/internal/Magento/Framework/MessageQueue/Publisher.php new file mode 100644 index 0000000000000..8fe77abe69136 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher.php @@ -0,0 +1,137 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\Amqp\Config as AmqpConfig; +use Magento\Framework\MessageQueue\ConfigInterface as MessageQueueConfig; +use Magento\Framework\MessageQueue\Publisher\ConfigInterface as PublisherConfig; + +/** + * A MessageQueue Publisher to handle publishing a message. + */ +class Publisher implements PublisherInterface +{ + /** + * @var ExchangeRepository + */ + private $exchangeRepository; + + /** + * @var EnvelopeFactory + */ + private $envelopeFactory; + + /** + * @var MessageEncoder + */ + private $messageEncoder; + + /** + * @var MessageValidator + */ + private $messageValidator; + + /** + * @var PublisherConfig + */ + private $publisherConfig; + + /** + * Help check whether Amqp is configured. + * + * @var AmqpConfig + */ + private $amqpConfig; + + /** + * Initialize dependencies. + * + * @param ExchangeRepository $exchangeRepository + * @param EnvelopeFactory $envelopeFactory + * @param MessageQueueConfig $messageQueueConfig + * @param MessageEncoder $messageEncoder + * @param MessageValidator $messageValidator + * @internal param ExchangeInterface $exchange + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __construct( + ExchangeRepository $exchangeRepository, + EnvelopeFactory $envelopeFactory, + MessageQueueConfig $messageQueueConfig, + MessageEncoder $messageEncoder, + MessageValidator $messageValidator + ) { + $this->exchangeRepository = $exchangeRepository; + $this->envelopeFactory = $envelopeFactory; + $this->messageEncoder = $messageEncoder; + $this->messageValidator = $messageValidator; + } + + /** + * {@inheritdoc} + */ + public function publish($topicName, $data) + { + $this->messageValidator->validate($topicName, $data); + $data = $this->messageEncoder->encode($topicName, $data); + $envelope = $this->envelopeFactory->create( + [ + 'body' => $data, + 'properties' => [ + 'delivery_mode' => 2, + 'message_id' => md5(uniqid($topicName)) + ] + ] + ); + $connectionName = $this->getPublisherConfig()->getPublisher($topicName)->getConnection()->getName(); + $connectionName = ($connectionName === 'amqp' && !$this->isAmqpConfigured()) ? 'db' : $connectionName; + $exchange = $this->exchangeRepository->getByConnectionName($connectionName); + $exchange->enqueue($topicName, $envelope); + return null; + } + + /** + * Check Amqp is configured. + * + * @return bool + */ + private function isAmqpConfigured() + { + return $this->getAmqpConfig()->getValue(AmqpConfig::HOST) ? true : false; + } + + /** + * Get publisher config. + * + * @return PublisherConfig + * + * @deprecated 100.2.0 + */ + private function getPublisherConfig() + { + if ($this->publisherConfig === null) { + $this->publisherConfig = \Magento\Framework\App\ObjectManager::getInstance()->get(PublisherConfig::class); + } + return $this->publisherConfig; + } + + /** + * Get Amqp config instance. + * + * @return AmqpConfig + * + * @deprecated + */ + private function getAmqpConfig() + { + if ($this->amqpConfig === null) { + $this->amqpConfig = \Magento\Framework\App\ObjectManager::getInstance()->get(AmqpConfig::class); + } + + return $this->amqpConfig; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config.php new file mode 100644 index 0000000000000..8f64ebedfeb14 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; +use \Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItem\Iterator; + +/** + * Publisher config provides access data declared in etc/queue_publisher.xml + */ +class Config implements ConfigInterface +{ + /** + * Publisher config data iterator. + * + * @var Iterator + */ + private $iterator; + + /** + * Initialize dependencies. + * + * @param Iterator $iterator + */ + public function __construct(Iterator $iterator) + { + $this->iterator = $iterator; + } + + /** + * {@inheritdoc} + */ + public function getPublisher($topic) + { + $publisher = $this->iterator[$topic]; + if (!$publisher) { + throw new LocalizedException( + new Phrase("Publisher '%publisher' is not declared.", ['publisher' => $topic]) + ); + } + return $publisher; + } + + /** + * {@inheritdoc} + */ + public function getPublishers() + { + return $this->iterator; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/CompositeReader.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/CompositeReader.php new file mode 100644 index 0000000000000..7c115c53c532a --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/CompositeReader.php @@ -0,0 +1,119 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +use Magento\Framework\MessageQueue\DefaultValueProvider; + +/** + * Composite reader for publisher config. + */ +class CompositeReader implements ReaderInterface +{ + /** + * Config validator. + * + * @var ValidatorInterface + */ + private $validator; + + /** + * Config reade list. + * + * @var ReaderInterface[] + */ + private $readers; + + /** + * @var DefaultValueProvider + */ + private $defaultValueProvider; + + /** + * Initialize dependencies. + * + * @param ValidatorInterface $validator + * @param DefaultValueProvider $defaultValueProvider + * @param ReaderInterface[] $readers + */ + public function __construct( + ValidatorInterface $validator, + DefaultValueProvider $defaultValueProvider, + array $readers + ) { + $this->validator = $validator; + $this->readers = $readers; + $this->defaultValueProvider = $defaultValueProvider; + } + + /** + * Read config. + * + * @param string|null $scope + * @return array + */ + public function read($scope = null) + { + $result = []; + foreach ($this->readers as $reader) { + $result = array_replace_recursive($result, $reader->read($scope)); + } + + $result = $this->addDefaultConnection($result); + + $this->validator->validate($result); + + foreach ($result as $key => &$value) { + //Find enabled connection + $connection = null; + foreach ($value['connections'] as $connectionConfig) { + if (!$connectionConfig['disabled']) { + $connection = $connectionConfig; + break; + } + } + $value['connection'] = $connection; + unset($value['connections']); + $result[$key] = $value; + } + return $result; + } + + /** + * Add default connection. + * + * @param array $config + * @return array + */ + private function addDefaultConnection(array $config) + { + $defaultConnectionName = $this->defaultValueProvider->getConnection(); + $default = [ + 'name' => $defaultConnectionName, + 'exchange' => $this->defaultValueProvider->getExchange(), + 'disabled' => false, + ]; + + foreach ($config as &$value) { + if (!isset($value['connections']) || empty($value['connections'])) { + $value['connections'][$defaultConnectionName] = $default; + continue; + } + + $hasActiveConnection = false; + /** Find enabled connection */ + foreach ($value['connections'] as $connectionConfig) { + if (!$connectionConfig['disabled']) { + $hasActiveConnection = true; + break; + } + } + if (!$hasActiveConnection) { + $value['connections'][$defaultConnectionName] = $default; + } + } + return $config; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/CompositeValidator.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/CompositeValidator.php new file mode 100644 index 0000000000000..6021354b37bec --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/CompositeValidator.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +/** + * Publisher config data validator. + */ +class CompositeValidator implements ValidatorInterface +{ + /** + * Config validator list. + * + * @var ValidatorInterface[] + */ + private $validators; + + /** + * Validator constructor. + * + * @param ValidatorInterface[] $validators + */ + public function __construct($validators) + { + $this->validators = $validators; + } + + /** + * Validate merged publisher config data. + * + * @param array $configData + * @throws \LogicException + * @return void + * @throws \LogicException + */ + public function validate($configData) + { + foreach ($this->validators as $validator) { + if (!$validator instanceof ValidatorInterface) { + throw new \LogicException( + sprintf( + 'Validator [%s] does not implements ' . + 'Magento\Framework\MessageQueue\Publisher\Config\ValidatorInterface', + get_class($validator) + ) + ); + } + $validator->validate($configData); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Data.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Data.php new file mode 100644 index 0000000000000..ae7552bf57496 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Data.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +use Magento\Framework\Serialize\SerializerInterface; + +/** + * Publisher config data storage. Caches merged config. + */ +class Data extends \Magento\Framework\Config\Data +{ + /** + * {@inheritdoc} + */ + public function __construct( + ReaderInterface $reader, + \Magento\Framework\Config\CacheInterface $cache, + $cacheId = 'message_queue_publisher_config_cache', + SerializerInterface $serializer = null + ) { + parent::__construct($reader, $cache, $cacheId, $serializer); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Env/Reader.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Env/Reader.php new file mode 100644 index 0000000000000..77926917bf0eb --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Env/Reader.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Publisher\Config\Env; + +use Magento\Framework\MessageQueue\Config\Data as MessageQueueConfigData; +use Magento\Framework\App\DeploymentConfig; +use Magento\Framework\MessageQueue\Config\Reader\Env as MessageQueueEnvReader; + +/** + * Publisher configuration reader. Reads data from env.php. + */ +class Reader implements \Magento\Framework\Config\ReaderInterface +{ + /** + * @var \Magento\Framework\MessageQueue\Config\Reader\Env + */ + private $deploymentConfig; + + /** + * @var MessageQueueConfigData + */ + private $configData; + + /** + * Mapping between default publishers name and connections + * + * @var array + */ + private $publisherNameToConnectionMap; + + /** + * @param DeploymentConfig $deploymentConfig + * @param MessageQueueConfigData $configData + * @param array $publisherNameToConnectionMap + */ + public function __construct( + DeploymentConfig $deploymentConfig, + MessageQueueConfigData $configData, + $publisherNameToConnectionMap = [] + ) { + $this->deploymentConfig = $deploymentConfig; + $this->configData = $configData; + $this->publisherNameToConnectionMap = $publisherNameToConnectionMap; + } + + /** + * Read publisher configuration from env.php + * + * @param string|null $scope + * @return array + */ + public function read($scope = null) + { + $configData = $this->deploymentConfig->getConfigData(MessageQueueEnvReader::ENV_QUEUE); + if (isset($configData['config'])) { + $configData = isset($configData['config'][MessageQueueEnvReader::ENV_PUBLISHERS]) + ? $configData['config'][MessageQueueEnvReader::ENV_PUBLISHERS] + : []; + } else { + $configData = isset($configData[MessageQueueEnvReader::ENV_PUBLISHERS]) + ? $this->convertConfigData($scope) + : []; + } + return $configData; + } + + /** + * Convert publisher related data to publisher config format + * + * @param string|null $scope + * @return array + */ + private function convertConfigData($scope) + { + $configData = []; + $topicsConfig = $this->configData->get('topics'); + foreach ($topicsConfig as $topicName => $topicConfig) { + $configData[$topicName] = []; + if (isset($topicConfig['disabled'])) { + $configData[$topicName]['disabled'] = $topicConfig['disabled']; + } + $publisherName = $this->configData->get('topics/' . $topicName . '/publisher', $scope); + $config = $this->configData->get('publishers/' . $publisherName, $scope); + if (!empty($config) && isset($this->publisherNameToConnectionMap[$publisherName])) { + $connectionName = $this->publisherNameToConnectionMap[$publisherName]; + $config['name'] = $config['connection']; + unset($config['connection']); + $disabled = isset($config['disabled']) ? $config['disabled'] : false; + $config['disabled'] = $disabled; + $configData[$topicName]['connections'][$connectionName] = $config; + } + } + return $configData; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItem.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItem.php new file mode 100644 index 0000000000000..426d39efd9403 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItem.php @@ -0,0 +1,80 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +/** + * {@inheritdoc} + */ +class PublisherConfigItem implements PublisherConfigItemInterface +{ + /** + * Publisher topic name. + * + * @var string + */ + private $topic; + + /** + * Publisher connection. + * + * @var PublisherConnectionInterface + */ + private $connection; + + /** + * Flag. Is publisher disabled. + * + * @var bool + */ + private $isDisabled; + + /** + * Initialize dependencies. + * + * @param PublisherConnectionFactory $connectionFactory + */ + public function __construct(PublisherConnectionFactory $connectionFactory) + { + $this->connection = $connectionFactory->create(); + } + + /** + * {@inheritdoc} + */ + public function getTopic() + { + return $this->topic; + } + + /** + * {@inheritdoc} + */ + public function isDisabled() + { + return $this->isDisabled; + } + + /** + * {@inheritdoc} + */ + public function getConnection() + { + return $this->connection; + } + + /** + * Set publisher config item data. + * + * @param array $data + * @return void + */ + public function setData(array $data) + { + $this->topic = $data['topic']; + $this->isDisabled = $data['disabled']; + $this->connection->setData($data['connection']); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItem/Iterator.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItem/Iterator.php new file mode 100644 index 0000000000000..f0414edfc0c02 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItem/Iterator.php @@ -0,0 +1,145 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItem; + +use Magento\Framework\MessageQueue\Publisher\Config\Data; +use Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItem; +use Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItemFactory; + +/** + * Publisher config data iterator. + */ +class Iterator implements \Iterator, \ArrayAccess +{ + /** + * Publisher config item. + * + * @var PublisherConfigItem + */ + private $object; + + /** + * Config data. + * + * @var array + */ + private $data; + + /** + * Initialize dependencies. + * + * @param Data $configData + * @param PublisherConfigItemFactory $itemFactory + */ + public function __construct(Data $configData, PublisherConfigItemFactory $itemFactory) + { + $this->data = $configData->get(); + $this->object = $itemFactory->create(); + $this->rewind(); + } + + /** + * Get current item. + * + * @return PublisherConfigItem + */ + public function current() + { + return $this->object; + } + + /** + * {@inheritdoc} + */ + public function next() + { + next($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + if ($this->current()->isDisabled()) { + $this->next(); + } + } + } + + /** + * Initialize object. + * + * @param array $data + * @return void + */ + private function initObject(array $data) + { + $this->object->setData($data); + } + + /** + * {@inheritdoc} + */ + public function key() + { + key($this->data); + } + + /** + * {@inheritdoc} + */ + public function valid() + { + return (bool)current($this->data); + } + + /** + * {@inheritdoc} + */ + public function rewind() + { + reset($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + if ($this->current()->isDisabled()) { + $this->next(); + } + } + } + + /** + * {@inheritdoc} + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->data); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($offset) + { + if (!$this->offsetExists($offset) || $this->data[$offset]['disabled'] == true) { + return null; + } + $item = clone $this->object; + $item->setData($this->data[$offset]); + return $item; + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItemFactory.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItemFactory.php new file mode 100644 index 0000000000000..c7e1577ed8cbb --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItemFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItem + */ +class PublisherConfigItemFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = PublisherConfigItem::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return \Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItem + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItemInterface.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItemInterface.php new file mode 100644 index 0000000000000..c9f583ddb7fca --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItemInterface.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +/** + * Instances of this class represent config items declared in etc/queue_publisher.xsd + */ +interface PublisherConfigItemInterface +{ + /** + * Get publisher name. + * + * @return string + */ + public function getTopic(); + + /** + * Check if connection disabled. + * + * @return bool + */ + public function isDisabled(); + + /** + * Get publisher connection. + * + * @return PublisherConnectionInterface + */ + public function getConnection(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConnection.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConnection.php new file mode 100644 index 0000000000000..542448747207b --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConnection.php @@ -0,0 +1,67 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +/** + * Representation of publisher connection configuration. + */ +class PublisherConnection implements PublisherConnectionInterface +{ + /** + * Connection name. + * + * @var string + */ + private $name; + + /** + * Exchange name. + * + * @var string + */ + private $exchange; + + /** + * Flag. Is connection disabled. + * + * @var bool + */ + private $isDisabled; + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function getExchange() + { + return $this->exchange; + } + + /** + * {@inheritdoc} + */ + public function isDisabled() + { + return $this->isDisabled; + } + + /** + * {@inheritdoc} + */ + public function setData(array $data) + { + $this->name = $data['name']; + $this->exchange = $data['exchange']; + $this->isDisabled = $data['disabled']; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConnectionFactory.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConnectionFactory.php new file mode 100644 index 0000000000000..a2b51ecb0e22d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConnectionFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\Publisher\Config\PublisherConnectionInterface + */ +class PublisherConnectionFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = PublisherConnection::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return \Magento\Framework\MessageQueue\Publisher\Config\PublisherConnection + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConnectionInterface.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConnectionInterface.php new file mode 100644 index 0000000000000..71ad8c6beaef4 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/PublisherConnectionInterface.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +/** + * Representation of publisher connection configuration. + */ +interface PublisherConnectionInterface +{ + /** + * Get Connection name. + * + * @return string + */ + public function getName(); + + /** + * Get exchange name. + * + * @return string + */ + public function getExchange(); + + /** + * Check if connection disabled. + * + * @return bool + */ + public function isDisabled(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/ReaderInterface.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/ReaderInterface.php new file mode 100644 index 0000000000000..669daef963a13 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/ReaderInterface.php @@ -0,0 +1,14 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +/** + * Publisher config reader interface + */ +interface ReaderInterface extends \Magento\Framework\Config\ReaderInterface +{ + +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/RemoteService/Reader.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/RemoteService/Reader.php new file mode 100644 index 0000000000000..656ed5450180f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/RemoteService/Reader.php @@ -0,0 +1,111 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config\RemoteService; + +use Magento\Framework\Communication\Config\ReflectionGenerator; +use Magento\Framework\MessageQueue\Code\Generator\RemoteServiceGenerator; +use Magento\Framework\MessageQueue\DefaultValueProvider; +use Magento\Framework\MessageQueue\Publisher\Config\ReaderInterface; +use Magento\Framework\ObjectManager\ConfigInterface as ObjectManagerConfig; +use Magento\Framework\Reflection\MethodsMap as ServiceMethodsMap; + +/** + * Reader for queue publisher configs based on remote service declaration in DI configs. + */ +class Reader implements ReaderInterface +{ + /** + * @var DefaultValueProvider + */ + private $defaultValueProvider; + + /** + * @var ObjectManagerConfig + */ + private $objectManagerConfig; + + /** + * @var ReflectionGenerator + */ + private $reflectionGenerator; + + /** + * @var ServiceMethodsMap + */ + private $serviceMethodsMap; + + /** + * Initialize dependencies. + * + * @param DefaultValueProvider $defaultValueProvider + * @param ObjectManagerConfig $objectManagerConfig + * @param ReflectionGenerator $reflectionGenerator + * @param ServiceMethodsMap $serviceMethodsMap + */ + public function __construct( + DefaultValueProvider $defaultValueProvider, + ObjectManagerConfig $objectManagerConfig, + ReflectionGenerator $reflectionGenerator, + ServiceMethodsMap $serviceMethodsMap + ) { + $this->defaultValueProvider = $defaultValueProvider; + $this->objectManagerConfig = $objectManagerConfig; + $this->reflectionGenerator = $reflectionGenerator; + $this->serviceMethodsMap = $serviceMethodsMap; + } + + /** + * {@inheritdoc} + * + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + */ + public function read($scope = null) + { + $result = []; + $connectionName = $this->defaultValueProvider->getConnection(); + $connections = [ + $connectionName => [ + 'name' => $connectionName, + 'exchange' => $this->defaultValueProvider->getExchange(), + 'disabled' => false, + ] + ]; + foreach ($this->getRemoteServices() as $serviceInterface => $remoteImplementation) { + try { + $methodsMap = $this->serviceMethodsMap->getMethodsMap($serviceInterface); + } catch (\Exception $e) { + throw new \LogicException(sprintf('Service interface was expected, "%s" given', $serviceInterface)); + } + foreach ($methodsMap as $methodName => $returnType) { + $topic = $this->reflectionGenerator->generateTopicName($serviceInterface, $methodName); + $result[$topic] = [ + 'topic' => $topic, + 'disabled' => false, + 'connections' => $connections, + + ]; + } + } + return $result; + } + + /** + * Get list of remote services declared in DI config. + * + * @return array + */ + private function getRemoteServices() + { + $preferences = $this->objectManagerConfig->getPreferences(); + $remoteServices = []; + foreach ($preferences as $type => $preference) { + if ($preference == $type . RemoteServiceGenerator::REMOTE_SERVICE_SUFFIX) { + $remoteServices[$type] = $preference; + } + } + return $remoteServices; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Validator/EnabledConnection.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Validator/EnabledConnection.php new file mode 100644 index 0000000000000..01a0dff3cc73c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Validator/EnabledConnection.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config\Validator; + +use Magento\Framework\MessageQueue\Publisher\Config\ValidatorInterface; + +/** + * Publisher config data validator. Validates that publisher has only one enabled connection at the same time + */ +class EnabledConnection implements ValidatorInterface +{ + /** + * {@inheritdoc} + */ + public function validate($configData) + { + $errors = []; + foreach ($configData as $name => $publisherData) { + if (!isset($publisherData['connections'])) { + continue; + } + $enabledConnections = 0; + foreach ($publisherData['connections'] as $connectionConfig) { + if ($connectionConfig['disabled'] == false) { + $enabledConnections++; + } + } + + if ($enabledConnections > 1) { + $errors[] = sprintf('More than 1 enabled connections configured for publisher %s.', $name); + } + } + + if (!empty($errors)) { + throw new \LogicException(implode(' ', $errors)); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Validator/Format.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Validator/Format.php new file mode 100644 index 0000000000000..10f8043649303 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Validator/Format.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config\Validator; + +use Magento\Framework\MessageQueue\Publisher\Config\ValidatorInterface; + +/** + * Publisher config data validator. Validates that publisher config has all required fields. + */ +class Format implements ValidatorInterface +{ + /** + * {@inheritdoc} + */ + public function validate($configData) + { + $requiredPublisherFields = ['topic', 'disabled', 'connections']; + $requiredConnectionFields = ['name', 'disabled', 'exchange']; + + $errors = []; + foreach ($configData as $name => $publisherData) { + $diff = array_diff($requiredPublisherFields, array_keys($publisherData)); + foreach ($diff as $field) { + $errors[] = sprintf('Missing %s field for publisher %s.', $field, $name); + } + + if (!array_key_exists('connections', $publisherData) || !is_array($publisherData['connections'])) { + $errors[] = sprintf('Invalid connections format for publisher %s.', $name); + continue; + } + + foreach ($publisherData['connections'] as $connectionConfig) { + $diff = array_diff($requiredConnectionFields, array_keys($connectionConfig)); + foreach ($diff as $field) { + $errors[] = sprintf('Missing %s field for publisher %s in connection config.', $field, $name); + } + } + } + + if (!empty($errors)) { + throw new \LogicException(implode(' ', $errors)); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/ValidatorInterface.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/ValidatorInterface.php new file mode 100644 index 0000000000000..8f210f44039c5 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/ValidatorInterface.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config; + +/** + * Publisher config data validator. + */ +interface ValidatorInterface +{ + /** + * Validate publisher config data. + * + * @param array $configData + * @throws \LogicException + * @return void + */ + public function validate($configData); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Xml/Converter.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Xml/Converter.php new file mode 100644 index 0000000000000..10fc9716cb650 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Xml/Converter.php @@ -0,0 +1,98 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config\Xml; + +use Magento\Framework\Stdlib\BooleanUtils; +use Magento\Framework\MessageQueue\DefaultValueProvider; + +/** + * Converts MessageQueue publishers config from \DOMDocument to array + */ +class Converter implements \Magento\Framework\Config\ConverterInterface +{ + /** + * Boolean value converter. + * + * @var BooleanUtils + */ + private $booleanUtils; + + /** + * Default value provider. + * + * @var DefaultValueProvider + */ + private $defaultValueProvider; + + /** + * Initialize dependencies. + * + * @param BooleanUtils $booleanUtils + * @param DefaultValueProvider $defaultValueProvider + */ + public function __construct(BooleanUtils $booleanUtils, DefaultValueProvider $defaultValueProvider) + { + $this->booleanUtils = $booleanUtils; + $this->defaultValueProvider = $defaultValueProvider; + } + + /** + * {@inheritdoc} + */ + public function convert($source) + { + $result = []; + /** @var $publisherConfig \DOMElement */ + foreach ($source->getElementsByTagName('publisher') as $publisherConfig) { + $topic = $this->getAttributeValue($publisherConfig, 'topic'); + + $connections = []; + /** @var \DOMNode $connectionConfig */ + foreach ($publisherConfig->childNodes as $connectionConfig) { + if ($connectionConfig->nodeName != 'connection' || $connectionConfig->nodeType != XML_ELEMENT_NODE) { + continue; + } + $connectionName = $this->getAttributeValue($connectionConfig, 'name'); + if (!$connectionName) { + throw new \InvalidArgumentException('Connection name is missing'); + } + $exchangeName = $this->getAttributeValue( + $connectionConfig, + 'exchange', + $this->defaultValueProvider->getExchange() + ); + $isDisabled = $this->getAttributeValue($connectionConfig, 'disabled', false); + $connections[$connectionName] = [ + 'name' => $connectionName, + 'exchange' => $exchangeName, + 'disabled' => $this->booleanUtils->toBoolean($isDisabled), + ]; + } + $isDisabled = $this->getAttributeValue($publisherConfig, 'disabled', false); + $result[$topic] = [ + 'topic' => $topic, + 'disabled' => $this->booleanUtils->toBoolean($isDisabled), + 'connections' => $connections, + + ]; + } + return $result; + } + + /** + * Get attribute value of the given node + * + * @param \DOMNode $node + * @param string $attributeName + * @param mixed $default + * @return string|null + */ + private function getAttributeValue(\DOMNode $node, $attributeName, $default = null) + { + $item = $node->attributes->getNamedItem($attributeName); + return $item ? $item->nodeValue : $default; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Xml/Reader.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Xml/Reader.php new file mode 100644 index 0000000000000..6a6625423f33e --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Xml/Reader.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config\Xml; + +use \Magento\Framework\MessageQueue\Publisher\Config\ReaderInterface; + +/** + * Reader for etc/queue_publisher.xml configs. + */ +class Reader extends \Magento\Framework\Config\Reader\Filesystem implements ReaderInterface +{ + /** + * {@inheritdoc} + */ + protected $_idAttributes = [ + '/config/publisher' => 'topic', + '/config/publisher/connection' => 'name' + ]; + + /** + * {@inheritdoc} + */ + public function __construct( + \Magento\Framework\Config\FileResolverInterface $fileResolver, + Converter $converter, + SchemaLocator $schemaLocator, + \Magento\Framework\Config\ValidationStateInterface $validationState, + $fileName = 'queue_publisher.xml', + $idAttributes = [], + $domDocumentClass = \Magento\Framework\Config\Dom::class, + $defaultScope = 'global' + ) { + parent::__construct( + $fileResolver, + $converter, + $schemaLocator, + $validationState, + $fileName, + $idAttributes, + $domDocumentClass, + $defaultScope + ); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Xml/SchemaLocator.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Xml/SchemaLocator.php new file mode 100644 index 0000000000000..aa9b2127f0ea1 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/Config/Xml/SchemaLocator.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher\Config\Xml; + +/** + * Schema locator for etc/queue_publisher.xml + */ +class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface +{ + /** + * Path to corresponding XSD file with validation rules for merged config + * + * @var string + */ + protected $schema; + + /** + * Path to corresponding XSD file with validation rules for separate config files + * + * @var string + */ + protected $perFileSchema; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\Config\Dom\UrnResolver $urnResolver + */ + public function __construct(\Magento\Framework\Config\Dom\UrnResolver $urnResolver) + { + $this->schema = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/publisher.xsd'); + $this->perFileSchema = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/publisher.xsd'); + } + + /** + * Get path to merged config schema + * + * @return string|null + */ + public function getSchema() + { + return $this->schema; + } + + /** + * Get path to per file validation schema + * + * @return string|null + */ + public function getPerFileSchema() + { + return $this->perFileSchema; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Publisher/ConfigInterface.php b/lib/internal/Magento/Framework/MessageQueue/Publisher/ConfigInterface.php new file mode 100644 index 0000000000000..7b5586b28a273 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Publisher/ConfigInterface.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Publisher; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItemInterface; + +/** + * Publisher config interface provides access data declared in etc/queue_publisher.xml + * + * @api + * @since 100.2.0 + */ +interface ConfigInterface +{ + /** + * Get publisher configuration by topic. + * + * @param string $topic + * @return PublisherConfigItemInterface + * @throws LocalizedException + * @throws \LogicException + * @since 100.2.0 + */ + public function getPublisher($topic); + + /** + * Get list of all publishers declared in the system. + * + * @return PublisherConfigItemInterface[] + * @throws \LogicException + * @since 100.2.0 + */ + public function getPublishers(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/PublisherInterface.php b/lib/internal/Magento/Framework/MessageQueue/PublisherInterface.php new file mode 100644 index 0000000000000..1aee963b1bd47 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/PublisherInterface.php @@ -0,0 +1,24 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Producer to publish messages via a specific transport to a specific queue or exchange. + * + * @api + */ +interface PublisherInterface +{ + /** + * Publishes a message to a specific queue or exchange. + * + * @param string $topicName + * @param array|object $data + * @return null|mixed + * @throws \InvalidArgumentException If message is not formed properly + */ + public function publish($topicName, $data); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/PublisherPool.php b/lib/internal/Magento/Framework/MessageQueue/PublisherPool.php new file mode 100644 index 0000000000000..2c1e4e64c7d71 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/PublisherPool.php @@ -0,0 +1,191 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue; + +use Magento\Framework\MessageQueue\ConfigInterface as QueueConfig; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; +use Magento\Framework\MessageQueue\Publisher\ConfigInterface as PublisherConfig; + +/** + * Publishers pool. + * + * @api + * @since 100.1.0 + */ +class PublisherPool implements PublisherInterface, BulkPublisherInterface +{ + const MODE_SYNC = 'sync'; + const MODE_ASYNC = 'async'; + + /** + * @deprecated + */ + const TYPE = 'type'; + + /** + * @deprecated + */ + const CONNECTION_NAME = 'connectionName'; + + /** + * Publisher objects pool. + * + * @var \Magento\Framework\MessageQueue\PublisherInterface[] + * @since 100.1.0 + */ + protected $publishers = []; + + /** + * Communication config. + * + * @var CommunicationConfig + * @since 100.1.0 + */ + protected $communicationConfig; + + /** + * @var PublisherConfig + */ + private $publisherConfig; + + /** + * @var ConnectionTypeResolver + */ + private $connectionTypeResolver; + + /** + * Initialize dependencies. + * + * @param CommunicationConfig $communicationConfig + * @param QueueConfig $queueConfig + * @param string[] $publishers + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + * @since 100.1.0 + */ + public function __construct( + CommunicationConfig $communicationConfig, + QueueConfig $queueConfig, + array $publishers + ) { + $this->communicationConfig = $communicationConfig; + $this->initializePublishers($publishers); + } + + /** + * {@inheritdoc} + * @since 100.1.0 + */ + public function publish($topicName, $data) + { + $publisherType = $this->communicationConfig->getTopic($topicName)[CommunicationConfig::TOPIC_IS_SYNCHRONOUS] + ? self::MODE_SYNC + : self::MODE_ASYNC; + $connectionName = $this->getPublisherConfig()->getPublisher($topicName)->getConnection()->getName(); + $publisher = $this->getPublisherForConnectionNameAndType($publisherType, $connectionName); + return $publisher->publish($topicName, $data); + } + + /** + * Initialize publisher objects pool. + * + * @param array $publishers + * @return void + */ + private function initializePublishers(array $publishers) + { + $asyncPublishers = isset($publishers[self::MODE_ASYNC]) ? $publishers[self::MODE_ASYNC] : []; + $syncPublishers = isset($publishers[self::MODE_SYNC]) ? $publishers[self::MODE_SYNC] : []; + foreach ($asyncPublishers as $connectionType => $publisher) { + $this->addPublisherToPool( + self::MODE_ASYNC, + $connectionType, + $publisher + ); + } + foreach ($syncPublishers as $connectionType => $publisher) { + $this->addPublisherToPool( + self::MODE_SYNC, + $connectionType, + $publisher + ); + } + } + + /** + * Add publisher. + * + * @param string $type + * @param string $connectionType + * @param PublisherInterface $publisher + * @return $this + */ + private function addPublisherToPool($type, $connectionType, PublisherInterface $publisher) + { + $this->publishers[$type][$connectionType] = $publisher; + return $this; + } + + /** + * Return an instance of a publisher for a connection name. + * + * @param string $type + * @param string $connectionName + * @return PublisherInterface + * @throws \LogicException + * @throws \InvalidArgumentException + */ + private function getPublisherForConnectionNameAndType($type, $connectionName) + { + $connectionType = $this->getConnectionTypeResolver()->getConnectionType($connectionName); + if (!isset($this->publishers[$type])) { + throw new \InvalidArgumentException('Unknown publisher type ' . $type); + } + + if (!isset($this->publishers[$type][$connectionType])) { + throw new \LogicException( + sprintf( + 'Could not find an implementation type for type "%s" and connection "%s".', + $type, + $connectionName + ) + ); + } + return $this->publishers[$type][$connectionType]; + } + + /** + * Get publisher config. + * + * @return PublisherConfig + * + * @deprecated 100.2.0 + */ + private function getPublisherConfig() + { + if ($this->publisherConfig === null) { + $this->publisherConfig = \Magento\Framework\App\ObjectManager::getInstance()->get(PublisherConfig::class); + } + return $this->publisherConfig; + } + + /** + * Get connection type resolver. + * + * @return ConnectionTypeResolver + * + * @deprecated 100.2.0 + */ + private function getConnectionTypeResolver() + { + if ($this->connectionTypeResolver === null) { + $this->connectionTypeResolver = \Magento\Framework\App\ObjectManager::getInstance() + ->get(ConnectionTypeResolver::class); + } + return $this->connectionTypeResolver; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/QueueFactory.php b/lib/internal/Magento/Framework/MessageQueue/QueueFactory.php new file mode 100644 index 0000000000000..eb734df06a59f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/QueueFactory.php @@ -0,0 +1,73 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\Queuenterface + * + * @api + * @since 100.2.0 + */ +class QueueFactory implements QueueFactoryInterface +{ + /** + * @var QueueFactoryInterface[] + */ + private $queueFactories; + + /** + * @var ConnectionTypeResolver + */ + private $connectionTypeResolver; + + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + * @since 100.2.0 + */ + protected $objectManager = null; + + /** + * Initialize dependencies. + * + * @param ConnectionTypeResolver $connectionTypeResolver + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param QueueFactoryInterface[] $queueFactories + * @since 100.2.0 + */ + public function __construct( + ConnectionTypeResolver $connectionTypeResolver, + \Magento\Framework\ObjectManagerInterface $objectManager, + array $queueFactories = [] + ) { + $this->objectManager = $objectManager; + $this->queueFactories = $queueFactories; + $this->connectionTypeResolver = $connectionTypeResolver; + } + + /** + * {@inheritdoc} + * @since 100.2.0 + */ + public function create($queueName, $connectionName) + { + $connectionType = $this->connectionTypeResolver->getConnectionType($connectionName); + if (!isset($this->queueFactories[$connectionType])) { + throw new \LogicException("Not found queue for connection name '{$connectionName}' in config"); + } + $factory = $this->queueFactories[$connectionType]; + $queue = $factory->create($queueName, $connectionName); + + if (!$queue instanceof QueueInterface) { + $queueInterface = \Magento\Framework\MessageQueue\QueueInterface::class; + throw new \LogicException( + "Queue for connection name '{$connectionName}' does not implement interface '{$queueInterface}'" + ); + } + return $queue; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/QueueFactoryInterface.php b/lib/internal/Magento/Framework/MessageQueue/QueueFactoryInterface.php new file mode 100644 index 0000000000000..697db9296b5b0 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/QueueFactoryInterface.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\QueueInterface + * + * @api + * @since 100.2.0 + */ +interface QueueFactoryInterface +{ + /** + * Create queue instance. + * + * @param string $queueName + * @param string $connectionName + * @return QueueInterface + * @since 100.2.0 + */ + public function create($queueName, $connectionName); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/QueueInterface.php b/lib/internal/Magento/Framework/MessageQueue/QueueInterface.php new file mode 100644 index 0000000000000..1b3814b8e857a --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/QueueInterface.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Interface for interaction with message queue. + * + * @api + */ +interface QueueInterface +{ + /** + * Get message from queue + * + * @return EnvelopeInterface + */ + public function dequeue(); + + /** + * Acknowledge message delivery + * + * @param EnvelopeInterface $envelope + * @return void + */ + public function acknowledge(EnvelopeInterface $envelope); + + /** + * Wait for messages and dispatch them + * + * @param callable|array $callback + * @return void + */ + public function subscribe($callback); + + /** + * Reject message + * + * @param EnvelopeInterface $envelope + * @param bool $requeue + * @param string $rejectionMessage + * @return void + */ + public function reject(EnvelopeInterface $envelope, $requeue = true, $rejectionMessage = null); + + /** + * Push message to queue directly, without using exchange + * + * @param EnvelopeInterface $envelope + * @return void + * @since 100.1.0 + */ + public function push(EnvelopeInterface $envelope); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/QueueRepository.php b/lib/internal/Magento/Framework/MessageQueue/QueueRepository.php new file mode 100644 index 0000000000000..5d04003c9ade0 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/QueueRepository.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue; + +/** + * Queue factory + */ +class QueueRepository +{ + /** + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager; + + /** + * @var QueueInterface[] + */ + private $queueInstances; + + /** + * @var QueueFactoryInterface + */ + private $queueFactory; + + /** + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string[] $queues + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager, array $queues = []) + { + $this->objectManager = $objectManager; + } + + /** + * Get queue instance by connection name and queue name. + * + * @param string $connectionName + * @param string $queueName + * @return QueueInterface + * @throws \LogicException + */ + public function get($connectionName, $queueName) + { + if (!isset($this->queueInstances[$connectionName][$queueName])) { + $queue = $this->getQueueFactory()->create($queueName, $connectionName); + $this->queueInstances[$connectionName][$queueName] = $queue; + } + return $this->queueInstances[$connectionName][$queueName]; + } + + /** + * Get queue factory. + * + * @return QueueFactoryInterface + * @deprecated 100.2.0 + */ + private function getQueueFactory() + { + if ($this->queueFactory === null) { + $this->queueFactory = $this->objectManager->get(QueueFactoryInterface::class); + } + return $this->queueFactory; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/README.md b/lib/internal/Magento/Framework/MessageQueue/README.md new file mode 100644 index 0000000000000..9708d30102f43 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/README.md @@ -0,0 +1 @@ +This component is designed to provide Message Queue Framework diff --git a/lib/internal/Magento/Framework/MessageQueue/Rpc/Consumer.php b/lib/internal/Magento/Framework/MessageQueue/Rpc/Consumer.php new file mode 100644 index 0000000000000..10ef24c462808 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Rpc/Consumer.php @@ -0,0 +1,16 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Rpc; + +/** + * A MessageQueue Consumer to handle receiving, processing and replying to an RPC message. + * + * @deprecated 100.2.0 + */ +class Consumer extends \Magento\Framework\MessageQueue\Consumer +{ +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Rpc/Publisher.php b/lib/internal/Magento/Framework/MessageQueue/Rpc/Publisher.php new file mode 100644 index 0000000000000..89b987cbb4405 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Rpc/Publisher.php @@ -0,0 +1,135 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Rpc; + +use Magento\Framework\MessageQueue\PublisherInterface; +use Magento\Framework\MessageQueue\EnvelopeFactory; +use Magento\Framework\MessageQueue\ExchangeRepository; +use Magento\Framework\MessageQueue\MessageEncoder; +use Magento\Framework\MessageQueue\MessageValidator; +use Magento\Framework\MessageQueue\Publisher\ConfigInterface as PublisherConfig; + +/** + * A MessageQueue Publisher to handle publishing a message. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class Publisher implements PublisherInterface +{ + /** + * @var ExchangeRepository + */ + private $exchangeRepository; + + /** + * @var EnvelopeFactory + */ + private $envelopeFactory; + + /** + * @var MessageEncoder + */ + private $messageEncoder; + + /** + * @var MessageValidator + */ + private $messageValidator; + + /** + * @var ResponseQueueNameBuilder + */ + private $responseQueueNameBuilder; + + /** + * @var PublisherConfig + */ + private $publisherConfig; + + //@codingStandardsIgnoreStart + /** + * Initialize dependencies. + * + * @param ExchangeRepository $exchangeRepository + * @param EnvelopeFactory $envelopeFactory + * @param null $messageQueueConfig @deprecated obsolete dependency + * @param null $amqpConfig @deprecated obsolete dependency + * @param MessageEncoder $messageEncoder + * @param MessageValidator $messageValidator + * + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function __construct( + ExchangeRepository $exchangeRepository, + EnvelopeFactory $envelopeFactory, + $messageQueueConfig = null, + $amqpConfig = null, + MessageEncoder $messageEncoder, + MessageValidator $messageValidator + ) { + $this->exchangeRepository = $exchangeRepository; + $this->envelopeFactory = $envelopeFactory; + $this->messageEncoder = $messageEncoder; + $this->messageValidator = $messageValidator; + } + //@codingStandardsIgnoreEnd + + /** + * {@inheritdoc} + */ + public function publish($topicName, $data) + { + $this->messageValidator->validate($topicName, $data); + $data = $this->messageEncoder->encode($topicName, $data); + $replyTo = $this->getResponseQueueNameBuilder()->getQueueName($topicName); + $envelope = $this->envelopeFactory->create( + [ + 'body' => $data, + 'properties' => [ + 'reply_to' => $replyTo, + 'delivery_mode' => 2, + 'correlation_id' => rand(), + 'message_id' => md5(uniqid($topicName)) + ] + ] + ); + $connectionName = $this->getPublisherConfig()->getPublisher($topicName)->getConnection()->getName(); + $exchange = $this->exchangeRepository->getByConnectionName($connectionName); + $responseMessage = $exchange->enqueue($topicName, $envelope); + return $this->messageEncoder->decode($topicName, $responseMessage, false); + } + + /** + * Get response queue name builder. + * + * @return ResponseQueueNameBuilder + * + * @deprecated 100.2.0 + */ + private function getResponseQueueNameBuilder() + { + if ($this->responseQueueNameBuilder === null) { + $this->responseQueueNameBuilder = \Magento\Framework\App\ObjectManager::getInstance() + ->get(ResponseQueueNameBuilder::class); + } + return $this->responseQueueNameBuilder; + } + + /** + * Get publisher config. + * + * @return PublisherConfig + * + * @deprecated 100.2.0 + */ + private function getPublisherConfig() + { + if ($this->publisherConfig === null) { + $this->publisherConfig = \Magento\Framework\App\ObjectManager::getInstance()->get(PublisherConfig::class); + } + return $this->publisherConfig; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Rpc/ResponseQueueNameBuilder.php b/lib/internal/Magento/Framework/MessageQueue/Rpc/ResponseQueueNameBuilder.php new file mode 100644 index 0000000000000..8115a5f6ee28d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Rpc/ResponseQueueNameBuilder.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Rpc; + +class ResponseQueueNameBuilder +{ + /** + * Response queue name prefix + */ + const RESPONSE_QUEUE_PREFIX = 'responseQueue.'; + + /** + * Get response queue name. + * + * @param string $topicName + * @return string + */ + public function getQueueName($topicName) + { + return self::RESPONSE_QUEUE_PREFIX . str_replace('-', '_', $topicName); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/BatchConsumerTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/BatchConsumerTest.php new file mode 100644 index 0000000000000..32120e12cf677 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/BatchConsumerTest.php @@ -0,0 +1,210 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit; + +/** + * Unit test for BatchConsumer class. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class BatchConsumerTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\ConsumerConfigurationInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $configuration; + + /** + * @var \Magento\Framework\MessageQueue\MessageEncoder|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageEncoder; + + /** + * @var \Magento\Framework\MessageQueue\QueueRepository|\PHPUnit_Framework_MockObject_MockObject + */ + private $queueRepository; + + /** + * @var \Magento\Framework\MessageQueue\MergerFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $mergerFactory; + + /** + * @var \Magento\Framework\MessageQueue\Consumer\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $consumerConfig; + + /** + * @var \Magento\Framework\MessageQueue\MessageController|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageController; + + /** + * @var \Magento\Framework\App\ResourceConnection|\PHPUnit_Framework_MockObject_MockObject + */ + private $resource; + + /** + * @var \Magento\Framework\MessageQueue\BatchConsumer + */ + private $batchConsumer; + + /** + * @var int + */ + private $batchSize = 10; + + /** + * @var \Magento\Framework\MessageQueue\MessageProcessorLoader|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageProcessorLoader; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->configuration = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\ConsumerConfigurationInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->messageEncoder = $this->getMockBuilder(\Magento\Framework\MessageQueue\MessageEncoder::class) + ->disableOriginalConstructor()->getMock(); + $this->queueRepository = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueRepository::class) + ->disableOriginalConstructor()->getMock(); + $this->mergerFactory = $this->getMockBuilder(\Magento\Framework\MessageQueue\MergerFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor()->getMock(); + $this->resource = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class) + ->disableOriginalConstructor()->getMock(); + $this->messageProcessorLoader = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\MessageProcessorLoader::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->batchConsumer = $objectManager->getObject( + \Magento\Framework\MessageQueue\BatchConsumer::class, + [ + 'configuration' => $this->configuration, + 'messageEncoder' => $this->messageEncoder, + 'queueRepository' => $this->queueRepository, + 'mergerFactory' => $this->mergerFactory, + 'resource' => $this->resource, + 'batchSize' => $this->batchSize, + 'messageProcessorLoader' => $this->messageProcessorLoader + ] + ); + + $this->consumerConfig = $this->getMockBuilder(\Magento\Framework\MessageQueue\Consumer\ConfigInterface::class) + ->disableOriginalConstructor()->getMock(); + $objectManager->setBackwardCompatibleProperty( + $this->batchConsumer, + 'consumerConfig', + $this->consumerConfig + ); + $this->messageController = $this->getMockBuilder(\Magento\Framework\MessageQueue\MessageController::class) + ->disableOriginalConstructor()->getMock(); + $objectManager->setBackwardCompatibleProperty( + $this->batchConsumer, + 'messageController', + $this->messageController + ); + } + + /** + * Test for process(). + * + * @return void + */ + public function testProcess() + { + $queueName = 'queue.name'; + $consumerName = 'consumerName'; + $connectionName = 'connection_name'; + $topicName = 'topicName'; + $messageBody = 'messageBody'; + $message = ['message_data']; + $numberOfMessages = 2; + $this->configuration->expects($this->once())->method('getQueueName')->willReturn($queueName); + $this->configuration->expects($this->atLeastOnce())->method('getConsumerName')->willReturn($consumerName); + $consumerConfigItem = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItemInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->consumerConfig->expects($this->once()) + ->method('getConsumer')->with($consumerName)->willReturn($consumerConfigItem); + $consumerConfigItem->expects($this->once())->method('getConnection')->willReturn($connectionName); + $queue = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->queueRepository->expects($this->once()) + ->method('get')->with($connectionName, $queueName)->willReturn($queue); + $merger = $this->getMockBuilder(\Magento\Framework\MessageQueue\MergerInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->mergerFactory->expects($this->once())->method('create')->with($consumerName)->willReturn($merger); + $envelope = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor()->getMock(); + $queue->expects($this->exactly($numberOfMessages))->method('dequeue')->willReturn($envelope); + $this->messageController->expects($this->exactly($numberOfMessages)) + ->method('lock')->with($envelope, $consumerName); + $envelope->expects($this->exactly($numberOfMessages)) + ->method('getProperties')->willReturn(['topic_name' => $topicName]); + $envelope->expects($this->exactly($numberOfMessages)) + ->method('getBody')->willReturn($messageBody); + $this->messageEncoder->expects($this->exactly($numberOfMessages)) + ->method('decode')->with($topicName, $messageBody)->willReturn($message); + $messageProcessor = $this->getMockBuilder(\Magento\Framework\MessageQueue\MessageProcessorInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->messageProcessorLoader->expects($this->atLeastOnce())->method('load')->willReturn($messageProcessor); + $merger->expects($this->once())->method('merge') + ->with([$topicName => [$message, $message]])->willReturnArgument(0); + + $this->batchConsumer->process($numberOfMessages); + } + + /** + * Test for process() with MessageLockException. + * + * @return void + */ + public function testProcessWithMessageLockException() + { + $queueName = 'queue.name'; + $consumerName = 'consumerName'; + $connectionName = 'connection_name'; + $numberOfMessages = 2; + $this->configuration->expects($this->once())->method('getQueueName')->willReturn($queueName); + $this->configuration->expects($this->atLeastOnce())->method('getConsumerName')->willReturn($consumerName); + $consumerConfigItem = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItemInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->consumerConfig->expects($this->once()) + ->method('getConsumer')->with($consumerName)->willReturn($consumerConfigItem); + $consumerConfigItem->expects($this->once())->method('getConnection')->willReturn($connectionName); + $queue = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->queueRepository->expects($this->once()) + ->method('get')->with($connectionName, $queueName)->willReturn($queue); + $merger = $this->getMockBuilder(\Magento\Framework\MessageQueue\MergerInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->mergerFactory->expects($this->once())->method('create')->with($consumerName)->willReturn($merger); + $envelope = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor()->getMock(); + $queue->expects($this->exactly($numberOfMessages))->method('dequeue')->willReturn($envelope); + $exception = new \Magento\Framework\MessageQueue\MessageLockException(__('Exception Message')); + $this->messageController->expects($this->atLeastOnce()) + ->method('lock')->with($envelope, $consumerName)->willThrowException($exception); + $messageProcessor = $this->getMockBuilder(\Magento\Framework\MessageQueue\MessageProcessorInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->messageProcessorLoader->expects($this->atLeastOnce())->method('load')->willReturn($messageProcessor); + $merger->expects($this->once())->method('merge')->willReturn([]); + + $this->batchConsumer->process($numberOfMessages); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/ExchangeFactoryTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/ExchangeFactoryTest.php new file mode 100644 index 0000000000000..fd8ccb86d970d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/ExchangeFactoryTest.php @@ -0,0 +1,111 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit\Bulk; + +/** + * Unit test for ExchangeFactory. + */ +class ExchangeFactoryTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\ConnectionTypeResolver|\PHPUnit_Framework_MockObject_MockObject + */ + private $connectionTypeResolver; + + /** + * @var \Magento\Framework\MessageQueue\Bulk\ExchangeInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $amqpExchangeFactory; + + /** + * @var \Magento\Framework\MessageQueue\Bulk\ExchangeFactory + */ + private $exchangeFactory; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->connectionTypeResolver = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\ConnectionTypeResolver::class) + ->disableOriginalConstructor()->getMock(); + + $this->amqpExchangeFactory = $this + ->getMockBuilder(\Magento\Framework\Amqp\ExchangeFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->exchangeFactory = $objectManager->getObject( + \Magento\Framework\MessageQueue\Bulk\ExchangeFactory::class, + [ + 'connectionTypeResolver' => $this->connectionTypeResolver, + 'exchangeFactories' => ['amqp' => $this->amqpExchangeFactory], + ] + ); + } + + /** + * Test for create method. + * + * @return void + */ + public function testCreate() + { + $connectionName = 'amqp'; + $data = ['key1' => 'value1']; + $this->connectionTypeResolver->expects($this->once()) + ->method('getConnectionType')->with($connectionName)->willReturn($connectionName); + $exchange = $this + ->getMockBuilder(\Magento\Framework\Amqp\Bulk\Exchange::class) + ->disableOriginalConstructor()->getMock(); + $this->amqpExchangeFactory->expects($this->once()) + ->method('create')->with($connectionName, $data)->willReturn($exchange); + $this->assertEquals($exchange, $this->exchangeFactory->create($connectionName, $data)); + } + + /** + * Test for create method with undefined connection type. + * + * @return void + * @expectedException \LogicException + * @expectedExceptionMessage Not found exchange for connection name 'db' in config + */ + public function testCreateWithUndefinedConnectionType() + { + $connectionName = 'db'; + $data = ['key1' => 'value1']; + $this->connectionTypeResolver->expects($this->once()) + ->method('getConnectionType')->with($connectionName)->willReturn($connectionName); + $this->amqpExchangeFactory->expects($this->never())->method('create'); + $this->exchangeFactory->create($connectionName, $data); + } + + /** + * Test for create method with wrong exchange type. + * + * @return void + * @expectedException \LogicException + * @expectedExceptionMessage Exchange for connection name 'amqp' does not implement interface + */ + public function testCreateWithWrongExchangeType() + { + $connectionName = 'amqp'; + $data = ['key1' => 'value1']; + $this->connectionTypeResolver->expects($this->once()) + ->method('getConnectionType')->with($connectionName)->willReturn($connectionName); + $exchange = $this + ->getMockBuilder(\Magento\Framework\Amqp\Exchange::class) + ->disableOriginalConstructor()->getMock(); + $this->amqpExchangeFactory->expects($this->once()) + ->method('create')->with($connectionName, $data)->willReturn($exchange); + $this->exchangeFactory->create($connectionName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/ExchangeRepositoryTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/ExchangeRepositoryTest.php new file mode 100644 index 0000000000000..63c7f37ff3f05 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/ExchangeRepositoryTest.php @@ -0,0 +1,60 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit\Bulk; + +/** + * Unit test for ExchangeRepository. + */ +class ExchangeRepositoryTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\Bulk\ExchangeFactoryInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $exchangeFactory; + + /** + * @var \Magento\Framework\MessageQueue\Bulk\ExchangeRepository + */ + private $exchangeRepository; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->exchangeFactory = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Bulk\ExchangeFactoryInterface::class) + ->disableOriginalConstructor()->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->exchangeRepository = $objectManager->getObject( + \Magento\Framework\MessageQueue\Bulk\ExchangeRepository::class + ); + $objectManager->setBackwardCompatibleProperty( + $this->exchangeRepository, + 'exchangeFactory', + $this->exchangeFactory + ); + } + + /** + * Test for getByConnectionName method. + * + * @return void + */ + public function testGetByConnectionName() + { + $connectionName = 'amqp'; + $exchange = $this + ->getMockBuilder(\Magento\Framework\Amqp\Bulk\Exchange::class) + ->disableOriginalConstructor()->getMock(); + $this->exchangeFactory->expects($this->once())->method('create')->with($connectionName)->willReturn($exchange); + $this->assertEquals($exchange, $this->exchangeRepository->getByConnectionName($connectionName)); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/PublisherTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/PublisherTest.php new file mode 100644 index 0000000000000..c429a17096f90 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/PublisherTest.php @@ -0,0 +1,133 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit\Bulk; + +/** + * Unit test for Publisher. + */ +class PublisherTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\Bulk\ExchangeRepository|\PHPUnit_Framework_MockObject_MockObject + */ + private $exchangeRepository; + + /** + * @var \Magento\Framework\MessageQueue\EnvelopeFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $envelopeFactory; + + /** + * @var \Magento\Framework\MessageQueue\MessageEncoder|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageEncoder; + + /** + * @var \Magento\Framework\MessageQueue\MessageValidator|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageValidator; + + /** + * @var \Magento\Framework\MessageQueue\Publisher\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $publisherConfig; + + /** + * @var \Magento\Framework\MessageQueue\MessageIdGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageIdGenerator; + + /** + * @var \Magento\Framework\MessageQueue\Bulk\Publisher + */ + private $publisher; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->exchangeRepository = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Bulk\ExchangeRepository::class) + ->disableOriginalConstructor()->getMock(); + $this->envelopeFactory = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor()->getMock(); + $this->messageEncoder = $this->getMockBuilder(\Magento\Framework\MessageQueue\MessageEncoder::class) + ->disableOriginalConstructor()->getMock(); + $this->messageValidator = $this->getMockBuilder(\Magento\Framework\MessageQueue\MessageValidator::class) + ->disableOriginalConstructor()->getMock(); + $this->publisherConfig = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Publisher\ConfigInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->messageIdGenerator = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\MessageIdGeneratorInterface::class) + ->disableOriginalConstructor()->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->publisher = $objectManager->getObject( + \Magento\Framework\MessageQueue\Bulk\Publisher::class, + [ + 'exchangeRepository' => $this->exchangeRepository, + 'envelopeFactory' => $this->envelopeFactory, + 'messageEncoder' => $this->messageEncoder, + 'messageValidator' => $this->messageValidator, + 'publisherConfig' => $this->publisherConfig, + 'messageIdGenerator' => $this->messageIdGenerator, + ] + ); + } + + /** + * Test for publish method. + * + * @return void + */ + public function testPublish() + { + $messageId = 'message-id-001'; + $topicName = 'topic.name'; + $message = 'messageBody'; + $encodedMessage = 'encodedMessageBody'; + $connectionName = 'amqp'; + $this->messageValidator->expects($this->once())->method('validate')->with($topicName, $message); + $this->messageEncoder->expects($this->once()) + ->method('encode')->with($topicName, $message)->willReturn($encodedMessage); + $envelope = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->messageIdGenerator->expects($this->once()) + ->method('generate')->with($topicName)->willReturn($messageId); + $this->envelopeFactory->expects($this->once())->method('create')->with( + [ + 'body' => $encodedMessage, + 'properties' => [ + 'delivery_mode' => 2, + 'message_id' => $messageId, + ] + ] + )->willReturn($envelope); + $publisher = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItemInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->publisherConfig->expects($this->once()) + ->method('getPublisher')->with($topicName)->willReturn($publisher); + $connection = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Publisher\Config\PublisherConnectionInterface::class) + ->disableOriginalConstructor()->getMock(); + $publisher->expects($this->once())->method('getConnection')->with()->willReturn($connection); + $connection->expects($this->once())->method('getName')->with()->willReturn($connectionName); + $exchange = $this + ->getMockBuilder(\Magento\Framework\Amqp\Bulk\Exchange::class) + ->disableOriginalConstructor()->getMock(); + $this->exchangeRepository->expects($this->once()) + ->method('getByConnectionName')->with($connectionName)->willReturn($exchange); + $exchange->expects($this->once())->method('enqueue')->with($topicName, [$envelope])->willReturn(null); + $this->assertNull($this->publisher->publish($topicName, [$message])); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/Rpc/PublisherTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/Rpc/PublisherTest.php new file mode 100644 index 0000000000000..014fc234f3a5b --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Bulk/Rpc/PublisherTest.php @@ -0,0 +1,145 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit\Bulk\Rpc; + +/** + * Unit test for Publisher. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class PublisherTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\Bulk\ExchangeRepository|\PHPUnit_Framework_MockObject_MockObject + */ + private $exchangeRepository; + + /** + * @var \Magento\Framework\MessageQueue\EnvelopeFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $envelopeFactory; + + /** + * @var \Magento\Framework\MessageQueue\MessageEncoder|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageEncoder; + + /** + * @var \Magento\Framework\MessageQueue\MessageValidator|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageValidator; + + /** + * @var \Magento\Framework\MessageQueue\Publisher\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $publisherConfig; + + /** + * @var \Magento\Framework\MessageQueue\Rpc\ResponseQueueNameBuilder|\PHPUnit_Framework_MockObject_MockObject + */ + private $responseQueueNameBuilder; + + /** + * @var \Magento\Framework\MessageQueue\MessageIdGeneratorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageIdGenerator; + + /** + * @var \Magento\Framework\MessageQueue\Bulk\Rpc\Publisher + */ + private $publisher; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->exchangeRepository = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Bulk\ExchangeRepository::class) + ->disableOriginalConstructor()->getMock(); + $this->envelopeFactory = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeFactory::class) + ->setMethods(['create']) + ->disableOriginalConstructor()->getMock(); + $this->messageEncoder = $this->getMockBuilder(\Magento\Framework\MessageQueue\MessageEncoder::class) + ->disableOriginalConstructor()->getMock(); + $this->messageValidator = $this->getMockBuilder(\Magento\Framework\MessageQueue\MessageValidator::class) + ->disableOriginalConstructor()->getMock(); + $this->publisherConfig = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Publisher\ConfigInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->responseQueueNameBuilder = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Rpc\ResponseQueueNameBuilder::class) + ->disableOriginalConstructor()->getMock(); + $this->messageIdGenerator = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\MessageIdGeneratorInterface::class) + ->disableOriginalConstructor()->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->publisher = $objectManager->getObject( + \Magento\Framework\MessageQueue\Bulk\Rpc\Publisher::class, + [ + 'exchangeRepository' => $this->exchangeRepository, + 'envelopeFactory' => $this->envelopeFactory, + 'messageEncoder' => $this->messageEncoder, + 'messageValidator' => $this->messageValidator, + 'publisherConfig' => $this->publisherConfig, + 'responseQueueNameBuilder' => $this->responseQueueNameBuilder, + 'messageIdGenerator' => $this->messageIdGenerator, + ] + ); + } + + /** + * Test for publish method. + * + * @return void + */ + public function testPublish() + { + $messageId = 'message-id-001'; + $topicName = 'topic.name'; + $message = 'messageBody'; + $encodedMessage = 'encodedMessageBody'; + $connectionName = 'amqp'; + $queueName = 'queueName'; + $this->responseQueueNameBuilder->expects($this->once()) + ->method('getQueueName')->with($topicName)->willReturn($queueName); + $this->messageValidator->expects($this->once())->method('validate')->with($topicName, $message); + $this->messageEncoder->expects($this->once()) + ->method('encode')->with($topicName, $message)->willReturn($encodedMessage); + $envelope = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->messageIdGenerator->expects($this->once()) + ->method('generate')->with($topicName)->willReturn($messageId); + $this->envelopeFactory->expects($this->once())->method('create')->with( + $this->logicalAnd( + $this->arrayHasKey('body'), + $this->arrayHasKey('properties'), + $this->contains($encodedMessage) + ) + )->willReturn($envelope); + $publisher = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItemInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->publisherConfig->expects($this->once()) + ->method('getPublisher')->with($topicName)->willReturn($publisher); + $connection = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\Publisher\Config\PublisherConnectionInterface::class) + ->disableOriginalConstructor()->getMock(); + $publisher->expects($this->once())->method('getConnection')->with()->willReturn($connection); + $connection->expects($this->once())->method('getName')->with()->willReturn($connectionName); + $exchange = $this + ->getMockBuilder(\Magento\Framework\Amqp\Bulk\Exchange::class) + ->disableOriginalConstructor()->getMock(); + $this->exchangeRepository->expects($this->once()) + ->method('getByConnectionName')->with($connectionName)->willReturn($exchange); + $exchange->expects($this->once())->method('enqueue')->with($topicName, [$envelope])->willReturn(null); + $this->assertNull($this->publisher->publish($topicName, [$message])); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/RemoteServiceGeneratorTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/RemoteServiceGeneratorTest.php new file mode 100644 index 0000000000000..e81dc65c6869e --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/RemoteServiceGeneratorTest.php @@ -0,0 +1,184 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Code\Generator; + +use Composer\Autoload\ClassLoader; +use Magento\Framework\Cache\FrontendInterface; +use Magento\Framework\Communication\Config\ReflectionGenerator; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfigInterface; +use Magento\Framework\MessageQueue\Code\Generator\RemoteServiceGenerator; +use Magento\Framework\Reflection\MethodsMap; +use Magento\Framework\Reflection\TypeProcessor; +use Magento\Framework\Serialize\SerializerInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use PHPUnit\Framework\MockObject_MockObject as MockObject; + +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class RemoteServiceGeneratorTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var CommunicationConfigInterface|MockObject + */ + private $communicationConfig; + + /** + * @var RemoteServiceGenerator|MockObject + */ + private $generator; + + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + + $this->communicationConfig = $this->getMockBuilder(CommunicationConfigInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $loader = new ClassLoader(); + $loader->addPsr4( + 'Magento\\Framework\\MessageQueue\\Code\\Generator\\', + __DIR__ . '/_files' + ); + $loader->register(); + } + + /** + * Checks a test case when generator should be possible to generate code + * for a specified interface. + * + * @param string $sourceClassName + * @param string $resultClassName + * @param string $topicName + * @param string $fileName + * @dataProvider interfaceDataProvider + */ + public function testGenerate($sourceClassName, $resultClassName, $topicName, $fileName) + { + $this->createGenerator($sourceClassName, $resultClassName); + + $this->communicationConfig->method('getTopic') + ->willReturnMap( + [ + [$topicName . '.save', [CommunicationConfigInterface::TOPIC_IS_SYNCHRONOUS => true]], + [$topicName . '.get', [CommunicationConfigInterface::TOPIC_IS_SYNCHRONOUS => true]], + [$topicName . '.getById', [CommunicationConfigInterface::TOPIC_IS_SYNCHRONOUS => true]], + [$topicName . '.getList', [CommunicationConfigInterface::TOPIC_IS_SYNCHRONOUS => true]], + [$topicName . '.delete', [CommunicationConfigInterface::TOPIC_IS_SYNCHRONOUS => true]], + [$topicName . '.deleteById', [CommunicationConfigInterface::TOPIC_IS_SYNCHRONOUS => true]], + ] + ); + $expectedResult = file_get_contents(__DIR__ . '/_files/' . $fileName); + $this->validateGeneratedCode($expectedResult); + } + + /** + * Get list of variations for testing remote service generator. + * + * @return array + */ + public function interfaceDataProvider() + { + return [ + [ + '\\' . \Magento\Customer\Api\CustomerRepositoryInterface::class, + '\\' . \Magento\Customer\Api\CustomerRepositoryInterfaceRemote::class, + 'magento.customer.api.customerRepositoryInterface', + 'RemoteService.txt' + ], + [ + '\\' . \Magento\Framework\MessageQueue\Code\Generator\TRepositoryInterface::class, + '\\' . \Magento\Framework\MessageQueue\Code\Generator\TRepositoryInterfaceRemote::class, + 'magento.framework.messageQueue.code.generator.tRepositoryInterface', + 'TRemoteService.txt' + ] + ]; + } + + /** + * Checks if generated code matches provided expected result. + * + * @param string $expectedResult + * @return void + */ + private function validateGeneratedCode($expectedResult) + { + $reflectionObject = new \ReflectionObject($this->generator); + $reflectionMethod = $reflectionObject->getMethod('_generateCode'); + $reflectionMethod->setAccessible(true); + $generatedCode = $reflectionMethod->invoke($this->generator); + self::assertEquals($expectedResult, $generatedCode); + } + + /** + * Creates instance of RemoveServiceGenerator::class with all required dependencies. + * + * @param string $sourceClassName + * @param string $resultClassName + */ + private function createGenerator($sourceClassName, $resultClassName) + { + $methodMap = $this->createMethodMap(); + $this->generator = $this->objectManager->getObject( + RemoteServiceGenerator::class, + [ + 'communicationConfig' => $this->communicationConfig, + 'serviceMethodsMap' => $methodMap, + 'sourceClassName' => $sourceClassName, + 'resultClassName' => $resultClassName, + 'classGenerator' => null + ] + ); + + $reflectionGenerator = $this->objectManager->getObject(ReflectionGenerator::class); + $this->objectManager->setBackwardCompatibleProperty( + $this->generator, + 'reflectionGenerator', + $reflectionGenerator + ); + } + + /** + * Creates instance of MethodsMap::class. + * + * @return MethodsMap + */ + private function createMethodMap() + { + $cache = $this->getMockBuilder(FrontendInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $cache->method('load') + ->willReturn(false); + + $serializer = $this->getMockBuilder(SerializerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $typeProcessor = $this->objectManager->getObject(TypeProcessor::class); + + /** @var MethodsMap $serviceMethodMap */ + $serviceMethodMap = $this->objectManager->getObject(MethodsMap::class, [ + 'cache' => $cache, + 'typeProcessor' => $typeProcessor + ]); + $this->objectManager->setBackwardCompatibleProperty( + $serviceMethodMap, + 'serializer', + $serializer + ); + + return $serviceMethodMap; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/RemoteService.txt b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/RemoteService.txt new file mode 100644 index 0000000000000..d5cfe74440699 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/RemoteService.txt @@ -0,0 +1,90 @@ +namespace Magento\Customer\Api; + +/** + * Remote class for @see \Magento\Customer\Api\CustomerRepositoryInterface + */ +class CustomerRepositoryInterfaceRemote implements CustomerRepositoryInterface +{ + /** + * Publisher + * + * @var \Magento\Framework\MessageQueue\PublisherInterface + */ + protected $publisher = null; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\MessageQueue\PublisherInterface $publisher + */ + public function __construct(\Magento\Framework\MessageQueue\PublisherInterface $publisher) + { + $this->publisher = $publisher; + } + + /** + * @inheritdoc + */ + public function save(\Magento\Customer\Api\Data\CustomerInterface $customer, $passwordHash = null) + { + return $this->publisher->publish( + 'magento.customer.api.customerRepositoryInterface.save', + ['customer' => $customer, 'passwordHash' => $passwordHash] + ); + } + + /** + * @inheritdoc + */ + public function get($email, $websiteId = null) + { + return $this->publisher->publish( + 'magento.customer.api.customerRepositoryInterface.get', + ['email' => $email, 'websiteId' => $websiteId] + ); + } + + /** + * @inheritdoc + */ + public function getById($customerId) + { + return $this->publisher->publish( + 'magento.customer.api.customerRepositoryInterface.getById', + ['customerId' => $customerId] + ); + } + + /** + * @inheritdoc + */ + public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria) + { + return $this->publisher->publish( + 'magento.customer.api.customerRepositoryInterface.getList', + ['searchCriteria' => $searchCriteria] + ); + } + + /** + * @inheritdoc + */ + public function delete(\Magento\Customer\Api\Data\CustomerInterface $customer) + { + return $this->publisher->publish( + 'magento.customer.api.customerRepositoryInterface.delete', + ['customer' => $customer] + ); + } + + /** + * @inheritdoc + */ + public function deleteById($customerId) + { + return $this->publisher->publish( + 'magento.customer.api.customerRepositoryInterface.deleteById', + ['customerId' => $customerId] + ); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/TInterface.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/TInterface.php new file mode 100644 index 0000000000000..687d1f0cc11ac --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/TInterface.php @@ -0,0 +1,11 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Code\Generator; + +interface TInterface +{ + +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/TRemoteService.txt b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/TRemoteService.txt new file mode 100644 index 0000000000000..6d88b6b59f8a4 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/TRemoteService.txt @@ -0,0 +1,90 @@ +namespace Magento\Framework\MessageQueue\Code\Generator; + +/** + * Remote class for @see \Magento\Framework\MessageQueue\Code\Generator\TRepositoryInterface + */ +class TRepositoryInterfaceRemote implements TRepositoryInterface +{ + /** + * Publisher + * + * @var \Magento\Framework\MessageQueue\PublisherInterface + */ + protected $publisher = null; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\MessageQueue\PublisherInterface $publisher + */ + public function __construct(\Magento\Framework\MessageQueue\PublisherInterface $publisher) + { + $this->publisher = $publisher; + } + + /** + * @inheritdoc + */ + public function save(\Magento\Framework\MessageQueue\Code\Generator\TInterface $t) : \Magento\Framework\MessageQueue\Code\Generator\TInterface + { + return $this->publisher->publish( + 'magento.framework.messageQueue.code.generator.tRepositoryInterface.save', + ['t' => $t] + ); + } + + /** + * @inheritdoc + */ + public function get(string $attribute, int $typeId = null) : \Magento\Framework\MessageQueue\Code\Generator\TInterface + { + return $this->publisher->publish( + 'magento.framework.messageQueue.code.generator.tRepositoryInterface.get', + ['attribute' => $attribute, 'typeId' => $typeId] + ); + } + + /** + * @inheritdoc + */ + public function getById(int $tId) : \Magento\Framework\MessageQueue\Code\Generator\TInterface + { + return $this->publisher->publish( + 'magento.framework.messageQueue.code.generator.tRepositoryInterface.getById', + ['tId' => $tId] + ); + } + + /** + * @inheritdoc + */ + public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria) + { + return $this->publisher->publish( + 'magento.framework.messageQueue.code.generator.tRepositoryInterface.getList', + ['searchCriteria' => $searchCriteria] + ); + } + + /** + * @inheritdoc + */ + public function delete(\Magento\Framework\MessageQueue\Code\Generator\TInterface $t) : bool + { + return $this->publisher->publish( + 'magento.framework.messageQueue.code.generator.tRepositoryInterface.delete', + ['t' => $t] + ); + } + + /** + * @inheritdoc + */ + public function deleteById(int $tId) : bool + { + return $this->publisher->publish( + 'magento.framework.messageQueue.code.generator.tRepositoryInterface.deleteById', + ['tId' => $tId] + ); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/TRepositoryInterface.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/TRepositoryInterface.php new file mode 100644 index 0000000000000..592cab83fef62 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Code/Generator/_files/TRepositoryInterface.php @@ -0,0 +1,63 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Code\Generator; + +/** + * Stub interface for remote service generator with PHP 7.0 syntax. + */ +interface TRepositoryInterface +{ + /** + * Saves TInterface entity. + * + * @param TInterface $t + * @return \Magento\Framework\MessageQueue\Code\Generator\TInterface + */ + public function save(\Magento\Framework\MessageQueue\Code\Generator\TInterface $t) + : \Magento\Framework\MessageQueue\Code\Generator\TInterface; + + /** + * Retrieves TInterfaces entity. + * + * @param string $attribute + * @param int|null $typeId + * @return TInterface + */ + public function get(string $attribute, int $typeId = null) + : \Magento\Framework\MessageQueue\Code\Generator\TInterface; + + /** + * Retrieves TInterface entity by id. + * + * @param int $tId + * @return TInterface + */ + public function getById(int $tId) : \Magento\Framework\MessageQueue\Code\Generator\TInterface; + + /** + * Gets list of TInterface entities. + * + * @param \Magento\Framework\Api\SearchCriteriaInterface $searchCriteria + * @return \Magento\Framework\MessageQueue\Code\Generator\TSearchResultsInterface + */ + public function getList(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria); + + /** + * Deletes TInterface entity. + * + * @param TInterface $t + * @return bool + */ + public function delete(\Magento\Framework\MessageQueue\Code\Generator\TInterface $t) : bool; + + /** + * Deletes TInterface entity by id. + * + * @param int $tId + * @return bool + */ + public function deleteById(int $tId) : bool; +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Consumer/ConfigReaderPluginTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Consumer/ConfigReaderPluginTest.php new file mode 100644 index 0000000000000..0eaddf35004e7 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Consumer/ConfigReaderPluginTest.php @@ -0,0 +1,100 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Config\Consumer; + +use Magento\Framework\MessageQueue\Config\Consumer\ConfigReaderPlugin as ConsumerConfigReaderPlugin; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\MessageQueue\ConfigInterface; +use Magento\Framework\MessageQueue\Consumer\Config\CompositeReader as ConsumerConfigCompositeReader; + +class ConfigReaderPluginTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ConsumerConfigReaderPlugin + */ + private $plugin; + + /** + * @var ObjectManagerHelper + */ + private $objectManagerHelper; + + /** + * @var ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $configMock; + + /** + * @var ConsumerConfigCompositeReader|\PHPUnit_Framework_MockObject_MockObject + */ + private $subjectMock; + + protected function setUp() + { + $this->configMock = $this->getMockBuilder(ConfigInterface::class) + ->getMockForAbstractClass(); + $this->subjectMock = $this->getMockBuilder(ConsumerConfigCompositeReader::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->plugin = $this->objectManagerHelper->getObject( + ConsumerConfigReaderPlugin::class, + ['config' => $this->configMock] + ); + } + + public function testAfterRead() + { + $result = ['consumer0' => []]; + $consumers = [ + [ + 'name' => 'consumer1', + 'handlers' => [ + ['handlerConfig1_1_1', 'handlerConfig1_1_2'], + ['handlerConfig1_2_1'] + ], + 'queue' => ['item1_1', 'item1_2'], + 'instance_type' => 'type1', + 'connection' => 'connection1', + 'max_messages' => 100 + ], + [ + 'name' => 'consumer2', + 'handlers' => [], + 'queue' => ['item2_1'], + 'instance_type' => 'type2', + 'connection' => 'connection2', + 'max_messages' => 2 + ] + ]; + $finalResult = [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => ['item1_1', 'item1_2'], + 'consumerInstance' => 'type1', + 'handlers' => ['handlerConfig1_1_1', 'handlerConfig1_1_2', 'handlerConfig1_2_1'], + 'connection' => 'connection1', + 'maxMessages' => 100 + ], + 'consumer2' => [ + 'name' => 'consumer2', + 'queue' => ['item2_1'], + 'consumerInstance' => 'type2', + 'handlers' => [], + 'connection' => 'connection2', + 'maxMessages' => 2 + ], + 'consumer0' => [] + ]; + + $this->configMock->expects(static::atLeastOnce()) + ->method('getConsumers') + ->willReturn($consumers); + + $this->assertEquals($finalResult, $this->plugin->afterRead($this->subjectMock, $result)); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/DataTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/DataTest.php new file mode 100644 index 0000000000000..e847420d15f5a --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/DataTest.php @@ -0,0 +1,92 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit\Config; + +use Magento\Framework\MessageQueue\Code\Generator\Config\RemoteServiceReader\MessageQueue as RemoteServiceReader; + +class DataTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\Config\Reader\Xml|\PHPUnit_Framework_MockObject_MockObject + */ + protected $xmlReaderMock; + + /** + * @var \Magento\Framework\MessageQueue\Config\Reader\Env|\PHPUnit_Framework_MockObject_MockObject + */ + protected $envReaderMock; + + /** + * @var RemoteServiceReader|\PHPUnit_Framework_MockObject_MockObject + */ + protected $remoteServiceReaderMock; + + /** + * @var \Magento\Framework\Config\CacheInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $cacheMock; + + /** + * @var \Magento\Framework\Serialize\SerializerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $serializerMock; + + protected function setUp() + { + $this->xmlReaderMock = $this->getMockBuilder(\Magento\Framework\MessageQueue\Config\Reader\Xml::class) + ->disableOriginalConstructor() + ->getMock(); + $this->envReaderMock = $this->getMockBuilder(\Magento\Framework\MessageQueue\Config\Reader\Env::class) + ->disableOriginalConstructor() + ->getMock(); + $this->remoteServiceReaderMock = $this + ->getMockBuilder( + \Magento\Framework\MessageQueue\Code\Generator\Config\RemoteServiceReader\MessageQueue::class + )->disableOriginalConstructor() + ->getMock(); + $this->cacheMock = $this->getMockBuilder(\Magento\Framework\Config\CacheInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->serializerMock = $this->createMock(\Magento\Framework\Serialize\SerializerInterface::class); + } + + public function testGet() + { + $expected = ['someData' => ['someValue', 'someKey' => 'someValue']]; + $this->cacheMock->expects($this->any()) + ->method('load') + ->willReturn(json_encode($expected)); + + $this->serializerMock->expects($this->once()) + ->method('unserialize') + ->willReturn($expected); + + $this->envReaderMock->expects($this->any())->method('read')->willReturn([]); + $this->remoteServiceReaderMock->expects($this->any())->method('read')->willReturn([]); + $this->assertEquals($expected, $this->getModel()->get()); + } + + /** + * Return Config Data Object + * + * @return \Magento\Framework\MessageQueue\Config\Data + */ + private function getModel() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + return $objectManager->getObject( + \Magento\Framework\MessageQueue\Config\Data::class, + [ + 'xmlReader' => $this->xmlReaderMock, + 'cache' => $this->cacheMock, + 'envReader' => $this->envReaderMock, + 'remoteServiceReader' => $this->remoteServiceReaderMock, + 'serializer' => $this->serializerMock, + ] + ); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Publisher/ConfigReaderPluginTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Publisher/ConfigReaderPluginTest.php new file mode 100644 index 0000000000000..52297da5422d9 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Publisher/ConfigReaderPluginTest.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Config\Publisher; + +use Magento\Framework\MessageQueue\Config\Publisher\ConfigReaderPlugin as PublisherConfigReaderPlugin; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\MessageQueue\ConfigInterface; +use Magento\Framework\MessageQueue\Publisher\Config\CompositeReader as PublisherConfigCompositeReader; + +class ConfigReaderPluginTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var PublisherConfigReaderPlugin + */ + private $plugin; + + /** + * @var ObjectManagerHelper + */ + private $objectManagerHelper; + + /** + * @var ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $configMock; + + /** + * @var PublisherConfigCompositeReader|\PHPUnit_Framework_MockObject_MockObject + */ + private $subjectMock; + + protected function setUp() + { + $this->configMock = $this->getMockBuilder(ConfigInterface::class) + ->getMockForAbstractClass(); + $this->subjectMock = $this->getMockBuilder(PublisherConfigCompositeReader::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->plugin = $this->objectManagerHelper->getObject( + PublisherConfigReaderPlugin::class, + ['config' => $this->configMock] + ); + } + + public function testAfterRead() + { + $result = ['topic0' => []]; + $binds = [ + [ + 'topic' => 'topic1', + 'exchange' => 'exchange1' + ], + [ + 'topic' => 'topic2', + 'exchange' => 'exchange2' + ] + ]; + $finalResult = [ + 'topic1' => [ + 'topic' => 'topic1', + 'connection' => [ + 'name' => 'connection1', + 'exchange' => 'exchange1', + 'disabled' => false + ], + 'disabled' => false + ], + 'topic2' => [ + 'topic' => 'topic2', + 'connection' => [ + 'name' => 'connection2', + 'exchange' => 'exchange2', + 'disabled' => false + ], + 'disabled' => false + ], + 'topic0' => [] + ]; + + $this->configMock->expects(static::atLeastOnce()) + ->method('getBinds') + ->willReturn($binds); + $this->configMock->expects(static::atLeastOnce()) + ->method('getConnectionByTopic') + ->willReturnMap( + [ + ['topic1', 'connection1'], + ['topic2', 'connection2'] + ] + ); + + $this->assertEquals($finalResult, $this->plugin->afterRead($this->subjectMock, $result)); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Reader/Env/Converter/PublisherTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Reader/Env/Converter/PublisherTest.php new file mode 100644 index 0000000000000..a4028f12300cf --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Reader/Env/Converter/PublisherTest.php @@ -0,0 +1,60 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Config\Reader\Env\Converter; + +use Magento\Framework\MessageQueue\Config\Reader\Env\Converter\Publisher as EnvPublisherConverter; +use Magento\Framework\MessageQueue\Config\Reader\Env as ReaderEnv; + +class PublisherTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var EnvPublisherConverter + */ + private $converter; + + protected function setUp() + { + $connectionToExchangeMap = [ + 'amqp' => 'magento', + 'db'=> 'magento-db' + ]; + $this->converter = new EnvPublisherConverter( + $connectionToExchangeMap + ); + } + + public function testConvert() + { + $source = include __DIR__ . '/../../../../_files/env_2_2.php'; + $expectedConfig = [ + 'amqp-magento' => [ + 'name' => 'amqp-magento', + 'exchange' => 'magento-db', + 'connection' =>'db' + ] + ]; + $actualResult = $this->converter->convert($source['config']); + $this->assertEquals($expectedConfig, $actualResult[ReaderEnv::ENV_PUBLISHERS]); + } + + public function testConvertIfPublisherConfigNotExist() + { + $source = include __DIR__ . '/../../../../_files/env_2_2.php'; + unset($source['config'][ReaderEnv::ENV_PUBLISHERS]); + $actualResult = $this->converter->convert($source['config']); + $this->assertEquals($source['config'], $actualResult); + } + public function testConvertIfConnectionConfigNotExist() + { + $source = include __DIR__ . '/../../../../_files/env_2_2.php'; + $topicName = 'inventory.counter.updated'; + unset($source['config'][ReaderEnv::ENV_PUBLISHERS][$topicName]['connections']); + $actualResult = $this->converter->convert($source['config']); + $expectedResult[ReaderEnv::ENV_CONSUMERS] = $source['config'][ReaderEnv::ENV_CONSUMERS]; + $expectedResult[ReaderEnv::ENV_PUBLISHERS] = []; + $this->assertEquals($expectedResult, $actualResult); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Reader/Xml/Converter/TopicConverterTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Reader/Xml/Converter/TopicConverterTest.php new file mode 100644 index 0000000000000..f6464a6d5be23 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Reader/Xml/Converter/TopicConverterTest.php @@ -0,0 +1,74 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Config\Reader\Xml\Converter; + +/** + * Class TopicConverterTest to test <topic> root node type definition of MQ + */ +class TopicConverterTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\Config\Reader\Xml\Converter\TopicConfig + */ + private $converter; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $methodMapMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $validatorMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $communicationConfigMock; + + /** + * Initialize parameters + */ + protected function setUp() + { + $this->methodMapMock = $this->createMock(\Magento\Framework\Reflection\MethodsMap::class); + $this->validatorMock = $this->createMock(\Magento\Framework\MessageQueue\Config\Validator::class); + $this->communicationConfigMock = $this->createMock(\Magento\Framework\Communication\ConfigInterface::class); + $wildcardPatternMap = include(__DIR__ . '/../../../../_files/wildcard_pattern_map.php'); + $topicsMap = include(__DIR__ . '/../../../../_files/topic_definitions_map.php'); + $this->validatorMock->expects($this->any()) + ->method('buildWildcardPattern') + ->willReturnMap($wildcardPatternMap); + + $topicsDefinitions = [ + 'user.created.remote' => [], + 'product.created.local' => [], + ]; + $this->communicationConfigMock->expects($this->once())->method('getTopics')->willReturn($topicsDefinitions); + + $this->communicationConfigMock->expects($this->any())->method('getTopic')->willReturnMap($topicsMap); + + $this->converter = new \Magento\Framework\MessageQueue\Config\Reader\Xml\Converter\TopicConfig( + $this->methodMapMock, + $this->validatorMock, + $this->communicationConfigMock + ); + } + + /** + * Test converting valid configuration + */ + public function testConvert() + { + $xmlFile = __DIR__ . '/../../../../_files/topic_config.xml'; + $expectedData = include(__DIR__ . '/../../../../_files/expected_topic_config.php'); + $dom = new \DOMDocument(); + $dom->load($xmlFile); + $result = $this->converter->convert($dom); + $this->assertEquals($expectedData, $result); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Reader/XmlReader/SchemaLocatorTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Reader/XmlReader/SchemaLocatorTest.php new file mode 100644 index 0000000000000..a3a74b3991bf5 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Reader/XmlReader/SchemaLocatorTest.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit\Config\Reader\XmlReader; + +class SchemaLocatorTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\Config\Reader\Xml\SchemaLocator + */ + protected $model; + + /** @var \Magento\Framework\Config\Dom\UrnResolver */ + protected $urnResolver; + + protected function setUp() + { + $this->urnResolver = new \Magento\Framework\Config\Dom\UrnResolver(); + $this->model = new \Magento\Framework\MessageQueue\Config\Reader\Xml\SchemaLocator($this->urnResolver); + } + + public function testGetSchema() + { + $expected = $this->urnResolver->getRealPath('urn:magento:framework-message-queue:etc/queue_merged.xsd'); + $actual = $this->model->getSchema(); + $this->assertEquals($expected, $actual); + } + + public function testGetPerFileSchema() + { + $expected = $this->urnResolver->getRealPath('urn:magento:framework-message-queue:etc/queue.xsd'); + $actual = $this->model->getPerFileSchema(); + $this->assertEquals($expected, $actual); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Topology/ConfigReaderPluginTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Topology/ConfigReaderPluginTest.php new file mode 100644 index 0000000000000..c270a923a759d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Config/Topology/ConfigReaderPluginTest.php @@ -0,0 +1,150 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Config\Topology; + +use Magento\Framework\MessageQueue\Config\Topology\ConfigReaderPlugin as TopologyConfigReaderPlugin; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\MessageQueue\ConfigInterface; +use Magento\Framework\MessageQueue\Topology\Config\CompositeReader as TopologyConfigCompositeReader; + +class ConfigReaderPluginTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var TopologyConfigReaderPlugin + */ + private $plugin; + + /** + * @var ObjectManagerHelper + */ + private $objectManagerHelper; + + /** + * @var ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $configMock; + + /** + * @var TopologyConfigCompositeReader|\PHPUnit_Framework_MockObject_MockObject + */ + private $subjectMock; + + protected function setUp() + { + $this->configMock = $this->getMockBuilder(ConfigInterface::class) + ->getMockForAbstractClass(); + $this->subjectMock = $this->getMockBuilder(TopologyConfigCompositeReader::class) + ->disableOriginalConstructor() + ->setMethods(['getBinds', 'getConnectionByTopic']) + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->plugin = $this->objectManagerHelper->getObject( + TopologyConfigReaderPlugin::class, + ['queueConfig' => $this->configMock] + ); + } + + public function testAfterRead() + { + $binding = [ + [ + 'queue' => 'catalog_product_removed_queue', + 'exchange' => 'magento-db', + 'topic' => 'catalog.product.removed' + ], + [ + 'queue' => 'inventory_qty_counter_queue', + 'exchange' => 'magento', + 'topic' => 'inventory.counter.updated' + ] + ]; + $magento = [ + 'name' => 'magento', + 'type' => 'topic', + 'connection' => 'amqp', + 'bindings' => [] + ]; + $dbDefaultBinding = [ + 'id' => 'defaultBinding', + 'destinationType' => 'queue', + 'destination' => 'catalog_product_removed_queue', + 'topic' => 'catalog.product.removed', + ]; + $amqpDefaultBinding = [ + 'id' => 'defaultBinding', + 'destinationType' => 'queue', + 'destination' => 'inventory_qty_counter_queue', + 'topic' => 'inventory.counter.updated', + ]; + $result = [ + 'magento' => $magento, + 'magento-db--db' => [ + 'name' => 'magento-db', + 'type' => 'topic', + 'connection' => 'db', + 'bindings' => [ + 'defaultBinding' => $dbDefaultBinding + ] + ], + 'magento--amqp' => [ + 'name' => 'magento', + 'type' => 'topic', + 'connection' => 'amqp', + 'bindings' => [ + 'defaultBinding' => $amqpDefaultBinding + ] + ] + ]; + $expectedResult = [ + 'magento' => $magento, + 'magento-db--db' => [ + 'name' => 'magento-db', + 'type' => 'topic', + 'connection' => 'db', + 'bindings' => [ + 'queue--catalog_product_removed_queue--catalog.product.removed' => [ + 'id' => 'queue--catalog_product_removed_queue--catalog.product.removed', + 'destinationType' => 'queue', + 'destination' => 'catalog_product_removed_queue', + 'disabled' => false, + 'topic' => 'catalog.product.removed', + 'arguments' => [] + ], + 'defaultBinding' => $dbDefaultBinding + ] + ], + 'magento--amqp' => [ + 'name' => 'magento', + 'type' => 'topic', + 'connection' => 'amqp', + 'bindings' => [ + 'queue--inventory_qty_counter_queue--inventory.counter.updated' => [ + 'id' => 'queue--inventory_qty_counter_queue--inventory.counter.updated', + 'destinationType' => 'queue', + 'destination' => 'inventory_qty_counter_queue', + 'disabled' => false, + 'topic' => 'inventory.counter.updated', + 'arguments' => [] + ], + 'defaultBinding' => $amqpDefaultBinding + ] + ] + ]; + + $this->configMock->expects(static::atLeastOnce()) + ->method('getBinds') + ->willReturn($binding); + $this->configMock->expects(static::exactly(2)) + ->method('getConnectionByTopic') + ->willReturnMap([ + ['catalog.product.removed', 'db'], + ['inventory.counter.updated', 'amqp'] + ]); + + $this->assertEquals($expectedResult, $this->plugin->afterRead($this->subjectMock, $result)); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/ConnectionTypeResolverTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/ConnectionTypeResolverTest.php new file mode 100644 index 0000000000000..14ccca75bb104 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/ConnectionTypeResolverTest.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit; + +use Magento\Framework\MessageQueue\ConnectionTypeResolverInterface; +use Magento\Framework\MessageQueue\ConnectionTypeResolver; + +class ConnectionTypeResolverTest extends \PHPUnit\Framework\TestCase +{ + public function testGetConnectionType() + { + $resolverOne = $this->createMock(ConnectionTypeResolverInterface::class); + $resolverOne->expects($this->once())->method('getConnectionType')->with('test')->willReturn(null); + + $resolverTwo = $this->createMock(ConnectionTypeResolverInterface::class); + $resolverTwo->expects($this->once())->method('getConnectionType')->with('test')->willReturn('some-type'); + + $model = new ConnectionTypeResolver([$resolverOne, $resolverTwo]); + $this->assertEquals('some-type', $model->getConnectionType('test')); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Unknown connection name test + */ + public function testGetConnectionTypeWithException() + { + $resolverOne = $this->createMock(ConnectionTypeResolverInterface::class); + $resolverOne->expects($this->once())->method('getConnectionType')->with('test')->willReturn(null); + + $resolverTwo = $this->createMock(ConnectionTypeResolverInterface::class); + $resolverTwo->expects($this->once())->method('getConnectionType')->with('test')->willReturn(null); + + $model = new ConnectionTypeResolver([$resolverOne, $resolverTwo]); + $model->getConnectionType('test'); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Env/ReaderTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Env/ReaderTest.php new file mode 100644 index 0000000000000..93feadccbd0c8 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Env/ReaderTest.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit\Consumer\Config\Env; + +use Magento\Framework\MessageQueue\Consumer\Config\Env\Reader; + +class ReaderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\Consumer\Config\Env\Reader + */ + private $reader; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $envConfig; + + protected function setUp() + { + $this->envConfig = + $this->getMockBuilder(\Magento\Framework\MessageQueue\Config\Reader\Env::class) + ->disableOriginalConstructor() + ->getMock(); + $this->reader = new Reader($this->envConfig); + } + + public function testRead() + { + $configData['consumers'] = ['consumerConfig']; + $this->envConfig->expects($this->once())->method('read')->willReturn($configData); + $actual = $this->reader->read(); + $this->assertEquals(['consumerConfig'], $actual); + } + + public function testReadIfConsumerConfigNotExist() + { + $this->envConfig->expects($this->once())->method('read')->willReturn([]); + $actual = $this->reader->read(); + $this->assertEquals([], $actual); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/ConsumerInstanceTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/ConsumerInstanceTest.php new file mode 100644 index 0000000000000..a69555ad742f5 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/ConsumerInstanceTest.php @@ -0,0 +1,111 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Consumer\Config\Validator; + +use Magento\Framework\MessageQueue\Consumer\Config\Validator\ConsumerInstance as ConsumerInstanceValidator; + +class ConsumerInstanceTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ConsumerInstanceValidator + */ + private $validator; + + /** + * Initialize parameters + */ + protected function setUp() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->validator = $objectManager->getObject(ConsumerInstanceValidator::class); + } + + /** + * @dataProvider validConfigDataProvider + * @param array $configData + */ + public function testValidateValid($configData) + { + $this->validator->validate($configData); + } + + /** + * @return array + */ + public function validConfigDataProvider() + { + return [ + 'valid' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => \Magento\Framework\MessageQueue\BatchConsumer::class, + 'handlers' => [ + ['type' => 'handlerClassOne', 'method' => 'handlerMethodOne'], + ['type' => 'handlerClassTwo', 'method' => 'handlerMethodTwo'], + ], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ] + ] + ]; + } + + /** + * @dataProvider invalidConfigDataProvider + * @param array $configData + * @param string $expectedExceptionMessage + */ + public function testValidateInvalid($configData, $expectedExceptionMessage) + { + $this->expectException('\LogicException', $expectedExceptionMessage); + $this->validator->validate($configData); + } + + /** + * @return array + */ + public function invalidConfigDataProvider() + { + return [ + 'invalid, consumerInstance not implementing consumer interface' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => ConsumerInstanceTest::class, + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + // @codingStandardsIgnoreStart + "'Magento\\Framework\\MessageQueue\\Test\\Unit\\Consumer\\Config\\Validator\\ConsumerInstanceTest'" + . " cannot be specified as 'consumerInstance' for 'consumer1' consumer, unless it implements" + . " 'Magento\\Framework\\MessageQueue\\ConsumerInterface' interface" + // @codingStandardsIgnoreEnd + ], + 'invalid, consumerInstance class does not exist' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [ + [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']] + ], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "'consumerClass1' does not exist and thus cannot be used as 'consumerInstance'" + . " for 'consumer1' consumer." + ] + ]; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/FieldsTypesTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/FieldsTypesTest.php new file mode 100644 index 0000000000000..086a05ccdaafb --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/FieldsTypesTest.php @@ -0,0 +1,171 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Consumer\Config\Validator; + +use Magento\Framework\MessageQueue\Consumer\Config\Validator\FieldsTypes as FieldsTypesValidator; + +class FieldsTypesTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var FieldsTypesValidator + */ + private $validator; + + /** + * Initialize parameters + */ + protected function setUp() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->validator = $objectManager->getObject(FieldsTypesValidator::class); + } + + /** + * @dataProvider validConfigDataProvider + * @param array $configData + */ + public function testValidateValid($configData) + { + $this->validator->validate($configData); + } + + /** + * @return array + */ + public function validConfigDataProvider() + { + return [ + 'valid' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ] + ], + 'valid, maxMessages == null' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => null, + ] + ] + ], + ]; + } + + /** + * @dataProvider invalidConfigDataProvider + * @param array $configData + * @param string $expectedExceptionMessage + */ + public function testValidateInvalid($configData, $expectedExceptionMessage) + { + $this->expectException('\LogicException', $expectedExceptionMessage); + $this->validator->validate($configData); + } + + /** + * @return array + */ + public function invalidConfigDataProvider() + { + return [ + 'invalid name' => [ + [ + 'consumer1' => [ + 'name' => true, + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "Type of 'name' field specified in configuration of 'consumer1' consumer is invalid." + . " Given 'boolean', 'string' was expected." + ], + 'invalid queue' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 1, + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "Type of 'queue' field specified in configuration of 'consumer1' consumer is invalid." + . " Given 'integer', 'string' was expected." + ], + 'invalid consumerInstance' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => (object)[], + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "Type of 'consumerInstance' field specified in configuration of 'consumer1' consumer is invalid." + . " Given 'object', 'string' was expected." + ], + 'invalid connection' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => [], + 'maxMessages' => '100', + ] + ], + "Type of 'connection' field specified in configuration of 'consumer1' consumer is invalid." + . " Given 'array', 'string' was expected." + ], + 'invalid handlers' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => '', + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "Type of 'handlers' field specified in configuration of 'consumer1' consumer is invalid." + . " Given 'string', 'array' was expected." + ], + 'invalid maxMessages' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => 'abc', + ] + ], + "Type of 'maxMessages' field specified in configuration of 'consumer1' consumer is invalid." + . " Given 'string', 'int|null' was expected." + ], + ]; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/HandlersTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/HandlersTest.php new file mode 100644 index 0000000000000..9abcc8b70eab3 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/HandlersTest.php @@ -0,0 +1,185 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Consumer\Config\Validator; + +use Magento\Framework\MessageQueue\Consumer\Config\Validator\Handlers as HandlersValidator; +use Magento\Framework\Reflection\MethodsMap; + +class HandlersTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var MethodsMap|\PHPUnit_Framework_MockObject_MockObject + */ + private $methodsMap; + + /** + * @var HandlersValidator + */ + private $validator; + + /** + * Initialize parameters + */ + protected function setUp() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->methodsMap = $this->getMockBuilder(MethodsMap::class)->disableOriginalConstructor()->getMock(); + $this->validator = $objectManager->getObject(HandlersValidator::class, ['methodsMap' => $this->methodsMap]); + } + + /** + * @dataProvider validConfigDataProvider + * @param array $configData + */ + public function testValidateValid($configData) + { + $this->validator->validate($configData); + } + + /** + * @return array + */ + public function validConfigDataProvider() + { + return [ + 'valid' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [ + ['type' => 'handlerClassOne', 'method' => 'handlerMethodOne'], + ['type' => 'handlerClassTwo', 'method' => 'handlerMethodTwo'], + ], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ] + ], + 'valid, empty handlers' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [], + 'connection' => 'connection1', + 'maxMessages' => null, + ] + ] + ], + ]; + } + + /** + * @dataProvider invalidConfigDataProvider + * @param array $configData + * @param string $expectedExceptionMessage + */ + public function testValidateInvalid($configData, $expectedExceptionMessage) + { + $this->expectException('\LogicException', $expectedExceptionMessage); + $this->validator->validate($configData); + } + + /** + * @return array + */ + public function invalidConfigDataProvider() + { + return [ + 'invalid, not an array' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => ['handlerClassOne::handlerMethodOne'], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "'consumer1' consumer declaration is invalid. Every handler element must be an array." + . " It must contain 'type' and 'method' elements." + ], + 'invalid, no required fields' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [ + ['handlerClassOne::handlerMethodOne'] + ], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "'consumer1' consumer declaration is invalid. Every handler element must be an array." + . " It must contain 'type' and 'method' elements." + ], + 'invalid, no method' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [ + ['type' => 'handlerClassOne'] + ], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "'consumer1' consumer declaration is invalid. Every handler element must be an array." + . " It must contain 'type' and 'method' elements." + ], + 'invalid, no type' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [ + ['method' => 'handlerMethodOne'] + ], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "'consumer1' consumer declaration is invalid. Every handler element must be an array." + . " It must contain 'type' and 'method' elements." + ] + ]; + } + + public function testValidateUndeclaredService() + { + $configData = [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [ + ['type' => 'handlerClassOne', 'method' => 'handlerMethodOne'], + ], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ]; + $expectedExceptionMessage = 'Service method specified as handler for of consumer "consumer1" is not available.' + . ' Given "handlerClassOne::handlerMethodOne"'; + $this->expectException('\LogicException', $expectedExceptionMessage); + + $this->methodsMap->expects($this->once()) + ->method('getMethodParams') + ->with('handlerClassOne', 'handlerMethodOne') + ->willThrowException(new \Exception('')); + + $this->validator->validate($configData); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/RequiredFieldsTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/RequiredFieldsTest.php new file mode 100644 index 0000000000000..61a31603ea7a7 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Validator/RequiredFieldsTest.php @@ -0,0 +1,147 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Consumer\Config\Validator; + +use Magento\Framework\MessageQueue\Consumer\Config\Validator\RequiredFields as RequiredFieldsValidator; + +class RequiredFieldsTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var RequiredFieldsValidator + */ + private $validator; + + /** + * Initialize parameters + */ + protected function setUp() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->validator = $objectManager->getObject(RequiredFieldsValidator::class); + } + + /** + * @dataProvider validConfigDataProvider + * @param array $configData + */ + public function testValidateValid($configData) + { + $this->validator->validate($configData); + } + + /** + * @return array + */ + public function validConfigDataProvider() + { + return [ + 'valid' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ] + ] + ]; + } + + /** + * @dataProvider invalidConfigDataProvider + * @param array $configData + * @param string $expectedExceptionMessage + */ + public function testValidateInvalid($configData, $expectedExceptionMessage) + { + $this->expectException('\LogicException', $expectedExceptionMessage); + $this->validator->validate($configData); + } + + /** + * @return array + */ + public function invalidConfigDataProvider() + { + return [ + 'missing name' => [ + [ + 'consumer1' => [ + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "'name' field must be specified for consumer 'consumer1'" + ], + 'missing queue' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "'queue' field must be specified for consumer 'consumer1'" + ], + 'missing consumerInstance' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "'consumerInstance' field must be specified for consumer 'consumer1'" + ], + 'missing connection' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'maxMessages' => '100', + ] + ], + "'connection' field must be specified for consumer 'consumer1'" + ], + 'missing handlers' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'connection' => 'connection1', + 'maxMessages' => '100', + ] + ], + "'handlers' field must be specified for consumer 'consumer1'" + ], + 'missing maxMessages' => [ + [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [['type' => 'handlerClassOne', 'method' => 'handlerMethodOne']], + 'connection' => 'connection1', + ] + ], + "'maxMessages' field must be specified for consumer 'consumer1'" + ], + ]; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Xml/ConverterTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Xml/ConverterTest.php new file mode 100644 index 0000000000000..cb68d845a263e --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/Xml/ConverterTest.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Consumer\Config\Xml; + +use Magento\Framework\Communication\Config\ConfigParser; +use Magento\Framework\MessageQueue\Consumer\Config\Xml\Converter; + +class ConverterTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Converter + */ + private $converter; + + /** + * @var ConfigParser|\PHPUnit_Framework_MockObject_MockObject + */ + protected $configParserMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $defaultConfigProviderMock; + + /** + * Initialize parameters + */ + protected function setUp() + { + $this->defaultConfigProviderMock = + $this->createMock(\Magento\Framework\MessageQueue\DefaultValueProvider::class); + $this->configParserMock = $this->createMock(ConfigParser::class); + $this->converter = new Converter($this->configParserMock, $this->defaultConfigProviderMock); + } + + public function testConvert() + { + $this->defaultConfigProviderMock->expects($this->any())->method('getConnection')->willReturn('amqp'); + $this->configParserMock->expects($this->any())->method('parseServiceMethod')->willReturnCallback( + function ($handler) { + $parsedHandler = explode('::', $handler); + return ['typeName' => $parsedHandler[0], 'methodName' => $parsedHandler[1]]; + } + ); + $fixtureDir = __DIR__ . '/../../../_files/queue_consumer'; + $xmlFile = $fixtureDir . '/valid.xml'; + $dom = new \DOMDocument(); + $dom->load($xmlFile); + $result = $this->converter->convert($dom); + + $expectedData = include($fixtureDir . '/valid.php'); + $this->assertEquals($expectedData, $result); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/XsdTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/XsdTest.php new file mode 100644 index 0000000000000..2e0120ad7ea82 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Consumer/Config/XsdTest.php @@ -0,0 +1,128 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Consumer\Config; + +class XsdTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var string + */ + protected $_schemaFile; + + protected function setUp() + { + if (!function_exists('libxml_set_external_entity_loader')) { + $this->markTestSkipped('Skipped on HHVM. Will be fixed in MAGETWO-45033'); + } + $urnResolver = new \Magento\Framework\Config\Dom\UrnResolver(); + $this->_schemaFile = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/consumer.xsd'); + } + + /** + * @param string $fixtureXml + * @param array $expectedErrors + * @dataProvider exemplarXmlDataProvider + */ + public function testExemplarXml($fixtureXml, array $expectedErrors) + { + $validationState = $this->createMock(\Magento\Framework\Config\ValidationStateInterface::class); + $validationState->expects($this->any()) + ->method('isValidationRequired') + ->willReturn(true); + $messageFormat = '%message%'; + $dom = new \Magento\Framework\Config\Dom($fixtureXml, $validationState, [], null, null, $messageFormat); + $actualErrors = []; + $actualResult = $dom->validate($this->_schemaFile, $actualErrors); + $this->assertEquals(empty($expectedErrors), $actualResult, "Validation result is invalid."); + $this->assertEquals($expectedErrors, $actualErrors, "Validation errors does not match."); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function exemplarXmlDataProvider() + { + // @codingStandardsIgnoreStart + return [ + /** Valid configurations */ + 'valid' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> + <consumer name="consumer1" queue="queue1" handler="handlerClassOne::handlerMethodOne" consumerInstance="consumerClass1" connection="amqp" maxMessages="100"/> + <consumer name="consumer2" queue="queue2" handler="handlerClassTwo::handlerMethodTwo" consumerInstance="consumerClass2" connection="db"/> + <consumer name="consumer3" queue="queue3" handler="handlerClassThree::handlerMethodThree" consumerInstance="consumerClass3"/> + <consumer name="consumer4" queue="queue4" handler="handlerClassFour::handlerMethodFour"/> + <consumer name="consumer5" queue="queue4"/> + </config>', + [], + ], + 'non unique consumer name' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> + <consumer name="consumer1" queue="queue1" handler="handlerClassOne::handlerMethodOne" consumerInstance="consumerClass1" connection="amqp" maxMessages="100"/> + <consumer name="consumer1" queue="queue2" handler="handlerClassTwo::handlerMethodTwo" consumerInstance="consumerClass2" connection="db"/> + <consumer name="consumer3" queue="queue3" handler="handlerClassThree::handlerMethodThree" consumerInstance="consumerClass3"/> + <consumer name="consumer4" queue="queue4" handler="handlerClassFour::handlerMethodFour"/> + <consumer name="consumer5" queue="queue4"/> + </config>', + [ + "Element 'consumer': Duplicate key-sequence ['consumer1'] in unique identity-constraint 'consumer-unique-name'." + ], + ], + 'invalid handler format' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> + <consumer name="consumer1" queue="queue1" handler="handlerClass1::handlerMethodOne" consumerInstance="consumerClass1" connection="amqp" maxMessages="100"/> + <consumer name="consumer2" queue="queue2" handler="handlerClassTwo::handlerMethod2" consumerInstance="consumerClass2" connection="db"/> + <consumer name="consumer3" queue="queue3" handler="handlerClassThree::handlerMethodThree" consumerInstance="consumerClass3"/> + <consumer name="consumer4" queue="queue4" handler="handlerClassFour::handlerMethodFour"/> + <consumer name="consumer5" queue="queue4"/> + </config>', + [ + "Element 'consumer', attribute 'handler': [facet 'pattern'] The value 'handlerClass1::handlerMethodOne' is not accepted by the pattern '[a-zA-Z\\\\]+::[a-zA-Z]+'.", + "Element 'consumer', attribute 'handler': 'handlerClass1::handlerMethodOne' is not a valid value of the atomic type 'handlerType'.", + "Element 'consumer', attribute 'handler': [facet 'pattern'] The value 'handlerClassTwo::handlerMethod2' is not accepted by the pattern '[a-zA-Z\\\\]+::[a-zA-Z]+'.", + "Element 'consumer', attribute 'handler': 'handlerClassTwo::handlerMethod2' is not a valid value of the atomic type 'handlerType'.", + ], + ], + 'invalid maxMessages format' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> + <consumer name="consumer1" queue="queue1" handler="handlerClassOne::handlerMethodOne" consumerInstance="consumerClass1" connection="amqp" maxMessages="ABC"/> + <consumer name="consumer2" queue="queue2" handler="handlerClassTwo::handlerMethodTwo" consumerInstance="consumerClass2" connection="db"/> + <consumer name="consumer3" queue="queue3" handler="handlerClassThree::handlerMethodThree" consumerInstance="consumerClass3"/> + <consumer name="consumer4" queue="queue4" handler="handlerClassFour::handlerMethodFour"/> + <consumer name="consumer5" queue="queue4"/> + </config>', + [ + "Element 'consumer', attribute 'maxMessages': 'ABC' is not a valid value of the atomic type 'xs:integer'.", + ], + ], + 'unexpected element' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> + <consumer name="consumer1" queue="queue1" handler="handlerClassOne::handlerMethodOne" consumerInstance="consumerClass1" connection="amqp" maxMessages="100"/> + <consumer name="consumer2" queue="queue2" handler="handlerClassTwo::handlerMethodTwo" consumerInstance="consumerClass2" connection="db"/> + <consumer name="consumer3" queue="queue3" handler="handlerClassThree::handlerMethodThree" consumerInstance="consumerClass3"/> + <consumer name="consumer4" queue="queue4" handler="handlerClassFour::handlerMethodFour"/> + <unexpected name="consumer5" queue="queue4"/> + </config>', + [ + "Element 'unexpected': This element is not expected. Expected is ( consumer ).", + ], + ], + 'unexpected attribute' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> + <consumer name="consumer1" queue="queue1" handler="handlerClassOne::handlerMethodOne" consumerInstance="consumerClass1" connection="amqp" maxMessages="100"/> + <consumer name="consumer2" queue="queue2" handler="handlerClassTwo::handlerMethodTwo" consumerInstance="consumerClass2" connection="db"/> + <consumer name="consumer3" queue="queue3" handler="handlerClassThree::handlerMethodThree" consumerInstance="consumerClass3"/> + <consumer name="consumer4" queue="queue4" handler="handlerClassFour::handlerMethodFour"/> + <consumer name="consumer5" queue="queue4" unexpected=""/> + </config>', + [ + "Element 'consumer', attribute 'unexpected': The attribute 'unexpected' is not allowed.", + ], + ], + ]; + // @codingStandardsIgnoreEnd + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/ConsumerFactoryTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/ConsumerFactoryTest.php new file mode 100644 index 0000000000000..1cf1b57af87aa --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/ConsumerFactoryTest.php @@ -0,0 +1,162 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit; + +use Magento\Framework\MessageQueue\ConsumerFactory; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; +use Magento\Framework\MessageQueue\Consumer\ConfigInterface as ConsumerConfig; +use Magento\Framework\MessageQueue\Consumer\Config\ConsumerConfigItem; + +class ConsumerFactoryTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** @var CommunicationConfig|\PHPUnit_Framework_MockObject_MockObject */ + protected $communicationConfigMock; + + /** @var ConsumerConfig|\PHPUnit_Framework_MockObject_MockObject */ + protected $consumerConfigMock; + + const TEST_CONSUMER_NAME = "test_consumer_name"; + const TEST_CONSUMER_QUEUE = "test_consumer_queue"; + const TEST_CONSUMER_METHOD = "test_consumer_method"; + + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + $this->communicationConfigMock = $this->getMockBuilder(CommunicationConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->consumerConfigMock = $this->getMockBuilder(ConsumerConfig::class) + ->disableOriginalConstructor() + ->getMock(); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage pecified consumer "test_consumer_name" is not declared. + */ + public function testUndeclaredConsumerName() + { + $consumerFactory = $this->objectManager->getObject(ConsumerFactory::class); + $this->objectManager->setBackwardCompatibleProperty( + $consumerFactory, + 'communicationConfig', + $this->communicationConfigMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $consumerFactory, + 'consumerConfig', + $this->consumerConfigMock + ); + $consumerFactory->get(self::TEST_CONSUMER_NAME); + } + + public function testConnectionInjectedForConsumer() + { + $consumerType = 'async'; + $consumerTypeValue = \Magento\Framework\MessageQueue\Model\TestConsumer::class; + $consumers = [ + [ + 'type' => [$consumerType => $consumerTypeValue] + ] + ]; + $consumerFactory = $this->getConsumerFactoryInstance($consumers); + $consumerInstanceMock = $this->getMockBuilder($consumerTypeValue)->getMock(); + $this->assertInstanceOf(get_class($consumerInstanceMock), $consumerFactory->get(self::TEST_CONSUMER_NAME)); + } + + /** + * Return Consumer Factory with mocked objects + * + * @param array $consumers + * @return ConsumerFactory + */ + private function getConsumerFactoryInstance($consumers) + { + $consumerTypeValue = \Magento\Framework\MessageQueue\Model\TestConsumer::class; + $handlerTypeValue = \Magento\Framework\DataObject::class; + $consumerType = 'async'; + + /** @var ConsumerConfigItem|\PHPUnit_Framework_MockObject_MockObject $consumerConfigItemMock */ + $consumerConfigItemMock = $this->getMockBuilder(ConsumerConfigItem::class)->disableOriginalConstructor() + ->getMock(); + $consumerConfigItemMock->expects($this->any())->method('getName')->willReturn(self::TEST_CONSUMER_NAME); + $consumerConfigItemMock->expects($this->any())->method('getQueue')->willReturn(self::TEST_CONSUMER_QUEUE); + $consumerConfigItemMock->expects($this->any())->method('getConsumerInstance')->willReturn($consumerTypeValue); + $consumerConfigItemMock->expects($this->any())->method('getHandlers')->willReturn([]); + $this->consumerConfigMock->expects($this->any()) + ->method('getConsumer') + ->with('test_consumer_name') + ->willReturn($consumerConfigItemMock); + $this->communicationConfigMock->expects($this->any()) + ->method('getTopics') + ->willReturn( + [ + [ + CommunicationConfig::TOPIC_NAME => 'topicName', + CommunicationConfig::TOPIC_IS_SYNCHRONOUS => false + ] + ] + ); + $this->communicationConfigMock->expects($this->any()) + ->method('getTopic') + ->with('topicName') + ->willReturn( + [ + CommunicationConfig::TOPIC_HANDLERS => [ + [ + CommunicationConfig::HANDLER_TYPE => $handlerTypeValue, + CommunicationConfig::HANDLER_METHOD => self::TEST_CONSUMER_METHOD + ] + ], + ] + ); + + $consumerInstanceMock = $this->getMockBuilder($consumerTypeValue)->getMock(); + $consumerMock = $this->getMockBuilder(\Magento\Framework\MessageQueue\ConsumerInterface::class) + ->setMethods(['configure']) + ->getMockForAbstractClass(); + + $consumerConfigurationMock = + $this->getMockBuilder(\Magento\Framework\MessageQueue\ConsumerConfigurationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $consumerConfigurationMock->expects($this->any())->method('getType')->willReturn($consumerType); + + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManagerInterface::class) + ->setMethods(['create']) + ->getMockForAbstractClass(); + + $objectManagerMock->expects($this->any()) + ->method('create') + ->willReturnOnConsecutiveCalls($consumerMock, $consumerConfigurationMock, $consumerInstanceMock); + + $consumerFactory = $this->objectManager->getObject( + \Magento\Framework\MessageQueue\ConsumerFactory::class, + [ + 'objectManager' => $objectManagerMock, + 'consumers' => $consumers + ] + ); + $this->objectManager->setBackwardCompatibleProperty( + $consumerFactory, + 'communicationConfig', + $this->communicationConfigMock + ); + $this->objectManager->setBackwardCompatibleProperty( + $consumerFactory, + 'consumerConfig', + $this->consumerConfigMock + ); + return $consumerFactory; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/ConsumerTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/ConsumerTest.php new file mode 100644 index 0000000000000..5eb7cd587aaa2 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/ConsumerTest.php @@ -0,0 +1,159 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit; + +use Magento\Framework\Phrase; + +/** + * Unit test for Consumer class. + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class ConsumerTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\ConsumerConfigurationInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $configuration; + + /** + * @var \Magento\Framework\MessageQueue\MessageEncoder|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageEncoder; + + /** + * @var \Magento\Framework\MessageQueue\QueueRepository|\PHPUnit_Framework_MockObject_MockObject + */ + private $queueRepository; + + /** + * @var \Magento\Framework\MessageQueue\CallbackInvoker + */ + private $callbackInvoker; + + /** + * @var \Magento\Framework\MessageQueue\Consumer\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $consumerConfig; + + /** + * @var \Magento\Framework\MessageQueue\MessageController|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageController; + + /** + * @var \Magento\Framework\App\ResourceConnection|\PHPUnit_Framework_MockObject_MockObject + */ + private $resource; + + /** + * @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $logger; + + /** + * @var \Magento\Framework\Communication\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $communicationConfig; + + /** + * @var \Magento\Framework\MessageQueue\Consumer + */ + private $consumer; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->configuration = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\ConsumerConfigurationInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->messageEncoder = $this->getMockBuilder(\Magento\Framework\MessageQueue\MessageEncoder::class) + ->disableOriginalConstructor()->getMock(); + $this->queueRepository = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueRepository::class) + ->disableOriginalConstructor()->getMock(); + $this->resource = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class) + ->disableOriginalConstructor()->getMock(); + $this->logger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class) + ->disableOriginalConstructor()->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + //Hard dependency used because CallbackInvoker invokes closure logic defined inside of Customer class. + $this->callbackInvoker = new \Magento\Framework\MessageQueue\CallbackInvoker(); + $this->consumer = $objectManager->getObject( + \Magento\Framework\MessageQueue\Consumer::class, + [ + 'configuration' => $this->configuration, + 'messageEncoder' => $this->messageEncoder, + 'queueRepository' => $this->queueRepository, + 'invoker' => $this->callbackInvoker, + 'resource' => $this->resource, + 'logger' => $this->logger + ] + ); + + $this->consumerConfig = $this->getMockBuilder(\Magento\Framework\MessageQueue\Consumer\ConfigInterface::class) + ->disableOriginalConstructor()->getMock(); + $objectManager->setBackwardCompatibleProperty( + $this->consumer, + 'consumerConfig', + $this->consumerConfig + ); + $this->messageController = $this->getMockBuilder(\Magento\Framework\MessageQueue\MessageController::class) + ->disableOriginalConstructor()->getMock(); + $objectManager->setBackwardCompatibleProperty( + $this->consumer, + 'messageController', + $this->messageController + ); + $this->communicationConfig = $this + ->createMock(\Magento\Framework\Communication\ConfigInterface::class); + $objectManager->setBackwardCompatibleProperty( + $this->consumer, + 'communicationConfig', + $this->communicationConfig + ); + } + + /** + * Test for process method with NotFoundException. + * + * @return void + */ + public function testProcessWithNotFoundException() + { + $properties = ['topic_name' => 'topic.name']; + $topicConfig = []; + $numberOfMessages = 1; + $consumerName = 'consumer.name'; + $exceptionPhrase = new Phrase('Exception successfully thrown'); + + $queue = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueInterface::class) + ->disableOriginalConstructor()->getMock(); + $this->configuration->expects($this->once())->method('getQueue')->willReturn($queue); + $envelope = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor()->getMock(); + $queue->expects($this->atLeastOnce())->method('dequeue')->willReturn($envelope); + $envelope->expects($this->once())->method('getProperties')->willReturn($properties); + $this->communicationConfig->expects($this->once())->method('getTopic')->with($properties['topic_name']) + ->willReturn($topicConfig); + $this->configuration->expects($this->once())->method('getConsumerName')->willReturn($consumerName); + $this->messageController->expects($this->once())->method('lock')->with($envelope, $consumerName) + ->willThrowException( + new \Magento\Framework\Exception\NotFoundException( + $exceptionPhrase + ) + ); + $queue->expects($this->once())->method('acknowledge')->with($envelope); + $this->logger->expects($this->once())->method('warning')->with($exceptionPhrase->render()); + + $this->consumer->process($numberOfMessages); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MergedMessageProcessorTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MergedMessageProcessorTest.php new file mode 100644 index 0000000000000..b3c80cf6af7c2 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MergedMessageProcessorTest.php @@ -0,0 +1,124 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * Unit test for MergedMessageProcessor. + */ +class MergedMessageProcessorTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\MessageStatusProcessor|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageStatusProcessor; + + /** + * @var \Magento\Framework\MessageQueue\MergedMessageProcessor + */ + private $mergedMessageProcessor; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->messageStatusProcessor = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\MessageStatusProcessor::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManagerHelper = new ObjectManagerHelper($this); + $this->mergedMessageProcessor = $objectManagerHelper->getObject( + \Magento\Framework\MessageQueue\MergedMessageProcessor::class, + [ + 'messageStatusProcessor' => $this->messageStatusProcessor + ] + ); + } + + /** + * Test for process(). + * + * @return void + */ + public function testProcess() + { + $topicName = 'topic'; + $messageId = 1; + $messagesToAcknowledge = []; + $queue = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $configuration = $this->getMockBuilder(\Magento\Framework\MessageQueue\ConsumerConfigurationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $configuration->expects($this->atLeastOnce())->method('getHandlers')->willReturn([]); + $this->messageStatusProcessor->expects($this->exactly(2))->method('acknowledgeMessages'); + $originalMessage = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $mergedMessage = $this->getMockBuilder(\Magento\Framework\MessageQueue\MergedMessageInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $mergedMessage->expects($this->atLeastOnce())->method('getOriginalMessagesIds')->willReturn([$messageId]); + $mergedMessages = [ + $topicName => [$mergedMessage] + ]; + $messages = [$messageId => $originalMessage]; + + $this->mergedMessageProcessor->process( + $queue, + $configuration, + $messages, + $messagesToAcknowledge, + $mergedMessages + ); + } + + /** + * Test for process() with Exception. + * + * @return void + */ + public function testProcessWithException() + { + $topicName = 'topic'; + $messageId = 1; + $messagesToAcknowledge = []; + $queue = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $configuration = $this->getMockBuilder(\Magento\Framework\MessageQueue\ConsumerConfigurationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->messageStatusProcessor->expects($this->once())->method('acknowledgeMessages'); + $exception = new \Exception(); + $configuration->expects($this->atLeastOnce())->method('getHandlers')->willThrowException($exception); + $this->messageStatusProcessor->expects($this->atLeastOnce())->method('rejectMessages'); + $originalMessage = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $mergedMessage = $this->getMockBuilder(\Magento\Framework\MessageQueue\MergedMessageInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $mergedMessages = [ + $topicName => [$mergedMessage] + ]; + $messages = [$messageId => $originalMessage]; + + $this->mergedMessageProcessor->process( + $queue, + $configuration, + $messages, + $messagesToAcknowledge, + $mergedMessages + ); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageControllerTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageControllerTest.php new file mode 100644 index 0000000000000..dc35a6dd26d47 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageControllerTest.php @@ -0,0 +1,64 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit; + +/** + * Unit test for MessageController class. + * + */ +class MessageControllerTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\LockInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $lockFactory; + + /** + * @var \Magento\Framework\MessageQueue\MessageController + */ + private $messageController; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->lockFactory = $this->getMockBuilder(\Magento\Framework\MessageQueue\LockInterfaceFactory::class) + ->disableOriginalConstructor()->setMethods(['create'])->getMock(); + + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->messageController = $objectManager->getObject( + \Magento\Framework\MessageQueue\MessageController::class, + [ + 'lockFactory' => $this->lockFactory + ] + ); + } + + /** + * Test for lock method with NotFoundException. + * + * @return void + */ + public function testLockWithNotFoundException() + { + $properties = []; + $consumerName = ''; + $this->expectException( + \Magento\Framework\Exception\NotFoundException::class, + "Property 'message_id' not found in properties." + ); + $this->lockFactory->expects($this->once())->method('create'); + $envelope = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableArgumentCloning()->getMock(); + $envelope->expects($this->once())->method('getProperties')->willReturn($properties); + + $this->messageController->lock($envelope, $consumerName); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageEncoderTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageEncoderTest.php new file mode 100644 index 0000000000000..58f11c6f7363c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageEncoderTest.php @@ -0,0 +1,127 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit; + +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\MessageQueue\MessageEncoder; + +/** + * Test class for Magento\Framework\MessageQueue\MessageEncoder + */ +class MessageEncoderTest extends \PHPUnit\Framework\TestCase +{ + /** @var MessageEncoder */ + protected $encoder; + + /** @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager */ + protected $objectManager; + + /** @var CommunicationConfig|\PHPUnit_Framework_MockObject_MockObject */ + protected $communicationConfigMock; + + /** @var \Magento\Framework\Webapi\ServiceOutputProcessor|\PHPUnit_Framework_MockObject_MockObject */ + protected $dataObjectEncoderMock; + + protected function setUp() + { + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->dataObjectEncoderMock = $this->getMockBuilder(\Magento\Framework\Webapi\ServiceOutputProcessor::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + $this->encoder = $this->objectManager->getObject( + MessageEncoder::class, + ['dataObjectEncoder' => $this->dataObjectEncoderMock] + ); + $this->communicationConfigMock = $this->getMockBuilder(CommunicationConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManager->setBackwardCompatibleProperty( + $this->encoder, + 'communicationConfig', + $this->communicationConfigMock + ); + parent::setUp(); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Specified topic "customer.created" is not declared. + */ + public function testEncodeInvalidTopic() + { + $this->encoder->encode('customer.created', 'Some message'); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Specified topic "customer.created" is not declared. + */ + public function testDecodeInvalidTopic() + { + $this->encoder->decode('customer.created', 'Some message'); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Message with topic "customer.created" must be an instance of "Magento\Customer\Api\Data + */ + public function testEncodeInvalidMessage() + { + $exceptionMessage = 'Message with topic "customer.created" must be an instance of "Magento\Customer\Api\Data"'; + $this->communicationConfigMock->expects($this->any())->method('getTopic')->willReturn( + $this->getQueueConfigData() + ); + $object = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + $this->dataObjectEncoderMock + ->expects($this->once()) + ->method('convertValue') + ->willThrowException(new LocalizedException(__($exceptionMessage))); + + $this->encoder->encode('customer.created', $object); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Message with topic "customer.created" must be an instance of "Magento\Customer\Api\Data + */ + public function testEncodeInvalidMessageArray() + { + $exceptionMessage = 'Message with topic "customer.created" must be an instance of "Magento\Customer\Api\Data"'; + $this->communicationConfigMock->expects($this->any())->method('getTopic')->willReturn( + $this->getQueueConfigData() + ); + $object = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + $this->dataObjectEncoderMock + ->expects($this->once()) + ->method('convertValue') + ->willThrowException(new LocalizedException(__($exceptionMessage))); + + $this->encoder->encode('customer.created', [$object]); + } + + /** + * Data provider for queue config + * + * @return array + */ + private function getQueueConfigData() + { + return [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => \Magento\Customer\Api\Data\CustomerInterface::class + ]; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageProcessorLoaderTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageProcessorLoaderTest.php new file mode 100644 index 0000000000000..e62f5682709c1 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageProcessorLoaderTest.php @@ -0,0 +1,94 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * Unit test for MessageProcessorLoader. + */ +class MessageProcessorLoaderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\MessageProcessorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $mergedMessageProcessor; + + /** + * @var \Magento\Framework\MessageQueue\MessageProcessorInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $defaultMessageProcessor; + + /** + * @var \Magento\Framework\MessageQueue\MessageProcessorLoader + */ + private $messageProcessorLoader; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->mergedMessageProcessor = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\MessageProcessorInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->defaultMessageProcessor = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\MessageProcessorInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $objectManagerHelper = new ObjectManagerHelper($this); + $this->messageProcessorLoader = $objectManagerHelper->getObject( + \Magento\Framework\MessageQueue\MessageProcessorLoader::class, + [ + 'mergedMessageProcessor' => $this->mergedMessageProcessor, + 'defaultMessageProcessor' => $this->defaultMessageProcessor + ] + ); + } + + /** + * Test for load(). + * + * @param $message + * @dataProvider loadDataProvider + */ + public function testLoad($message) + { + $messageTopic = 'topic'; + $messages = [ + $messageTopic => [$message] + ]; + + $this->assertInstanceOf( + \Magento\Framework\MessageQueue\MessageProcessorInterface::class, + $this->messageProcessorLoader->load($messages) + ); + } + + /** + * DataProvider for load(). + * + * @return array + */ + public function loadDataProvider() + { + $mergedMessage = $this->getMockBuilder(\Magento\Framework\MessageQueue\MergedMessageInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $message = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + return [ + [$mergedMessage], + [$message] + ]; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageProcessorTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageProcessorTest.php new file mode 100644 index 0000000000000..5e64d737034c8 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageProcessorTest.php @@ -0,0 +1,176 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * Unit test for MessageProcessor. + */ +class MessageProcessorTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\MessageStatusProcessor|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageStatusProcessor; + + /** + * @var \Magento\Framework\App\ResourceConnection|\PHPUnit_Framework_MockObject_MockObject + */ + private $resource; + + /** + * @var \Magento\Framework\MessageQueue\MessageProcessor + */ + private $messageProcessor; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $this->messageStatusProcessor = $this + ->getMockBuilder(\Magento\Framework\MessageQueue\MessageStatusProcessor::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resource = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManagerHelper = new ObjectManagerHelper($this); + $this->messageProcessor = $objectManagerHelper->getObject( + \Magento\Framework\MessageQueue\MessageProcessor::class, + [ + 'messageStatusProcessor' => $this->messageStatusProcessor, + 'resource' => $this->resource + ] + ); + } + + /** + * Test for process(). + * + * @return void + */ + public function testProcess() + { + $topicName = 'topic'; + $messagesToAcknowledge = []; + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $connection->expects($this->atLeastOnce())->method('beginTransaction'); + $connection->expects($this->atLeastOnce())->method('commit'); + $this->resource->expects($this->atLeastOnce())->method('getConnection')->willReturn($connection); + $queue = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $configuration = $this->getMockBuilder(\Magento\Framework\MessageQueue\ConsumerConfigurationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $configuration->expects($this->atLeastOnce())->method('getHandlers')->willReturn([]); + $this->messageStatusProcessor->expects($this->exactly(2))->method('acknowledgeMessages'); + $mergedMessage = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $message = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $mergedMessages = [ + $topicName => [$mergedMessage] + ]; + $messages = [ + $topicName => [$message] + ]; + + $this->messageProcessor->process($queue, $configuration, $messages, $messagesToAcknowledge, $mergedMessages); + } + + /** + * Test for process() with ConnectionLostException. + * + * @return void + */ + public function testProcessWithConnectionLostException() + { + $topicName = 'topic'; + $messagesToAcknowledge = []; + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $connection->expects($this->atLeastOnce())->method('beginTransaction'); + $connection->expects($this->never())->method('commit'); + $connection->expects($this->atLeastOnce())->method('rollBack'); + $this->resource->expects($this->atLeastOnce())->method('getConnection')->willReturn($connection); + $queue = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $configuration = $this->getMockBuilder(\Magento\Framework\MessageQueue\ConsumerConfigurationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $exception = new \Magento\Framework\MessageQueue\ConnectionLostException(__('Exception Message')); + $configuration->expects($this->atLeastOnce())->method('getHandlers')->willThrowException($exception); + $this->messageStatusProcessor->expects($this->once())->method('acknowledgeMessages'); + $mergedMessage = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $message = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $mergedMessages = [ + $topicName => [$mergedMessage] + ]; + $messages = [ + $topicName => [$message] + ]; + + $this->messageProcessor->process($queue, $configuration, $messages, $messagesToAcknowledge, $mergedMessages); + } + + /** + * Test for process() with Exception. + * + * @return void + */ + public function testProcessWithException() + { + $topicName = 'topic'; + $messagesToAcknowledge = []; + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $connection->expects($this->atLeastOnce())->method('beginTransaction'); + $connection->expects($this->never())->method('commit'); + $connection->expects($this->atLeastOnce())->method('rollBack'); + $this->resource->expects($this->atLeastOnce())->method('getConnection')->willReturn($connection); + $queue = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $configuration = $this->getMockBuilder(\Magento\Framework\MessageQueue\ConsumerConfigurationInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $exception = new \Exception(); + $configuration->expects($this->atLeastOnce())->method('getHandlers')->willThrowException($exception); + $this->messageStatusProcessor->expects($this->once())->method('acknowledgeMessages'); + $this->messageStatusProcessor->expects($this->atLeastOnce())->method('rejectMessages'); + $mergedMessage = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $message = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $mergedMessages = [ + $topicName => [$mergedMessage] + ]; + $messages = [ + $topicName => [$message] + ]; + + $this->messageProcessor->process($queue, $configuration, $messages, $messagesToAcknowledge, $mergedMessages); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageStatusProcessorTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageStatusProcessorTest.php new file mode 100644 index 0000000000000..041f73f3a268a --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageStatusProcessorTest.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +/** + * Unit test for MessageStatusProcessor. + */ +class MessageStatusProcessorTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\MessageQueue\MessageStatusProcessor + */ + private $messageStatusProcessor; + + /** + * Set up. + * + * @return void + */ + protected function setUp() + { + $objectManagerHelper = new ObjectManagerHelper($this); + $this->messageStatusProcessor = $objectManagerHelper->getObject( + \Magento\Framework\MessageQueue\MessageStatusProcessor::class + ); + } + + /** + * Test for acknowledgeMessages(). + * + * @return void + */ + public function testAcknowledgeMessages() + { + $queue = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $queue->expects($this->atLeastOnce())->method('acknowledge'); + $message = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->messageStatusProcessor->acknowledgeMessages($queue, [$message]); + } + + /** + * Test for rejectMessages(). + * + * @return void + */ + public function testRejectMessages() + { + $queue = $this->getMockBuilder(\Magento\Framework\MessageQueue\QueueInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $queue->expects($this->atLeastOnce())->method('reject'); + $message = $this->getMockBuilder(\Magento\Framework\MessageQueue\EnvelopeInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->messageStatusProcessor->rejectMessages($queue, [$message]); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageValidatorTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageValidatorTest.php new file mode 100644 index 0000000000000..c0303ba5c2701 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/MessageValidatorTest.php @@ -0,0 +1,254 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit; + +use Doctrine\Instantiator\Exception\InvalidArgumentException; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; +use Magento\Framework\MessageQueue\MessageValidator; + +/** + * @covers Magento\Framework\MessageQueue\MessageValidator + * @SuppressWarnings(PHPMD) + */ +class MessageValidatorTest extends \PHPUnit\Framework\TestCase +{ + /** @var MessageValidator */ + protected $model; + + /** @var CommunicationConfig|\PHPUnit_Framework_MockObject_MockObject */ + protected $communicationConfigMock; + + protected function setUp() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->model = $objectManager->getObject(MessageValidator::class); + $this->communicationConfigMock = $this->getMockBuilder(CommunicationConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager->setBackwardCompatibleProperty( + $this->model, + 'communicationConfig', + $this->communicationConfigMock + ); + } + + /** + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage Specified topic "customer.created" is not declared. + */ + public function testValidateInvalidTopic() + { + $this->model->validate('customer.created', 'Some message', true); + } + + public function testValidateValidObjectType() + { + $this->communicationConfigMock->expects($this->any())->method('getTopic')->willReturn( + $this->getQueueConfigDataObjectType() + ); + $object = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->model->validate('customer.created', $object, true); + } + + public function testValidateValidMethodType() + { + $this->communicationConfigMock->expects($this->any())->method('getTopic')->willReturn( + $this->getQueueConfigDataMethodType() + ); + $object = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + $this->model->validate('customer.created', [$object, 'password', 'redirect'], true); + } + + public function testEncodeValidMessageObjectType() + { + $this->communicationConfigMock->expects($this->any())->method('getTopic')->willReturn( + $this->getQueueConfigDataObjectType() + ); + $this->model->validate('customer.created', [], true); + } + + /** + * @expectedException InvalidArgumentException + * @expectedExceptionMessage Data in topic "customer.created" must be of type "Magento\Customer\Api\Data\CustomerInt + */ + public function testEncodeInvalidMessageMethodType() + { + $this->communicationConfigMock->expects($this->any())->method('getTopic')->willReturn( + $this->getQueueConfigDataMethodType() + ); + $this->model->validate('customer.created', [1, 2, 3], true); + } + + /** + * Data provider for queue config of object type + * + * @return array + */ + private function getQueueConfigDataObjectType() + { + return [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => \Magento\Customer\Api\Data\CustomerInterface::class + ]; + } + + /** + * Data provider for queue config of method type + * + * @return array + */ + private function getQueueConfigDataMethodType() + { + return [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_METHOD, + CommunicationConfig::TOPIC_REQUEST => [ + [ + 'param_name' => 'customer', + 'param_position' => 0, + 'is_required' => true, + 'param_type' => \Magento\Customer\Api\Data\CustomerInterface::class, + ], + [ + 'param_name' => 'password', + 'param_position' => 1, + 'is_required' => false, + 'param_type' => 'string', + ], + [ + 'param_name' => 'redirectUrl', + 'param_position' => 2, + 'is_required' => false, + 'param_type' => 'string', + ], + ] + ]; + } + + /** + * @dataProvider getQueueConfigRequestType + */ + public function testInvalidMessageType($requestType, $message, $expectedResult = null) + { + $this->communicationConfigMock->expects($this->any())->method('getTopic')->willReturn($requestType); + if ($expectedResult) { + $this->expectException('InvalidArgumentException', $expectedResult); + } + $this->model->validate('topic', $message); + } + + public function getQueueConfigRequestType() + { + $customerMock = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + $customerMockTwo = $this->getMockBuilder(\Magento\Customer\Api\Data\CustomerInterface::class) + ->disableOriginalConstructor() + ->setMethods([]) + ->getMock(); + + return [ + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => 'string' + ], + 'valid string', + null + ], + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => 'string' + ], + 1, + 'Data in topic "topic" must be of type "string". "int" given.' + ], + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => 'string[]' + ], + ['string1', 'string2'], + null + ], + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => 'string[]' + ], + [], + null + ], + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => 'string[]' + ], + 'single string', + 'Data in topic "topic" must be of type "string[]". "string" given.' + ], + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => \Magento\Customer\Api\Data\CustomerInterface::class + ], + $customerMock, + null + ], + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'customer', + 'Data in topic "topic" must be of type "Magento\Customer\Api\Data\CustomerInterface". "string" given.' + ], + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => 'Magento\Customer\Api\Data\CustomerInterface[]' + ], + [$customerMock, $customerMockTwo], + null + ], + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => 'Magento\Customer\Api\Data\CustomerInterface[]' + ], + [], + null + ], + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => 'Magento\Customer\Api\Data\CustomerInterface[]' + ], + 'customer', + 'Data in topic "topic" must be of type "Magento\Customer\Api\Data\CustomerInterface[]". "string" given.' + ], + [ + [ + CommunicationConfig::TOPIC_REQUEST_TYPE => CommunicationConfig::TOPIC_REQUEST_TYPE_CLASS, + CommunicationConfig::TOPIC_REQUEST => 'Magento\Customer\Api\Data\CustomerInterface[]' + ], + $customerMock, + 'Data in topic "topic" must be of type "Magento\Customer\Api\Data\CustomerInterface[]". ' + ], + ]; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/CompositeReaderTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/CompositeReaderTest.php new file mode 100644 index 0000000000000..88f33598366e8 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/CompositeReaderTest.php @@ -0,0 +1,113 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Publisher\Config; + +use Magento\Framework\MessageQueue\Publisher\Config\CompositeReader; +use Magento\Framework\MessageQueue\Publisher\Config\ValidatorInterface; +use Magento\Framework\MessageQueue\Publisher\Config\ReaderInterface; + +class CompositeReaderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var CompositeReader + */ + private $reader; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $validatorMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $readerOneMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $readerTwoMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $readerThreeMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $defaultConfigProviderMock; + + /** + * Initialize parameters + */ + protected function setUp() + { + $this->validatorMock = $this->createMock(ValidatorInterface::class); + $this->readerOneMock = $this->createMock(ReaderInterface::class); + $this->readerTwoMock = $this->createMock(ReaderInterface::class); + $this->readerThreeMock = $this->createMock(ReaderInterface::class); + $this->defaultConfigProviderMock = + $this->createMock(\Magento\Framework\MessageQueue\DefaultValueProvider::class); + + $this->reader = new CompositeReader( + $this->validatorMock, + $this->defaultConfigProviderMock, + [ + 'readerOne' => $this->readerOneMock, + 'readerThree' => $this->readerThreeMock, + 'readerTwo' => $this->readerTwoMock, + ] + ); + } + + public function testRead() + { + $this->defaultConfigProviderMock->expects($this->any())->method('getConnection')->willReturn('amqp'); + $this->defaultConfigProviderMock->expects($this->any())->method('getExchange')->willReturn('magento'); + + $dataOne = include __DIR__ . '/../../_files/queue_publisher/reader_one.php'; + $dataTwo = include __DIR__ . '/../../_files/queue_publisher/reader_two.php'; + $expectedValidationData = include __DIR__ . '/../../_files/queue_publisher/data_to_validate.php'; + + $this->readerOneMock->expects($this->once())->method('read')->with(null)->willReturn($dataOne); + $this->readerTwoMock->expects($this->once())->method('read')->with(null)->willReturn($dataTwo); + $this->readerThreeMock->expects($this->once())->method('read')->with(null)->willReturn([]); + + $this->validatorMock->expects($this->once())->method('validate')->with($expectedValidationData); + + $data = $this->reader->read(); + + $expectedData = [ + //disabling existing connection and adding new + 'top04' => [ + 'topic' => 'top04', + 'disabled' => false, + 'connection' => ['name' => 'db', 'disabled' => false, 'exchange' => 'magento2'], + ], + //two disabled connections are ignored + 'top05' => [ + 'topic' => 'top05', + 'disabled' => false, + 'connection' => ['name' => 'amqp', 'exchange' => 'exch01', 'disabled' => false], + ], + //added default connection if not declared + 'top06' => [ + 'topic' => 'top06', + 'disabled' => false, + 'connection' => ['name' => 'amqp', 'exchange' => 'magento', 'disabled' => false], + ], + //added default connection if all declared connections are disabled + 'top07' => [ + 'topic' => 'top07', + 'disabled' => false, + 'connection' => ['name' => 'amqp', 'exchange' => 'magento', 'disabled' => false], + ], + ]; + + $this->assertEquals($expectedData, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/CompositeValidatorTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/CompositeValidatorTest.php new file mode 100644 index 0000000000000..f53899f318d09 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/CompositeValidatorTest.php @@ -0,0 +1,74 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Publisher\Config; + +use Magento\Framework\MessageQueue\Publisher\Config\CompositeValidator; +use Magento\Framework\MessageQueue\Publisher\Config\ValidatorInterface; + +class CompositeValidatorTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var CompositeValidator + */ + private $model; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $validatorOneMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $validatorTwoMock; + + /** + * Initialize parameters + */ + protected function setUp() + { + $this->validatorOneMock = $this->createMock(ValidatorInterface::class); + $this->validatorTwoMock = $this->createMock(ValidatorInterface::class); + + $this->model = new CompositeValidator([$this->validatorOneMock, $this->validatorTwoMock]); + } + + public function testValidate() + { + $expectedValidationData = include __DIR__ . '/../../_files/queue_publisher/data_to_validate.php'; + $this->validatorOneMock->expects($this->once())->method('validate')->with($expectedValidationData); + $this->validatorTwoMock->expects($this->once())->method('validate')->with($expectedValidationData); + $this->model->validate($expectedValidationData); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage test + */ + public function testValidatorThrowsException() + { + $expectedValidationData = include __DIR__ . '/../../_files/queue_publisher/data_to_validate.php'; + $this->validatorOneMock + ->expects($this->once()) + ->method('validate') + ->willThrowException(new \LogicException('test')); + $this->validatorTwoMock->expects($this->never())->method('validate'); + $this->model->validate($expectedValidationData); + } + + public function testInvalidReaderInstance() + { + $this->expectException( + '\LogicException', + 'Validator [stdClass] does not implements ' . + 'Magento\Framework\MessageQueue\Publisher\Config\ValidatorInterface' + ); + $validator = new \stdClass(); + $model = new CompositeValidator([$validator]); + $expectedValidationData = include __DIR__ . '/../../_files/queue_publisher/data_to_validate.php'; + $model->validate($expectedValidationData); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Env/ReaderTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Env/ReaderTest.php new file mode 100644 index 0000000000000..96528019cff85 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Env/ReaderTest.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit\Publisher\Config\Env; + +use Magento\Framework\MessageQueue\Publisher\Config\Env\Reader; + +class ReaderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $deploymentConfigMock; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $configDataMock; + + /** + * @var Reader + * + */ + private $reader; + + protected function setUp() + { + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->deploymentConfigMock = $this->getMockBuilder(\Magento\Framework\App\DeploymentConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $cache = $this->getMockBuilder(\Magento\Framework\Config\CacheInterface::class) + ->getMock(); + $data = [ + 'topics' => [ + 'inventory.counter.updated' => [ + 'disabled' => false, + 'publisher' => 'amqp-magento' + ], + ], + 'publishers' => [ + 'amqp-magento' => [ + 'name' => 'amqp-magento', + 'connection' => 'db', + 'exchange' => 'magento-db' + ], + ] + + ]; + $reader = $this->getMockBuilder(\Magento\Framework\MessageQueue\Config\CompositeReader::class) + ->disableOriginalConstructor() + ->getMock(); + $reader->expects($this->any())->method('read')->willReturn($data); + $cache->expects($this->any())->method('load')->willReturn(false); + $this->configDataMock = $objectManager->getObject( + \Magento\Framework\MessageQueue\Config\Data::class, + [ + 'cache' => $cache, + 'reader' => $reader + ] + ); + + $this->reader = new Reader( + $this->deploymentConfigMock, + $this->configDataMock, + [ + 'amqp-magento' => 'amqp', + 'db-magento-db' => 'db' + ] + ); + } + + public function testReadCurrentConfig() + { + $configData = include __DIR__ . '/../../../_files/env_2_2.php'; + $this->deploymentConfigMock->expects($this->once())->method('getConfigData') + ->with('queue')->willReturn($configData); + $actualResult = $this->reader->read(); + $this->assertEquals($configData['config']['publishers'], $actualResult); + } + + public function testReadPreviousConfig() + { + $configData = include __DIR__ . '/../../../_files/env_2_1.php'; + $this->deploymentConfigMock->expects($this->once())->method('getConfigData') + ->with('queue')->willReturn($configData); + $actualResult = $this->reader->read(); + $expectedResult = [ + 'inventory.counter.updated' => [ + 'connections' => [ + 'amqp' => [ + 'name' => 'db', + 'exchange' => 'magento-db', + 'disabled' => false + ] + ], + 'disabled' => false + ] + ]; + $this->assertEquals($expectedResult, $actualResult); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/RemoteService/ReaderTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/RemoteService/ReaderTest.php new file mode 100644 index 0000000000000..47c37077a5460 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/RemoteService/ReaderTest.php @@ -0,0 +1,125 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Publisher\Config\RemoteService; + +use Magento\Framework\Communication\Config\ReflectionGenerator; +use Magento\Framework\MessageQueue\DefaultValueProvider; +use Magento\Framework\MessageQueue\Publisher\Config\RemoteService\Reader; +use Magento\Framework\ObjectManager\ConfigInterface as ObjectManagerConfig; +use Magento\Framework\Reflection\MethodsMap as ServiceMethodsMap; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +class ReaderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Reader + */ + private $reader; + + /** + * @var DefaultValueProvider|\PHPUnit_Framework_MockObject_MockObject + */ + protected $defaultValueProvider; + + /** + * @var ObjectManagerConfig|\PHPUnit_Framework_MockObject_MockObject + */ + protected $objectManagerConfig; + + /** + * @var ReflectionGenerator|\PHPUnit_Framework_MockObject_MockObject + */ + protected $reflectionGenerator; + + /** + * @var ServiceMethodsMap|\PHPUnit_Framework_MockObject_MockObject + */ + protected $serviceMethodsMap; + + /** + * Initialize parameters + */ + protected function setUp() + { + $objectManager = new ObjectManager($this); + $this->defaultValueProvider = $this->createMock(DefaultValueProvider::class); + $this->objectManagerConfig = $this->createMock(ObjectManagerConfig::class); + $this->reflectionGenerator = $this->createMock(ReflectionGenerator::class); + $this->serviceMethodsMap = $this->createMock(ServiceMethodsMap::class); + $this->reader = $objectManager->getObject( + Reader::class, + [ + 'defaultValueProvider' => $this->defaultValueProvider, + 'objectManagerConfig' => $this->objectManagerConfig, + 'reflectionGenerator' => $this->reflectionGenerator, + 'serviceMethodsMap' => $this->serviceMethodsMap, + ] + ); + } + + public function testRead() + { + $this->defaultValueProvider->expects($this->any())->method('getConnection')->willReturn('amqp'); + $this->defaultValueProvider->expects($this->any())->method('getExchange')->willReturn('magento'); + + $this->objectManagerConfig->expects($this->any())->method('getPreferences')->willReturn( + [ + 'Some\Service\NameInterface' => 'Some\Service\NameInterfaceRemote', + 'Some\Service\NonRemoteInterface' => 'Some\Service\NonRemote' + ] + ); + + $this->serviceMethodsMap->expects($this->any())->method('getMethodsMap')->willReturn( + ['methodOne' => 'string', 'methodTwo' => 'string'] + ); + + $this->reflectionGenerator->expects($this->exactly(2))->method('generateTopicName')->willReturnMap( + [ + ['Some\Service\NameInterface', 'methodOne', 'topicOne'], + ['Some\Service\NameInterface', 'methodTwo', 'topicTwo'] + ] + ); + + $expectedResult = [ + 'topicOne' => [ + 'topic' => 'topicOne', + 'disabled' => false, + 'connections' => ['amqp' => ['name' => 'amqp', 'exchange' => 'magento', 'disabled' => false]] + ], + 'topicTwo' => [ + 'topic' => 'topicTwo', + 'disabled' => false, + 'connections' => ['amqp' => ['name' => 'amqp', 'exchange' => 'magento', 'disabled' => false]] + ], + ]; + + $this->assertEquals($expectedResult, $this->reader->read()); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Service interface was expected, "Some\Service\NameInterface" given + */ + public function testReadInvalidService() + { + $this->defaultValueProvider->expects($this->any())->method('getConnection')->willReturn('amqp'); + $this->defaultValueProvider->expects($this->any())->method('getExchange')->willReturn('magento'); + + $this->objectManagerConfig->expects($this->any())->method('getPreferences')->willReturn( + [ + 'Some\Service\NameInterface' => 'Some\Service\NameInterfaceRemote', + 'Some\Service\NonRemoteInterface' => 'Some\Service\NonRemote' + ] + ); + + $this->serviceMethodsMap->expects($this->any())->method('getMethodsMap') + ->willThrowException(new \Exception('')); + + $this->reflectionGenerator->expects($this->exactly(0))->method('generateTopicName'); + + $this->reader->read(); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Validator/EnabledConnectionTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Validator/EnabledConnectionTest.php new file mode 100644 index 0000000000000..334bd20de5e58 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Validator/EnabledConnectionTest.php @@ -0,0 +1,77 @@ +<?php + +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit\Publisher\Config\Validator; + +use \Magento\Framework\MessageQueue\Publisher\Config\Validator\EnabledConnection; + +class EnabledConnectionTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var EnabledConnection + */ + private $model; + + protected function setUp() + { + $this->model = new EnabledConnection(); + } + + public function testValidateValidConfig() + { + $configData = [ + 'pub01' => [ + 'topic' => 'pub01', + 'disabled' => false, + 'connections' => [ + 'con01' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => true], + 'con02' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + ], + ], + 'pub02' => [ + 'topic' => 'pub02', + 'disabled' => false, + 'connections' => [ + 'con01' => ['name' => 'amqp', 'exchange' => 'magento', 'disabled' => true], + ] + ], + 'pub03' => [ + 'topic' => 'pub02', + 'disabled' => false, + ] + ]; + $this->model->validate($configData); + } + + public function testValidateMultipleEnabledConnections() + { + $this->expectException( + '\LogicException', + 'More than 1 enabled connections configured for publisher pub01. ' . + 'More than 1 enabled connections configured for publisher pub02.' + ); + $configData = [ + 'pub01' => [ + 'topic' => 'pub01', + 'disabled' => false, + 'connections' => [ + 'con01' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + 'con02' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + ], + ], + 'pub02' => [ + 'topic' => 'pub02', + 'disabled' => false, + 'connections' => [ + 'con01' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + 'con02' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + ], + ], + ]; + $this->model->validate($configData); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Validator/FormatTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Validator/FormatTest.php new file mode 100644 index 0000000000000..1df7f078d9af8 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Validator/FormatTest.php @@ -0,0 +1,189 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Publisher\Config\Validator; + +use \Magento\Framework\MessageQueue\Publisher\Config\Validator\Format; + +class FormatTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Format + */ + private $model; + + protected function setUp() + { + $this->model = new Format(); + } + + public function testValidateValidConfig() + { + $configData = [ + 'pub01' => [ + 'topic' => 'pub01', + 'disabled' => false, + 'connections' => [ + 'con01' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => true], + 'con02' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + ], + ], + 'pub02' => [ + 'topic' => 'pub02', + 'disabled' => false, + 'connections' => [ + 'con01' => ['name' => 'amqp', 'exchange' => 'magento', 'disabled' => true], + ] + ] + ]; + $this->model->validate($configData); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Missing topic field for publisher pub01. + */ + public function testValidateMissingTopicName() + { + $configData = [ + 'pub01' => [ + 'disabled' => false, + 'connections' => [ + 'con01' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + 'con02' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + ], + ], + ]; + $this->model->validate($configData); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Missing disabled field for publisher pub01. + */ + public function testValidateMissingDisabledField() + { + $configData = [ + 'pub01' => [ + 'topic' => 'pub01', + 'connections' => [ + 'con01' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + 'con02' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + ], + ], + ]; + $this->model->validate($configData); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Missing connections field for publisher pub01. + */ + public function testValidateMissingConnectionsField() + { + $configData = [ + 'pub01' => [ + 'topic' => 'pub01', + 'disabled' => false, + ], + ]; + $this->model->validate($configData); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Invalid connections format for publisher pub01. + */ + public function testValidateInvalidConnectionsFormat() + { + $configData = [ + 'pub01' => [ + 'topic' => 'pub01', + 'disabled' => false, + 'connections' => 'con1' + ], + ]; + $this->model->validate($configData); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Missing name field for publisher pub01 in connection config. + */ + public function testValidateInvalidPublisherConnectionName() + { + $configData = [ + 'pub01' => [ + 'topic' => 'pub01', + 'disabled' => false, + 'connections' => [ + 'con01' => ['exchange' => 'exchange01', 'disabled' => false], + ] + ], + ]; + $this->model->validate($configData); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Missing exchange field for publisher pub01 in connection config. + */ + public function testValidateInvalidConnectionExchange() + { + $configData = [ + 'pub01' => [ + 'topic' => 'pub01', + 'disabled' => false, + 'connections' => [ + 'con01' => ['name' => 'con1', 'disabled' => false], + ] + ], + ]; + $this->model->validate($configData); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Missing disabled field for publisher pub01 in connection config. + */ + public function testValidateInvalidConnectionDisabledField() + { + $configData = [ + 'pub01' => [ + 'topic' => 'pub01', + 'disabled' => false, + 'connections' => [ + 'con01' => ['name' => 'con1', 'exchange' => 'default'], + ] + ], + ]; + $this->model->validate($configData); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Missing topic field for publisher pub01. Missing disabled field for publisher pub02. + */ + public function testValidateMultipleExceptions() + { + $configData = [ + 'pub01' => [ + 'disabled' => false, + 'connections' => [ + 'con01' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + 'con02' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + ], + ], + 'pub02' => [ + 'topic' => 'pub02', + 'connections' => [ + 'con01' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + 'con02' => ['name' => 'con1', 'exchange' => 'exchange01', 'disabled' => false], + ], + ], + ]; + $this->model->validate($configData); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Xml/ConverterTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Xml/ConverterTest.php new file mode 100644 index 0000000000000..86e8526114780 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/Config/Xml/ConverterTest.php @@ -0,0 +1,60 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Publisher\Config\Xml; + +use Magento\Framework\MessageQueue\Publisher\Config\Xml\Converter; +use Magento\Framework\Stdlib\BooleanUtils; + +class ConverterTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Converter + */ + private $converter; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $defaultConfigProviderMock; + + /** + * Initialize parameters + */ + protected function setUp() + { + $this->defaultConfigProviderMock = + $this->createMock(\Magento\Framework\MessageQueue\DefaultValueProvider::class); + $this->converter = new Converter(new BooleanUtils(), $this->defaultConfigProviderMock); + } + + public function testConvert() + { + $fixtureDir = __DIR__ . '/../../../_files/queue_publisher'; + $xmlFile = $fixtureDir . '/valid.xml'; + $dom = new \DOMDocument(); + $dom->load($xmlFile); + $this->defaultConfigProviderMock->expects($this->any())->method('getExchange')->willReturn('magento'); + $result = $this->converter->convert($dom); + + $expectedData = include($fixtureDir . '/valid.php'); + foreach ($expectedData as $key => $value) { + $this->assertEquals($value, $result[$key], 'Invalid data for ' . $key); + } + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Connection name is missing + */ + public function testConvertWithException() + { + $fixtureDir = __DIR__ . '/../../../_files/queue_publisher'; + $xmlFile = $fixtureDir . '/invalid.xml'; + $dom = new \DOMDocument(); + $dom->load($xmlFile); + $this->converter->convert($dom); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/XsdTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/XsdTest.php new file mode 100644 index 0000000000000..048ec82fb57c4 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Publisher/XsdTest.php @@ -0,0 +1,171 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Publisher; + +class XsdTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var string + */ + protected $_schemaFile; + + protected function setUp() + { + if (!function_exists('libxml_set_external_entity_loader')) { + $this->markTestSkipped('Skipped on HHVM. Will be fixed in MAGETWO-45033'); + } + $urnResolver = new \Magento\Framework\Config\Dom\UrnResolver(); + $this->_schemaFile = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/publisher.xsd'); + } + + /** + * @param string $fixtureXml + * @param array $expectedErrors + * @dataProvider exemplarXmlDataProvider + */ + public function testExemplarXml($fixtureXml, array $expectedErrors) + { + $validationState = $this->createMock(\Magento\Framework\Config\ValidationStateInterface::class); + $validationState->expects($this->any()) + ->method('isValidationRequired') + ->willReturn(true); + $messageFormat = '%message%'; + $dom = new \Magento\Framework\Config\Dom($fixtureXml, $validationState, [], null, null, $messageFormat); + $actualErrors = []; + $actualResult = $dom->validate($this->_schemaFile, $actualErrors); + $this->assertEquals(empty($expectedErrors), $actualResult, "Validation result is invalid."); + $this->assertEquals($expectedErrors, $actualErrors, "Validation errors does not match."); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function exemplarXmlDataProvider() + { + // @codingStandardsIgnoreStart + return [ + /** Valid configurations */ + 'valid' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="topic.message.queue.config.01"> + <connection name="amqp" exchange="magento2" /> + <connection name="db" exchange="magento2" disabled="true" /> + </publisher> + <publisher topic="topic.message.queue.config.02"> + <connection name="amqp" exchange="magento2" disabled="true"/> + <connection name="db" exchange="magento2" disabled="true" /> + </publisher> + <publisher topic="topic.message.queue.config.03" disabled="true" /> + </config>', + [], + ], + 'non unique publisher topic' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="topic.message.queue.config.01"> + <connection name="amqp" exchange="magento2" /> + </publisher> + <publisher topic="topic.message.queue.config.01"> + <connection name="amqp" exchange="magento2" disabled="true"/> + </publisher> + </config>', + [ + "Element 'publisher': Duplicate key-sequence ['topic.message.queue.config.01'] in unique identity-constraint 'unique-publisher-topic'." + ], + ], + 'non unique publisher connection name' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="topic.message.queue.config.01"> + <connection name="amqp" exchange="magento2" /> + <connection name="amqp" exchange="magento2" /> + </publisher> + </config>', + [ + "Element 'connection': Duplicate key-sequence ['amqp'] in unique identity-constraint 'unique-connection-name'." + ], + ], + 'missed required publisher attribute' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher disabled="false"> + <connection name="amqp" exchange="magento2" /> + </publisher> + </config>', + [ + "Element 'publisher': The attribute 'topic' is required but missing." + ], + ], + 'missed required connection attribute' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="top01"> + <connection exchange="magento2" /> + </publisher> + </config>', + [ + "Element 'connection': The attribute 'name' is required but missing." + ], + ], + 'unexpected publisher element' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <unexpected name="10">20</unexpected> + <publisher topic="topic.message.queue.config.03" disabled="true" /> + </config>', + [ + "Element 'unexpected': This element is not expected. Expected is ( publisher )." + ], + ], + 'unexpected connection element' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="topic.message.queue.config.03" disabled="true"> + <connection name="amqp" exchange="magento2" /> + <unexpected name="10">20</unexpected> + </publisher> + </config>', + [ + "Element 'unexpected': This element is not expected. Expected is ( connection )." + ], + ], + 'unexpected publisher attribute' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="topic.message.queue.config.03" disabled="true" unexpected="10"/> + </config>', + [ + "Element 'publisher', attribute 'unexpected': The attribute 'unexpected' is not allowed.", + ], + ], + 'unexpected connection attribute' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="topic.message.queue.config.03" disabled="true"> + <connection name="amqp" exchange="magento2" unexpected="10"/> + </publisher> + </config>', + [ + "Element 'connection', attribute 'unexpected': The attribute 'unexpected' is not allowed.", + ], + ], + 'invalid connection attribute value' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="topic.message.queue.config.03" disabled="true"> + <connection name="amqp" exchange="magento2" disabled="disabled"/> + </publisher> + </config>', + [ + "Element 'connection', attribute 'disabled': 'disabled' is not a valid value of the atomic type 'xs:boolean'.", + ], + ], + 'invalid publisher attribute value' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="topic.message.queue.config.03" disabled="disabled"> + <connection name="amqp" exchange="magento2" /> + </publisher> + </config>', + [ + "Element 'publisher', attribute 'disabled': 'disabled' is not a valid value of the atomic type 'xs:boolean'.", + ], + ], + ]; + // @codingStandardsIgnoreEnd + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/PublisherTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/PublisherTest.php new file mode 100644 index 0000000000000..576da8b9a006b --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/PublisherTest.php @@ -0,0 +1,165 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Test\Unit; + +use Magento\Framework\Amqp\Config as AmqpConfig; +use Magento\Framework\MessageQueue\Envelope; +use Magento\Framework\MessageQueue\EnvelopeFactory; +use Magento\Framework\MessageQueue\ExchangeRepository; +use Magento\Framework\MessageQueue\MessageEncoder; +use Magento\Framework\MessageQueue\MessageValidator; +use Magento\Framework\MessageQueue\Publisher; +use Magento\Framework\MessageQueue\Publisher\Config\PublisherConfigItem; +use Magento\Framework\MessageQueue\Publisher\Config\PublisherConnection; +use Magento\Framework\MessageQueue\Publisher\ConfigInterface as PublisherConfig; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\MysqlMq\Model\Driver\Exchange; + +/** + * Class PublisherTest @covers \Magento\Framework\MessageQueue\Publisher + */ +class PublisherTest extends \PHPUnit\Framework\TestCase +{ + /** + * Test subject. + * + * @var Publisher + */ + private $publisher; + + /** + * Publisher config mock. + * + * @var PublisherConfig|\PHPUnit_Framework_MockObject_MockObject + */ + private $publisherConfig; + + /** + * Amqp config mock. + * + * @var AmqpConfig|\PHPUnit_Framework_MockObject_MockObject + */ + private $amqpConfig; + + /** + * Message validator mock. + * + * @var MessageValidator|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageValidator; + + /** + * Message encoder mock. + * + * @var MessageEncoder|\PHPUnit_Framework_MockObject_MockObject + */ + private $messageEncoder; + + /** + * Exchange repository mock. + * + * @var ExchangeRepository|\PHPUnit_Framework_MockObject_MockObject + */ + private $exchangeRepository; + + /** + * Envelope factory mock. + * + * @var EnvelopeFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $envelopeFactory; + + /** + * @inheritdoc + */ + protected function setUp() + { + $this->publisherConfig = $this->getMockBuilder(PublisherConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->amqpConfig = $this->getMockBuilder(AmqpConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->messageValidator = $this->getMockBuilder(MessageValidator::class) + ->disableOriginalConstructor() + ->getMock(); + $this->messageEncoder = $this->getMockBuilder(MessageEncoder::class) + ->disableOriginalConstructor() + ->getMock(); + $this->exchangeRepository = $this->getMockBuilder(ExchangeRepository::class) + ->disableOriginalConstructor() + ->getMock(); + $this->envelopeFactory = $this->getMockBuilder(EnvelopeFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager = new ObjectManager($this); + $this->publisher = $objectManager->getObject( + Publisher::class, + [ + 'messageValidator' => $this->messageValidator, + 'envelopeFactory' => $this->envelopeFactory, + 'messageEncoder' => $this->messageEncoder, + 'exchangeRepository' => $this->exchangeRepository, + ] + ); + $objectManager->setBackwardCompatibleProperty($this->publisher, 'publisherConfig', $this->publisherConfig); + $objectManager->setBackwardCompatibleProperty($this->publisher, 'amqpConfig', $this->amqpConfig); + } + + /** + * @covers \Magento\Framework\MessageQueue\Publisher::publish() + */ + public function testPublish() + { + $topicName = 'tesTopicName'; + $data = ['testData']; + $encodedData = 'testEncodedData'; + $body = 'testBody'; + $envelope = new Envelope($body); + $exchange = $this->getMockBuilder(Exchange::class) + ->disableOriginalConstructor() + ->getMock(); + $exchange->expects(self::once()) + ->method('enqueue') + ->with(self::identicalTo($topicName), self::identicalTo($envelope)) + ->willReturn(null); + $connection = $this->getMockBuilder(PublisherConnection::class) + ->disableOriginalConstructor() + ->getMock(); + $connection->expects(self::once()) + ->method('getName') + ->willReturn('amqp'); + $publisher = $this->getMockBuilder(PublisherConfigItem::class) + ->disableOriginalConstructor() + ->getMock(); + $publisher->expects(self::once()) + ->method('getConnection') + ->willReturn($connection); + $this->messageValidator->expects(self::once()) + ->method('validate'); + $this->messageEncoder->expects(self::once()) + ->method('encode') + ->with(self::identicalTo($topicName), self::identicalTo($data)) + ->willReturn($encodedData); + $this->envelopeFactory->expects(self::once()) + ->method('create') + ->willReturn($envelope); + $this->publisherConfig->expects(self::once()) + ->method('getPublisher') + ->with($topicName) + ->willReturn($publisher); + $this->amqpConfig->expects(self::once()) + ->method('getValue') + ->with(AmqpConfig::HOST) + ->willReturn(''); + $this->exchangeRepository->expects(self::once()) + ->method('getByConnectionName') + ->with('db') + ->willReturn($exchange); + self::assertNull($this->publisher->publish($topicName, $data)); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Rpc/ResponseQueueNameBuilderTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Rpc/ResponseQueueNameBuilderTest.php new file mode 100644 index 0000000000000..5034dc44d80e0 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Rpc/ResponseQueueNameBuilderTest.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Rpc; + +use Magento\Framework\MessageQueue\Rpc\ResponseQueueNameBuilder; + +class ResponseQueueNameBuilderTest extends \PHPUnit\Framework\TestCase +{ + public function testGetQueueName() + { + $model = new ResponseQueueNameBuilder(); + $this->assertEquals('responseQueue.topic.01', $model->getQueueName('topic.01')); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/QueueConfigItem/DataMapperTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/QueueConfigItem/DataMapperTest.php new file mode 100644 index 0000000000000..cc5c4ac84440d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/QueueConfigItem/DataMapperTest.php @@ -0,0 +1,265 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Topology\Config\QueueConfigItem; + +use Magento\Framework\MessageQueue\Topology\Config\Data; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; +use Magento\Framework\MessageQueue\Rpc\ResponseQueueNameBuilder; +use Magento\Framework\MessageQueue\Topology\Config\QueueConfigItem\DataMapper; + +class DataMapperTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $configData; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $communicationConfig; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $queueNameBuilder; + + /** + * @var DataMapper + */ + private $model; + + protected function setUp() + { + $this->configData = $this->createMock(Data::class); + $this->communicationConfig = $this->createMock(CommunicationConfig::class); + $this->queueNameBuilder = $this->createMock(ResponseQueueNameBuilder::class); + $this->model = new DataMapper($this->configData, $this->communicationConfig, $this->queueNameBuilder); + } + + public function testGetMappedData() + { + $data = [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'topic01', + 'destinationType' => 'queue', + 'destination' => 'some.queue', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + 'bind02' => [ + 'id' => 'bind02', + 'topic' => 'topic02', + 'destinationType' => 'queue', + 'destination' => 'some.queue', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + 'ex02' => [ + 'name' => 'ex02', + 'type' => 'exchange', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'topic01', + 'destinationType' => 'exchange', + 'destination' => 'some.exchange', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ]; + + $communicationMap = [ + ['topic01', ['name' => 'topic01', 'is_synchronous' => true]], + ['topic02', ['name' => 'topic02', 'is_synchronous' => false]], + ]; + + $this->communicationConfig->expects($this->exactly(2))->method('getTopic')->willReturnMap($communicationMap); + $this->configData->expects($this->once())->method('get')->willReturn($data); + $this->queueNameBuilder->expects($this->once()) + ->method('getQueueName') + ->with('topic01') + ->willReturn('responseQueue.topic01'); + + $actualResult = $this->model->getMappedData(); + $expectedResult = [ + 'responseQueue.topic01--amqp' => [ + 'name' => 'responseQueue.topic01', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ], + 'some.queue--amqp' => [ + 'name' => 'some.queue', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ], + ]; + $this->assertEquals($expectedResult, $actualResult); + } + + /** + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testGetMappedDataForWildcard() + { + $data = [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => '#', + 'destinationType' => 'queue', + 'destination' => 'some.queue', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + 'bind02' => [ + 'id' => 'bind02', + 'topic' => '*.*.*', + 'destinationType' => 'queue', + 'destination' => 'some.queue', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + 'bind03' => [ + 'id' => 'bind03', + 'topic' => 'topic01', + 'destinationType' => 'queue', + 'destination' => 'some.queue', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + 'ex02' => [ + 'name' => 'ex02', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => '#.some.*', + 'destinationType' => 'queue', + 'destination' => 'some.queue', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ]; + + $communicationData = [ + 'topic01' => ['name' => 'topic01', 'is_synchronous' => true], + 'topic02' => ['name' => 'topic02', 'is_synchronous' => true], + 'topic03' => ['name' => 'topic03', 'is_synchronous' => true], + 'topic04.04.04' => ['name' => 'topic04.04.04', 'is_synchronous' => true], + 'topic05.05' => ['name' => 'topic05.05', 'is_synchronous' => true], + 'topic06.06.06' => ['name' => 'topic06.06.06', 'is_synchronous' => false], + 'topic07' => ['name' => 'topic07', 'is_synchronous' => false], + 'topic08.part2.some.test' => ['name' => 'topic08.part2.some.test', 'is_synchronous' => true], + ]; + + $this->communicationConfig->expects($this->once()) + ->method('getTopic') + ->with('topic01') + ->willReturn(['name' => 'topic01', 'is_synchronous' => true]); + $this->communicationConfig->expects($this->any())->method('getTopics')->willReturn($communicationData); + $this->configData->expects($this->once())->method('get')->willReturn($data); + $this->queueNameBuilder->expects($this->any()) + ->method('getQueueName') + ->willReturnCallback(function ($value) { + return 'responseQueue.' . $value; + }); + + $actualResult = $this->model->getMappedData(); + $expectedResult = [ + 'responseQueue.topic01--amqp' => [ + 'name' => 'responseQueue.topic01', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ], + 'some.queue--amqp' => [ + 'name' => 'some.queue', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ], + 'responseQueue.topic02--amqp' => [ + 'name' => 'responseQueue.topic02', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ], + 'responseQueue.topic03--amqp' => [ + 'name' => 'responseQueue.topic03', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ], + 'responseQueue.topic04.04.04--amqp' => [ + 'name' => 'responseQueue.topic04.04.04', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ], + 'responseQueue.topic05.05--amqp' => [ + 'name' => 'responseQueue.topic05.05', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ], + 'responseQueue.topic08.part2.some.test--amqp' => [ + 'name' => 'responseQueue.topic08.part2.some.test', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ] + ]; + $this->assertEquals($expectedResult, $actualResult); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/RemoteService/ReaderTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/RemoteService/ReaderTest.php new file mode 100644 index 0000000000000..df402eb0331ec --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/RemoteService/ReaderTest.php @@ -0,0 +1,142 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Topology\Config\RemoteService; + +use Magento\Framework\Communication\Config\ReflectionGenerator; +use Magento\Framework\MessageQueue\DefaultValueProvider; +use Magento\Framework\MessageQueue\Topology\Config\RemoteService\Reader; +use Magento\Framework\ObjectManager\ConfigInterface as ObjectManagerConfig; +use Magento\Framework\Reflection\MethodsMap as ServiceMethodsMap; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; + +class ReaderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Reader + */ + private $reader; + + /** + * @var DefaultValueProvider|\PHPUnit_Framework_MockObject_MockObject + */ + protected $defaultValueProvider; + + /** + * @var ObjectManagerConfig|\PHPUnit_Framework_MockObject_MockObject + */ + protected $objectManagerConfig; + + /** + * @var ReflectionGenerator|\PHPUnit_Framework_MockObject_MockObject + */ + protected $reflectionGenerator; + + /** + * @var ServiceMethodsMap|\PHPUnit_Framework_MockObject_MockObject + */ + protected $serviceMethodsMap; + + /** + * Initialize parameters + */ + protected function setUp() + { + $objectManager = new ObjectManager($this); + $this->defaultValueProvider = $this->createMock(DefaultValueProvider::class); + $this->objectManagerConfig = $this->createMock(ObjectManagerConfig::class); + $this->reflectionGenerator = $this->createMock(ReflectionGenerator::class); + $this->serviceMethodsMap = $this->createMock(ServiceMethodsMap::class); + $this->reader = $objectManager->getObject( + Reader::class, + [ + 'defaultValueProvider' => $this->defaultValueProvider, + 'objectManagerConfig' => $this->objectManagerConfig, + 'reflectionGenerator' => $this->reflectionGenerator, + 'serviceMethodsMap' => $this->serviceMethodsMap, + ] + ); + } + + public function testRead() + { + $this->defaultValueProvider->expects($this->any())->method('getConnection')->willReturn('amqp'); + $this->defaultValueProvider->expects($this->any())->method('getExchange')->willReturn('magento'); + + $this->objectManagerConfig->expects($this->any())->method('getPreferences')->willReturn( + [ + 'Some\Service\NameInterface' => 'Some\Service\NameInterfaceRemote', + 'Some\Service\NonRemoteInterface' => 'Some\Service\NonRemote' + ] + ); + + $this->serviceMethodsMap->expects($this->any())->method('getMethodsMap')->willReturn( + ['methodOne' => 'string', 'methodTwo' => 'string'] + ); + + $this->reflectionGenerator->expects($this->exactly(2))->method('generateTopicName')->willReturnMap( + [ + ['Some\Service\NameInterface', 'methodOne', 'topicOne'], + ['Some\Service\NameInterface', 'methodTwo', 'topicTwo'] + ] + ); + + $expectedResult = [ + 'magento' => [ + 'name' => 'magento', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'internal' => false, + 'bindings' => [ + 'topicOne--magento--queue.topicOne' => [ + 'id' => 'topicOne--magento--queue.topicOne', + 'destinationType' => 'queue', + 'destination' => 'queue.topicOne', + 'disabled' => false, + 'topic' => 'topicOne', + 'arguments' => [] + ], + 'topicTwo--magento--queue.topicTwo' => [ + 'id' => 'topicTwo--magento--queue.topicTwo', + 'destinationType' => 'queue', + 'destination' => 'queue.topicTwo', + 'disabled' => false, + 'topic' => 'topicTwo', + 'arguments' => [] + ] + ], + 'arguments' => [] + ] + ]; + + $this->assertEquals($expectedResult, $this->reader->read()); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessage Service interface was expected, "Some\Service\NameInterface" given + */ + public function testReadInvalidService() + { + $this->defaultValueProvider->expects($this->any())->method('getConnection')->willReturn('amqp'); + $this->defaultValueProvider->expects($this->any())->method('getExchange')->willReturn('magento'); + + $this->objectManagerConfig->expects($this->any())->method('getPreferences')->willReturn( + [ + 'Some\Service\NameInterface' => 'Some\Service\NameInterfaceRemote', + 'Some\Service\NonRemoteInterface' => 'Some\Service\NonRemote' + ] + ); + + $this->serviceMethodsMap->expects($this->any())->method('getMethodsMap') + ->willThrowException(new \Exception('')); + + $this->reflectionGenerator->expects($this->exactly(0))->method('generateTopicName'); + + $this->reader->read(); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Validator/DependantFieldsTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Validator/DependantFieldsTest.php new file mode 100644 index 0000000000000..56c597dd8d83c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Validator/DependantFieldsTest.php @@ -0,0 +1,92 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Topology\Config\Validator; + +use \Magento\Framework\MessageQueue\Topology\Config\Validator\DependentFields; + +class DependantFieldsTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var DependentFields + */ + private $model; + + protected function setUp() + { + $this->model = new DependentFields(); + } + + public function testValidateValidConfig() + { + $configData = [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + 'ex02' => [ + 'name' => 'ex01', + 'type' => 'headers', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'some.queue', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ]; + $this->model->validate($configData); + } + + public function testValidateMissingTopicField() + { + $expectedMessage = "Topic name is required for topic based exchange: ex01"; + $this->expectException('\LogicException', $expectedMessage); + $configData = [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ] + ]; + $this->model->validate($configData); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Validator/FieldsTypesTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Validator/FieldsTypesTest.php new file mode 100644 index 0000000000000..8e5106033b8f1 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Validator/FieldsTypesTest.php @@ -0,0 +1,458 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Topology\Config\Validator; + +use Magento\Framework\MessageQueue\Topology\Config\Validator\FieldsTypes; + +class FieldsTypesTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var FieldsTypes + */ + private $model; + + protected function setUp() + { + $this->model = new FieldsTypes(); + } + + public function testValidateValidConfig() + { + $configData = [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ] + ]; + $this->model->validate($configData); + } + + /** + * @dataProvider invalidConfigDataProvider + * @param array $configData + * @param string $expectedExceptionMessage + */ + public function testValidateInvalid($configData, $expectedExceptionMessage) + { + $this->expectException('\LogicException', $expectedExceptionMessage); + $this->model->validate($configData); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function invalidConfigDataProvider() + { + return [ + 'type name' => [ + [ + 'ex01' => [ + 'name' => true, + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ], + "Type of 'name' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'boolean', 'string' was expected." + ], + 'type type' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 100, + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ], + "Type of 'type' field specified in configuration of 'ex01' exchange is invalid. Given 'integer" + ], + 'invalid type' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'some', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ], + "Value of 'type' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'some', 'topic' was expected." + ], + 'type connection' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => false, + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ], + "Type of 'connection' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'boolean', 'string' was expected." + ], + 'type durable' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => 100, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ], + "Type of 'durable' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'integer', 'boolean' was expected." + ], + 'type internal' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => null, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ], + "Type of 'internal' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'NULL', 'boolean' was expected." + ], + 'type autoDelete' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => 1, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ], + "Type of 'autoDelete' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'integer', 'boolean' was expected." + ], + 'type arguments' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => 'argument', + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ], + ], + "Type of 'arguments' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'string', 'array' was expected." + ], + 'type bindings' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => false, + ], + ], + "Type of 'bindings' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'boolean', 'array' was expected." + ], + 'type binding id' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 100, + 'destinationType' => 'queue', + 'destination' => 'queue01', + 'disabled' => false, + 'topic' => 'topic01', + 'arguments' => ['some' => 'arg'] + ] + ], + ], + ], + "Type of 'id' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'integer', 'string' was expected." + ], + 'type binding destinationType' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'destinationType' => false, + 'destination' => 'queue01', + 'disabled' => false, + 'topic' => 'topic01', + 'arguments' => ['some' => 'arg'] + ] + ], + ], + ], + "Type of 'destinationType' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'boolean', 'string' was expected." + ], + 'invalid binding destinationType' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'destinationType' => 'test', + 'destination' => 'queue01', + 'disabled' => false, + 'topic' => 'topic01', + 'arguments' => ['some' => 'arg'] + ] + ], + ], + ], + "Value of 'destinationType' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'test', 'queue' was expected." + ], + 'type binding destination' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'destinationType' => 'queue', + 'destination' => null, + 'disabled' => false, + 'topic' => 'topic01', + 'arguments' => ['some' => 'arg'] + ] + ], + ], + ], + "Type of 'destination' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'NULL', 'string' was expected." + ], + 'type binding disabled' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'queue01', + 'disabled' => 1, + 'topic' => 'topic01', + 'arguments' => ['some' => 'arg'] + ] + ], + ], + ], + "Type of 'disabled' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'integer', 'boolean' was expected." + ], + 'type binding topic' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'queue01', + 'disabled' => false, + 'topic' => false, + 'arguments' => ['some' => 'arg'] + ] + ] + ], + ], + "Type of 'topic' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'boolean', 'string' was expected." + ], + 'type binding arguments' => [ + [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'queue01', + 'disabled' => false, + 'topic' => 'topic01', + 'arguments' => 'args' + ] + ] + ], + ], + "Type of 'arguments' field specified in configuration of 'ex01' exchange is invalid." + . " Given 'string', 'array' was expected." + ], + ]; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Validator/FormatTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Validator/FormatTest.php new file mode 100644 index 0000000000000..c918aecf983a6 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Validator/FormatTest.php @@ -0,0 +1,122 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Topology\Config\Validator; + +use \Magento\Framework\MessageQueue\Topology\Config\Validator\Format; + +class FormatTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Format + */ + private $model; + + protected function setUp() + { + $this->model = new Format(); + } + + public function testValidateValidConfig() + { + $configData = [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ] + ]; + $this->model->validate($configData); + } + + public function testValidateMissingRequiredExchangeFields() + { + $expectedMessage = "Missing [name] field for exchange ex01." . PHP_EOL . + "Missing [type] field for exchange ex01." . PHP_EOL . + "Missing [connection] field for exchange ex01." . PHP_EOL . + "Missing [durable] field for exchange ex01." . PHP_EOL . + "Missing [autoDelete] field for exchange ex01." . PHP_EOL . + "Missing [internal] field for exchange ex01." . PHP_EOL . + "Missing [arguments] field for exchange ex01."; + $this->expectException('\LogicException', $expectedMessage); + $configData = [ + 'ex01' => [ + 'invalid' => 'format', + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'topic' => 'bind01', + 'destinationType' => 'bind01', + 'destination' => 'bind01', + 'disabled' => false, + 'arguments' => ['some' => 'arguments'], + ], + ], + ] + ]; + $this->model->validate($configData); + } + + public function testValidateMissingRequiredBindingFields() + { + $expectedMessage = "Missing [id] field for binding ex01 in exchange config." . PHP_EOL . + "Missing [destinationType] field for binding ex01 in exchange config." . PHP_EOL . + "Missing [destination] field for binding ex01 in exchange config." . PHP_EOL . + "Missing [disabled] field for binding ex01 in exchange config." . PHP_EOL . + "Missing [topic] field for binding ex01 in exchange config." . PHP_EOL . + "Missing [arguments] field for binding ex01 in exchange config."; + $this->expectException('\LogicException', $expectedMessage); + $configData = [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => [ + 'bind01' => [ + 'invalid' => 'format' + ], + ], + ] + ]; + $this->model->validate($configData); + } + + public function testValidateInvalidBindingsFormat() + { + $expectedMessage = "Invalid bindings format for exchange ex01."; + $this->expectException('\LogicException', $expectedMessage); + $configData = [ + 'ex01' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'internal' => false, + 'autoDelete' => false, + 'arguments' => ['some' => 'argument'], + 'bindings' => 'binding' + ] + ]; + $this->model->validate($configData); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Xml/ConverterTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Xml/ConverterTest.php new file mode 100644 index 0000000000000..9d574685730cd --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/Config/Xml/ConverterTest.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Topology\Config\Xml; + +use Magento\Framework\MessageQueue\Topology\Config\Xml\Converter; +use Magento\Framework\Stdlib\BooleanUtils; +use Magento\Framework\Data\Argument\InterpreterInterface; + +class ConverterTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Converter + */ + private $converter; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $interpreter; + + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + protected $defaultConfigProviderMock; + + /** + * Initialize parameters + */ + protected function setUp() + { + $this->defaultConfigProviderMock = + $this->createMock(\Magento\Framework\MessageQueue\DefaultValueProvider::class); + $this->interpreter = $this->createMock(InterpreterInterface::class); + $this->converter = new Converter(new BooleanUtils(), $this->interpreter, $this->defaultConfigProviderMock); + $this->defaultConfigProviderMock->expects($this->any())->method('getConnection')->willReturn('amqp'); + } + + public function testConvert() + { + $fixtureDir = __DIR__ . '/../../../_files/queue_topology'; + $xmlFile = $fixtureDir . '/valid.xml'; + $dom = new \DOMDocument(); + $dom->load($xmlFile); + + $this->interpreter->expects($this->any())->method('evaluate')->willReturn(10); + $result = $this->converter->convert($dom); + + $expectedData = include($fixtureDir . '/valid.php'); + foreach ($expectedData as $key => $value) { + $this->assertEquals($value, $result[$key], 'Invalid data for ' . $key); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/MergedXsdTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/MergedXsdTest.php new file mode 100644 index 0000000000000..59f52c83a5f74 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/MergedXsdTest.php @@ -0,0 +1,127 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Topology; + +class MergedXsdTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var string + */ + private $schemaFile; + + protected function setUp() + { + if (!function_exists('libxml_set_external_entity_loader')) { + $this->markTestSkipped('Skipped on HHVM. Will be fixed in MAGETWO-45033'); + } + $urnResolver = new \Magento\Framework\Config\Dom\UrnResolver(); + $this->schemaFile = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/topology_merged.xsd'); + } + + /** + * @param string $fixtureXml + * @param array $expectedErrors + * @dataProvider exemplarXmlDataProvider + */ + public function testExemplarXml($fixtureXml, array $expectedErrors) + { + $validationState = $this->createMock(\Magento\Framework\Config\ValidationStateInterface::class); + $validationState->expects($this->any()) + ->method('isValidationRequired') + ->willReturn(true); + $messageFormat = '%message%'; + $dom = new \Magento\Framework\Config\Dom($fixtureXml, $validationState, [], null, null, $messageFormat); + $actualErrors = []; + $actualResult = $dom->validate($this->schemaFile, $actualErrors); + $this->assertEquals(empty($expectedErrors), $actualResult, "Validation result is invalid."); + $this->assertEquals($expectedErrors, $actualErrors, "Validation errors does not match."); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function exemplarXmlDataProvider() + { + // @codingStandardsIgnoreStart + return [ + /** Valid configurations */ + 'valid' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" type="topic" connection="amqp" /> + <exchange name="ex02" type="topic" connection="amqp" /> + <exchange name="ex03" autoDelete="true" durable="false" internal="true" type="topic" connection="db"> + <arguments> + <argument name="arg1" xsi:type="string">10</argument> + </arguments> + </exchange> + <exchange name="ex04" type="topic" connection="amqp"> + <binding id="bind01" destinationType="queue" destination="queue01" topic="top01" disabled="true" /> + <binding id="bind02" destinationType="queue" destination="queue01" topic="top01"> + <arguments> + <argument name="arg01" xsi:type="string">10</argument> + </arguments> + </binding> + </exchange> + </config>', + [], + ], + 'non-unique-exchange' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" type="topic" connection="amqp"/> + <exchange name="ex01" type="topic" connection="amqp" /> + </config>', + [ + "Element 'exchange': Duplicate key-sequence ['ex01', 'amqp'] in unique identity-constraint 'unique-exchange-name-connection'." + ], + ], + 'non-unique-exchange-binding' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" connection="amqp" type="topic"> + <binding id="bind01" destinationType="queue" destination="queue01" topic="top01" disabled="true" /> + <binding id="bind01" destinationType="queue" destination="queue01" topic="top01" /> + </exchange> + </config>', + [ + "Element 'binding': Duplicate key-sequence ['bind01'] in unique identity-constraint 'unique-binding-id'." + ], + ], + 'invalid-destination-type-binding' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" type="topic" connection="amqp"> + <binding id="bind01" destinationType="topic" destination="queue01" topic="top01" /> + </exchange> + </config>', + [ + "Element 'binding', attribute 'destinationType': [facet 'enumeration'] The value 'topic' is not an element of the set {'queue'}.", + "Element 'binding', attribute 'destinationType': 'topic' is not a valid value of the atomic type 'destinationType'." + ], + ], + 'invalid-exchange-type-binding' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" type="exchange" connection="db"> + <binding id="bind01" destinationType="queue" destination="queue01" topic="top01" /> + </exchange> + </config>', + [ + "Element 'exchange', attribute 'type': [facet 'enumeration'] The value 'exchange' is not an element of the set {'topic'}.", + "Element 'exchange', attribute 'type': 'exchange' is not a valid value of the atomic type 'exchangeType'." + ], + ], + 'missed-required-attributes' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" type="topic" /> + <exchange name="ex02" connection="amqp" /> + </config>', + [ + "Element 'exchange': The attribute 'connection' is required but missing.", + "Element 'exchange': The attribute 'type' is required but missing." + ], + ], + ]; + // @codingStandardsIgnoreEnd + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/XsdTest.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/XsdTest.php new file mode 100644 index 0000000000000..46f57fc572914 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/Topology/XsdTest.php @@ -0,0 +1,117 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Test\Unit\Topology; + +class XsdTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var string + */ + private $schemaFile; + + protected function setUp() + { + if (!function_exists('libxml_set_external_entity_loader')) { + $this->markTestSkipped('Skipped on HHVM. Will be fixed in MAGETWO-45033'); + } + $urnResolver = new \Magento\Framework\Config\Dom\UrnResolver(); + $this->schemaFile = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/topology.xsd'); + } + + /** + * @param string $fixtureXml + * @param array $expectedErrors + * @dataProvider exemplarXmlDataProvider + */ + public function testExemplarXml($fixtureXml, array $expectedErrors) + { + $validationState = $this->createMock(\Magento\Framework\Config\ValidationStateInterface::class); + $validationState->expects($this->any()) + ->method('isValidationRequired') + ->willReturn(true); + $messageFormat = '%message%'; + $dom = new \Magento\Framework\Config\Dom($fixtureXml, $validationState, [], null, null, $messageFormat); + $actualErrors = []; + $actualResult = $dom->validate($this->schemaFile, $actualErrors); + $this->assertEquals(empty($expectedErrors), $actualResult, "Validation result is invalid."); + $this->assertEquals($expectedErrors, $actualErrors, "Validation errors does not match."); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function exemplarXmlDataProvider() + { + // @codingStandardsIgnoreStart + return [ + /** Valid configurations */ + 'valid' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" type="topic" connection="amqp"/> + <exchange name="ex02" type="topic" connection="amqp-02" /> + <exchange name="ex03" autoDelete="true" durable="false" internal="true" type="topic" connection="db"> + <arguments> + <argument name="arg1" xsi:type="string">10</argument> + </arguments> + </exchange> + <exchange name="ex04" connection="amqp-03"> + <binding id="bind01" destinationType="queue" destination="queue01" topic="top01" disabled="true" /> + <binding id="bind02" destinationType="queue" destination="queue01" topic="top01"> + <arguments> + <argument name="arg01" xsi:type="string">10</argument> + </arguments> + </binding> + </exchange> + </config>', + [], + ], + 'non-unique-exchange' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" type="topic" connection="amqp"/> + <exchange name="ex01" type="topic" connection="amqp" /> + </config>', + [ + "Element 'exchange': Duplicate key-sequence ['ex01', 'amqp'] in unique identity-constraint 'unique-exchange-name-connection'." + ], + ], + 'non-unique-exchange-binding' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" connection="amqp"> + <binding id="bind01" destinationType="queue" destination="queue01" topic="top01" disabled="true" /> + <binding id="bind01" destinationType="queue" destination="queue01" topic="top01" /> + </exchange> + </config>', + [ + "Element 'binding': Duplicate key-sequence ['bind01'] in unique identity-constraint 'unique-binding-id'." + ], + ], + 'invalid-destination-type-binding' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" type="topic" connection="amqp"> + <binding id="bind01" destinationType="topic" destination="queue01" topic="top01" /> + </exchange> + </config>', + [ + "Element 'binding', attribute 'destinationType': [facet 'enumeration'] The value 'topic' is not an element of the set {'queue'}.", + "Element 'binding', attribute 'destinationType': 'topic' is not a valid value of the atomic type 'destinationType'." + ], + ], + 'invalid-exchange-type-binding' => [ + '<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" type="exchange" connection="amqp"> + <binding id="bind01" destinationType="queue" destination="queue01" topic="top01" /> + </exchange> + </config>', + [ + "Element 'exchange', attribute 'type': [facet 'enumeration'] The value 'exchange' is not an element of the set {'topic'}.", + "Element 'exchange', attribute 'type': 'exchange' is not a valid value of the atomic type 'exchangeType'." + ], + ], + ]; + // @codingStandardsIgnoreEnd + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/env_2_1.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/env_2_1.php new file mode 100644 index 0000000000000..f73846d21f809 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/env_2_1.php @@ -0,0 +1,19 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +return [ + 'publishers' => [ + 'amqp-magento' => [ + 'name' => 'amqp-magento', + 'connection' => 'db', + 'exchange' => 'magento-db' + ], + ], + 'consumers' => [ + 'inventoryQtyCounter' => [ + 'connection' => 'db' + ], + ] +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/env_2_2.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/env_2_2.php new file mode 100644 index 0000000000000..c8f71fe7b4748 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/env_2_2.php @@ -0,0 +1,24 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +return [ + 'config' => [ + 'publishers' => [ + 'inventory.counter.updated' => [ + 'connections' => [ + 'amqp' => [ + 'name' => 'db', + 'exchange' => 'magento-db' + ], + ] + ] + ], + 'consumers' => [ + 'inventoryQtyCounter' => [ + 'connection' => 'db' + ] + ] + ] +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/expected_queue.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/expected_queue.php new file mode 100644 index 0000000000000..5dacfb241189d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/expected_queue.php @@ -0,0 +1,272 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + 'publishers' => [ + 'test-publisher-1' => [ + 'name' => 'test-publisher-1', + 'connection' => 'amqp', + 'exchange' => 'magento', + ], + 'test-publisher-2' => [ + 'name' => 'test-publisher-2', + 'connection' => 'db', + 'exchange' => 'magento', + ], + 'test-publisher-3' => [ + 'name' => 'test-publisher-3', + 'connection' => 'amqp', + 'exchange' => 'test-exchange-1', + ], + ], + 'topics' => [ + 'customer.created' => [ + 'name' => 'customer.created', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'test-publisher-1', + "response_schema" => [ + "schema_type" => null, + "schema_value" => null + ], + 'is_synchronous' => false, + ], + 'customer.created.one' => [ + 'name' => 'customer.created.one', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'test-publisher-1', + "response_schema" => [ + "schema_type" => null, + "schema_value" => null + ], + 'is_synchronous' => false, + ], + 'customer.created.one.two' => [ + 'name' => 'customer.created.one.two', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'test-publisher-1', + "response_schema" => [ + "schema_type" => null, + "schema_value" => null + ], + 'is_synchronous' => false, + ], + 'customer.created.two' => [ + 'name' => 'customer.created.two', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'test-publisher-1', + "response_schema" => [ + "schema_type" => null, + "schema_value" => null + ], + 'is_synchronous' => false, + ], + 'customer.updated' => [ + 'name' => 'customer.updated', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'test-publisher-2', + "response_schema" => [ + "schema_type" => null, + "schema_value" => null + ], + 'is_synchronous' => false, + ], + 'customer.deleted' => [ + 'name' => 'customer.deleted', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'test-publisher-2', + "response_schema" => [ + "schema_type" => null, + "schema_value" => null + ], + 'is_synchronous' => false, + ], + 'cart.created' => [ + 'name' => 'cart.created', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Quote\Api\Data\CartInterface::class + ], + 'publisher' => 'test-publisher-3', + "response_schema" => [ + "schema_type" => null, + "schema_value" => null + ], + 'is_synchronous' => false, + ], + 'cart.created.one' => [ + 'name' => 'cart.created.one', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Quote\Api\Data\CartInterface::class + ], + 'publisher' => 'test-publisher-3', + "response_schema" => [ + "schema_type" => null, + "schema_value" => null + ], + 'is_synchronous' => false, + ], + ], + 'consumers' => [ + 'customerCreatedListener' => [ + 'name' => 'customerCreatedListener', + 'queue' => 'test-queue-1', + 'connection' => 'amqp', + 'max_messages' => null, + 'instance_type' => 'Test\Executor', + 'consumer_type' => 'async', + 'handlers' => [ + 'customer.created' => [ + 'defaultHandler' => [ + 'type' => 'Data\Type', + 'method' => 'processMessage' + ] + ], + 'customer.created.one' => [ + 'defaultHandler' => [ + 'type' => 'Data\Type', + 'method' => 'processMessage' + ] + ], + 'customer.created.one.two' => [ + 'defaultHandler' => [ + 'type' => 'Data\Type', + 'method' => 'processMessage' + ] + ], + 'customer.created.two' => [ + 'defaultHandler' => [ + 'type' => 'Data\Type', + 'method' => 'processMessage' + ] + ], + 'customer.updated' => [ + 'defaultHandler' => [ + 'type' => 'Data\Type', + 'method' => 'processMessage' + ] + ], + 'cart.created' => [ + 'defaultHandler' => [ + 'type' => 'Data\Type', + 'method' => 'processMessage' + ] + ] + ] + ], + 'customerDeletedListener' => [ + 'name' => 'customerDeletedListener', + 'queue' => 'test-queue-2', + 'connection' => 'db', + 'max_messages' => '98765', + 'instance_type' => null, + 'consumer_type' => 'async', + 'handlers' => [ + 'customer.created' => [ + 'defaultHandler' => [ + 'type' => 'Other\Type', + 'method' => 'processMessage2' + ] + ], + 'customer.deleted' => [ + 'defaultHandler' => [ + 'type' => 'Other\Type', + 'method' => 'processMessage2' + ] + ] + ] + ], + 'cartCreatedListener' => [ + 'name' => 'cartCreatedListener', + 'queue' => 'test-queue-3', + 'connection' => 'amqp', + 'max_messages' => null, + 'instance_type' => null, + 'consumer_type' => 'async', + 'handlers' => [ + 'cart.created' => [ + 'defaultHandler' => [ + 'type' => 'Other\Type', + 'method' => 'processMessage3' + ] + ], + 'cart.created.one' => [ + 'defaultHandler' => [ + 'type' => 'Other\Type', + 'method' => 'processMessage3' + ] + ] + ] + ], + ], + 'binds' => [ + 'customer.created--magento--test-queue-1' => + ['queue' => "test-queue-1", 'exchange' => "magento", 'topic' => "customer.created"], + 'customer.created.one--magento--test-queue-1' => + ['queue' => "test-queue-1", 'exchange' => "magento", 'topic' => "customer.created.one"], + 'customer.created.one.two--magento--test-queue-1' => + ['queue' => "test-queue-1", 'exchange' => "magento", 'topic' => "customer.created.one.two"], + 'customer.created.two--magento--test-queue-1' => + ['queue' => "test-queue-1", 'exchange' => "magento", 'topic' => "customer.created.two"], + 'customer.updated--magento--test-queue-1' => + ['queue' => "test-queue-1", 'exchange' => "magento", 'topic' => "customer.updated"], + 'cart.created--test-exchange-1--test-queue-1' => + ['queue' => "test-queue-1", 'exchange' => "test-exchange-1", 'topic' => "cart.created"], + 'customer.created--magento--test-queue-2' => + ['queue' => "test-queue-2", 'exchange' => "magento", 'topic' => "customer.created"], + 'customer.deleted--magento--test-queue-2' => + ['queue' => "test-queue-2", 'exchange' => "magento", 'topic' => "customer.deleted"], + 'cart.created--magento--test-queue-3' => + ['queue' => "test-queue-3", 'exchange' => "magento", 'topic' => "cart.created"], + 'cart.created.one--magento--test-queue-3' => + ['queue' => "test-queue-3", 'exchange' => "magento", 'topic' => "cart.created.one"], + 'cart.created--test-exchange-1--test-queue-3' => + ['queue' => "test-queue-3", 'exchange' => "test-exchange-1", 'topic' => "cart.created"], + 'customer.*--magento--test-queue-4' => + ['queue' => "test-queue-4", 'exchange' => "magento", 'topic' => "customer.*"], + 'customer.#--magento--test-queue-5' => + ['queue' => "test-queue-5", 'exchange' => "magento", 'topic' => "customer.#"], + 'customer.*.one--magento--test-queue-6' => + ['queue' => "test-queue-6", 'exchange' => "magento", 'topic' => "customer.*.one"], + '*.created.*--magento--test-queue-7' => + ['queue' => "test-queue-7", 'exchange' => "magento", 'topic' => "*.created.*"], + '*.created.#--magento--test-queue-8' => + ['queue' => "test-queue-8", 'exchange' => "magento", 'topic' => "*.created.#"], + '#--magento--test-queue-9' => + ['queue' => "test-queue-9", 'exchange' => "magento", 'topic' => "#"], + ], + 'exchange_topic_to_queues_map' => [ + 'magento--customer.created' => ['test-queue-1', 'test-queue-2', 'test-queue-4', 'test-queue-5', 'test-queue-9'], + 'magento--customer.created.one' => + ['test-queue-1', 'test-queue-5', 'test-queue-6', 'test-queue-7', 'test-queue-8', 'test-queue-9'], + 'magento--customer.created.one.two' => ['test-queue-1', 'test-queue-5', 'test-queue-8', 'test-queue-9'], + 'magento--customer.created.two' => + ['test-queue-1', 'test-queue-5', 'test-queue-7', 'test-queue-8', 'test-queue-9'], + 'magento--customer.updated' => ['test-queue-1', 'test-queue-4', 'test-queue-5', 'test-queue-9'], + 'test-exchange-1--cart.created' => ['test-queue-1', 'test-queue-3'], + 'magento--customer.deleted' => ['test-queue-2', 'test-queue-4', 'test-queue-5', 'test-queue-9'], + 'magento--cart.created' => ['test-queue-3', 'test-queue-9'], + 'magento--cart.created.one' => ['test-queue-3', 'test-queue-7', 'test-queue-8', 'test-queue-9'], + ] +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/expected_topic_config.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/expected_topic_config.php new file mode 100644 index 0000000000000..d2d1bfc200462 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/expected_topic_config.php @@ -0,0 +1,236 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + 'publishers' => [ + 'amqp-ex.01' => [ + 'name' => 'amqp-ex.01', + 'connection' => 'amqp', + 'exchange' => 'ex.01', + ], + 'db-magento' => [ + 'name' => 'db-magento', + 'connection' => 'db', + 'exchange' => 'magento', + ], + 'amqp-magento' => [ + 'name' => 'amqp-magento', + 'connection' => 'amqp', + 'exchange' => 'magento', + ], + ], + 'binds' => [ + 'top.01--ex.01--q.01' => ['queue' => 'q.01', 'exchange' => 'ex.01', 'topic' => 'top.01'], + 'top.03--magento--q.03' => ['queue' => 'q.03', 'exchange' => 'magento', 'topic' => 'top.03'], + 'top.04--magento--q.04' => ['queue' => 'q.04', 'exchange' => 'magento', 'topic' => 'top.04'], + 'top.04--magento--q.05' => ['queue' => 'q.05', 'exchange' => 'magento', 'topic' => 'top.04'], + 'top.04--magento--q.06' => ['queue' => 'q.06', 'exchange' => 'magento', 'topic' => 'top.04'], + 'top.03--magento--q.04' => ['queue' => 'q.04', 'exchange' => 'magento', 'topic' => 'top.03'], + 'user.created.remote--magento--q.log' => [ + 'queue' => 'q.log', 'exchange' => 'magento', 'topic' => 'user.created.remote' + ], + 'product.created.local--magento--q.log' => [ + 'queue' => 'q.log', 'exchange' => 'magento', 'topic' => 'product.created.local' + ], + ], + 'exchange_topic_to_queues_map' => [ + 'amqp-ex.01--top.01' => ['q.01'], + 'amqp-magento--top.03' => ['q.03', 'q.04'], + 'db-magento--top.04' => ['q.04', 'q.05', 'q.06'], + 'amqp-magento--user.created.remote' => ['q.log'], + 'amqp-magento--product.created.local' => ['q.log'], + ], + 'consumers' => [ + 'cons.01' => [ + 'name' => 'cons.01', + 'handlers' => [ + 'top.01' => [ + '0' => [ + 'type' => 'Magento\Handler\Class\Name', + 'method' => 'methodName' + ] + ] + ], + 'instance_type' => 'Magento\Consumer\Instance', + 'consumer_type' => 'async', + 'max_messages' => '512', + 'connection' => 'amqp', + 'queue' => 'q.01' + ], + 'cons.03' => [ + 'name' => 'cons.03', + 'handlers' => [ + 'top.03' => [ + '0' => [ + 'type' => \Magento\Customer\Api\CustomerRepositoryInterface::class, + 'method' => 'save', + ], + '1' => [ + 'type' => \Magento\Customer\Api\CustomerRepositoryInterface::class, + 'method' => 'delete', + ], + ] + ], + 'instance_type' => 'Magento\Framework\MessageQueue\ConsumerInterface', + 'consumer_type' => 'async', + 'max_messages' => null, + 'connection' => 'amqp', + 'queue' => 'q.03' + ], + 'cons.04' => [ + 'name' => 'cons.04', + 'handlers' => [ + 'top.04' => [ + '0' => [ + 'type' => 'Magento\Handler\Class\Name', + 'method' => 'methodName' + ] + ] + ], + 'instance_type' => 'Magento\Consumer\Instance', + 'consumer_type' => 'async', + 'max_messages' => '512', + 'connection' => 'db', + 'queue' => 'q.04' + ], + 'cons.05' => [ + 'name' => 'cons.05', + 'handlers' => [ + 'top.04' => [ + '0' => [ + 'type' => 'Magento\Handler\Class\Name', + 'method' => 'methodName' + ] + ] + ], + 'instance_type' => 'Magento\Consumer\Instance', + 'consumer_type' => 'async', + 'max_messages' => '512', + 'connection' => 'db', + 'queue' => 'q.05' + ], + 'cons.06' => [ + 'name' => 'cons.06', + 'handlers' => [ + 'top.04' => [ + '0' => [ + 'type' => 'Magento\Handler\Class\Name', + 'method' => 'methodName' + ] + ] + ], + 'instance_type' => 'Magento\Consumer\Instance', + 'consumer_type' => 'async', + 'max_messages' => '512', + 'connection' => 'db', + 'queue' => 'q.06' + ], + 'cons.07' => [ + 'name' => 'cons.07', + 'handlers' => [ + 'top.03' => [ + '0' => [ + 'type' => \Magento\Customer\Api\CustomerRepositoryInterface::class, + 'method' => 'save', + ], + '1' => [ + 'type' => \Magento\Customer\Api\CustomerRepositoryInterface::class, + 'method' => 'delete', + ], + ] + ], + 'instance_type' => 'Magento\Framework\MessageQueue\ConsumerInterface', + 'consumer_type' => 'async', + 'max_messages' => null, + 'connection' => 'amqp', + 'queue' => 'q.04' + ], + 'cons.logger' => [ + 'name' => 'cons.logger', + 'handlers' => [ + 'product.created.local' => [ + '0' => [ + 'type' => 'Magento\Handler\Class\Name', + 'method' => 'logger' + ] + ] + ], + 'instance_type' => 'Magento\Framework\MessageQueue\ConsumerInterface', + 'consumer_type' => 'async', + 'max_messages' => null, + 'connection' => 'amqp', + 'queue' => 'q.log' + ], + ], + 'topics' => [ + 'top.01' => [ + 'name' => 'top.01', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'response_schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'amqp-ex.01', + 'is_synchronous' => false, + ], + 'top.03' => [ + 'name' => 'top.03', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'response_schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'amqp-magento', + 'is_synchronous' => false, + ], + 'top.04' => [ + 'name' => 'top.04', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'response_schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'db-magento', + 'is_synchronous' => false, + ], + 'user.created.remote' => [ + 'name' => 'user.created.remote', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'response_schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'amqp-magento', + 'is_synchronous' => false, + ], + 'product.created.local' => [ + 'name' => 'product.created.local', + 'schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'response_schema' => [ + 'schema_type' => 'object', + 'schema_value' => \Magento\Customer\Api\Data\CustomerInterface::class + ], + 'publisher' => 'amqp-magento', + 'is_synchronous' => false, + ], + ] + +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_consumer/valid.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_consumer/valid.php new file mode 100644 index 0000000000000..5d22103b4c531 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_consumer/valid.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + 'consumer1' => [ + 'name' => 'consumer1', + 'queue' => 'queue1', + 'consumerInstance' => 'consumerClass1', + 'handlers' => [ + 0 => [ + 'type' => 'handlerClassOne', + 'method' => 'handlerMethodOne' + ], + ], + 'connection' => 'connection1', + 'maxMessages' => '100', + ], + 'consumer2' => [ + 'name' => 'consumer2', + 'queue' => 'queue2', + 'consumerInstance' => 'consumerClass2', + 'handlers' => [ + 0 => [ + 'type' => 'handlerClassTwo', + 'method' => 'handlerMethodTwo' + ], + ], + 'connection' => 'connection2', + 'maxMessages' => null, + ], + 'consumer3' => [ + 'name' => 'consumer3', + 'queue' => 'queue3', + 'consumerInstance' => 'consumerClass3', + 'handlers' => [ + 0 => [ + 'type' => 'handlerClassThree', + 'method' => 'handlerMethodThree' + ], + ], + 'connection' => 'amqp', + 'maxMessages' => null, + ], + 'consumer4' => [ + 'name' => 'consumer4', + 'queue' => 'queue4', + 'consumerInstance' => \Magento\Framework\MessageQueue\ConsumerInterface::class, + 'handlers' => [ + 0 => [ + 'type' => 'handlerClassFour', + 'method' => 'handlerMethodFour' + ], + ], + 'connection' => 'amqp', + 'maxMessages' => null, + ], + 'consumer5' => [ + 'name' => 'consumer5', + 'queue' => 'queue5', + 'consumerInstance' => \Magento\Framework\MessageQueue\ConsumerInterface::class, + 'handlers' => [], + 'connection' => 'amqp', + 'maxMessages' => null, + ], +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_consumer/valid.xml b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_consumer/valid.xml new file mode 100644 index 0000000000000..f020c64a06965 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_consumer/valid.xml @@ -0,0 +1,14 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/consumer.xsd"> + <consumer name="consumer1" queue="queue1" handler="handlerClassOne::handlerMethodOne" consumerInstance="consumerClass1" connection="connection1" maxMessages="100"/> + <consumer name="consumer2" queue="queue2" handler="handlerClassTwo::handlerMethodTwo" consumerInstance="consumerClass2" connection="connection2"/> + <consumer name="consumer3" queue="queue3" handler="handlerClassThree::handlerMethodThree" consumerInstance="consumerClass3"/> + <consumer name="consumer4" queue="queue4" handler="handlerClassFour::handlerMethodFour"/> + <consumer name="consumer5" queue="queue5"/> +</config> diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/data_to_validate.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/data_to_validate.php new file mode 100644 index 0000000000000..c4b750767e738 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/data_to_validate.php @@ -0,0 +1,38 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +return [ + 'top04' => [ + 'topic' => 'top04', + 'disabled' => false, + 'connections' => [ + 'amqp' => ['name' => 'amqp', 'exchange' => 'magento8', 'disabled' => true], + 'db' => ['name' => 'db', 'exchange' => 'magento2', 'disabled' => false] + ] + ], + 'top05' => [ + 'topic' => 'top05', + 'disabled' => false, + 'connections' => [ + 'amqp' => ['name' => 'amqp', 'exchange' => 'exch01', 'disabled' => false], + 'db' => ['name' => 'db', 'exchange' => 'exch02', 'disabled' => true], + ] + ], + 'top06' => [ + 'topic' => 'top06', + 'disabled' => false, + 'connections' => [ + 'amqp' => ['name' => 'amqp', 'exchange' => 'magento', 'disabled' => false] + ] + ], + 'top07' => [ + 'topic' => 'top07', + 'disabled' => false, + 'connections' => [ + 'amqp' => ['name' => 'amqp', 'exchange' => 'magento', 'disabled' => false], + 'db' => ['name' => 'db', 'exchange' => 'exch02', 'disabled' => true], + ] + ], +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/invalid.xml b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/invalid.xml new file mode 100644 index 0000000000000..52a438b0a953a --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/invalid.xml @@ -0,0 +1,12 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="top04"> + <connection ecxhange="exch01" /> + </publisher> +</config> diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/reader_one.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/reader_one.php new file mode 100644 index 0000000000000..37db3771d0fae --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/reader_one.php @@ -0,0 +1,16 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +return [ + 'top04' => [ + 'topic' => 'top04', + 'disabled' => false, + 'connections' => ['amqp' => ['name' => 'amqp', 'exchange' => 'magento8', 'disabled' => false]] + ], + 'top06' => [ + 'topic' => 'top06', + 'disabled' => false, + ], +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/reader_two.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/reader_two.php new file mode 100644 index 0000000000000..8f8c3486a5394 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/reader_two.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +return [ + 'top04' => [ + 'topic' => 'top04', + 'connections' => [ + 'amqp' => ['name' => 'amqp', 'disabled' => true], + 'db' => ['name' => 'db', 'exchange' => 'magento2', 'disabled' => false] + ] + ], + 'top05' => [ + 'topic' => 'top05', + 'disabled' => false, + 'connections' => [ + 'amqp' => ['name' => 'amqp', 'exchange' => 'exch01', 'disabled' => false], + 'db' => ['name' => 'db', 'exchange' => 'exch02', 'disabled' => true], + ] + ], + 'top07' => [ + 'topic' => 'top07', + 'disabled' => false, + 'connections' => [ + 'amqp' => ['name' => 'amqp', 'exchange' => 'exch01', 'disabled' => true], + 'db' => ['name' => 'db', 'exchange' => 'exch02', 'disabled' => true], + ] + ], +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/valid.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/valid.php new file mode 100644 index 0000000000000..f2266665aea76 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/valid.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + 'top01' => [ + 'topic' => 'top01', + 'disabled' => false, + 'connections' => [] + ], + 'top02' => [ + 'topic' => 'top02', + 'disabled' => false, + 'connections' => [] + ], + 'top03' => [ + 'topic' => 'top03', + 'disabled' => true, + 'connections' => [] + ], + 'top04' => [ + 'topic' => 'top04', + 'disabled' => false, + 'connections' => [ + 'amqp' => ['name' => 'amqp', 'exchange' => 'magento', 'disabled' => false] + ] + ], + 'top05' => [ + 'topic' => 'top05', + 'disabled' => false, + 'connections' => [ + 'amqp' => ['name' => 'amqp', 'exchange' => 'exch01', 'disabled' => false], + 'db' => ['name' => 'db', 'exchange' => 'exch02', 'disabled' => true], + ] + ], + 'top06' => [ + 'topic' => 'top06', + 'disabled' => true, + 'connections' => [ + 'amqp' => ['name' => 'amqp', 'exchange' => 'exch01', 'disabled' => false], + 'db' => ['name' => 'db', 'exchange' => 'exch02', 'disabled' => true] + ] + ], +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/valid.xml b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/valid.xml new file mode 100644 index 0000000000000..8fd0b0a0e6bf5 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_publisher/valid.xml @@ -0,0 +1,23 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/publisher.xsd"> + <publisher topic="top01" /> + <publisher topic="top02" disabled="false" /> + <publisher topic="top03" disabled="true" /> + <publisher topic="top04"> + <connection name="amqp" /> + </publisher> + <publisher topic="top05"> + <connection name="amqp" exchange="exch01" /> + <connection name="db" exchange="exch02" disabled="true"/> + </publisher> + <publisher topic="top06" disabled="true"> + <connection name="amqp" exchange="exch01" /> + <connection name="db" exchange="exch02" disabled="true"/> + </publisher> +</config> diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_topology/valid.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_topology/valid.php new file mode 100644 index 0000000000000..17049a5e0973f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_topology/valid.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + 'ex01--amqp' => [ + 'name' => 'ex01', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'internal' => false, + 'bindings' => [], + 'arguments' => [], + ], + 'ex02--amqp' => [ + 'name' => 'ex02', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'internal' => false, + 'bindings' => [], + 'arguments' => [], + ], + 'ex03--amqp' => [ + 'name' => 'ex03', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => false, + 'autoDelete' => true, + 'internal' => true, + 'bindings' => [], + 'arguments' => [ + 'arg1' => '10', + ], + ], + 'ex04--amqp' => [ + 'name' => 'ex04', + 'type' => 'topic', + 'connection' => 'amqp', + 'durable' => true, + 'autoDelete' => false, + 'internal' => false, + 'bindings' => [ + 'bind01' => [ + 'id' => 'bind01', + 'destinationType' => 'queue', + 'destination' => 'queue01', + 'disabled' => true, + 'topic' => 'top01', + 'arguments' => [] + ], + 'bind02' => [ + 'id' => 'bind02', + 'destinationType' => 'queue', + 'destination' => 'queue01', + 'disabled' => false, + 'topic' => 'top01', + 'arguments' => [ + 'arg01' => 10 + ] + ], + ], + 'arguments' => [], + ], +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_topology/valid.xml b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_topology/valid.xml new file mode 100644 index 0000000000000..8686841e57fae --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/queue_topology/valid.xml @@ -0,0 +1,24 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <exchange name="ex01" type="topic" connection="amqp"/> + <exchange name="ex02" type="topic" connection="amqp" /> + <exchange name="ex03" autoDelete="true" durable="false" internal="true" type="topic" connection="amqp"> + <arguments> + <argument name="arg1" xsi:type="string">10</argument> + </arguments> + </exchange> + <exchange name="ex04" type="topic" connection="amqp"> + <binding id="bind01" destinationType="queue" destination="queue01" topic="top01" disabled="true" /> + <binding id="bind02" destinationType="queue" destination="queue01" topic="top01"> + <arguments> + <argument name="arg01" xsi:type="string">10</argument> + </arguments> + </binding> + </exchange> +</config> diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/topic_config.xml b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/topic_config.xml new file mode 100644 index 0000000000000..6553d0468c3e9 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/topic_config.xml @@ -0,0 +1,24 @@ +<?xml version="1.0"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<config> + <broker topic="top.01" type="amqp" exchange="ex.01"> +     <queue name="q.01" handler="Magento\Handler\Class\Name::methodName" consumer="cons.01" consumerInstance="Magento\Consumer\Instance" maxMessages="512" /> + </broker> + <broker topic="top.03"> +     <queue name="q.03" consumer="cons.03" /> +     <queue name="q.04" consumer="cons.07" /> + </broker> + <broker topic="top.04" type="db"> +     <queue name="q.04" handler="Magento\Handler\Class\Name::methodName" consumer="cons.04" consumerInstance="Magento\Consumer\Instance" maxMessages="512" /> +     <queue name="q.05" handler="Magento\Handler\Class\Name::methodName" consumer="cons.05" consumerInstance="Magento\Consumer\Instance" maxMessages="512" /> +     <queue name="q.06" handler="Magento\Handler\Class\Name::methodName" consumer="cons.06" consumerInstance="Magento\Consumer\Instance" maxMessages="512" /> + </broker> + <broker topic="*.created.*"> +     <queue name="q.log" handler="Magento\Handler\Class\Name::logger" consumer="cons.logger" /> + </broker> +</config> diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/topic_definitions_map.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/topic_definitions_map.php new file mode 100644 index 0000000000000..27fe84a9ef8bd --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/topic_definitions_map.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + [ + 'top.01', + [ + 'is_synchronous' => false, + 'request' => \Magento\Customer\Api\Data\CustomerInterface::class, + 'request_type' => 'object_interface', + 'response' => \Magento\Customer\Api\Data\CustomerInterface::class, + ] + ], + [ + 'top.03', + [ + 'is_synchronous' => false, + 'request' => \Magento\Customer\Api\Data\CustomerInterface::class, + 'request_type' => 'object_interface', + 'response' => \Magento\Customer\Api\Data\CustomerInterface::class, + 'handlers' => [ + 'customerCreatedFirst' => [ + 'type' => \Magento\Customer\Api\CustomerRepositoryInterface::class, + 'method' => 'save', + ], + 'customerCreatedSecond' => [ + 'type' => \Magento\Customer\Api\CustomerRepositoryInterface::class, + 'method' => 'delete', + ], + ] + ] + ], + [ + 'top.04', + [ + 'is_synchronous' => false, + 'request' => \Magento\Customer\Api\Data\CustomerInterface::class, + 'request_type' => 'object_interface', + 'response' => \Magento\Customer\Api\Data\CustomerInterface::class, + ] + ], + [ + 'top.05', + [ + 'is_synchronous' => false, + 'request' => \Magento\Customer\Api\Data\CustomerInterface::class, + 'request_type' => 'object_interface', + 'response' => \Magento\Customer\Api\Data\CustomerInterface::class, + ] + ], + [ + 'user.created.remote', + [ + 'is_synchronous' => false, + 'request' => \Magento\Customer\Api\Data\CustomerInterface::class, + 'request_type' => 'object_interface', + 'response' => \Magento\Customer\Api\Data\CustomerInterface::class, + ] + ], + [ + 'product.created.local', + [ + 'is_synchronous' => false, + 'request' => \Magento\Customer\Api\Data\CustomerInterface::class, + 'request_type' => 'object_interface', + 'response' => \Magento\Customer\Api\Data\CustomerInterface::class, + ] + ], +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/wildcard_pattern_map.php b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/wildcard_pattern_map.php new file mode 100644 index 0000000000000..0f2f0b2a3359d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Test/Unit/_files/wildcard_pattern_map.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +return [ + ['customer.created', '/^customer\.created$/'], + ['customer.created.one', '/^customer\.created\.one$/'], + ['customer.created.one.two', '/^customer\.created\.one\.two$/'], + ['customer.created.two', '/^customer\.created\.two$/'], + ['customer.updated', '/^customer\.updated$/'], + ['cart.created', '/^cart\.created$/'], + ['customer.deleted', '/^customer\.deleted$/'], + ['cart.created.one', '/^cart\.created\.one$/'], + ['customer.*', '/^customer\.[^\.]+$/'], + ['customer.#', '/^customer\..+$/'], + ['customer.*.one', '/^customer\.[^\.]+\.one$/'], + ['*.created.*', '/^[^\.]+\.created\.[^\.]+$/'], + ['*.created.#', '/^[^\.]+\.created\..+$/'], + ['#', '/^.+$/'] +]; diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config.php new file mode 100644 index 0000000000000..7add2bd286e1d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config.php @@ -0,0 +1,80 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\MessageQueue\Topology; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\Phrase; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\Iterator as ExchangeIterator; +use Magento\Framework\MessageQueue\Topology\Config\QueueConfigItem\Iterator as QueueIterator; + +/** + * Topology config provides access to data declared in etc/queue_topology.xml + */ +class Config implements ConfigInterface +{ + /** + * Exchange config data iterator. + * + * @var ExchangeIterator + */ + private $exchangeIterator; + + /** + * Exchange config data iterator. + * + * @var ExchangeIterator + */ + private $queueIterator; + + /** + * Initialize dependencies. + * + * @param ExchangeIterator $exchangeIterator + * @param QueueIterator $queueIterator + */ + public function __construct(ExchangeIterator $exchangeIterator, QueueIterator $queueIterator) + { + $this->exchangeIterator = $exchangeIterator; + $this->queueIterator = $queueIterator; + } + + /** + * {@inheritdoc} + */ + public function getExchange($name, $connection) + { + $topology = $this->exchangeIterator[$name . '--' . $connection]; + if (!$topology) { + throw new LocalizedException( + new Phrase( + 'The "%exchange" exchange is not declared for the "%connection" connection. Verify and try again.', + [ + 'exchange' => $name, + 'connection' => $connection + ] + ) + ); + } + return $topology; + } + + /** + * {@inheritdoc} + */ + public function getExchanges() + { + return $this->exchangeIterator; + } + + /** + * {@inheritdoc} + */ + public function getQueues() + { + return $this->queueIterator; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/CompositeReader.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/CompositeReader.php new file mode 100644 index 0000000000000..b565916c7246a --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/CompositeReader.php @@ -0,0 +1,56 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +use Magento\Framework\Phrase; + +/** + * Composite reader for topology config. + */ +class CompositeReader implements ReaderInterface +{ + /** + * Config validator. + * + * @var ValidatorInterface + */ + private $validator; + + /** + * Config reade list. + * + * @var ReaderInterface[] + */ + private $readers; + + /** + * Initialize dependencies. + * + * @param ValidatorInterface $validator + * @param ReaderInterface[] $readers + */ + public function __construct(ValidatorInterface $validator, array $readers) + { + $this->validator = $validator; + $this->readers = $readers; + } + + /** + * Read config. + * + * @param string|null $scope + * @return array + */ + public function read($scope = null) + { + $result = []; + foreach ($this->readers as $reader) { + $result = array_replace_recursive($result, $reader->read($scope)); + } + $this->validator->validate($result); + return $result; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/CompositeValidator.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/CompositeValidator.php new file mode 100644 index 0000000000000..279652419982c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/CompositeValidator.php @@ -0,0 +1,53 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +/** + * Topology config data validator. + */ +class CompositeValidator implements ValidatorInterface +{ + /** + * Config validator list. + * + * @var ValidatorInterface[] + */ + private $validators; + + /** + * Validator constructor. + * + * @param ValidatorInterface[] $validators + */ + public function __construct($validators) + { + $this->validators = $validators; + } + + /** + * Validate merged topology config data. + * + * @param array $configData + * @throws \LogicException + * @return void + * @throws \LogicException + */ + public function validate($configData) + { + foreach ($this->validators as $validator) { + if (!$validator instanceof ValidatorInterface) { + throw new \LogicException( + sprintf( + 'Validator [%s] does not implements %s', + ValidatorInterface::class, + get_class($validator) + ) + ); + } + $validator->validate($configData); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Data.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Data.php new file mode 100644 index 0000000000000..6711428f06654 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Data.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +use Magento\Framework\Serialize\SerializerInterface; + +/** + * Topology config data storage. Caches merged config. + */ +class Data extends \Magento\Framework\Config\Data +{ + /** + * {@inheritdoc} + */ + public function __construct( + ReaderInterface $reader, + \Magento\Framework\Config\CacheInterface $cache, + $cacheId = 'message_queue_topology_config_cache', + SerializerInterface $serializer = null + ) { + parent::__construct($reader, $cache, $cacheId, $serializer); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem.php new file mode 100644 index 0000000000000..b767a516833af --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem.php @@ -0,0 +1,163 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\Binding\IteratorFactory; + +/** + * {@inheritdoc} + */ +class ExchangeConfigItem implements ExchangeConfigItemInterface +{ + /** + * Exchange name. + * + * @var string + */ + private $name; + + /** + * Exchange type. + * + * @var string + */ + private $type; + + /** + * Connection name. + * + * @var string + */ + private $connection; + + /** + * Exchange bindings. + * + * @var BindingInterface[] + */ + private $bindings; + + /** + * Exchange arguments. + * + * @var array + */ + private $arguments; + + /** + * Flag. Is exchange durable. + * + * @var bool + */ + private $isDurable; + + /** + * Flag. Is auto-delete + * + * @var bool + */ + private $isAutoDelete; + + /** + * Flag. Is exchange internal. + * + * @var bool + */ + private $isInternal; + + /** + * Initialize dependencies. + * + * @param IteratorFactory $iteratorFactory + */ + public function __construct(IteratorFactory $iteratorFactory) + { + $this->bindings = $iteratorFactory->create(); + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function getType() + { + return $this->type; + } + + /** + * {@inheritdoc} + */ + public function getConnection() + { + return $this->connection; + } + + /** + * {@inheritdoc} + */ + public function isDurable() + { + return $this->isDurable; + } + + /** + * {@inheritdoc} + */ + public function isAutoDelete() + { + return $this->isAutoDelete; + } + + /** + * {@inheritdoc} + */ + public function isInternal() + { + return $this->isInternal; + } + + /** + * {@inheritdoc} + */ + public function getBindings() + { + return $this->bindings; + } + + /** + * {@inheritdoc} + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * Set exchange config item data. + * + * @param array $data + * @return void + */ + public function setData(array $data) + { + $this->name = $data['name']; + $this->type = $data['type']; + $this->connection = $data['connection']; + $this->isInternal = $data['internal']; + $this->isDurable = $data['durable']; + $this->isAutoDelete = $data['autoDelete']; + $this->arguments = $data['arguments']; + $this->bindings->setData($data['bindings']); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Binding.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Binding.php new file mode 100644 index 0000000000000..f6d964c3d081e --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Binding.php @@ -0,0 +1,117 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem; + +/** + * Instances of this class represent config binding items declared in etc/queue_topology.xsd + */ +class Binding implements BindingInterface +{ + /** + * Binding id. + * + * @var string + */ + private $id; + + /** + * Binding destination type. + * + * @var string + */ + private $destinationType; + + /** + * Binding destination. + * + * @var string + */ + private $destination; + + /** + * Flag. Is binding disabled. + * @var bool + */ + private $isDisabled; + + /** + * Topic name. + * + * @var string + */ + private $topic; + + /** + * Binding arguments. + * + * @var array + */ + private $arguments; + + /** + * {@inheritdoc} + */ + public function getId() + { + return $this->id; + } + + /** + * {@inheritdoc} + */ + public function getDestinationType() + { + return $this->destinationType; + } + + /** + * {@inheritdoc} + */ + public function getDestination() + { + return $this->destination; + } + + /** + * {@inheritdoc} + */ + public function isDisabled() + { + return $this->isDisabled; + } + + /** + * {@inheritdoc} + */ + public function getTopic() + { + return $this->topic; + } + + /** + * {@inheritdoc} + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * Set binding data. + * + * @param array $data + * @return void + */ + public function setData(array $data) + { + $this->id = $data['id']; + $this->destinationType = $data['destinationType']; + $this->destination = $data['destination']; + $this->arguments = $data['arguments']; + $this->topic = $data['topic']; + $this->isDisabled = $data['disabled']; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Binding/Iterator.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Binding/Iterator.php new file mode 100644 index 0000000000000..1bc9adef61f51 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Binding/Iterator.php @@ -0,0 +1,153 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\Binding; + +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\Binding; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingFactory; + +/** + * Exchange binding config data iterator. + */ +class Iterator implements \Iterator, \ArrayAccess +{ + /** + * Exchange binding config. + * + * @var Binding + */ + private $object; + + /** + * Config data. + * + * @var array + */ + private $data; + + /** + * Initialize dependencies. + * + * @param BindingFactory $itemFactory + */ + public function __construct(BindingFactory $itemFactory) + { + $this->object = $itemFactory->create(); + } + + /** + * Set iterator data. + * + * @param array $data + * @return void + */ + public function setData(array $data) + { + $this->data = $data; + $this->rewind(); + } + + /** + * Get current item. + * + * @return Binding + */ + public function current() + { + return $this->object; + } + + /** + * {@inheritdoc} + */ + public function next() + { + next($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + if ($this->current()->isDisabled()) { + $this->next(); + } + } + } + + /** + * Initialize object. + * + * @param array $data + * @return void + */ + private function initObject(array $data) + { + $this->object->setData($data); + } + + /** + * {@inheritdoc} + */ + public function key() + { + key($this->data); + } + + /** + * {@inheritdoc} + */ + public function valid() + { + return (bool)current($this->data); + } + + /** + * {@inheritdoc} + */ + public function rewind() + { + reset($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + if ($this->current()->isDisabled()) { + $this->next(); + } + } + } + + /** + * {@inheritdoc} + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->data); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($offset) + { + if (!$this->offsetExists($offset) || $this->data[$offset]['disabled'] == true) { + return null; + } + $item = clone $this->object; + $item->setData($this->data[$offset]); + return $item; + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Binding/IteratorFactory.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Binding/IteratorFactory.php new file mode 100644 index 0000000000000..bc2faca4f341f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Binding/IteratorFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\Binding; + +/** + * Factory class for @see Iterator + */ +class IteratorFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = Iterator::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return Iterator + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/BindingFactory.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/BindingFactory.php new file mode 100644 index 0000000000000..be83da6979912 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/BindingFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\Binding + */ +class BindingFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = Binding::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return Binding + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/BindingInterface.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/BindingInterface.php new file mode 100644 index 0000000000000..d6a5689f5b43c --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/BindingInterface.php @@ -0,0 +1,54 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem; + +/** + * Instances of this interface represent config binging items declared in etc/queue_topology.xsd + */ +interface BindingInterface +{ + /** + * Get binding name. + * + * @return string + */ + public function getId(); + + /** + * Get binding destination type. + * + * @return string + */ + public function getDestinationType(); + + /** + * Get destination. + * + * @return string + */ + public function getDestination(); + + /** + * Check if binding is disabled. + * + * @return bool + */ + public function isDisabled(); + + /** + * Get topic name. + * + * @return string + */ + public function getTopic(); + + /** + * Get binding arguments + * + * @return array + */ + public function getArguments(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Iterator.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Iterator.php new file mode 100644 index 0000000000000..85dad637191fe --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem/Iterator.php @@ -0,0 +1,139 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem; + +use Magento\Framework\MessageQueue\Topology\Config\Data; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItemFactory; + +/** + * Exchange config data iterator. + */ +class Iterator implements \Iterator, \ArrayAccess +{ + /** + * Exchange config. + * + * @var ExchangeConfigItem + */ + private $object; + + /** + * Config data. + * + * @var array + */ + private $data; + + /** + * Initialize dependencies. + * + * @param Data $configData + * @param ExchangeConfigItemFactory $itemFactory + */ + public function __construct(Data $configData, ExchangeConfigItemFactory $itemFactory) + { + $this->data = $configData->get(); + $this->object = $itemFactory->create(); + $this->rewind(); + } + + /** + * Get current item. + * + * @return ExchangeConfigItem + */ + public function current() + { + return $this->object; + } + + /** + * {@inheritdoc} + */ + public function next() + { + next($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + } + } + + /** + * Initialize object. + * + * @param array $data + * @return void + */ + private function initObject(array $data) + { + $this->object->setData($data); + } + + /** + * {@inheritdoc} + */ + public function key() + { + key($this->data); + } + + /** + * {@inheritdoc} + */ + public function valid() + { + return (bool)current($this->data); + } + + /** + * {@inheritdoc} + */ + public function rewind() + { + reset($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + } + } + + /** + * {@inheritdoc} + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->data); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($offset) + { + if (!$this->offsetExists($offset)) { + return null; + } + $item = clone $this->object; + $item->setData($this->data[$offset]); + return $item; + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItemFactory.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItemFactory.php new file mode 100644 index 0000000000000..b684f36673637 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItemFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem + */ +class ExchangeConfigItemFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = ExchangeConfigItem::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return \Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItemInterface.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItemInterface.php new file mode 100644 index 0000000000000..c5d6680a4bb22 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItemInterface.php @@ -0,0 +1,70 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +use \Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItem\BindingInterface; + +/** + * Instances of this class represent config items declared in etc/queue_topology.xsd + */ +interface ExchangeConfigItemInterface +{ + /** + * Get exchange name. + * + * @return string + */ + public function getName(); + + /** + * Get exchange type. + * + * @return string + */ + public function getType(); + + /** + * Get exchange connection. + * + * @return string + */ + public function getConnection(); + + /** + * Check if exchange is durable. + * + * @return bool + */ + public function isDurable(); + + /** + * Check if exchange is auto delete. + * + * @return bool + */ + public function isAutoDelete(); + + /** + * Check if exchange is internal. + * + * @return bool + */ + public function isInternal(); + + /** + * Get exchange bindings. + * + * @return BindingInterface[] + */ + public function getBindings(); + + /** + * Get exchange arguments + * + * @return array + */ + public function getArguments(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItem.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItem.php new file mode 100644 index 0000000000000..ba201cdc1b6d5 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItem.php @@ -0,0 +1,102 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +/** + * Instances of this class represent queue config items. + */ +class QueueConfigItem implements QueueConfigItemInterface +{ + /** + * Queue name. + * + * @var string + */ + private $name; + + /** + * Connection name. + * + * @var string + */ + private $connection; + + /** + * Queue arguments. + * + * @var array + */ + private $arguments; + + /** + * Flag. Is queue durable. + * + * @var bool + */ + private $isDurable; + + /** + * Flag. Is auto-delete + * + * @var bool + */ + private $isAutoDelete; + + /** + * {@inheritdoc} + */ + public function getName() + { + return $this->name; + } + + /** + * {@inheritdoc} + */ + public function getConnection() + { + return $this->connection; + } + + /** + * {@inheritdoc} + */ + public function getArguments() + { + return $this->arguments; + } + + /** + * {@inheritdoc} + */ + public function isDurable() + { + return $this->isDurable; + } + + /** + * {@inheritdoc} + */ + public function isAutoDelete() + { + return $this->isAutoDelete; + } + + /** + * Set exchange config item data. + * + * @param array $data + * @return void + */ + public function setData(array $data) + { + $this->name = $data['name']; + $this->connection = $data['connection']; + $this->isDurable = $data['durable']; + $this->isAutoDelete = $data['autoDelete']; + $this->arguments = $data['arguments']; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItem/DataMapper.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItem/DataMapper.php new file mode 100644 index 0000000000000..7e8d35fb0940f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItem/DataMapper.php @@ -0,0 +1,177 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\QueueConfigItem; + +use Magento\Framework\MessageQueue\Topology\Config\Data; +use Magento\Framework\Communication\ConfigInterface as CommunicationConfig; +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\MessageQueue\Rpc\ResponseQueueNameBuilder; +use Magento\Framework\Phrase; + +/** + * Topology queue config data mapper. + */ +class DataMapper +{ + /** + * Config data. + * + * @var array + */ + private $mappedData; + + /** + * @var Data + */ + private $configData; + + /** + * @var CommunicationConfig + */ + private $communicationConfig; + + /** + * @var ResponseQueueNameBuilder + */ + private $queueNameBuilder; + + /** + * Initialize dependencies. + * + * @param Data $configData + * @param CommunicationConfig $communicationConfig + * @param ResponseQueueNameBuilder $queueNameBuilder + */ + public function __construct( + Data $configData, + CommunicationConfig $communicationConfig, + ResponseQueueNameBuilder $queueNameBuilder + ) { + $this->configData = $configData; + $this->communicationConfig = $communicationConfig; + $this->queueNameBuilder = $queueNameBuilder; + } + + /** + * Get mapped config data. + * + * @return array + */ + public function getMappedData() + { + if (null === $this->mappedData) { + $this->mappedData = []; + foreach ($this->configData->get() as $exchange) { + $connection = $exchange['connection']; + foreach ($exchange['bindings'] as $binding) { + if ($binding['destinationType'] === 'queue') { + $queueItems = $this->createQueueItems($binding['destination'], $binding['topic'], $connection); + $this->mappedData = array_merge($this->mappedData, $queueItems); + } + } + } + } + return $this->mappedData; + } + + /** + * Create queue config item. + * + * @param string $name + * @param string $topic + * @param string $connection + * @return array + */ + private function createQueueItems($name, $topic, $connection) + { + $output = []; + $synchronousTopics = []; + + if (strpos($topic, '*') !== false || strpos($topic, '#') !== false) { + $synchronousTopics = $this->matchSynchronousTopics($topic); + } elseif ($this->isSynchronousTopic($topic)) { + $synchronousTopics[$topic] = $topic; + } + + foreach ($synchronousTopics as $topicName) { + $callbackQueueName = $this->queueNameBuilder->getQueueName($topicName); + $output[$callbackQueueName . '--' . $connection] = [ + 'name' => $callbackQueueName, + 'connection' => $connection, + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ]; + } + + $output[$name . '--' . $connection] = [ + 'name' => $name, + 'connection' => $connection, + 'durable' => true, + 'autoDelete' => false, + 'arguments' => [], + ]; + return $output; + } + + /** + * Check whether the topic is in synchronous mode + * + * @param string $topicName + * @return bool + * @throws LocalizedException + */ + private function isSynchronousTopic($topicName) + { + try { + $topic = $this->communicationConfig->getTopic($topicName); + $isSync = (bool)$topic[CommunicationConfig::TOPIC_IS_SYNCHRONOUS]; + } catch (LocalizedException $e) { + throw new LocalizedException(new Phrase('Error while checking if topic is synchronous')); + } + return $isSync; + } + + /** + * Generate topics list based on wildcards. + * + * @param string $wildcard + * @return array + */ + private function matchSynchronousTopics($wildcard) + { + $topicDefinitions = array_filter( + $this->communicationConfig->getTopics(), + function ($item) { + return (bool)$item[CommunicationConfig::TOPIC_IS_SYNCHRONOUS]; + } + ); + + $topics = []; + $pattern = $this->buildWildcardPattern($wildcard); + foreach (array_keys($topicDefinitions) as $topicName) { + if (preg_match($pattern, $topicName)) { + $topics[$topicName] = $topicName; + } + } + return $topics; + } + + /** + * Construct perl regexp pattern for matching topic names from wildcard key. + * + * @param string $wildcardKey + * @return string + */ + private function buildWildcardPattern($wildcardKey) + { + $pattern = '/^' . str_replace('.', '\.', $wildcardKey); + $pattern = str_replace('#', '.+', $pattern); + $pattern = str_replace('*', '[^\.]+', $pattern); + $pattern .= strpos($wildcardKey, '#') === strlen($wildcardKey) ? '/' : '$/'; + return $pattern; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItem/Iterator.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItem/Iterator.php new file mode 100644 index 0000000000000..e76c88f556a4f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItem/Iterator.php @@ -0,0 +1,138 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\QueueConfigItem; + +use Magento\Framework\MessageQueue\Topology\Config\QueueConfigItem; +use Magento\Framework\MessageQueue\Topology\Config\QueueConfigItemFactory; + +/** + * Queue config item iterator. + */ +class Iterator implements \Iterator, \ArrayAccess +{ + /** + * Consumer config item. + * + * @var QueueConfigItem + */ + private $object; + + /** + * Config data. + * + * @var array + */ + private $data; + + /** + * Initialize dependencies. + * + * @param DataMapper $configData + * @param QueueConfigItemFactory $itemFactory + */ + public function __construct(DataMapper $configData, QueueConfigItemFactory $itemFactory) + { + $this->data = $configData->getMappedData(); + $this->object = $itemFactory->create(); + $this->rewind(); + } + + /** + * Get current item. + * + * @return QueueConfigItem + */ + public function current() + { + return $this->object; + } + + /** + * {@inheritdoc} + */ + public function next() + { + next($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + } + } + + /** + * Initialize object. + * + * @param array $data + * @return void + */ + private function initObject(array $data) + { + $this->object->setData($data); + } + + /** + * {@inheritdoc} + */ + public function key() + { + key($this->data); + } + + /** + * {@inheritdoc} + */ + public function valid() + { + return (bool)current($this->data); + } + + /** + * {@inheritdoc} + */ + public function rewind() + { + reset($this->data); + if (current($this->data)) { + $this->initObject(current($this->data)); + } + } + + /** + * {@inheritdoc} + */ + public function offsetExists($offset) + { + return array_key_exists($offset, $this->data); + } + + /** + * {@inheritdoc} + */ + public function offsetGet($offset) + { + if (!$this->offsetExists($offset)) { + return null; + } + $item = clone $this->object; + $item->setData($this->data[$offset]); + return $item; + } + + /** + * {@inheritdoc} + */ + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + /** + * {@inheritdoc} + */ + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItemFactory.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItemFactory.php new file mode 100644 index 0000000000000..977bc80cd3542 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItemFactory.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +/** + * Factory class for @see \Magento\Framework\MessageQueue\Queue\Config\QueueConfigItem + */ +class QueueConfigItemFactory +{ + /** + * Object Manager instance + * + * @var \Magento\Framework\ObjectManagerInterface + */ + private $objectManager = null; + + /** + * Instance name to create + * + * @var string + */ + private $instanceName = null; + + /** + * Factory constructor + * + * @param \Magento\Framework\ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + \Magento\Framework\ObjectManagerInterface $objectManager, + $instanceName = QueueConfigItem::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @param array $data + * @return QueueConfigItem + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItemInterface.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItemInterface.php new file mode 100644 index 0000000000000..fbae97a9c17cc --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/QueueConfigItemInterface.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +/** + * Instances of this class represent queue config items. + */ +interface QueueConfigItemInterface +{ + /** + * Get queue name. + * + * @return string + */ + public function getName(); + + /** + * Get queue connection. + * + * @return string + */ + public function getConnection(); + + /** + * Check if queue is durable. + * + * @return bool + */ + public function isDurable(); + + /** + * Check if queue is auto delete. + * + * @return bool + */ + public function isAutoDelete(); + + /** + * Get queue arguments + * + * @return array + */ + public function getArguments(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ReaderInterface.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ReaderInterface.php new file mode 100644 index 0000000000000..60eda0d3b8a9f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ReaderInterface.php @@ -0,0 +1,14 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +/** + * Topology config reader interface + */ +interface ReaderInterface extends \Magento\Framework\Config\ReaderInterface +{ + +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/RemoteService/Reader.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/RemoteService/Reader.php new file mode 100644 index 0000000000000..59b3fb716a407 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/RemoteService/Reader.php @@ -0,0 +1,132 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\RemoteService; + +use Magento\Framework\Communication\Config\ReflectionGenerator; +use Magento\Framework\MessageQueue\Code\Generator\RemoteServiceGenerator; +use Magento\Framework\MessageQueue\DefaultValueProvider; +use Magento\Framework\MessageQueue\Topology\Config\ReaderInterface; +use Magento\Framework\ObjectManager\ConfigInterface as ObjectManagerConfig; +use Magento\Framework\Reflection\MethodsMap as ServiceMethodsMap; + +/** + * Reader for queue topology configs based on remote service declaration in DI configs. + */ +class Reader implements ReaderInterface +{ + /** + * @var DefaultValueProvider + */ + private $defaultValueProvider; + + /** + * @var ObjectManagerConfig + */ + private $objectManagerConfig; + + /** + * @var ReflectionGenerator + */ + private $reflectionGenerator; + + /** + * @var ServiceMethodsMap + */ + private $serviceMethodsMap; + + /** + * Initialize dependencies. + * + * @param DefaultValueProvider $defaultValueProvider + * @param ObjectManagerConfig $objectManagerConfig + * @param ReflectionGenerator $reflectionGenerator + * @param ServiceMethodsMap $serviceMethodsMap + */ + public function __construct( + DefaultValueProvider $defaultValueProvider, + ObjectManagerConfig $objectManagerConfig, + ReflectionGenerator $reflectionGenerator, + ServiceMethodsMap $serviceMethodsMap + ) { + $this->defaultValueProvider = $defaultValueProvider; + $this->objectManagerConfig = $objectManagerConfig; + $this->reflectionGenerator = $reflectionGenerator; + $this->serviceMethodsMap = $serviceMethodsMap; + } + + /** + * {@inheritdoc} + */ + public function read($scope = null) + { + $exchangeName = $this->defaultValueProvider->getExchange(); + return [ + $exchangeName => [ + 'name' => $exchangeName, + 'type' => 'topic', + 'connection' => $this->defaultValueProvider->getConnection(), + 'durable' => true, + 'autoDelete' => false, + 'internal' => false, + 'bindings' => $this->generateBindings(), + 'arguments' => [], + ] + ]; + } + + /** + * Generate list of bindings based on information about remote services declared in DI config. + * + * @return array + * + * @throws \LogicException + * + * @SuppressWarnings(PHPMD.UnusedLocalVariable) + */ + private function generateBindings() + { + $bindings = []; + foreach ($this->getRemoteServices() as $serviceInterface => $remoteImplementation) { + try { + $methodsMap = $this->serviceMethodsMap->getMethodsMap($serviceInterface); + } catch (\Exception $e) { + throw new \LogicException(sprintf('Service interface was expected, "%s" given', $serviceInterface)); + } + foreach ($methodsMap as $methodName => $returnType) { + $topic = $this->reflectionGenerator->generateTopicName($serviceInterface, $methodName); + $exchangeName = $this->defaultValueProvider->getExchange(); + $destination = 'queue.' . $topic; + $id = $topic . '--' . $exchangeName . '--' . $destination; + $bindings[$id] = [ + 'id' => $id, + 'destinationType' => 'queue', + 'destination' => $destination, + 'disabled' => false, + 'topic' => $topic, + 'arguments' => [] + ]; + } + } + return $bindings; + } + + /** + * Get list of remote services declared in DI config. + * + * @return array + */ + private function getRemoteServices() + { + $preferences = $this->objectManagerConfig->getPreferences(); + $remoteServices = []; + foreach ($preferences as $type => $preference) { + if ($preference == $type . RemoteServiceGenerator::REMOTE_SERVICE_SUFFIX) { + $remoteServices[$type] = $preference; + } + } + return $remoteServices; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/DependentFields.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/DependentFields.php new file mode 100644 index 0000000000000..fcf10053e4148 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/DependentFields.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\Validator; + +use Magento\Framework\MessageQueue\Topology\Config\ValidatorInterface; + +/** + * Topology config data validator. + */ +class DependentFields implements ValidatorInterface +{ + /** + * {@inheritdoc} + */ + public function validate($configData) + { + $errors = []; + foreach ($configData as $name => $data) { + foreach ((array)$data['bindings'] as $binding) { + if (isset($data['type']) && $data['type'] == 'topic' && !isset($binding['topic'])) { + $errors[] = 'Topic name is required for topic based exchange: ' . $name; + } + } + } + + if (!empty($errors)) { + throw new \LogicException(implode(PHP_EOL, $errors)); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/FieldsTypes.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/FieldsTypes.php new file mode 100644 index 0000000000000..2e1cf52ee4cbe --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/FieldsTypes.php @@ -0,0 +1,131 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\Validator; + +use Magento\Framework\MessageQueue\Topology\Config\ValidatorInterface; + +/** + * Consumer config data validator for fields types. + */ +class FieldsTypes implements ValidatorInterface +{ + /** + * {@inheritdoc} + */ + public function validate($configData) + { + foreach ($configData as $exchangeName => $exchangeConfig) { + $this->validateFieldsTypes($exchangeName, $exchangeConfig); + } + } + + /** + * Make sure types of all fields in the exchange item config are correct. + * + * @param string $exchangeName + * @param array $exchangeConfig + * @return void + * @throws \LogicException + */ + private function validateFieldsTypes($exchangeName, $exchangeConfig) + { + $fields = [ + 'name' => ['type' => 'string', 'value' => null], + 'type' => ['type' => 'string', 'value' => ['topic']], + 'connection' => ['type' => 'string', 'value' => null], + 'durable' => ['type' => 'boolean', 'value' => null], + 'autoDelete' => ['type' => 'boolean', 'value' => null], + 'internal' => ['type' => 'boolean', 'value' => null], + 'bindings' => ['type' => 'array', 'value' => null], + 'arguments' => ['type' => 'array', 'value' => null], + ]; + + $bindingFields = [ + 'id' => ['type' => 'string', 'value' => null], + 'destinationType' => ['type' => 'string', 'value' => ['queue']], + 'destination' => ['type' => 'string', 'value' => null], + 'disabled' => ['type' => 'boolean', 'value' => null], + 'topic' => ['type' => 'string', 'value' => null], + 'arguments' => ['type' => 'array', 'value' => null], + ]; + + foreach ($fields as $fieldName => $expectedType) { + $actualType = gettype($exchangeConfig[$fieldName]); + if ($actualType !== $expectedType['type']) { + throw new \LogicException( + sprintf( + "Type of '%s' field specified in configuration of '%s' exchange is invalid. " + . "Given '%s', '%s' was expected.", + $fieldName, + $exchangeName, + $actualType, + $expectedType['type'] + ) + ); + } + + if ($expectedType['value'] && !in_array($exchangeConfig[$fieldName], $expectedType['value'])) { + throw new \LogicException( + sprintf( + "Value of '%s' field specified in configuration of '%s' exchange is invalid. " + . "Given '%s', '%s' was expected.", + $fieldName, + $exchangeName, + $exchangeConfig[$fieldName], + implode(' or ', $expectedType['value']) + ) + ); + } + } + + $this->validateBindings($exchangeName, $exchangeConfig, $bindingFields); + } + + /** + * Validate binding config. + * + * @param string $exchangeName + * @param array $exchangeConfig + * @param array $bindingFields + * @return void + * @throws \LogicException + */ + private function validateBindings($exchangeName, $exchangeConfig, $bindingFields) + { + foreach ($bindingFields as $bindFieldName => $bindExpectedType) { + foreach ($exchangeConfig['bindings'] as $bindingConfig) { + $actualType = gettype($bindingConfig[$bindFieldName]); + if ($actualType !== $bindExpectedType['type']) { + throw new \LogicException( + sprintf( + "Type of '%s' field specified in configuration of '%s' exchange is invalid. " + . "Given '%s', '%s' was expected.", + $bindFieldName, + $exchangeName, + $actualType, + $bindExpectedType['type'] + ) + ); + } + + if ($bindExpectedType['value'] && + !in_array($bindingConfig[$bindFieldName], $bindExpectedType['value']) + ) { + throw new \LogicException( + sprintf( + "Value of '%s' field specified in configuration of '%s' exchange is invalid. " + . "Given '%s', '%s' was expected.", + $bindFieldName, + $exchangeName, + $bindingConfig[$bindFieldName], + implode(' or ', $bindExpectedType['value']) + ) + ); + } + } + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/Format.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/Format.php new file mode 100644 index 0000000000000..50acb6cbd5fc3 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Validator/Format.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\Validator; + +use Magento\Framework\MessageQueue\Topology\Config\ValidatorInterface; + +/** + * Topology config data validator. + */ +class Format implements ValidatorInterface +{ + /** + * {@inheritdoc} + */ + public function validate($configData) + { + $requiredFields = ['name', 'type', 'connection', 'durable', 'autoDelete', 'internal', 'bindings', 'arguments']; + $requiredBindingFields = ['id', 'destinationType', 'destination', 'disabled', 'topic', 'arguments']; + $errors = []; + foreach ($configData as $name => $data) { + $diff = array_diff($requiredFields, array_keys($data)); + foreach ($diff as $field) { + $errors[] = sprintf('Missing [%s] field for exchange %s.', $field, $name); + } + + if (!array_key_exists('bindings', $data) || !is_array($data['bindings'])) { + $errors[] = sprintf('Invalid bindings format for exchange %s.', $name); + continue; + } + + foreach ($data['bindings'] as $bindingConfig) { + $diff = array_diff($requiredBindingFields, array_keys($bindingConfig)); + foreach ($diff as $field) { + $errors[] = sprintf('Missing [%s] field for binding %s in exchange config.', $field, $name); + } + } + } + + if (!empty($errors)) { + throw new \LogicException(implode(PHP_EOL, $errors)); + } + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ValidatorInterface.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ValidatorInterface.php new file mode 100644 index 0000000000000..499671711736b --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/ValidatorInterface.php @@ -0,0 +1,21 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config; + +/** + * Topology config data validator. + */ +interface ValidatorInterface +{ + /** + * Validate topology config data. + * + * @param array $configData + * @throws \LogicException + * @return void + */ + public function validate($configData); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/Converter.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/Converter.php new file mode 100644 index 0000000000000..516a4f080973f --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/Converter.php @@ -0,0 +1,184 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\Xml; + +use Magento\Framework\Stdlib\BooleanUtils; +use Magento\Framework\Data\Argument\InterpreterInterface; +use Magento\Framework\Config\Converter\Dom\Flat as FlatConverter; +use Magento\Framework\Config\Dom\ArrayNodeConfig; +use Magento\Framework\Config\Dom\NodePathMatcher; +use Magento\Framework\MessageQueue\DefaultValueProvider; + +/** + * Converts MessageQueue topology config from \DOMDocument to array + */ +class Converter implements \Magento\Framework\Config\ConverterInterface +{ + /** + * @var FlatConverter + */ + private $converter; + + /** + * Boolean value converter. + * + * @var BooleanUtils + */ + private $booleanUtils; + + /** + * Argument interpreter. + * + * @var InterpreterInterface + */ + private $argumentInterpreter; + + /** + * @var DefaultValueProvider + */ + private $defaultValue; + + /** + * Initialize dependencies. + * + * @param BooleanUtils $booleanUtils + * @param InterpreterInterface $argumentInterpreter + * @param DefaultValueProvider $defaultValueProvider + */ + public function __construct( + BooleanUtils $booleanUtils, + InterpreterInterface $argumentInterpreter, + DefaultValueProvider $defaultValueProvider + ) { + $this->booleanUtils = $booleanUtils; + $this->argumentInterpreter = $argumentInterpreter; + $this->defaultValue = $defaultValueProvider; + } + + /** + * {@inheritdoc} + */ + public function convert($source) + { + $result = []; + /** @var $exchange \DOMElement */ + foreach ($source->getElementsByTagName('exchange') as $exchange) { + $name = $this->getAttributeValue($exchange, 'name'); + $connection = $this->getAttributeValue($exchange, 'connection'); + + $bindings = []; + $exchangeArguments = []; + /** @var \DOMNode $node */ + foreach ($exchange->childNodes as $node) { + if (!in_array($node->nodeName, ['binding', 'arguments']) || $node->nodeType != XML_ELEMENT_NODE) { + continue; + } + switch ($node->nodeName) { + case 'binding': + $bindings = $this->processBindings($node, $bindings); + break; + + case 'arguments': + $exchangeArguments = $this->processArguments($node); + break; + } + } + + $autoDelete = $this->getAttributeValue($exchange, 'autoDelete', false); + $result[$name . '--' . $connection] = [ + 'name' => $name, + 'type' => $this->getAttributeValue($exchange, 'type'), + 'connection' => $connection, + 'durable' => $this->booleanUtils->toBoolean($this->getAttributeValue($exchange, 'durable', true)), + 'autoDelete' => $this->booleanUtils->toBoolean($autoDelete), + 'internal' => $this->booleanUtils->toBoolean($this->getAttributeValue($exchange, 'internal', false)), + 'bindings' => $bindings, + 'arguments' => $exchangeArguments, + ]; + } + return $result; + } + + /** + * Retrieve instance of XML converter + * + * @return FlatConverter + */ + private function getConverter() + { + if (!$this->converter) { + $arrayNodeConfig = new ArrayNodeConfig(new NodePathMatcher(), ['argument(/item)+' => 'name']); + $this->converter = new FlatConverter($arrayNodeConfig); + } + return $this->converter; + } + + /** + * Process arguments. + * + * @param \DOMNode $node + * @return array + */ + private function processArguments(\DOMNode $node) + { + $output = []; + /** @var \DOMNode $argumentNode */ + foreach ($node->childNodes as $argumentNode) { + if ($argumentNode->nodeType != XML_ELEMENT_NODE || $argumentNode->nodeName != 'argument') { + continue; + } + $argumentName = $argumentNode->attributes->getNamedItem('name')->nodeValue; + $argumentData = $this->getConverter()->convert($argumentNode, 'argument'); + $output[$argumentName] = $this->argumentInterpreter->evaluate($argumentData); + } + return $output; + } + + /** + * Get attribute value of the given node + * + * @param \DOMNode $node + * @param string $attributeName + * @param mixed $default + * @return string|null + */ + private function getAttributeValue(\DOMNode $node, $attributeName, $default = null) + { + $item = $node->attributes->getNamedItem($attributeName); + return $item ? $item->nodeValue : $default; + } + + /** + * Parse bindings. + * + * @param \DOMNode $node + * @param array $bindings + * @return array + */ + private function processBindings($node, $bindings) + { + $bindingArguments = []; + $id = $this->getAttributeValue($node, 'id'); + $isDisabled = $this->booleanUtils->toBoolean( + $this->getAttributeValue($node, 'disabled', false) + ); + foreach ($node->childNodes as $arguments) { + if ($arguments->nodeName != 'arguments' || $arguments->nodeType != XML_ELEMENT_NODE) { + continue; + } + $bindingArguments = $this->processArguments($arguments); + } + $bindings[$id] = [ + 'id' => $id, + 'destinationType' => $this->getAttributeValue($node, 'destinationType'), + 'destination' => $this->getAttributeValue($node, 'destination'), + 'disabled' => $isDisabled, + 'topic' => $this->getAttributeValue($node, 'topic'), + 'arguments' => $bindingArguments + ]; + return $bindings; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/Reader.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/Reader.php new file mode 100644 index 0000000000000..6dbdf78d1f084 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/Reader.php @@ -0,0 +1,51 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\Xml; + +use \Magento\Framework\MessageQueue\Topology\Config\ReaderInterface; + +/** + * Reader for etc/queue_topology.xml configs. + */ +class Reader extends \Magento\Framework\Config\Reader\Filesystem implements ReaderInterface +{ + /** + * {@inheritdoc} + */ + protected $_idAttributes = [ + '/config/exchange' => ['name', 'connection'], + '/config/exchange/arguments/argument' => 'name', + '/config/exchange/arguments/argument(/item)+' => 'name', + '/config/exchange/binding' => 'id', + '/config/exchange/binding/arguments/argument' => 'name', + '/config/exchange/binding/arguments/argument(/item)+' => 'name', + ]; + + /** + * {@inheritdoc} + */ + public function __construct( + \Magento\Framework\Config\FileResolverInterface $fileResolver, + Converter $converter, + SchemaLocator $schemaLocator, + \Magento\Framework\Config\ValidationStateInterface $validationState, + $fileName = 'queue_topology.xml', + $idAttributes = [], + $domDocumentClass = \Magento\Framework\Config\Dom::class, + $defaultScope = 'global' + ) { + parent::__construct( + $fileResolver, + $converter, + $schemaLocator, + $validationState, + $fileName, + $idAttributes, + $domDocumentClass, + $defaultScope + ); + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/SchemaLocator.php b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/SchemaLocator.php new file mode 100644 index 0000000000000..0ed9f3f21df79 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/Config/Xml/SchemaLocator.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology\Config\Xml; + +/** + * Schema locator for etc/queue_topology.xml + */ +class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface +{ + /** + * Path to corresponding XSD file with validation rules for merged config + * + * @var string + */ + protected $schema; + + /** + * Path to corresponding XSD file with validation rules for separate config files + * + * @var string + */ + protected $perFileSchema; + + /** + * Initialize dependencies. + * + * @param \Magento\Framework\Config\Dom\UrnResolver $urnResolver + */ + public function __construct(\Magento\Framework\Config\Dom\UrnResolver $urnResolver) + { + $this->schema = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/topology_merged.xsd'); + $this->perFileSchema = $urnResolver->getRealPath('urn:magento:framework-message-queue:etc/topology.xsd'); + } + + /** + * Get path to merged config schema + * + * @return string|null + */ + public function getSchema() + { + return $this->schema; + } + + /** + * Get path to per file validation schema + * + * @return string|null + */ + public function getPerFileSchema() + { + return $this->perFileSchema; + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/Topology/ConfigInterface.php b/lib/internal/Magento/Framework/MessageQueue/Topology/ConfigInterface.php new file mode 100644 index 0000000000000..81d056999b573 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/Topology/ConfigInterface.php @@ -0,0 +1,49 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\MessageQueue\Topology; + +use Magento\Framework\Exception\LocalizedException; +use Magento\Framework\MessageQueue\Topology\Config\ExchangeConfigItemInterface; +use Magento\Framework\MessageQueue\Topology\Config\QueueConfigItemInterface; + +/** + * Topology config interface provides access data declared in etc/queue_topology.xml + * + * @api + * @since 100.2.0 + */ +interface ConfigInterface +{ + /** + * Get exchange configuration by exchange name. + * + * @param string $name + * @param string $connection + * @return ExchangeConfigItemInterface + * @throws LocalizedException + * @throws \LogicException + * @since 100.2.0 + */ + public function getExchange($name, $connection); + + /** + * Get list of all exchanges declared in the system. + * + * @return ExchangeConfigItemInterface[] + * @throws \LogicException + * @since 100.2.0 + */ + public function getExchanges(); + + /** + * Get list of all queues declared in the system. + * + * @return QueueConfigItemInterface[] + * @throws \LogicException + * @since 100.2.0 + */ + public function getQueues(); +} diff --git a/lib/internal/Magento/Framework/MessageQueue/composer.json b/lib/internal/Magento/Framework/MessageQueue/composer.json new file mode 100644 index 0000000000000..05f119630a4fe --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/composer.json @@ -0,0 +1,25 @@ +{ + "name": "magento/framework-message-queue", + "description": "N/A", + "config": { + "sort-packages": true + }, + "type": "magento2-library", + "version": "100.3.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "require": { + "magento/framework": "100.3.*", + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0" + }, + "autoload": { + "psr-4": { + "Magento\\Framework\\MessageQueue\\": "" + }, + "files": [ + "registration.php" + ] + } +} diff --git a/lib/internal/Magento/Framework/MessageQueue/etc/consumer.xsd b/lib/internal/Magento/Framework/MessageQueue/etc/consumer.xsd new file mode 100644 index 0000000000000..52bfc77bbb511 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/etc/consumer.xsd @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="config"> + <xs:complexType> + <xs:sequence> + <xs:element name="consumer" type="consumerType" maxOccurs="unbounded" minOccurs="0"/> + </xs:sequence> + </xs:complexType> + <xs:unique name="consumer-unique-name"> + <xs:selector xpath="consumer"/> + <xs:field xpath="@name"/> + </xs:unique> + </xs:element> + <xs:complexType name="consumerType"> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="xs:string" name="queue" use="required"/> + <xs:attribute type="handlerType" name="handler" use="optional"/> + <xs:attribute type="xs:string" name="consumerInstance" use="optional"/> + <xs:attribute name="connection" use="optional" type="xs:string" /> + <xs:attribute type="xs:integer" name="maxMessages" use="optional"/> + </xs:complexType> + <xs:simpleType name="handlerType"> + <xs:annotation> + <xs:documentation> + Handler is expected in a format "Vendor\Module\Api\ServiceName::methodName". + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <xs:pattern value="[a-zA-Z\\]+::[a-zA-Z]+" /> + <xs:minLength value="5" /> + </xs:restriction> + </xs:simpleType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/MessageQueue/etc/publisher.xsd b/lib/internal/Magento/Framework/MessageQueue/etc/publisher.xsd new file mode 100644 index 0000000000000..812c4690545ac --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/etc/publisher.xsd @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="config"> + <xs:annotation> + <xs:documentation>XML Schema Definition for queue_publisher.xml</xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:sequence> + <xs:element type="publisherType" name="publisher" minOccurs="1" maxOccurs="unbounded"> + <xs:unique name="unique-connection-name"> + <xs:annotation> + <xs:documentation> + Publisher connection name must be unique + </xs:documentation> + </xs:annotation> + <xs:selector xpath="connection"/> + <xs:field xpath="@name"/> + </xs:unique> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:unique name="unique-publisher-topic"> + <xs:annotation> + <xs:documentation> + Publisher topic must be unique + </xs:documentation> + </xs:annotation> + <xs:selector xpath="publisher"/> + <xs:field xpath="@topic"/> + </xs:unique> + </xs:element> + + <xs:complexType name="publisherType"> + <xs:sequence> + <xs:element type="connectionType" name="connection" minOccurs="0" maxOccurs="unbounded" /> + </xs:sequence> + <xs:attribute type="xs:string" name="topic" use="required" /> + <xs:attribute type="xs:boolean" name="disabled" use="optional" /> + </xs:complexType> + + <xs:complexType name="connectionType"> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="name" use="required" type="xs:string" /> + <xs:attribute type="xs:string" name="exchange" use="optional"/> + <xs:attribute type="xs:boolean" name="disabled" use="optional"/> + </xs:extension> + </xs:simpleContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/MessageQueue/etc/queue.xsd b/lib/internal/Magento/Framework/MessageQueue/etc/queue.xsd new file mode 100644 index 0000000000000..7c018403d176d --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/etc/queue.xsd @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:include schemaLocation="urn:magento:framework-message-queue:etc/queue_base.xsd" /> + <xs:element name="config"> + <xs:annotation> + <xs:documentation> + @deprecated + </xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="broker" type="brokerType"/> + </xs:choice> + </xs:complexType> + <xs:unique name="broker-unique-name"> + <xs:selector xpath="broker"/> + <xs:field xpath="@topic"/> + </xs:unique> + <xs:unique name="broker-queue-unique-name"> + <xs:selector xpath="broker/queue"/> + <xs:field xpath="@name"/> + </xs:unique> + </xs:element> +</xs:schema> diff --git a/lib/internal/Magento/Framework/MessageQueue/etc/queue_base.xsd b/lib/internal/Magento/Framework/MessageQueue/etc/queue_base.xsd new file mode 100644 index 0000000000000..4b326d637f274 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/etc/queue_base.xsd @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:complexType name="brokerType"> + <xs:annotation> + <xs:documentation> + @deprecated + Broker configuration describes relations for topic, publisher, consumer, queue and exchange server + </xs:documentation> + </xs:annotation> + <xs:sequence minOccurs="0" maxOccurs="unbounded"> + <xs:element name="queue" type="brokerQueueType" /> + </xs:sequence> + <xs:attribute name="topic" type="xs:string" use="required"/> + <xs:attribute name="type" type="xs:string" use="optional"/> + <xs:attribute name="exchange" type="xs:string" use="optional"/> + </xs:complexType> + <xs:complexType name="brokerQueueType"> + <xs:annotation> + <xs:documentation> + @deprecated + Queue element of the broker element + </xs:documentation> + </xs:annotation> + <xs:attribute name="name" type="xs:string" use="required" /> + <xs:attribute name="handler" type="handlerType" use="optional" /> + <xs:attribute name="consumer" type="xs:string" use="required" /> + <xs:attribute name="consumerInstance" type="instanceType" use="optional" /> + <xs:attribute name="maxMessages" type="xs:integer" use="optional"/> + </xs:complexType> + <xs:simpleType name="instanceType"> + <xs:annotation> + <xs:documentation> + @deprecated + Instance is expected in a format "Vendor\Module\Api\ServiceName". + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <xs:pattern value="[a-zA-Z\\]+" /> + <xs:minLength value="4" /> + </xs:restriction> + </xs:simpleType> + <xs:simpleType name="handlerType"> + <xs:annotation> + <xs:documentation> + @deprecated + Handler is expected in a format "Vendor\Module\Api\ServiceName::methodName". + </xs:documentation> + </xs:annotation> + <xs:restriction base="xs:string"> + <xs:pattern value="[a-zA-Z\\]+::[a-zA-Z]+" /> + <xs:minLength value="5" /> + </xs:restriction> + </xs:simpleType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/MessageQueue/etc/queue_merged.xsd b/lib/internal/Magento/Framework/MessageQueue/etc/queue_merged.xsd new file mode 100644 index 0000000000000..2c3f947969190 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/etc/queue_merged.xsd @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:include schemaLocation="urn:magento:framework-message-queue:etc/queue_base.xsd" /> + <xs:element name="config"> + <xs:annotation> + <xs:documentation> + @deprecated + </xs:documentation> + </xs:annotation> + <xs:complexType> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="broker" type="brokerType"/> + </xs:choice> + </xs:complexType> + <xs:unique name="broker-unique-name"> + <xs:selector xpath="broker"/> + <xs:field xpath="@topic"/> + </xs:unique> + </xs:element> +</xs:schema> diff --git a/lib/internal/Magento/Framework/MessageQueue/etc/topology.xsd b/lib/internal/Magento/Framework/MessageQueue/etc/topology.xsd new file mode 100644 index 0000000000000..39862007b1d12 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/etc/topology.xsd @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:complexType name="argumentType" abstract="true" mixed="true"> + <xs:attribute name="name" use="required"/> + </xs:complexType> + + <xs:complexType name="argumentsType"> + <xs:sequence> + <xs:element name="argument" type="argumentType" minOccurs="1" maxOccurs="unbounded"> + <xs:key name="argumentItemName"> + <xs:selector xpath="item"></xs:selector> + <xs:field xpath="@name"></xs:field> + </xs:key> + </xs:element> + </xs:sequence> + </xs:complexType> + + <xs:complexType name="array" mixed="true"> + <xs:complexContent> + <xs:extension base="argumentType"> + <xs:sequence> + <xs:element name="item" type="argumentType" minOccurs="0" maxOccurs="unbounded"> + <xs:key name="itemName"> + <xs:selector xpath="item"></xs:selector> + <xs:field xpath="@name"></xs:field> + </xs:key> + </xs:element> + </xs:sequence> + </xs:extension> + </xs:complexContent> + </xs:complexType> + + <xs:complexType name="number"> + <xs:complexContent> + <xs:extension base="argumentType"/> + </xs:complexContent> + </xs:complexType> + + <xs:complexType name="boolean"> + <xs:complexContent> + <xs:extension base="argumentType"/> + </xs:complexContent> + </xs:complexType> + + <xs:complexType name="string"> + <xs:complexContent> + <xs:extension base="argumentType" /> + </xs:complexContent> + </xs:complexType> + + <xs:element name="config"> + <xs:complexType> + <xs:sequence> + <xs:element type="exchangeConfigType" name="exchange" maxOccurs="unbounded" minOccurs="0"> + <xs:unique name="unique-binding-id"> + <xs:annotation> + <xs:documentation> + Binding id must be unique + </xs:documentation> + </xs:annotation> + <xs:selector xpath="binding"/> + <xs:field xpath="@id"/> + </xs:unique> + </xs:element> + </xs:sequence> + </xs:complexType> + <xs:unique name="unique-exchange-name-connection"> + <xs:annotation> + <xs:documentation> + Exchange name must be unique + </xs:documentation> + </xs:annotation> + <xs:selector xpath="exchange"/> + <xs:field xpath="@name"/> + <xs:field xpath="@connection"/> + </xs:unique> + </xs:element> + + <xs:complexType name="bindingType" mixed="true"> + <xs:sequence> + <xs:element type="argumentsType" name="arguments" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute type="xs:string" name="id" use="required"/> + <xs:attribute type="destinationType" name="destinationType" use="optional"/> + <xs:attribute type="xs:string" name="destination" use="optional"/> + <xs:attribute type="xs:boolean" name="disabled" use="optional"/> + <xs:attribute type="xs:string" name="topic" use="optional"/> + </xs:complexType> + + <xs:complexType name="exchangeConfigType"> + <xs:choice maxOccurs="unbounded"> + <xs:element type="argumentsType" name="arguments" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="bindingType" name="binding" maxOccurs="unbounded" minOccurs="0"/> + </xs:choice> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="exchangeType" name="type" use="optional"/> + <xs:attribute name="connection" type="xs:string" use="required" /> + <xs:attribute type="xs:boolean" name="durable" use="optional"/> + <xs:attribute type="xs:boolean" name="autoDelete" use="optional"/> + <xs:attribute type="xs:boolean" name="internal" use="optional"/> + </xs:complexType> + + <xs:simpleType name="exchangeType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="topic" /> + </xs:restriction> + </xs:simpleType> + + <xs:simpleType name="destinationType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="queue" /> + </xs:restriction> + </xs:simpleType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/MessageQueue/etc/topology_merged.xsd b/lib/internal/Magento/Framework/MessageQueue/etc/topology_merged.xsd new file mode 100644 index 0000000000000..e2b90343110f1 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/etc/topology_merged.xsd @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:redefine schemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <xs:complexType name="bindingType" mixed="true"> + <xs:complexContent> + <xs:restriction base="bindingType"> + <xs:sequence> + <xs:element type="argumentsType" name="arguments" minOccurs="0" maxOccurs="unbounded"/> + </xs:sequence> + <xs:attribute type="xs:string" name="id" use="required"/> + <xs:attribute type="destinationType" name="destinationType" use="required"/> + <xs:attribute type="xs:string" name="destination" use="required"/> + <xs:attribute type="xs:boolean" name="disabled" use="optional"/> + <xs:attribute type="xs:string" name="topic" use="optional"/> + </xs:restriction> + </xs:complexContent> + </xs:complexType> + </xs:redefine> + + <xs:redefine schemaLocation="urn:magento:framework-message-queue:etc/topology.xsd"> + <xs:complexType name="exchangeConfigType"> + <xs:complexContent> + <xs:restriction base="exchangeConfigType"> + <xs:choice maxOccurs="unbounded"> + <xs:element type="argumentsType" name="arguments" minOccurs="0" maxOccurs="unbounded"/> + <xs:element type="bindingType" name="binding" maxOccurs="unbounded" minOccurs="0"/> + </xs:choice> + <xs:attribute type="xs:string" name="name" use="required"/> + <xs:attribute type="exchangeType" name="type" use="required"/> + <xs:attribute name="connection" type="xs:string" use="required" /> + <xs:attribute type="xs:boolean" name="durable" use="optional"/> + <xs:attribute type="xs:boolean" name="autoDelete" use="optional"/> + <xs:attribute type="xs:boolean" name="internal" use="optional"/> + </xs:restriction> + </xs:complexContent> + </xs:complexType> + </xs:redefine> +</xs:schema> diff --git a/lib/internal/Magento/Framework/MessageQueue/registration.php b/lib/internal/Magento/Framework/MessageQueue/registration.php new file mode 100644 index 0000000000000..aafb0fcffa7c5 --- /dev/null +++ b/lib/internal/Magento/Framework/MessageQueue/registration.php @@ -0,0 +1,9 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +use \Magento\Framework\Component\ComponentRegistrar; + +ComponentRegistrar::register(ComponentRegistrar::LIBRARY, 'magento/framework-message-queue', __DIR__); diff --git a/lib/internal/Magento/Framework/Module/DbVersionInfo.php b/lib/internal/Magento/Framework/Module/DbVersionInfo.php index bc4f8eeeca40b..fdc74e412ab9d 100644 --- a/lib/internal/Magento/Framework/Module/DbVersionInfo.php +++ b/lib/internal/Magento/Framework/Module/DbVersionInfo.php @@ -130,17 +130,20 @@ private function getDataInfo($moduleName) * @param string $moduleName * @param string|bool $version * @return bool - * @throws \UnexpectedValueException */ private function isModuleVersionEqual($moduleName, $version) { $module = $this->moduleList->getOne($moduleName); - if (empty($module['setup_version'])) { - throw new \UnexpectedValueException("Setup version for module '$moduleName' is not specified"); + $configVer = isset($module['setup_version']) ? $module['setup_version'] : null; + + if (empty($configVer)) { + /** + * If setup_version was removed, this means that we want to ignore old scripts and do installation only + * with declarative schema and data/schema patches + */ + return true; } - $configVer = $module['setup_version']; - return ($version !== false - && version_compare($configVer, $version) === ModuleDataSetupInterface::VERSION_COMPARE_EQUAL); + return version_compare($configVer, $version) === ModuleDataSetupInterface::VERSION_COMPARE_EQUAL; } } diff --git a/lib/internal/Magento/Framework/Module/Declaration/Converter/Dom.php b/lib/internal/Magento/Framework/Module/Declaration/Converter/Dom.php index 4759ee7c4f3d4..990f72c536dd8 100644 --- a/lib/internal/Magento/Framework/Module/Declaration/Converter/Dom.php +++ b/lib/internal/Magento/Framework/Module/Declaration/Converter/Dom.php @@ -26,12 +26,8 @@ public function convert($source) throw new \Exception('Attribute "name" is required for module node.'); } $moduleData['name'] = $nameNode->nodeValue; - $name = $moduleData['name']; $versionNode = $moduleAttributes->getNamedItem('setup_version'); - if ($versionNode === null) { - throw new \Exception("Attribute 'setup_version' is missing for module '{$name}'."); - } - $moduleData['setup_version'] = $versionNode->nodeValue; + $moduleData['setup_version'] = $versionNode ? $versionNode->nodeValue : null; $moduleData['sequence'] = []; /** @var $childNode \DOMNode */ foreach ($moduleNode->childNodes as $childNode) { diff --git a/lib/internal/Magento/Framework/Module/Dir.php b/lib/internal/Magento/Framework/Module/Dir.php index 936fce3a046b7..77174bb51305d 100644 --- a/lib/internal/Magento/Framework/Module/Dir.php +++ b/lib/internal/Magento/Framework/Module/Dir.php @@ -20,6 +20,7 @@ class Dir const MODULE_I18N_DIR = 'i18n'; const MODULE_VIEW_DIR = 'view'; const MODULE_CONTROLLER_DIR = 'Controller'; + const MODULE_SETUP_DIR = 'Setup'; /**#@-*/ /**#@-*/ @@ -45,12 +46,19 @@ public function getDir($moduleName, $type = '') { $path = $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, $moduleName); + // An empty $type means it's getting the directory of the module itself. + if (empty($type) && !isset($path)) { + // Note: do not throw \LogicException, as it would break backwards-compatibility. + throw new \InvalidArgumentException("Module '$moduleName' is not correctly registered."); + } + if ($type) { if (!in_array($type, [ self::MODULE_ETC_DIR, self::MODULE_I18N_DIR, self::MODULE_VIEW_DIR, - self::MODULE_CONTROLLER_DIR + self::MODULE_CONTROLLER_DIR, + self::MODULE_SETUP_DIR ])) { throw new \InvalidArgumentException("Directory type '{$type}' is not recognized."); } diff --git a/lib/internal/Magento/Framework/Module/ModuleResource.php b/lib/internal/Magento/Framework/Module/ModuleResource.php index ed740d459060e..427f8a6f8e959 100644 --- a/lib/internal/Magento/Framework/Module/ModuleResource.php +++ b/lib/internal/Magento/Framework/Module/ModuleResource.php @@ -10,6 +10,9 @@ /** * Resource Model + * + * @deprecated Declarative schema and data patches replace old functionality and setup_module table + * So all resources related to this table, will be deprecated since 2.3.0 */ class ModuleResource extends AbstractDb implements ResourceInterface { @@ -134,4 +137,17 @@ public function setDataVersion($moduleName, $version) $this->getConnection()->insert($this->getMainTable(), $data); } } + + /** + * Flush all class cache + * + * @deprecated This method was added as temporary solution, to increase modularity: + * Because before new modules appears in resource only on next bootstrap + * @return void + */ + public static function flush() + { + self::$dataVersions = null; + self::$schemaVersions = []; + } } diff --git a/lib/internal/Magento/Framework/Module/Test/Unit/DbVersionInfoTest.php b/lib/internal/Magento/Framework/Module/Test/Unit/DbVersionInfoTest.php index f6c978c3cef96..c36d4bf7d5e93 100644 --- a/lib/internal/Magento/Framework/Module/Test/Unit/DbVersionInfoTest.php +++ b/lib/internal/Magento/Framework/Module/Test/Unit/DbVersionInfoTest.php @@ -65,6 +65,12 @@ public function testIsDbSchemaUpToDate($moduleName, $dbVersion, $expectedResult) ->method('getDbVersion') ->with($moduleName) ->will($this->returnValue($dbVersion)); + $this->moduleList->expects(self::once()) + ->method('getOne') + ->with($moduleName) + ->willReturn( + ['setup_version' => $dbVersion] + ); $this->assertEquals( $expectedResult, $this->dbVersionInfo->isSchemaUpToDate($moduleName) @@ -84,6 +90,12 @@ public function testIsDbDataUpToDate($moduleName, $dbVersion, $expectedResult) ->method('getDataVersion') ->with($moduleName) ->will($this->returnValue($dbVersion)); + $this->moduleList->expects(self::once()) + ->method('getOne') + ->with($moduleName) + ->willReturn( + ['setup_version' => $dbVersion] + ); $this->assertEquals( $expectedResult, $this->dbVersionInfo->isDataUpToDate($moduleName) @@ -142,20 +154,18 @@ public function testGetDbVersionErrors() } /** - * @expectedException \UnexpectedValueException - * @expectedExceptionMessage Setup version for module 'Module_No_Schema' is not specified + * Test is DB schema up to date for module with no schema */ public function testIsDbSchemaUpToDateException() { - $this->dbVersionInfo->isSchemaUpToDate('Module_No_Schema'); + $this->assertTrue($this->dbVersionInfo->isSchemaUpToDate('Module_No_Schema')); } /** - * @expectedException \UnexpectedValueException - * @expectedExceptionMessage Setup version for module 'Module_No_Schema' is not specified + * Test is DB Data up to date for module with no schema */ public function testIsDbDataUpToDateException() { - $this->dbVersionInfo->isDataUpToDate('Module_No_Schema'); + $this->assertTrue($this->dbVersionInfo->isDataUpToDate('Module_No_Schema')); } } diff --git a/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/DomTest.php b/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/DomTest.php index ec9b41ff1b957..bf878257c89de 100644 --- a/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/DomTest.php +++ b/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/DomTest.php @@ -47,7 +47,7 @@ public function convertWithInvalidDomDataProvider() return [ 'Module node without "name" attribute' => ['<?xml version="1.0"?><config><module /></config>'], 'Sequence module node without "name" attribute' => [ - '<?xml version="1.0"?><config><module name="Module_One" setup_version="1.0.0.0">' . + '<?xml version="1.0"?><config><module name="Module_One" >' . '<sequence><module/></sequence></module></config>', ], ]; diff --git a/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/_files/converted_valid_module.php b/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/_files/converted_valid_module.php index 810052fe5e237..d572cf2814fc9 100644 --- a/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/_files/converted_valid_module.php +++ b/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/_files/converted_valid_module.php @@ -6,12 +6,17 @@ return [ 'Module_One' => [ 'name' => 'Module_One', - 'setup_version' => '1.0.0.0', + 'setup_version' => null, + 'sequence' => [], + ], + 'Module_OneAndHalf' => [ + 'name' => 'Module_OneAndHalf', + 'setup_version' => '2.0', 'sequence' => [], ], 'Module_Two' => [ 'name' => 'Module_Two', - 'setup_version' => '2.0.0.0', + 'setup_version' => null, 'sequence' => ['Module_One'], ] ]; diff --git a/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/_files/valid_module.xml b/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/_files/valid_module.xml index cec18c9bae7cc..e55ebcdfd7c2f 100644 --- a/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/_files/valid_module.xml +++ b/lib/internal/Magento/Framework/Module/Test/Unit/Declaration/Converter/_files/valid_module.xml @@ -7,9 +7,11 @@ --> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd"> <!-- commented text --> - <module name="Module_One" setup_version="1.0.0.0"> + <module name="Module_One"> </module> - <module name="Module_Two" setup_version="2.0.0.0"> + <module name="Module_OneAndHalf" setup_version="2.0"> + </module> + <module name="Module_Two"> <sequence> <module name="Module_One" /> </sequence> diff --git a/lib/internal/Magento/Framework/Module/Test/Unit/DirTest.php b/lib/internal/Magento/Framework/Module/Test/Unit/DirTest.php index 335228888cc4b..a1c891df7bcb4 100644 --- a/lib/internal/Magento/Framework/Module/Test/Unit/DirTest.php +++ b/lib/internal/Magento/Framework/Module/Test/Unit/DirTest.php @@ -46,6 +46,16 @@ public function testGetDirModuleSubDir() $this->assertEquals('/Test/Module/etc', $this->_model->getDir('Test_Module', 'etc')); } + public function testGetSetupDirModule() + { + $this->moduleRegistryMock->expects($this->once()) + ->method('getPath') + ->with(ComponentRegistrar::MODULE, 'Test_Module') + ->willReturn('/Test/Module'); + + $this->assertEquals('/Test/Module/Setup', $this->_model->getDir('Test_Module', 'Setup')); + } + /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage Directory type 'unknown' is not recognized @@ -59,4 +69,17 @@ public function testGetDirModuleSubDirUnknown() $this->_model->getDir('Test_Module', 'unknown'); } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Module 'Test Module' is not correctly registered. + */ + public function testGetDirModuleIncorrectlyRegistered() + { + $this->moduleRegistryMock->expects($this->once()) + ->method('getPath') + ->with($this->identicalTo(ComponentRegistrar::MODULE), $this->identicalTo('Test Module')) + ->willReturn(null); + $this->_model->getDir('Test Module'); + } } diff --git a/lib/internal/Magento/Framework/Module/etc/module.xsd b/lib/internal/Magento/Framework/Module/etc/module.xsd index 839bddb982c73..ffc4101e70700 100644 --- a/lib/internal/Magento/Framework/Module/etc/module.xsd +++ b/lib/internal/Magento/Framework/Module/etc/module.xsd @@ -43,7 +43,7 @@ </xs:element> </xs:all> <xs:attribute name="name" type="moduleName" use="required" /> - <xs:attribute name="setup_version" type="setupVersion" use="required" /> + <xs:attribute name="setup_version" type="setupVersion" use="optional" /> </xs:complexType> <xs:complexType name="moduleSequence"> diff --git a/lib/internal/Magento/Framework/Session/SaveHandler/Redis/Config.php b/lib/internal/Magento/Framework/Session/SaveHandler/Redis/Config.php index 724f949ca5b23..5a4ed1700da55 100644 --- a/lib/internal/Magento/Framework/Session/SaveHandler/Redis/Config.php +++ b/lib/internal/Magento/Framework/Session/SaveHandler/Redis/Config.php @@ -100,6 +100,26 @@ class Config implements \Cm\RedisSession\Handler\ConfigInterface */ const PARAM_BREAK_AFTER = 'session/redis/break_after'; + /** + * Configuration path for comma separated list of sentinel servers + */ + const PARAM_SENTINEL_SERVERS = 'session/redis/sentinel_servers'; + + /** + * Configuration path for sentinel master + */ + const PARAM_SENTINEL_MASTER = 'session/redis/sentinel_master'; + + /** + * Configuration path for verify sentinel master flag + */ + const PARAM_SENTINEL_VERIFY_MASTER = 'session/redis/sentinel_verify_master'; + + /** + * Configuration path for number of sentinel connection retries + */ + const PARAM_SENTINEL_CONNECT_RETRIES = 'session/redis/sentinel_connect_retries'; + /** * Cookie lifetime config path */ @@ -115,6 +135,11 @@ class Config implements \Cm\RedisSession\Handler\ConfigInterface */ const SESSION_MAX_LIFETIME = 31536000; + /** + * Try to break lock for at most this many seconds + */ + const DEFAULT_FAIL_AFTER = 15; + /** * Deployment config * @@ -293,4 +318,44 @@ public function getLifetime() } return (int)$this->scopeConfig->getValue(self::XML_PATH_COOKIE_LIFETIME, StoreScopeInterface::SCOPE_STORE); } + + /** + * {@inheritdoc} + */ + public function getSentinelServers() + { + return $this->deploymentConfig->get(self::PARAM_SENTINEL_SERVERS); + } + + /** + * {@inheritdoc} + */ + public function getSentinelMaster() + { + return $this->deploymentConfig->get(self::PARAM_SENTINEL_MASTER); + } + + /** + * {@inheritdoc} + */ + public function getSentinelVerifyMaster() + { + return $this->deploymentConfig->get(self::PARAM_SENTINEL_VERIFY_MASTER); + } + + /** + * {@inheritdoc} + */ + public function getSentinelConnectRetries() + { + return $this->deploymentConfig->get(self::PARAM_SENTINEL_CONNECT_RETRIES); + } + + /** + * {@inheritdoc} + */ + public function getFailAfter() + { + return self::DEFAULT_FAIL_AFTER; + } } diff --git a/lib/internal/Magento/Framework/Session/SidResolver.php b/lib/internal/Magento/Framework/Session/SidResolver.php index 18f6138b661bf..feb4877028dae 100644 --- a/lib/internal/Magento/Framework/Session/SidResolver.php +++ b/lib/internal/Magento/Framework/Session/SidResolver.php @@ -7,6 +7,8 @@ */ namespace Magento\Framework\Session; +use Magento\Framework\App\State; + class SidResolver implements SidResolverInterface { /** @@ -54,34 +56,47 @@ class SidResolver implements SidResolverInterface */ protected $_scopeType; + /** + * @var State + */ + private $appState; + /** * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig * @param \Magento\Framework\UrlInterface $urlBuilder * @param \Magento\Framework\App\RequestInterface $request * @param string $scopeType * @param array $sidNameMap + * @param State|null $appState */ public function __construct( \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, \Magento\Framework\UrlInterface $urlBuilder, \Magento\Framework\App\RequestInterface $request, $scopeType, - array $sidNameMap = [] + array $sidNameMap = [], + State $appState = null ) { $this->scopeConfig = $scopeConfig; $this->urlBuilder = $urlBuilder; $this->request = $request; $this->sidNameMap = $sidNameMap; $this->_scopeType = $scopeType; + $this->appState = $appState ?: \Magento\Framework\App\ObjectManager::getInstance()->get(State::class); } /** * @param SessionManagerInterface $session - * @return string + * @return string|null */ public function getSid(SessionManagerInterface $session) { + if ($this->appState->getAreaCode() !== \Magento\Framework\App\Area::AREA_FRONTEND) { + return null; + } + $sidKey = null; + $useSidOnFrontend = $this->getUseSessionInUrl(); if ($useSidOnFrontend && $this->request->getQuery( $this->getSessionIdQueryParam($session), diff --git a/lib/internal/Magento/Framework/Session/SidResolverInterface.php b/lib/internal/Magento/Framework/Session/SidResolverInterface.php index 8dd044adb6860..6f242c1c9e308 100644 --- a/lib/internal/Magento/Framework/Session/SidResolverInterface.php +++ b/lib/internal/Magento/Framework/Session/SidResolverInterface.php @@ -22,7 +22,7 @@ interface SidResolverInterface * Get SID * * @param \Magento\Framework\Session\SessionManagerInterface $session - * @return string + * @return string|null */ public function getSid(\Magento\Framework\Session\SessionManagerInterface $session); diff --git a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php index 26f3d4c4c4e89..2859b486ec7a1 100644 --- a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php +++ b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php @@ -246,4 +246,49 @@ public function testGetLifetimeFrontend() ->willReturn($expectedLifetime); $this->assertEquals($this->config->getLifetime(), $expectedLifetime); } + + public function testGetSentinelServers() + { + $expected = 'server-1,server-2'; + $this->deploymentConfigMock->expects($this->once()) + ->method('get') + ->with(Config::PARAM_SENTINEL_SERVERS) + ->willReturn($expected); + $this->assertEquals($expected, $this->config->getSentinelServers()); + } + + public function testGetSentinelMaster() + { + $expected = 'master'; + $this->deploymentConfigMock->expects($this->once()) + ->method('get') + ->with(Config::PARAM_SENTINEL_MASTER) + ->willReturn($expected); + $this->assertEquals($this->config->getSentinelMaster(), $expected); + } + + public function testGetSentinelVerifyMaster() + { + $expected = '1'; + $this->deploymentConfigMock->expects($this->once()) + ->method('get') + ->with(Config::PARAM_SENTINEL_VERIFY_MASTER) + ->willReturn($expected); + $this->assertEquals($this->config->getSentinelVerifyMaster(), $expected); + } + + public function testGetSentinelConnectRetries() + { + $expected = '10'; + $this->deploymentConfigMock->expects($this->once()) + ->method('get') + ->willReturn(Config::PARAM_SENTINEL_CONNECT_RETRIES) + ->willReturn($expected); + $this->assertEquals($this->config->getSentinelConnectRetries(), $expected); + } + + public function testGetFailAfter() + { + $this->assertEquals($this->config->getFailAfter(), Config::DEFAULT_FAIL_AFTER); + } } diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Comparator.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Comparator.php similarity index 77% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Comparator.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Comparator.php index b862e19ced39f..0c1f9ae42eaf3 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Comparator.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Comparator.php @@ -4,10 +4,10 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema; +namespace Magento\Framework\Setup\Declaration\Schema; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; /** * Comparator allows to compare only sensitive params of 2 nodes diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Config/Converter.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Config/Converter.php new file mode 100644 index 0000000000000..ed3f6326cd604 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Config/Converter.php @@ -0,0 +1,124 @@ +<?php +/** + * Attributes configuration converter + * + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Config; + +/** + * This converter is required for Declaration Filesystem reader: + * + * @see \Magento\Framework\Setup\Declaration\Schema\FileSystem\XmlReader + * + * Allows to convert declarative schema to raw array and add default values + * for column types and for constraints. + */ +class Converter implements \Magento\Framework\Config\ConverterInterface +{ + /** + * Convert config from XML to array. + * + * @param \DOMDocument $source + * @return array + */ + public function convert($source) + { + $output = $this->recursiveConvert($this->getTablesNode($source)); + return $output; + } + + /** + * We exactly know, that our schema is consists from tables. + * So we do not need root elements in result, only table names. + * So proposed to select only tables from all DOMDocument. + * + * @param \DOMDocument $element + * @return \DOMNodeList + */ + private function getTablesNode(\DOMDocument $element) + { + return $element->getElementsByTagName('table'); + } + + /** + * Convert elements. + * + * @param \Traversable $source + * @return array + */ + private function recursiveConvert(\Traversable $source) + { + $output = []; + foreach ($source as $element) { + if ($element instanceof \DOMElement) { + $key = $element->getAttribute('name'); + + if ($element->hasChildNodes()) { + $output[$element->tagName][$key] = + array_replace( + $this->recursiveConvert($element->childNodes), + $this->interpretateAttributes($element) + ); + } else if ($this->hasAttributesExceptName($element)) { + $output[$element->tagName][$key] = $this->interpretateAttributes($element); + } else { + $output[$element->tagName][$key] = $key; + } + } + } + + return $output; + } + + /** + * Check whether we have any attributes except name XSI:TYPE is in another namespace. + * Note: name is mandatory attribute. + * + * @param \DOMElement $element + * @return bool + */ + private function hasAttributesExceptName(\DOMElement $element) + { + return $element->hasAttribute('xsi:type') || $element->attributes->length >= 2; + } + + /** + * Mix attributes that comes from XML schema with default ones. + * So if you will not have some attribute in schema - it will be taken from default one. + * + * @param \DOMElement $domElement + * @return mixed + */ + private function interpretateAttributes(\DOMElement $domElement) + { + $attributes = $this->getAttributes($domElement); + $xsiType = $domElement->getAttribute('xsi:type'); + + if ($xsiType) { + $attributes['type'] = $xsiType; + } + + return $attributes; + } + + /** + * Convert XML attributes into raw array with attributes. + * + * @param \DOMElement $element + * @return array + */ + private function getAttributes(\DOMElement $element) + { + $attributes = []; + $attributeNodes = $element->attributes; + + /** @var \DOMAttr $attribute */ + foreach ($attributeNodes as $domAttr) { + $attributes[$domAttr->name] = $domAttr->value; + } + + return $attributes; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Config/SchemaLocator.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Config/SchemaLocator.php new file mode 100644 index 0000000000000..5319c469f0458 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Config/SchemaLocator.php @@ -0,0 +1,60 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Config; + +/** + * This is system class that provides .xsd file for validation XML schema. + */ +class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface +{ + /** + * Path to corresponding XSD file with validation rules for merged config. + * + * @var string + */ + protected $_schema = null; + + /** + * Path to corresponding XSD file with validation rules for separate config files. + * + * @var string + */ + protected $_perFileSchema = null; + + /** + * Constructor. + * + * @param \Magento\Framework\Config\Dom\UrnResolver $urnResolver + * @param string $schemaUrn + */ + public function __construct( + \Magento\Framework\Config\Dom\UrnResolver $urnResolver, + $schemaUrn = 'urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd' + ) { + $this->_schema = $urnResolver->getRealPath($schemaUrn); + $this->_perFileSchema = $this->_schema; + } + + /** + * Get path to merged config schema. + * + * @return string|null + */ + public function getSchema() + { + return $this->_schema; + } + + /** + * Get path to pre file validation schema. + * + * @return string|null + */ + public function getPerFileSchema() + { + return $this->_perFileSchema; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/ColumnSavior.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/ColumnSavior.php new file mode 100644 index 0000000000000..8394e9e16208e --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/ColumnSavior.php @@ -0,0 +1,173 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\DataSavior; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\SelectFactory; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Allows to dump and restore data for one specific field + */ +class ColumnSavior implements DataSaviorInterface +{ + /** + * @var SelectGeneratorFactory + */ + private $selectGeneratorFactory; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var UniqueConstraintsResolver + */ + private $uniqueConstraintsResolver; + + /** + * @var DumpAccessorInterface + */ + private $dumpAccessor; + + /** + * @var SelectFactory + */ + private $selectFactory; + + /** + * TableDump constructor. + * @param ResourceConnection $resourceConnection + * @param SelectGeneratorFactory $selectGeneratorFactory + * @param DumpAccessorInterface $dumpAccessor + * @param UniqueConstraintsResolver $uniqueConstraintsResolver + * @param SelectFactory $selectFactory + */ + public function __construct( + ResourceConnection $resourceConnection, + SelectGeneratorFactory $selectGeneratorFactory, + DumpAccessorInterface $dumpAccessor, + UniqueConstraintsResolver $uniqueConstraintsResolver, + SelectFactory $selectFactory + ) { + $this->selectGeneratorFactory = $selectGeneratorFactory; + $this->resourceConnection = $resourceConnection; + $this->uniqueConstraintsResolver = $uniqueConstraintsResolver; + $this->dumpAccessor = $dumpAccessor; + $this->selectFactory = $selectFactory; + } + + /** + * Prepare select to database + * + * @param Column $column + * @param array $fieldsToDump + * @return \Magento\Framework\DB\Select + */ + private function prepareColumnSelect(Column $column, array $fieldsToDump) + { + $adapter = $this->resourceConnection->getConnection($column->getTable()->getResource()); + $select = $this->selectFactory->create($adapter); + $select->from($column->getTable()->getName(), $fieldsToDump); + return $select; + } + + /** + * @inheritdoc + * @param Column | ElementInterface $column + * @return void + */ + public function dump(ElementInterface $column) + { + $columns = $this->uniqueConstraintsResolver->resolve($column->getTable()); + + /** + * Only if table have unique keys or primary key + */ + if ($columns) { + $connectionName = $column->getTable()->getResource(); + $columns[] = $column->getName(); + $select = $this->prepareColumnSelect($column, $columns); + $selectGenerator = $this->selectGeneratorFactory->create(); + $resourceSignature = $this->generateDumpFileSignature($column); + + foreach ($selectGenerator->generator($select, $connectionName) as $data) { + $this->dumpAccessor->save($resourceSignature, $data); + } + } + } + + /** + * Do Insert on duplicate to table, where field should be restored + * + * @param Table $table + * @param array $data + */ + private function applyDumpChunk(Table $table, $data) + { + $columns = []; + $adapter = $this->resourceConnection->getConnection($table->getResource()); + $firstRow = reset($data); + + /** + * Prepare all table fields + */ + foreach ($table->getColumns() as $column) { + $columns[$column->getName()] = $column->getName(); + } + + $adapter->insertOnDuplicate($table->getName(), $data, array_keys($firstRow)); + } + + /** + * @param Column | ElementInterface $column + * @return string + */ + private function generateDumpFileSignature(Column $column) + { + $dimensions = [ + $column->getTable()->getName(), + $column->getElementType(), + $column->getName() + ]; + + return implode("_", $dimensions); + } + + /** + * @param Column | ElementInterface $column + * @inheritdoc + */ + public function restore(ElementInterface $column) + { + $file = $this->generateDumpFileSignature($column); + $generator = $this->dumpAccessor->read($file); + + while ($generator->valid()) { + $data = $generator->current(); + $this->applyDumpChunk( + $column->getTable(), + $data + ); + $generator->next(); + } + + $this->dumpAccessor->destruct($file); + } + + /** + * @param ElementInterface $element + * @return bool + */ + public function isAcceptable(ElementInterface $element) + { + return $element instanceof Column; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/DataSaviorInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/DataSaviorInterface.php new file mode 100644 index 0000000000000..d8453b3a76222 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/DataSaviorInterface.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\DataSavior; + +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * This interface allows to dump data during declarative installation process + * and revert changes with applying previously saved data, if something goes wrong + */ +interface DataSaviorInterface +{ + /** + * Generate dump file by element + * + * For example, it can generate file for removed column is_allowed, in this case + * this file will consists of data in is_allowed column and additional data, that allows + * to identify each `is_allowed` value + * + * @param ElementInterface $element + * @return void + */ + public function dump(ElementInterface $element); + + /** + * Find the field, that was backed up by file name, and tries to restore data + * that is in this file + * + * @param ElementInterface $element + * @return mixed + */ + public function restore(ElementInterface $element); + + /** + * Check whether this element is acceptable by current implementation of data savior + * + * @param ElementInterface $element + * @return bool + */ + public function isAcceptable(ElementInterface $element); +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/DumpAccessorInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/DumpAccessorInterface.php new file mode 100644 index 0000000000000..dbfb5eb8512c5 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/DumpAccessorInterface.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\DataSavior; + +/** + * Allows to access dump, that can be persisted in any file format or in database + */ +interface DumpAccessorInterface +{ + /** + * Allows to persist data to different sources: file, database, etc + * + * @param string $resource - can be for example absolute path to file + * @param array $data - data format, in which data should be stored + * @return void + */ + public function save($resource, array $data); + + /** + * Allows to read data by batches from different resources + * + * By resource means connection to database to absolute path to file, depends to implementation + * + * @param string $resource + * @return \Generator + */ + public function read($resource); + + /** + * Destruct resource + * + * @param string $resource + * @return void + */ + public function destruct($resource); +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/SelectGenerator.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/SelectGenerator.php new file mode 100644 index 0000000000000..9e560acf1f62a --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/SelectGenerator.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\DataSavior; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Db\Select; + +/** + * Yields data from database by select objects + */ +class SelectGenerator +{ + /** + * @var int + */ + private $batchSize = 12000; + + /** + * @var int + */ + private $baseBatchSize; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * TableDump constructor. + * @param ResourceConnection $resourceConnection + * @param int $baseBatchSize + */ + public function __construct( + ResourceConnection $resourceConnection, + $baseBatchSize = 15000 + ) { + $this->baseBatchSize = $baseBatchSize; + $this->resourceConnection = $resourceConnection; + } + + /** + * It retrieves data by batches + * + * Select generator do not know what data he will fetch, so you need to pass builded Select statement in it + * + * @param Select $select + * @param string $connectionName + * @return \Generator + */ + public function generator(Select $select, $connectionName) + { + $page = 0; + $select->limit($this->batchSize, $page * $this->batchSize); + $adapter = $this->resourceConnection->getConnection($connectionName); + $data = $adapter->fetchAll($select); + yield $data; + + while (count($data)) { + ++$page; + $select->limit($this->batchSize, $page * $this->batchSize + 1); + $data = $adapter->fetchAll($select); + yield $data; + } + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/SelectGeneratorFactory.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/SelectGeneratorFactory.php new file mode 100644 index 0000000000000..35b39a520d2d7 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/SelectGeneratorFactory.php @@ -0,0 +1,48 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\DataSavior; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Factory which allows to create SQL select generator + */ +class SelectGeneratorFactory +{ + /** + * @var string + */ + private $instanceName; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * SelectGeneratorFactory constructor. + * @param ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + ObjectManagerInterface $objectManager, + $instanceName = SelectGenerator::class + ) { + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters + * + * @return SelectGenerator + */ + public function create() + { + return $this->objectManager->create($this->instanceName); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/TableSavior.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/TableSavior.php new file mode 100644 index 0000000000000..806f5df0c774e --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/TableSavior.php @@ -0,0 +1,155 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\DataSavior; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\SelectFactory; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Allows to dump and restore data for specific table + */ +class TableSavior implements DataSaviorInterface +{ + /** + * @var SelectGeneratorFactory + */ + private $selectGeneratorFactory; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var DumpAccessorInterface + */ + private $dumpAccessor; + + /** + * @var SelectFactory + */ + private $selectFactory; + + /** + * TableDump constructor. + * @param ResourceConnection $resourceConnection + * @param SelectGeneratorFactory $selectGeneratorFactory + * @param DumpAccessorInterface $dumpAccessor + * @param SelectFactory $selectFactory + */ + public function __construct( + ResourceConnection $resourceConnection, + SelectGeneratorFactory $selectGeneratorFactory, + DumpAccessorInterface $dumpAccessor, + SelectFactory $selectFactory + ) { + $this->selectGeneratorFactory = $selectGeneratorFactory; + $this->resourceConnection = $resourceConnection; + $this->dumpAccessor = $dumpAccessor; + $this->selectFactory = $selectFactory; + } + + /** + * Prepare select to database + * + * @param Table $table + * @return \Magento\Framework\DB\Select + */ + private function prepareTableSelect(Table $table) + { + $adapter = $this->resourceConnection->getConnection($table->getResource()); + $select = $this->selectFactory->create($adapter); + $select->from($table->getName()); + return $select; + } + + /** + * @inheritdoc + * @param Table | ElementInterface $table + * @return void + */ + public function dump(ElementInterface $table) + { + $connectionName = $table->getResource(); + $select = $this->prepareTableSelect($table); + $selectGenerator = $this->selectGeneratorFactory->create(); + $resourceSignature = $this->generateDumpFileSignature($table); + + foreach ($selectGenerator->generator($select, $connectionName) as $data) { + $this->dumpAccessor->save($resourceSignature, $data); + } + } + + /** + * Prepare list of column names + * + * @param Table $table + * @return array + */ + private function getTableColumnNames(Table $table) + { + $columns = []; + /** + * Prepare all table fields + */ + foreach ($table->getColumns() as $column) { + $columns[] = $column->getName(); + } + + return $columns; + } + + /** + * Do Insert to table, that should be restored + * + * @param Table $table + * @param array $data + */ + private function applyDumpChunk(Table $table, $data) + { + $columns = $this->getTableColumnNames($table); + $adapter = $this->resourceConnection->getConnection($table->getResource()); + $adapter->insertArray($table->getName(), $columns, $data); + } + + /** + * @param Table $table + * @return string + */ + private function generateDumpFileSignature(Table $table) + { + return $table->getName(); + } + + /** + * @param Table | ElementInterface $table + * @inheritdoc + */ + public function restore(ElementInterface $table) + { + $file = $this->generateDumpFileSignature($table); + $generator = $this->dumpAccessor->read($file); + + while ($generator->valid()) { + $data = $generator->current(); + $this->applyDumpChunk($table, $data); + $generator->next(); + } + + $this->dumpAccessor->destruct($file); + } + + /** + * @inheritdoc + */ + public function isAcceptable(ElementInterface $element) + { + return $element instanceof Table; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/UniqueConstraintsResolver.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/UniqueConstraintsResolver.php new file mode 100644 index 0000000000000..823f6e3e91590 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DataSavior/UniqueConstraintsResolver.php @@ -0,0 +1,41 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\DataSavior; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Search for any unique constraints in table + */ +class UniqueConstraintsResolver +{ + /** + * Retrieve list of all columns that are in one unique constraints. Yields the first constraint and stop on it + * + * @param Table $table + * @return array | bool If method return false, it means that table do not have any unique constraints and can`t be + * processed + */ + public function resolve(Table $table) + { + $primaryKey = $table->getPrimaryConstraint(); + if ($primaryKey) { + return $primaryKey->getColumnNames(); + } + + $constraints = $table->getConstraints(); + + foreach ($constraints as $constraint) { + if ($constraint instanceof Internal) { + return $constraint->getColumnNames(); + } + } + + return false; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/DDLTriggerInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DDLTriggerInterface.php similarity index 84% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/DDLTriggerInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DDLTriggerInterface.php index ede8f74cd101e..fa074d4ba16d3 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/DDLTriggerInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DDLTriggerInterface.php @@ -4,9 +4,9 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Declaration\Schema\Db; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; /** * DDL triggers is events that can be fired: @@ -31,7 +31,7 @@ public function isApplicable($statement); * Setup callback to current statement, can generate new statements. * * @param ElementInterface $element - * @return Callable + * @return callable */ public function getCallback(ElementInterface $element); } diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/DbDefinitionProcessorInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DbDefinitionProcessorInterface.php similarity index 85% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/DbDefinitionProcessorInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DbDefinitionProcessorInterface.php index b9837937d9951..1bfae47601568 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/DbDefinitionProcessorInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DbDefinitionProcessorInterface.php @@ -4,9 +4,9 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Declaration\Schema\Db; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; /** * Do processing strings to desired format: diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/DbSchemaReaderInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DbSchemaReaderInterface.php similarity index 96% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/DbSchemaReaderInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DbSchemaReaderInterface.php index af34442d894d7..9f1391970e975 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/DbSchemaReaderInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DbSchemaReaderInterface.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Declaration\Schema\Db; /** * This class is responsible for read different schema diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/DbSchemaWriterInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DbSchemaWriterInterface.php similarity index 96% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/DbSchemaWriterInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DbSchemaWriterInterface.php index 6f06b7e49efd0..d8c2e7148562d 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/DbSchemaWriterInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DbSchemaWriterInterface.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Declaration\Schema\Db; /** * This class is responsible for read different schema structural elements: indexes, constraints, @@ -109,7 +109,8 @@ public function dropElement($resource, $elementName, $tableName, $type); * Compile statements and make SQL request from them. * * @param StatementAggregator $statementAggregator + * @param bool $dryRun * @return void */ - public function compile(StatementAggregator $statementAggregator); + public function compile(StatementAggregator $statementAggregator, $dryRun); } diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/DefinitionAggregator.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DefinitionAggregator.php similarity index 92% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/DefinitionAggregator.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DefinitionAggregator.php index 1785058c6b672..f9918a1b8d504 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/DefinitionAggregator.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/DefinitionAggregator.php @@ -4,9 +4,9 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Declaration\Schema\Db; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; /** * Holds different definitions and apply them depends on column, constraint, index types. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DDL/Triggers/MigrateDataFrom.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/DDL/Triggers/MigrateDataFrom.php similarity index 86% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DDL/Triggers/MigrateDataFrom.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/DDL/Triggers/MigrateDataFrom.php index 61651403d2841..b2cc0f4d91379 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DDL/Triggers/MigrateDataFrom.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/DDL/Triggers/MigrateDataFrom.php @@ -4,13 +4,13 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\DDL\Triggers; +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\DDL\Triggers; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Sql\Expression; -use Magento\Setup\Model\Declaration\Schema\Db\DDLTriggerInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DDLTriggerInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; /** * Used to migrate data from one column to another in scope of one table. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DbSchemaReader.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/DbSchemaReader.php similarity index 95% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DbSchemaReader.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/DbSchemaReader.php index 96edcfab68be3..fed4aa32d9e56 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DbSchemaReader.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/DbSchemaReader.php @@ -4,13 +4,13 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL; +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Sql\Expression; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaReaderInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DefinitionAggregator; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraint; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaReaderInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DefinitionAggregator; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraint; /** * @inheritdoc diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DbSchemaWriter.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/DbSchemaWriter.php similarity index 75% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DbSchemaWriter.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/DbSchemaWriter.php index 40f97ef43d0c9..ab3d0c7fb0be7 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DbSchemaWriter.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/DbSchemaWriter.php @@ -4,18 +4,17 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL; +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL; use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Constraints\Internal; -use Magento\Setup\Model\Declaration\Schema\Db\Statement; -use Magento\Setup\Model\Declaration\Schema\Db\StatementAggregator; -use Magento\Setup\Model\Declaration\Schema\Db\StatementFactory; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraint; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\Statement; +use Magento\Framework\Setup\Declaration\Schema\Db\StatementAggregator; +use Magento\Framework\Setup\Declaration\Schema\Db\StatementFactory; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraint; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\DryRunLogger; /** * @inheritdoc @@ -43,18 +42,26 @@ class DbSchemaWriter implements DbSchemaWriterInterface */ private $statementFactory; + /** + * @var DryRunLogger + */ + private $dryRunLogger; + /** * Constructor. * * @param ResourceConnection $resourceConnection * @param StatementFactory $statementFactory + * @param DryRunLogger $dryRunLogger */ public function __construct( ResourceConnection $resourceConnection, - StatementFactory $statementFactory + StatementFactory $statementFactory, + DryRunLogger $dryRunLogger ) { $this->resourceConnection = $resourceConnection; $this->statementFactory = $statementFactory; + $this->dryRunLogger = $dryRunLogger; } /** @@ -110,7 +117,7 @@ private function getDropElementSQL($type, $name) return 'DROP PRIMARY KEY'; case Constraint::UNIQUE_TYPE: return sprintf('DROP KEY %s', $name); - case \Magento\Setup\Model\Declaration\Schema\Dto\Index::TYPE: + case \Magento\Framework\Setup\Declaration\Schema\Dto\Index::TYPE: return sprintf('DROP INDEX %s', $name); case Reference::TYPE: return sprintf('DROP FOREIGN KEY %s', $name); @@ -217,7 +224,7 @@ public function resetAutoIncrement($tableName, $resource) /** * @inheritdoc */ - public function compile(StatementAggregator $statementAggregator) + public function compile(StatementAggregator $statementAggregator, $dryRun) { foreach ($statementAggregator->getStatementsBank() as $statementBank) { $statementsSql = []; @@ -225,18 +232,28 @@ public function compile(StatementAggregator $statementAggregator) foreach ($statementBank as $statement) { $statementsSql[] = $statement->getStatement(); } - $adapter = $this->resourceConnection->getConnection($statement->getResource()); - $adapter->query( - sprintf( - $this->statementDirectives[$statement->getType()], - $adapter->quoteIdentifier($statement->getTableName()), - implode(", ", $statementsSql) - ) - ); - //Do post update, like SQL DML operations or etc... - foreach ($statement->getTriggers() as $trigger) { - call_user_func($trigger); + + if ($dryRun) { + $this->dryRunLogger->log( + sprintf( + $this->statementDirectives[$statement->getType()], + $adapter->quoteIdentifier($statement->getTableName()), + implode(", ", $statementsSql) + ) + ); + } else { + $adapter->query( + sprintf( + $this->statementDirectives[$statement->getType()], + $adapter->quoteIdentifier($statement->getTableName()), + implode(", ", $statementsSql) + ) + ); + //Do post update, like SQL DML operations or etc... + foreach ($statement->getTriggers() as $trigger) { + call_user_func($trigger); + } } } } diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Blob.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Blob.php new file mode 100644 index 0000000000000..213e4a52beee0 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Blob.php @@ -0,0 +1,77 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Process blob and text types. + * + * @inheritdoc + */ +class Blob implements DbDefinitionProcessorInterface +{ + /** + * @var Nullable + */ + private $nullable; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + /** + * @var Comment + */ + private $comment; + + /** + * Blob constructor. + * + * @param Nullable $nullable + * @param Comment $comment + * @param ResourceConnection $resourceConnection + */ + public function __construct( + Nullable $nullable, + Comment $comment, + ResourceConnection $resourceConnection + ) { + $this->nullable = $nullable; + $this->resourceConnection = $resourceConnection; + $this->comment = $comment; + } + + /** + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + return sprintf( + '%s %s %s %s', + $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), + $column->getType(), + $this->nullable->toDefinition($column), + $this->comment->toDefinition($column) + ); + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + $matches = []; + if (preg_match('/^text\s*\((\d+)\)/', $data['definition'], $matches) && isset($matches[1])) { + $data['length'] = $matches[1]; + } + + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Boolean.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Boolean.php new file mode 100644 index 0000000000000..5b8c5e2d4a60b --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Boolean.php @@ -0,0 +1,103 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * As all MySQL aliases as BOOL or BOOLEAN are converted to TINYINT(1) + * proposed to processed tinyint as boolean. + * + * @inheritdoc + */ +class Boolean implements DbDefinitionProcessorInterface +{ + /** + * Type the column is persisted with. + */ + const TYPE = 'BOOLEAN'; + + /** + * Type of integer that is used in MySQL for boolean. + */ + const INTEGER_TYPE = 'tinyint'; + + /** + * Padding for integer described below. + */ + const INTEGER_PADDING = '1'; + + /** + * @var Nullable + */ + private $nullable; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var Comment + */ + private $comment; + + /** + * Constructor. + * + * @param Nullable $nullable + * @param ResourceConnection $resourceConnection + * @param Comment $comment + */ + public function __construct( + Nullable $nullable, + ResourceConnection $resourceConnection, + Comment $comment + ) { + $this->nullable = $nullable; + $this->resourceConnection = $resourceConnection; + $this->comment = $comment; + } + + /** + * @param \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Boolean $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + return sprintf( + '%s %s %s %s %s', + $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), + self::TYPE, + $this->nullable->toDefinition($column), + $column->getDefault() !== null ? + sprintf('DEFAULT %s', $column->getDefault() ? 1 : 0) : '', + $this->comment->toDefinition($column) + ); + } + + /** + * Boolean is presented as tinyint(1). + * + * @inheritdoc + */ + public function fromDefinition(array $data) + { + if ($data['type'] === self::INTEGER_TYPE && $data['padding'] === self::INTEGER_PADDING) { + $data['type'] = strtolower(self::TYPE); + if (isset($data['default'])) { + $data['default'] = $data['default'] === null ? null : (bool) $data['default']; + } + $data['unsigned'] = false; //Not signed for boolean + unset($data['padding']); + } + + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Comment.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Comment.php new file mode 100644 index 0000000000000..203c9d7f86280 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Comment.php @@ -0,0 +1,37 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\ColumnNullableAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Comment definition processor. + * + * @inheritdoc + */ +class Comment implements DbDefinitionProcessorInterface +{ + /** + * @param Column $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + return $column->getComment() !== null ? sprintf('COMMENT "%s"', $column->getComment()) : ''; + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Date.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Date.php new file mode 100644 index 0000000000000..bc933e12f67b6 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Date.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Date type processor. + * + * @inheritdoc + */ +class Date implements DbDefinitionProcessorInterface +{ + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var Comment + */ + private $comment; + + /** + * @var Nullable + */ + private $nullable; + + /** + * Constructor. + * + * @param ResourceConnection $resourceConnection + * @param Nullable $nullable + * @param Comment $comment + */ + public function __construct(ResourceConnection $resourceConnection, Nullable $nullable, Comment $comment) + { + $this->resourceConnection = $resourceConnection; + $this->comment = $comment; + $this->nullable = $nullable; + } + + /** + * @param \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + return sprintf( + '%s %s %s %s', + $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), + $column->getType(), + $this->nullable->toDefinition($column), + $this->comment->toDefinition($column) + ); + } + + /** + * @inheritdoc + * @codeCoverageIgnore + */ + public function fromDefinition(array $data) + { + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Identity.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Identity.php new file mode 100644 index 0000000000000..cf0c2b6edd2c9 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Identity.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\ColumnIdentityAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Identity (auto_increment) column processor. + * + * @inheritdoc + */ +class Identity implements DbDefinitionProcessorInterface +{ + /** + * Auto increment flag. + */ + const IDENTITY_FLAG = 'auto_increment'; + + /** + * @param ColumnIdentityAwareInterface $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + return $column->isIdentity() ? strtoupper(self::IDENTITY_FLAG) : ''; + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + if (!empty($data['extra']) && stripos($data['extra'], self::IDENTITY_FLAG) !== false) { + $data['identity'] = true; + } + + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Integer.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Integer.php new file mode 100644 index 0000000000000..07ba03d033106 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Integer.php @@ -0,0 +1,119 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Integer type processor. + * + * Processes integer type and separate it on type and padding. + * + * @inheritdoc + */ +class Integer implements DbDefinitionProcessorInterface +{ + /** + * @var Unsigned + */ + private $unsigned; + + /** + * @var \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean + */ + private $boolean; + + /** + * @var Nullable + */ + private $nullable; + + /** + * @var Identity + */ + private $identity; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var Comment + */ + private $comment; + + /** + * Constructor. + * + * @param Unsigned $unsigned + * @param bool $boolean + * @param Nullable $nullable + * @param Identity $identity + * @param Comment $comment + * @param ResourceConnection $resourceConnection + */ + public function __construct( + Unsigned $unsigned, + Boolean $boolean, + Nullable $nullable, + Identity $identity, + Comment $comment, + ResourceConnection $resourceConnection + ) { + $this->unsigned = $unsigned; + $this->boolean = $boolean; + $this->nullable = $nullable; + $this->identity = $identity; + $this->resourceConnection = $resourceConnection; + $this->comment = $comment; + } + + /** + * @param \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + return sprintf( + '%s %s(%s) %s %s %s %s %s', + $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), + $column->getType(), + $column->getPadding(), + $this->unsigned->toDefinition($column), + $this->nullable->toDefinition($column), + $column->getDefault() !== null ? + sprintf('DEFAULT %s', (string) intval($column->getDefault())) : '', + $this->identity->toDefinition($column), + $this->comment->toDefinition($column) + ); + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + $matches = []; + if (preg_match('/^(big|small|tiny|medium)?int\((\d+)\)/', $data['definition'], $matches)) { + /** + * match[1] - prefix + * match[2] - padding, like 5 or 11 + */ + //Use shortcut for mediuminteger + $data['padding'] = $matches[2]; + $data = $this->unsigned->fromDefinition($data); + $data = $this->nullable->fromDefinition($data); + $data = $this->identity->fromDefinition($data); + $data = $this->boolean->fromDefinition($data); + } + + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Nullable.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Nullable.php new file mode 100644 index 0000000000000..95b2a5eed5476 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Nullable.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\ColumnNullableAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Nullable columns processor. + * + * @inheritdoc + */ +class Nullable implements DbDefinitionProcessorInterface +{ + /** + * @param ColumnNullableAwareInterface $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + if ($column instanceof ColumnNullableAwareInterface) { + return $column->isNullable() ? 'NULL' : 'NOT NULL'; + } + + return ''; + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdate.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdate.php new file mode 100644 index 0000000000000..187f710b40edf --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdate.php @@ -0,0 +1,45 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * On update statement processor. + * + * @inheritdoc + */ +class OnUpdate implements DbDefinitionProcessorInterface +{ + /** + * @param \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + if ($column instanceof \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp) { + return $column->getOnUpdate() ? + 'ON UPDATE CURRENT_TIMESTAMP' : ''; + } + + return ''; + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + $matches = []; + if (preg_match('/^(?:on update)\s([\_\-\s\w\d]+)/', $data['extra'], $matches)) { + $data['on_update'] = true; + } + + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Real.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Real.php new file mode 100644 index 0000000000000..43542f617f857 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Real.php @@ -0,0 +1,106 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Process real types and separate them into type, scale and precision. + * See https://dev.mysql.com/doc/refman/5.7/en/precision-math-decimal-characteristics.html + * + * @inheritdoc + */ +class Real implements DbDefinitionProcessorInterface +{ + /** + * @var Nullable + */ + private $nullable; + + /** + * @var Unsigned + */ + private $unsigned; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var Comment + */ + private $comment; + + /** + * @param Nullable $nullable + * @param Unsigned $unsigned + * @param Comment $comment + * @param ResourceConnection $resourceConnection + */ + public function __construct( + Nullable $nullable, + Unsigned $unsigned, + Comment $comment, + ResourceConnection $resourceConnection + ) { + $this->nullable = $nullable; + $this->unsigned = $unsigned; + $this->resourceConnection = $resourceConnection; + $this->comment = $comment; + } + + /** + * @param \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Real $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + if ($column->getPrecision() === 0 && $column->getScale() === 0) { + $type = $column->getType(); + } else { + $type = sprintf('%s(%s, %s)', $column->getType(), $column->getPrecision(), $column->getScale()); + } + + return sprintf( + '%s %s %s %s %s %s', + $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), + $type, + $this->unsigned->toDefinition($column), + $this->nullable->toDefinition($column), + $column->getDefault() !== null ? + sprintf('DEFAULT %s', $column->getDefault()) : '', + $this->comment->toDefinition($column) + ); + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + $matches = []; + if (preg_match('/^(float|decimal|double)\s*\((\d+)\s*,\s*(\d+)\)/i', $data['definition'], $matches)) { + /** + * match[1] - type + * match[2] - precision + * match[3] - scale + */ + $data['precision'] = $matches[2]; + $data['scale'] = $matches[3]; + $data = $this->nullable->fromDefinition($data); + $data = $this->unsigned->fromDefinition($data); + } elseif (preg_match('/^decimal\s*\(\s*(\d+)\s*\)/i', $data['definition'], $matches)) { + $data['precision'] = $matches[1]; + $data['scale'] = 0; + } + + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinary.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinary.php new file mode 100644 index 0000000000000..c2fd270a8f949 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinary.php @@ -0,0 +1,81 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Processor for following types: char, varchar, varbinary, binary. + * + * @inheritdoc + */ +class StringBinary implements DbDefinitionProcessorInterface +{ + /** + * @var Nullable + */ + private $nullable; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var Comment + */ + private $comment; + + /** + * @param Nullable $nullable + * @param ResourceConnection $resourceConnection + * @param Comment $comment + */ + public function __construct(Nullable $nullable, ResourceConnection $resourceConnection, Comment $comment) + { + $this->nullable = $nullable; + $this->resourceConnection = $resourceConnection; + $this->comment = $comment; + } + + /** + * @param \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\StringBinary $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + if ($column->getDefault() !== null) { + $default = sprintf('DEFAULT "%s"', $column->getDefault()); + } else { + $default = ''; + } + + return sprintf( + '%s %s(%s) %s %s %s', + $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), + $column->getType(), + $column->getLength(), + $this->nullable->toDefinition($column), + $default, + $this->comment->toDefinition($column) + ); + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + $matches = []; + if (preg_match('/^(char|binary|varchar|varbinary)\s*\((\d+)\)/', $data['definition'], $matches)) { + $data['length'] = $matches[2]; + } + + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Timestamp.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Timestamp.php new file mode 100644 index 0000000000000..6313fa7286dc1 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Timestamp.php @@ -0,0 +1,99 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Processor for timestamp/datetime types. + * + * @inheritdoc + */ +class Timestamp implements DbDefinitionProcessorInterface +{ + /** + * This date and time can be used, when const value as DEFAULT 0 was passed for datetime type. + */ + const CONST_DEFAULT_TIMESTAMP = '0000-00-00 00:00:00'; + + /** + * @var OnUpdate + */ + private $onUpdate; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var Nullable + */ + private $nullable; + + /** + * @var Comment + */ + private $comment; + + /** + * Constructor. + * + * @param OnUpdate $onUpdate + * @param Nullable $nullable + * @param Comment $comment + * @param ResourceConnection $resourceConnection + */ + public function __construct( + OnUpdate $onUpdate, + Nullable $nullable, + Comment $comment, + ResourceConnection $resourceConnection + ) { + $this->onUpdate = $onUpdate; + $this->resourceConnection = $resourceConnection; + $this->nullable = $nullable; + $this->comment = $comment; + } + + /** + * @param \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + $nullable = $this->nullable->toDefinition($column); + $default = $column->getDefault() === 'NULL' + ? '' + : sprintf('DEFAULT %s', $column->getDefault()); + + return sprintf( + '%s %s %s %s %s %s', + $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), + $column->getType(), + $nullable, + $default, + $this->onUpdate->toDefinition($column), + $this->comment->toDefinition($column) + ); + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + if ($data['default'] === self::CONST_DEFAULT_TIMESTAMP) { + $data['default'] = '0'; + } + $data = $this->nullable->fromDefinition($data); + $data = $this->onUpdate->fromDefinition($data); + return $data; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Unsigned.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Unsigned.php new file mode 100644 index 0000000000000..776998e8bc4a9 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Columns/Unsigned.php @@ -0,0 +1,43 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\ColumnUnsignedAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Unsigned flag processor. + * Unsigned can be used for all numeric types. + * + * @inheritdoc + */ +class Unsigned implements DbDefinitionProcessorInterface +{ + /** + * Unsigned flag. Applicable only to numeric types. + */ + const UNSIGNED_FLAG = 'unsigned'; + + /** + * @param ColumnUnsignedAwareInterface $column + * @inheritdoc + */ + public function toDefinition(ElementInterface $column) + { + return $column->isUnsigned() ? strtoupper(self::UNSIGNED_FLAG) : ''; + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + $data['unsigned'] = stripos($data['definition'], self::UNSIGNED_FLAG) !== false; + return $data; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKey.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKey.php similarity index 90% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKey.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKey.php index 5e108a1510b58..b2c520de4e78f 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKey.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKey.php @@ -4,12 +4,12 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Constraints; +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Constraints; use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; /** * Foreign key constraint processor. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Constraints/Internal.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Constraints/Internal.php new file mode 100644 index 0000000000000..52abd28a1c7a9 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Constraints/Internal.php @@ -0,0 +1,91 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Constraints; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Internal key (index) processor. + * + * Detect primary or unique constraints and map them to appropriate format. + * + * @inheritdoc + */ +class Internal implements DbDefinitionProcessorInterface +{ + /** + * Name of Primary Key. + */ + const PRIMARY_NAME = 'PRIMARY'; + + /** + * Primary key statement. + */ + const PRIMARY_KEY_NAME = 'PRIMARY KEY'; + + /** + * Unique key statement. + */ + const UNIQUE_KEY_NAME = 'UNIQUE KEY'; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * Constructor. + * + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @param \Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal $constraint + * @inheritdoc + */ + public function toDefinition(ElementInterface $constraint) + { + $adapter = $this->resourceConnection->getConnection( + $constraint->getTable()->getResource() + ); + $columnsList = array_map( + function ($columnName) use ($adapter) { + return $adapter->quoteIdentifier($columnName); + }, + $constraint->getColumnNames() + ); + $isPrimary = $constraint->getType() === 'primary'; + + return sprintf( + 'CONSTRAINT %s %s (%s)', + $isPrimary ? '' : $adapter->quoteIdentifier($constraint->getName()), + $isPrimary ? 'PRIMARY KEY' : 'UNIQUE KEY', + implode(',', $columnsList) + ); + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + return [ + 'name' => $data['Key_name'], + 'column' => [ + $data['Column_name'] => $data['Column_name'] + ], + 'type' => $data['Key_name'] === self::PRIMARY_NAME ? 'primary' : 'unique' + ]; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Index.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Index.php new file mode 100644 index 0000000000000..30150efd51774 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/MySQL/Definition/Index.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * Index (key) processor. + * + * @inheritdoc + */ +class Index implements DbDefinitionProcessorInterface +{ + /** + * Index statement. + */ + const INDEX_KEY_NAME = 'INDEX'; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * Index constructor. + * + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * @param \Magento\Framework\Setup\Declaration\Schema\Dto\Index $index + * @inheritdoc + */ + public function toDefinition(ElementInterface $index) + { + $indexType = $index->getIndexType(); + //There is no matter what connection to use -> so use default one + $adapter = $this->resourceConnection->getConnection(); + $isFullText = $indexType === \Magento\Framework\Setup\Declaration\Schema\Dto\Index::FULLTEXT_INDEX; + //index types, that are similar to MySQL ones, can just be uppercased. + //[FULLTEXT ]INDEX `name` [USING [BTREE|HASH]] (columns) + return sprintf( + '%sINDEX %s%s (%s)', + $isFullText ? 'FULLTEXT ' : '', + $adapter->quoteIdentifier($index->getName()), + '', // placeholder for USING HASH|BTREE statement for non-fulltext indexes + implode( + ',', + array_map( + function ($columnName) use ($adapter) { + return $adapter->quoteIdentifier($columnName); + }, + $index->getColumnNames() + ) + ) + ); + } + + /** + * @inheritdoc + */ + public function fromDefinition(array $data) + { + return [ + 'indexType' => strtolower($data['Index_type']), + 'name' => $data['Key_name'], + 'column' => [ + $data['Column_name'] => $data['Column_name'] + ], + 'type' => 'index' + ]; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/ReferenceStatement.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/ReferenceStatement.php similarity index 78% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/ReferenceStatement.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/ReferenceStatement.php index e7279af28e779..234f3f048c5ea 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/ReferenceStatement.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/ReferenceStatement.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Declaration\Schema\Db; /** * Foreign key statement. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/SchemaBuilder.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/SchemaBuilder.php new file mode 100644 index 0000000000000..2b9e593975d67 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/SchemaBuilder.php @@ -0,0 +1,196 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Db; + +use Magento\Framework\Phrase; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementFactory; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Sharding; +use Magento\Framework\Setup\Exception; + +/** + * This type of builder is responsible for converting ENTIRE data, that comes from db + * into DTO`s format, with aggregation root: Schema. + * + * Note: SchemaBuilder can not be used for one structural element, like column or constraint + * because it should have references to other DTO objects. + * In order to convert build only 1 structural element use directly it factory. + * + * @see Schema + * @inheritdoc + */ +class SchemaBuilder +{ + /** + * @var ElementFactory + */ + private $elementFactory; + + /** + * @var DbSchemaReaderInterface + */ + private $dbSchemaReader; + + /** + * @var Sharding + */ + private $sharding; + + /** + * Constructor. + * + * @param ElementFactory $elementFactory + * @param DbSchemaReaderInterface $dbSchemaReader + * @param Sharding $sharding + */ + public function __construct( + ElementFactory $elementFactory, + DbSchemaReaderInterface $dbSchemaReader, + Sharding $sharding + ) { + $this->elementFactory = $elementFactory; + $this->dbSchemaReader = $dbSchemaReader; + $this->sharding = $sharding; + } + + /** + * @inheritdoc + */ + public function build(Schema $schema) + { + $tables = []; + + foreach ($this->sharding->getResources() as $resource) { + foreach ($this->dbSchemaReader->readTables($resource) as $tableName) { + $columns = []; + $indexes = []; + $constraints = []; + + $tableOptions = $this->dbSchemaReader->getTableOptions($tableName, $resource); + $columnsData = $this->dbSchemaReader->readColumns($tableName, $resource); + $indexesData = $this->dbSchemaReader->readIndexes($tableName, $resource); + $constrainsData = $this->dbSchemaReader->readConstraints($tableName, $resource); + + /** + * @var Table $table + */ + $table = $this->elementFactory->create( + 'table', + [ + 'name' => $tableName, + 'resource' => $resource, + 'engine' => strtolower($tableOptions['Engine']), + 'comment' => $tableOptions['Comment'] === '' ? null : $tableOptions['Comment'] + ] + ); + + // Process columns + foreach ($columnsData as $columnData) { + $columnData['table'] = $table; + $column = $this->elementFactory->create($columnData['type'], $columnData); + $columns[$column->getName()] = $column; + } + + $table->addColumns($columns); + //Process indexes + foreach ($indexesData as $indexData) { + $indexData['table'] = $table; + $indexData['columns'] = $this->resolveInternalRelations($columns, $indexData); + $index = $this->elementFactory->create('index', $indexData); + $indexes[$index->getName()] = $index; + } + //Process internal constraints + foreach ($constrainsData as $constraintData) { + $constraintData['table'] = $table; + $constraintData['columns'] = $this->resolveInternalRelations($columns, $constraintData); + $constraint = $this->elementFactory->create($constraintData['type'], $constraintData); + $constraints[$constraint->getName()] = $constraint; + } + + $table->addIndexes($indexes); + $table->addConstraints($constraints); + $tables[$table->getName()] = $table; + $schema->addTable($table); + } + } + + $this->processReferenceKeys($tables); + return $schema; + } + + /** + * Process references for all tables. Schema validation required. + * + * @param Table[] $tables + * @return Table[] + */ + private function processReferenceKeys(array $tables) + { + foreach ($tables as $table) { + $tableName = $table->getName(); + $referencesData = $this->dbSchemaReader->readReferences($tableName, $table->getResource()); + $references = []; + + foreach ($referencesData as $referenceData) { + //Prepare reference data + $referenceData['table'] = $tables[$tableName]; + $referenceData['column'] = $tables[$tableName]->getColumnByName($referenceData['column']); + $referenceData['referenceTable'] = $tables[$referenceData['referenceTable']]; + $referenceData['referenceColumn'] = $referenceData['referenceTable']->getColumnByName( + $referenceData['referenceColumn'] + ); + + $references[$referenceData['name']] = $this->elementFactory->create('foreign', $referenceData); + } + + $tables[$tableName]->addConstraints($references); + } + + return $tables; + } + + /** + * Retrieve column objects from names. + * + * @param Column[] $columns + * @param array $data + * @return Column[] + * @throws Exception + */ + private function resolveInternalRelations(array $columns, array $data) + { + if (!is_array($data['column'])) { + throw new Exception( + new Phrase("Cannot find columns for internal index") + ); + } + + $referenceColumns = []; + foreach ($data['column'] as $columnName) { + if (!isset($columns[$columnName])) { + $tableName = isset($data['table']) ? $data['table']->getName() : ''; + trigger_error( + new Phrase( + 'Column %1 does not exist for index/constraint %2 in table %3.', + [ + $columnName, + $data['name'], + $tableName + ] + ), + E_USER_WARNING + ); + } else { + $referenceColumns[] = $columns[$columnName]; + } + } + + return $referenceColumns; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/Statement.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/Statement.php similarity index 95% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/Statement.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/Statement.php index 8c40deced27ea..ccc4e38968e89 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/Statement.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/Statement.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Declaration\Schema\Db; /** * Statement aggregator for SQL statements for one table. @@ -36,7 +36,7 @@ class Statement private $resource; /** - * @var Callable[] + * @var callable[] */ private $triggers = []; @@ -122,7 +122,7 @@ public function getResource(): string /** * Get triggers array. * - * @return Callable[] + * @return callable[] */ public function getTriggers(): array { diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/StatementAggregator.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/StatementAggregator.php similarity index 98% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/StatementAggregator.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/StatementAggregator.php index 31a4983352772..2003ff18900ff 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/StatementAggregator.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/StatementAggregator.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Declaration\Schema\Db; /** * Statement aggregator. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/StatementAggregatorFactory.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/StatementAggregatorFactory.php similarity index 94% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/StatementAggregatorFactory.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/StatementAggregatorFactory.php index f7bcefceedefd..474742de26a92 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/StatementAggregatorFactory.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/StatementAggregatorFactory.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Declaration\Schema\Db; use Magento\Framework\ObjectManagerInterface; diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/StatementFactory.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/StatementFactory.php similarity index 93% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Db/StatementFactory.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/StatementFactory.php index 94326a1bebf14..ecc2bf08331fd 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/StatementFactory.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Db/StatementFactory.php @@ -4,10 +4,10 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Declaration\Schema\Db; use Magento\Framework\ObjectManagerInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; /** * Statement factory. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ReaderComposite.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ReaderComposite.php similarity index 92% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ReaderComposite.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ReaderComposite.php index 729eaf0fc5963..5f3d5af4d3b13 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ReaderComposite.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ReaderComposite.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Declaration; +namespace Magento\Framework\Setup\Declaration\Schema\Declaration; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\Config\ReaderInterface; @@ -27,8 +27,6 @@ class ReaderComposite implements ReaderInterface private $deploymentConfig; /** - * Constructor. - * * @param DeploymentConfig $deploymentConfig * @param ReaderInterface[] $readers */ diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/SchemaBuilder.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/SchemaBuilder.php new file mode 100644 index 0000000000000..63d42e182e7ef --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/SchemaBuilder.php @@ -0,0 +1,372 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Declaration; + +use Magento\Framework\Phrase; +use Magento\Framework\Stdlib\BooleanUtils; +use Magento\Framework\Setup\Exception; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraint; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementFactory; +use Magento\Framework\Setup\Declaration\Schema\Dto\Index; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Sharding; + +/** + * This type of builder is responsible for converting ENTIRE data, that comes from XML + * into DTO`s format, with aggregation root: Schema. + * + * Note: SchemaBuilder can not be used for one structural element, like column or constraint + * because it should have references to other DTO objects. + * In order to convert build only 1 structural element use directly it factory. + * + * structure + * - table[N,] + * -column + * -constraint + * -internal (unique, primary, check, nullable) + * -reference (referenceTable=<DTO>, referenceColumn=<DTO>, ...) + * -index + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class SchemaBuilder +{ + /** + * @var array + */ + private $tablesData = []; + + /** + * @var Sharding + */ + private $sharding; + + /** + * @var ElementFactory + */ + private $elementFactory; + + /** + * @var BooleanUtils + */ + private $booleanUtils; + + /** + * @var ValidationComposite + */ + private $validationComposite; + + /** + * @var \Magento\Framework\App\ResourceConnection + */ + private $resourceConnection; + + /** + * SchemaBuilder constructor. + * + * @param ElementFactory $elementFactory + * @param BooleanUtils $booleanUtils + * @param Sharding $sharding + * @param ValidationComposite $validationComposite + * @param \Magento\Framework\App\ResourceConnection $resourceConnection + * @internal param array $tablesData + */ + public function __construct( + ElementFactory $elementFactory, + BooleanUtils $booleanUtils, + Sharding $sharding, + ValidationComposite $validationComposite, + \Magento\Framework\App\ResourceConnection $resourceConnection + ) { + $this->sharding = $sharding; + $this->elementFactory = $elementFactory; + $this->booleanUtils = $booleanUtils; + $this->validationComposite = $validationComposite; + $this->resourceConnection = $resourceConnection; + } + + /** + * Add tables data to builder. + * Tables data holds tables information: columns, constraints, indexes, attributes. + * + * @param array $tablesData + * @return self + */ + public function addTablesData(array $tablesData) + { + $this->tablesData = $tablesData; + return $this; + } + + /** + * Do schema validation and print all errors. + * + * @param Schema $schema + * @throws Exception + */ + private function validate(Schema $schema) + { + $errors = $this->validationComposite->validate($schema); + + if (!empty($errors)) { + $messages = ''; + foreach ($errors as $error) { + $messages .= sprintf("%s%s", PHP_EOL, $error['message']); + } + + throw new Exception(new Phrase($messages)); + } + } + + /** + * Build schema. + * + * @param Schema $schema + * @throws Exception + * @return Schema + */ + public function build(Schema $schema) + { + foreach ($this->tablesData as $tableData) { + if (!$schema->getTableByName($tableData['name'])) { + if (!$this->isDisabled($tableData)) { + $this->processTable($schema, $tableData); + } + } + } + + $this->validate($schema); + + return $schema; + } + + /** + * Get resource for structural elements. + * + * @param array $tableData + * @return string + */ + private function getStructuralElementResource(array $tableData) + { + return isset($tableData['resource']) && $this->sharding->canUseResource($tableData['resource']) ? + $tableData['resource'] : 'default'; + } + + /** + * Check whether element is disabled and should not appear in final declaration. + * + * @param array $structuralElementData + * @return bool + */ + private function isDisabled($structuralElementData) + { + return isset($structuralElementData['disabled']) && + $this->booleanUtils->toBoolean($structuralElementData['disabled']); + } + + /** + * Instantiate column DTO objects from array. + * If column was renamed new key will be associated to it. + * + * @param array $tableData + * @param string $resource + * @param Table $table + * @return array + */ + private function processColumns(array $tableData, $resource, Table $table) + { + $columns = []; + + foreach ($tableData['column'] as $columnData) { + if ($this->isDisabled($columnData)) { + continue; + } + + $columnData = $this->processGenericData($columnData, $resource, $table); + $column = $this->elementFactory->create($columnData['type'], $columnData); + $columns[$column->getName()] = $column; + } + + return $columns; + } + + /** + * Process generic data that is support by all 3 child types: columns, constraints, indexes. + * + * @param array $elementData + * @param Table $table + * @param $resource + * @return array + */ + private function processGenericData(array $elementData, $resource, Table $table) + { + $elementData['table'] = $table; + $elementData['resource'] = $resource; + + return $elementData; + } + + /** + * Process tables and add them to schema. + * If table already exists - then we need to skip it. + * + * @param Schema $schema + * @param array $tableData + * @return \Magento\Framework\Setup\Declaration\Schema\Dto\Table + */ + private function processTable(Schema $schema, array $tableData) + { + if (!$schema->getTableByName($tableData['name'])) { + $resource = $this->getStructuralElementResource($tableData); + $tableParams = [ + 'name' => $tableData['name'], + 'resource' => $resource, + 'engine' => $tableData['engine'] ?? null, + 'comment' => $tableData['comment'] ?? null + ]; + /** @var Table $table */ + $table = $this->elementFactory->create('table', $tableParams); + $columns = $this->processColumns($tableData, $resource, $table); + $table->addColumns($columns); + //Add indexes to table + $table->addIndexes($this->processIndexes($tableData, $resource, $table)); + //Add internal and reference constraints + $table->addConstraints($this->processConstraints($tableData, $resource, $schema, $table)); + $schema->addTable($table); + } + + return $schema->getTableByName($tableData['name']); + } + + /** + * @param string $columnName + * @param Table $table + * @return Column + */ + private function getColumnByName(string $columnName, Table $table) + { + $columnCandidate = $table->getColumnByName($columnName); + + if (!$columnCandidate) { + throw new \LogicException( + sprintf('Table %s do not have column with name %s', $table->getName(), $columnName) + ); + } + + return $columnCandidate; + } + + /** + * Convert column names to objects. + * + * @param array $columnNames + * @param Table $table + * @return array + */ + private function convertColumnNamesToObjects(array $columnNames, Table $table) + { + $columns = []; + + foreach ($columnNames as $columnName) { + $columns[] = $this->getColumnByName($columnName, $table); + } + + return $columns; + } + + /** + * Convert and instantiate index objects. + * + * @param array $tableData + * @param $resource + * @param Table $table + * @return Index[] + */ + private function processIndexes(array $tableData, $resource, Table $table) + { + if (!isset($tableData['index'])) { + return []; + } + + $indexes = []; + + foreach ($tableData['index'] as $indexData) { + if ($this->isDisabled($indexData)) { + continue; + } + + $indexData = $this->processGenericData($indexData, $resource, $table); + $indexData['columns'] = $this->convertColumnNamesToObjects($indexData['column'], $table); + $index = $this->elementFactory->create('index', $indexData); + $indexes[$index->getName()] = $index; + } + + return $indexes; + } + + /** + * Convert and instantiate constraint objects. + * + * @param array $tableData + * @param $resource + * @param Schema $schema + * @param Table $table + * @return Constraint[] + */ + private function processConstraints(array $tableData, $resource, Schema $schema, Table $table) + { + if (!isset($tableData['constraint'])) { + return []; + } + + $constraints = []; + + foreach ($tableData['constraint'] as $constraintData) { + if ($this->isDisabled($constraintData)) { + continue; + } + $constraintData = $this->processGenericData($constraintData, $resource, $table); + //As foreign constraint has different schema we need to process it in different way + if ($constraintData['type'] === 'foreign') { + $constraintData['column'] = $this->getColumnByName($constraintData['column'], $table); + $referenceTableData = $this->tablesData[$constraintData['referenceTable']]; + //If we are referenced to the same table we need to specify it + //Get table name from resource connection regarding prefix settings + $refTableName = $this->resourceConnection->getTableName($referenceTableData['name']); + $referenceTable = $refTableName === $table->getName() ? + $table : + $this->processTable($schema, $referenceTableData); + + if ($referenceTable->getResource() !== $table->getResource()) { + continue; //we should avoid creating foreign keys + //for tables that are on another shard + } + $constraintData['referenceTable'] = $referenceTable; + + if (!$constraintData['referenceTable']) { + throw new \LogicException( + sprintf('Cannot find reference table with name %s', $constraints['referenceTable']) + ); + } + + $constraintData['referenceColumn'] = $this->getColumnByName( + $constraintData['referenceColumn'], + $constraintData['referenceTable'] + ); + $constraint = $this->elementFactory->create($constraintData['type'], $constraintData); + $constraints[$constraint->getName()] = $constraint; + } else { + $constraintData['columns'] = $this->convertColumnNamesToObjects($constraintData['column'], $table); + $constraint = $this->elementFactory->create($constraintData['type'], $constraintData); + $constraints[$constraint->getName()] = $constraint; + } + } + + return $constraints; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationComposite.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationComposite.php similarity index 86% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationComposite.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationComposite.php index 2b788c24ad6da..bf04f80c0e45e 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationComposite.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationComposite.php @@ -3,9 +3,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Declaration; +namespace Magento\Framework\Setup\Declaration\Schema\Declaration; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; /** * This validator holds different validations rules. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationInterface.php similarity index 77% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationInterface.php index c2057d4326c80..0f90a6bb8b1e5 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationInterface.php @@ -3,9 +3,9 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Declaration; +namespace Magento\Framework\Setup\Declaration\Schema\Declaration; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; /** * This class is responsible for basic validation rules. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/AutoIncrementColumnValidation.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/AutoIncrementColumnValidation.php new file mode 100644 index 0000000000000..fb31f7fcc6d98 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/AutoIncrementColumnValidation.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules; + +use Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\ColumnIdentityAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; + +/** + * Check whether autoincrement column is valid + * + * @inheritdoc + */ +class AutoIncrementColumnValidation implements ValidationInterface +{ + /** + * Error code. + */ + const ERROR_TYPE = 'auto_increment_column_is_valid'; + + /** + * Error message, that will be shown. + */ + const ERROR_MESSAGE = 'Auto Increment column do not have index. Column - "%s", table - "%s"'; + + /** + * @inheritdoc + */ + public function validate(Schema $schema) + { + $errors = []; + foreach ($schema->getTables() as $table) { + foreach ($table->getColumns() as $column) { + if ($column instanceof ColumnIdentityAwareInterface && $column->isIdentity()) { + foreach ($table->getConstraints() as $constraint) { + if ($constraint instanceof Internal && + in_array($column->getName(), $constraint->getColumnNames()) + ) { + //If we find that for auto increment column we have index or key + continue 3; + } + } + + foreach ($table->getIndexes() as $index) { + if (in_array($column->getName(), $index->getColumnNames())) { + //If we find that for auto increment column we have index or key + continue 3; + } + } + + $errors[] = [ + 'column' => $column->getName(), + 'message' => sprintf(self::ERROR_MESSAGE, $column->getName(), $table->getName()) + ]; + } + } + } + + return $errors; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationRules/CheckReferenceColumnHasIndex.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/CheckReferenceColumnHasIndex.php similarity index 83% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationRules/CheckReferenceColumnHasIndex.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/CheckReferenceColumnHasIndex.php index 81d516f2b7522..21c62ec2b29cc 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationRules/CheckReferenceColumnHasIndex.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/CheckReferenceColumnHasIndex.php @@ -3,12 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Declaration\ValidationRules; +namespace Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules; -use Magento\Setup\Model\Declaration\Schema\Declaration\ValidationInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Internal; -use Magento\Setup\Model\Declaration\Schema\Dto\Index; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal; +use Magento\Framework\Setup\Declaration\Schema\Dto\Index; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; /** * Go through all tables in schema and see if reference columns in foreign keys diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/IncosistentReferenceDefinition.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/IncosistentReferenceDefinition.php new file mode 100644 index 0000000000000..02d2cee9979e2 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/IncosistentReferenceDefinition.php @@ -0,0 +1,138 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules; + +use Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\ColumnNullableAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\ColumnUnsignedAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\StringBinary; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; + +/** + * Go through all tables and find out what foreign keys columns definitions are not match each other + * + * @inheritdoc + */ +class IncosistentReferenceDefinition implements ValidationInterface +{ + /** + * Error code. + */ + const ERROR_TYPE = 'reference_incosistence_definition'; + + /** + * Assert that column dimensions are the same + * + * This check should goes after types assertion + * + * @param Column $column + * @param Column | ColumnUnsignedAwareInterface | ColumnNullableAwareInterface $referenceColumn + * @return bool + */ + private function assertDefinitionEqual(Column $column, Column $referenceColumn) + { + /** + * Columns should have the same types + */ + if ($column->getType() !== $referenceColumn->getType()) { + return true; + } + + return $this->assertUnsigned($column, $referenceColumn) && + $this->assertIntegersEquals($column, $referenceColumn) && + $this->assertStringBinariesEqual($column, $referenceColumn); + } + + /** + * @param Column $column + * @param Column | ColumnUnsignedAwareInterface $referenceColumn + * @return bool + */ + private function assertUnsigned(Column $column, Column $referenceColumn) + { + /** + * Check on unsigned + */ + if ($column instanceof ColumnUnsignedAwareInterface && + $column->isUnsigned() !== $referenceColumn->isUnsigned() + ) { + return false; + } + + return true; + } + + /** + * @param Column $column + * @param Column $referenceColumn + * @return bool + */ + private function assertStringBinariesEqual(Column $column, Column $referenceColumn) + { + /** + * Check whether column sizes are equal + * @var StringBinary $referenceColumn + */ + if ($column instanceof StringBinary && + $column->getLength() !== $referenceColumn->getLength() + ) { + return false; + } + + return true; + } + + /** + * @param Column $column + * @param Column | Integer $referenceColumn + * @return bool + */ + private function assertIntegersEquals(Column $column, Column $referenceColumn) + { + /** + * Check whether column sizes are equal + */ + if ($column instanceof Integer && + $column->getPadding() !== $referenceColumn->getPadding() + ) { + return false; + } + + return true; + } + + /** + * @inheritdoc + */ + public function validate(Schema $schema) + { + $message = 'Column definition "%s" and reference column definition "%s" are different in tables "%s" and "%s"'; + $errors = []; + foreach ($schema->getTables() as $table) { + foreach ($table->getReferenceConstraints() as $reference) { + $column = $reference->getColumn(); + $referenceColumn = $reference->getReferenceColumn(); + + if (!$this->assertDefinitionEqual($column, $referenceColumn)) { + $errors[] = [ + 'column' => $column->getName(), + 'message' => sprintf( + $message, + $column->getName(), + $referenceColumn->getName(), + $column->getTable()->getName(), + $referenceColumn->getTable()->getName() + ) + ]; + } + } + } + + return $errors; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/PrimaryKeyCanBeCreated.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/PrimaryKeyCanBeCreated.php new file mode 100644 index 0000000000000..6e3703af9b098 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/PrimaryKeyCanBeCreated.php @@ -0,0 +1,57 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules; + +use Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\ColumnNullableAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; + +/** + * Go through all tables and find out if primary keys can be applied + * + * @inheritdoc + */ +class PrimaryKeyCanBeCreated implements ValidationInterface +{ + /** + * Error code. + */ + const ERROR_TYPE = 'primary_key_cant_be_applied'; + + /** + * Error message, that will be shown. + */ + const ERROR_MESSAGE = 'Primary key can`t be applied on table "%s". '; + + /** + * @inheritdoc + */ + public function validate(Schema $schema) + { + $errors = []; + foreach ($schema->getTables() as $table) { + $primaryConstraint = $table->getPrimaryConstraint(); + + if (!$primaryConstraint) { + continue; + } + + foreach ($primaryConstraint->getColumns() as $column) { + if ($column instanceof ColumnNullableAwareInterface && + $column->isNullable() + ) { + $errors[] = [ + 'column' => $column->getName(), + 'message' => sprintf(self::ERROR_MESSAGE, $table->getName()) . + "All columns should be not nullable" + ]; + } + } + } + + return $errors; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationRules/RealTypes.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/RealTypes.php similarity index 83% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationRules/RealTypes.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/RealTypes.php index 866896da25ea2..8cb6ff3f95cb0 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/ValidationRules/RealTypes.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Declaration/ValidationRules/RealTypes.php @@ -3,11 +3,11 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Declaration\ValidationRules; +namespace Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules; -use Magento\Setup\Model\Declaration\Schema\Declaration\ValidationInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Real; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Real; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; /** * Go through all tables in schema and validate real types basis and fraction sizes are valid. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/Diff.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/Diff.php similarity index 77% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Diff/Diff.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/Diff.php index 915e4d399810a..70711d4900afc 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/Diff.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/Diff.php @@ -4,17 +4,14 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Diff; +namespace Magento\Framework\Setup\Declaration\Schema\Diff; -use Magento\Developer\Console\Command\TablesWhitelistGenerateCommand; use Magento\Framework\Component\ComponentRegistrar; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\Dto\TableElementInterface; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\ElementHistoryFactory; -use Magento\Setup\Model\Declaration\Schema\Request; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Dto\TableElementInterface; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\ElementHistoryFactory; /** * Holds information about all changes between 2 schemas: db and declaration XML. @@ -24,6 +21,11 @@ */ class Diff implements DiffInterface { + /** + * Whitelist file name. + */ + const GENERATED_WHITELIST_FILE_NAME = 'db_schema_whitelist.json'; + /** * @var array */ @@ -41,16 +43,6 @@ class Diff implements DiffInterface */ private $whiteListTables = []; - /** - * @var Schema - */ - private $schema; - - /** - * @var Request - */ - private $request; - /** * @var ComponentRegistrar */ @@ -137,7 +129,7 @@ private function getWhiteListTables() if (!$this->whiteListTables) { foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $path) { $whiteListPath = $path . DIRECTORY_SEPARATOR . 'etc' . - DIRECTORY_SEPARATOR . TablesWhitelistGenerateCommand::GENERATED_FILE_NAME; + DIRECTORY_SEPARATOR . 'db_schema_whitelist.json'; if (file_exists($whiteListPath)) { $this->whiteListTables = array_replace_recursive( @@ -177,17 +169,6 @@ private function canBeRegistered(ElementInterface $object, $operation) return isset($whiteList[$object->getNameWithoutPrefix()]); } - /** - * Register request for installation. - * - * @param Request $request - * @return void - */ - public function registerInstallationRequest(Request $request) - { - $this->request = $request; - } - /** * Register DTO object. * @@ -215,34 +196,4 @@ public function register( $this->debugChanges[$operation][] = $history; return $this; } - - /** - * @inheritdoc - */ - public function registerSchema(Schema $schema) - { - $this->schema = $schema; - } - - /** - * Retrieve current schema. - * This function needs for rollback functionality. - * - * @return Schema - */ - public function getCurrentSchemaState() - { - return $this->schema; - } - - /** - * Request holds some information from cli command or UI - * like: save mode or dry-run mode. - * - * @return Request - */ - public function getCurrentInstallationRequest() - { - return $this->request; - } } diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/DiffFactory.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/DiffFactory.php similarity index 92% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Diff/DiffFactory.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/DiffFactory.php index 05c395e07c59a..342bb87e1807e 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/DiffFactory.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/DiffFactory.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Diff; +namespace Magento\Framework\Setup\Declaration\Schema\Diff; use Magento\Framework\ObjectManagerInterface; diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/DiffInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/DiffInterface.php new file mode 100644 index 0000000000000..4b6e3555256fb --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/DiffInterface.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Diff; + +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\Request; + +/** + * DiffInterface is type of classes, that holds all information + * that need to be changed from one installation to another. + */ +interface DiffInterface +{ + /** + * Retrieve operations by type. + * + * Please note: that we wants to save history and we retrieve next structure: + * [ + * 'column_a' => ElementHistory [ + * 'new' => [ + * ... + * ], + * 'old' => [ + * ... + * ] + * ] + * ] + * + * @return array + */ + public function getAll(); + + /** + * Register operation. + * + * @param ElementInterface|object $dtoObject + * @param string $operation + * @param ElementInterface $oldDtoObject + * @return void + */ + public function register( + ElementInterface $dtoObject, + $operation, + ElementInterface $oldDtoObject = null + ); +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/DiffManager.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/DiffManager.php similarity index 83% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Diff/DiffManager.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/DiffManager.php index eb1dc1b267d64..9a268d0eaa9d0 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/DiffManager.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/DiffManager.php @@ -4,22 +4,22 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Diff; - -use Magento\Setup\Model\Declaration\Schema\Comparator; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\Operations\AddColumn; -use Magento\Setup\Model\Declaration\Schema\Operations\AddComplexElement; -use Magento\Setup\Model\Declaration\Schema\Operations\CreateTable; -use Magento\Setup\Model\Declaration\Schema\Operations\DropElement; -use Magento\Setup\Model\Declaration\Schema\Operations\DropReference; -use Magento\Setup\Model\Declaration\Schema\Operations\DropTable; -use Magento\Setup\Model\Declaration\Schema\Operations\ModifyColumn; -use Magento\Setup\Model\Declaration\Schema\Operations\ModifyTable; -use Magento\Setup\Model\Declaration\Schema\Operations\ReCreateTable; +namespace Magento\Framework\Setup\Declaration\Schema\Diff; + +use Magento\Framework\Setup\Declaration\Schema\Comparator; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Operations\AddColumn; +use Magento\Framework\Setup\Declaration\Schema\Operations\AddComplexElement; +use Magento\Framework\Setup\Declaration\Schema\Operations\CreateTable; +use Magento\Framework\Setup\Declaration\Schema\Operations\DropElement; +use Magento\Framework\Setup\Declaration\Schema\Operations\DropReference; +use Magento\Framework\Setup\Declaration\Schema\Operations\DropTable; +use Magento\Framework\Setup\Declaration\Schema\Operations\ModifyColumn; +use Magento\Framework\Setup\Declaration\Schema\Operations\ModifyTable; +use Magento\Framework\Setup\Declaration\Schema\Operations\ReCreateTable; /** * Helper which provide methods, that helps to compare 2 different nodes: diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/SchemaDiff.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/SchemaDiff.php similarity index 94% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Diff/SchemaDiff.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/SchemaDiff.php index b609618b62148..0486b5f645d19 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/SchemaDiff.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/SchemaDiff.php @@ -4,10 +4,10 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Diff; +namespace Magento\Framework\Setup\Declaration\Schema\Diff; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; -use Magento\Setup\Model\Declaration\Schema\OperationsExecutor; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\OperationsExecutor; /** * Aggregation root of all diffs. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/TableDiff.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/TableDiff.php similarity index 92% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Diff/TableDiff.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/TableDiff.php index 1a2750b657e5c..73a1d86f262ad 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/TableDiff.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Diff/TableDiff.php @@ -4,14 +4,14 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Diff; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Index; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\Operations\AddComplexElement; -use Magento\Setup\Model\Declaration\Schema\Operations\ModifyColumn; +namespace Magento\Framework\Setup\Declaration\Schema\Diff; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Index; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Operations\AddComplexElement; +use Magento\Framework\Setup\Declaration\Schema\Operations\ModifyColumn; /** * As table can have different types of elements inside itself. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/DryRunLogger.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DryRunLogger.php new file mode 100644 index 0000000000000..dcecfc4159619 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/DryRunLogger.php @@ -0,0 +1,147 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema; + +use Magento\Framework\App\Filesystem\DirectoryList; + +/** + * This class is responsible for logging dry run SQL`s + * By default it logs them into filesystem, but it can be extended and you can log them in CLI + * Current problem with logging output to CLI, is that we have redudant things in CLI output, like modules progress + */ +class DryRunLogger +{ + /** + * We will run installation or upgrade in Dry Run mode + */ + const INPUT_KEY_DRY_RUN_MODE = 'dry-run'; + + /** + * File name, where all dry-run SQL`s will be puted + */ + const FILE_NAME = 'dry-run-installation.log'; + + /** + * Allows to separate 2 different sql statements with this separator + * Be default is used 2 empty lines + */ + const LINE_SEPARATOR = "\n\n"; + + /** + * @var \Magento\Framework\Filesystem\Driver\File + */ + private $fileDriver; + + /** + * @var DirectoryList + */ + private $directoryList; + + /** + * @param \Magento\Framework\Filesystem\Driver\File $fileDriver + * @param DirectoryList $directoryList + */ + public function __construct( + \Magento\Framework\Filesystem\Driver\File $fileDriver, + DirectoryList $directoryList + ) { + $this->fileDriver = $fileDriver; + $this->directoryList = $directoryList; + } + + /** + * Create log directory if it doest not exists + * + * @param string $logFolderPath + * @throws \Exception + */ + private function assertLogFolderExists($logFolderPath) + { + if (!$this->fileDriver->isDirectory($logFolderPath)) { + $this->fileDriver->createDirectory($logFolderPath); + } + + if (!$this->fileDriver->isDirectory($logFolderPath)) { + throw new \Exception(sprintf("Can`t create log directory: %s", $logFolderPath)); + } + } + + /** + * @param string $fileName + * @throws \Exception + */ + private function assertFileExists($fileName) + { + if (!$this->fileDriver->isExists($fileName)) { + $this->fileDriver->touch($fileName); + } + + if (!$this->fileDriver->isExists($fileName)) { + throw new \Exception(sprintf("Can`t create file %s", $fileName)); + } + } + + /** + * Make file empty from request to request + * @throws \Exception + * @return void + */ + public function prepareToDryRun() + { + if ($this->fileDriver->isExists($this->getLoggerFile())) { + if (!$this->fileDriver->isWritable($this->getLoggerFile())) { + throw new \Exception(sprintf('Dry run logger file is not writable')); + } + + $this->fileDriver->deleteFile($this->getLoggerFile()); + $this->fileDriver->touch($this->getLoggerFile()); + } + } + + /** + * Return folder path, where dry run logged file will be placed + * + * @return string + */ + private function getLoggerFolder() + { + return $this->directoryList->getPath(DirectoryList::VAR_DIR) . + DIRECTORY_SEPARATOR . 'log'; + } + + /** + * Return dry run logger file + * + * @return string + */ + private function getLoggerFile() + { + return $this->getLoggerFolder() . DIRECTORY_SEPARATOR . self::FILE_NAME; + } + + /** + * Do log of SQL query, 2 different SQL`s will be divided by one empty line + * + * @param string $sql + * @throws \Exception + * @return void + */ + public function log($sql) + { + $loggerFolder = $this->getLoggerFolder(); + $loggerFile = $this->getLoggerFile(); + $this->assertLogFolderExists($loggerFolder); + $this->assertFileExists($loggerFile); + + if ($this->fileDriver->isWritable($loggerFile)) { + $fd = $this->fileDriver->fileOpen($loggerFile, 'a'); + $this->fileDriver->fileWrite($fd, $sql . self::LINE_SEPARATOR); + } else { + throw new \Exception(sprintf('Can`t write to file %s', $loggerFile)); + } + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Column.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Column.php similarity index 96% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Column.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Column.php index 95cf6e2dd0de3..6dd2f554c6805 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Column.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Column.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto; +namespace Magento\Framework\Setup\Declaration\Schema\Dto; /** * Column structural element. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Blob.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Blob.php new file mode 100644 index 0000000000000..0f202d9d98b6b --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Blob.php @@ -0,0 +1,69 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * This column represent binary type. + * We can have few binary types: blob, mediumblob, longblob. + * Declared in SQL, like blob. + */ +class Blob extends Column implements + ElementDiffAwareInterface, + ColumnNullableAwareInterface +{ + /** + * @var bool + */ + private $nullable; + + /** + * Constructor. + * + * @param string $name + * @param string $type + * @param Table $table + * @param bool $nullable + * @param string|null $comment + * @param string|null $onCreate + */ + public function __construct( + string $name, + string $type, + Table $table, + bool $nullable = true, + string $comment = null, + string $onCreate = null + ) { + parent::__construct($name, $type, $table, $comment, $onCreate); + $this->nullable = $nullable; + } + + /** + * Check whether column can be nullable. + * + * @return bool + */ + public function isNullable() + { + return $this->nullable; + } + + /** + * @inheritdoc + */ + public function getDiffSensitiveParams() + { + return [ + 'type' => $this->getType(), + 'nullable' => $this->isNullable(), + 'comment' => $this->getComment() + ]; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Boolean.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Boolean.php new file mode 100644 index 0000000000000..df1ee502d46be --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Boolean.php @@ -0,0 +1,88 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Boolean column. + * Declared in SQL, like TINYINT(1) or BOOL or BOOLEAN. Alias for integer or binary type. + */ +class Boolean extends Column implements + ElementDiffAwareInterface, + ColumnNullableAwareInterface, + ColumnDefaultAwareInterface +{ + /** + * @var bool + */ + private $nullable; + + /** + * @var bool + */ + private $default; + + /** + * Constructor. + * + * @param string $name + * @param string $type + * @param Table $table + * @param bool $nullable + * @param bool $default + * @param string|null $comment + * @param string|null $onCreate + */ + public function __construct( + string $name, + string $type, + Table $table, + bool $nullable = true, + bool $default = null, + string $comment = null, + string $onCreate = null + ) { + parent::__construct($name, $type, $table, $comment, $onCreate); + $this->nullable = $nullable; + $this->default = $default; + } + + /** + * Check whether column can be nullable. + * + * @return bool + */ + public function isNullable() + { + return $this->nullable; + } + + /** + * Return default value. + * Note: default value should be int. + * + * @return int|null + */ + public function getDefault() + { + return $this->default; + } + + /** + * @inheritdoc + */ + public function getDiffSensitiveParams() + { + return [ + 'nullable' => $this->isNullable(), + 'default' => $this->getDefault(), + 'comment' => $this->getComment() + ]; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnDefaultAwareInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnDefaultAwareInterface.php similarity index 82% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnDefaultAwareInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnDefaultAwareInterface.php index 91c206373d1ae..6c043cd8ed838 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnDefaultAwareInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnDefaultAwareInterface.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; /** * Provides default value for column. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnIdentityAwareInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnIdentityAwareInterface.php similarity index 83% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnIdentityAwareInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnIdentityAwareInterface.php index 6f0a5aa572d82..63c13711404fd 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnIdentityAwareInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnIdentityAwareInterface.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; /** * Provides auto_increment flag for column. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnNullableAwareInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnNullableAwareInterface.php similarity index 86% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnNullableAwareInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnNullableAwareInterface.php index 91db2b41a4437..0ae403abd5702 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnNullableAwareInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnNullableAwareInterface.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; /** * Provides nullable flag for element. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnUnsignedAwareInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnUnsignedAwareInterface.php similarity index 86% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnUnsignedAwareInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnUnsignedAwareInterface.php index 6f5c5263b6dd7..be5d6bf91ef75 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/ColumnUnsignedAwareInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/ColumnUnsignedAwareInterface.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; /** * Unsigned flag provider for element. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Date.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Date.php new file mode 100644 index 0000000000000..13f6c0da0499d --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Date.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Date column. + * Declared in SQL, like DATE. + * Does not have any additional params. + * Is represented like: YY:MM:DD. + */ +class Date extends Column implements + ElementDiffAwareInterface, + ColumnNullableAwareInterface +{ + /** + * @var bool + */ + private $nullable; + + /** + * Constructor. + * + * @param string $name + * @param string $type + * @param Table $table + * @param bool $nullable + * @param string|null $comment + * @param string|null $onCreate + */ + public function __construct( + string $name, + string $type, + Table $table, + bool $nullable = true, + string $comment = null, + string $onCreate = null + ) { + parent::__construct($name, $type, $table, $comment, $onCreate); + $this->nullable = $nullable; + } + + /** + * @inheritdoc + */ + public function getDiffSensitiveParams() + { + return [ + 'type' => $this->getType(), + 'nullable' => $this->isNullable(), + 'comment' => $this->getComment() + ]; + } + + /** + * {@inheritdoc} + */ + public function isNullable(): bool + { + return $this->nullable; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Integer.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Integer.php new file mode 100644 index 0000000000000..5c0c89dd0b4b8 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Integer.php @@ -0,0 +1,149 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Integer column. + * Declared in SQL, like INT(11) or BIGINT(20). + * Where digit is padding, how many zeros should be added before first non-zero digit. + */ +class Integer extends Column implements + ElementDiffAwareInterface, + ColumnUnsignedAwareInterface, + ColumnNullableAwareInterface, + ColumnIdentityAwareInterface, + ColumnDefaultAwareInterface +{ + /** + * @var bool + */ + private $nullable; + + /** + * @var int + */ + private $default; + + /** + * @var bool + */ + private $unsigned; + /** + * @var int + */ + private $padding; + /** + * @var bool + */ + private $identity; + + /** + * Constructor. + * + * @param string $name + * @param string $type + * @param Table $table + * @param int $padding + * @param bool $nullable + * @param bool $unsigned + * @param bool $identity + * @param float|int $default + * @param string|null $comment + * @param string|null $onCreate + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + */ + public function __construct( + string $name, + string $type, + Table $table, + int $padding, + bool $nullable = true, + bool $unsigned = false, + bool $identity = false, + int $default = null, + string $comment = null, + string $onCreate = null + ) { + parent::__construct($name, $type, $table, $comment, $onCreate); + $this->nullable = $nullable; + $this->default = $default; + $this->unsigned = $unsigned; + $this->padding = $padding; + $this->identity = $identity; + } + + /** + * Column padding. + * + * @return int + */ + public function getPadding() + { + return $this->padding; + } + + /** + * Check whether column can be nullable. + * + * @return bool + */ + public function isNullable() + { + return $this->nullable; + } + + /** + * Return default value. + * Note: default value should be int. + * + * @return int | null + */ + public function getDefault() + { + return $this->default; + } + + /** + * Check whether element is unsigned or not. + * + * @return bool + */ + public function isUnsigned() + { + return $this->unsigned; + } + + /** + * Define whether column can be autoincrement or not. + * + * @return bool + */ + public function isIdentity() + { + return $this->identity; + } + + /** + * @inheritdoc + */ + public function getDiffSensitiveParams() + { + return [ + 'type' => $this->getType(), + 'nullable' => $this->isNullable(), + 'padding' => $this->getPadding(), + 'unsigned' => $this->isUnsigned(), + 'identity' => $this->isIdentity(), + 'default' => $this->getDefault(), + 'comment' => $this->getComment() + ]; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Real.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Real.php new file mode 100644 index 0000000000000..fd24ff1c5523a --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Real.php @@ -0,0 +1,151 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Real data column. + * Declared in SQL, like FLOAT(P, S), DOUBLE(P, S) or DECIMAL(P, S) + * where S - is scale, P - is precision. + * https://dev.mysql.com/doc/refman/5.7/en/precision-math-decimal-characteristics.html + */ +class Real extends Column implements + ElementDiffAwareInterface, + ColumnUnsignedAwareInterface, + ColumnNullableAwareInterface, + ColumnDefaultAwareInterface +{ + /** + * @var int + */ + private $precision; + + /** + * @var int + */ + private $scale; + + /** + * @var bool + */ + private $nullable; + + /** + * @var float + */ + private $default; + + /** + * @var bool + */ + private $unsigned; + + /** + * Constructor. + * + * @param string $name + * @param string $type + * @param Table $table + * @param int $precision + * @param int $scale + * @param bool $nullable + * @param bool $unsigned + * @param float $default + * @param string|null $comment + * @param string|null $onCreate + * + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + */ + public function __construct( + string $name, + string $type, + Table $table, + int $precision, + int $scale, + bool $nullable = true, + bool $unsigned = false, + float $default = null, + string $comment = null, + string $onCreate = null + ) { + parent::__construct($name, $type, $table, $comment, $onCreate); + $this->precision = $precision; + $this->scale = $scale; + $this->nullable = $nullable; + $this->default = $default; + $this->unsigned = $unsigned; + } + + /** + * Column precision. + * + * @return int + */ + public function getPrecision() + { + return (int)$this->precision; + } + + /** + * Column scale. + * + * @return int + */ + public function getScale() + { + return (int)$this->scale; + } + + /** + * Check whether column can be nullable. + * + * @return bool + */ + public function isNullable() + { + return (bool)$this->nullable; + } + + /** + * Return default value. + * Note: default value should be float. + * + * @return float|null + */ + public function getDefault() + { + return $this->default; + } + + /** + * Check whether element is unsigned or not. + * + * @return bool + */ + public function isUnsigned() + { + return (bool)$this->unsigned; + } + + /** + * @inheritdoc + */ + public function getDiffSensitiveParams() + { + return [ + 'type' => $this->getType(), + 'nullable' => $this->isNullable(), + 'precision' => $this->getPrecision(), + 'scale' => $this->getScale(), + 'unsigned' => $this->isUnsigned(), + 'default' => $this->getDefault(), + 'comment' => $this->getComment() + ]; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/StringBinary.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/StringBinary.php new file mode 100644 index 0000000000000..58e6df1146300 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/StringBinary.php @@ -0,0 +1,109 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * String or Binary column. + * Declared in SQL, like VARCHAR(L), BINARY(L) + * where L - length. + */ +class StringBinary extends Column implements + ElementDiffAwareInterface, + ColumnNullableAwareInterface, + ColumnDefaultAwareInterface +{ + /** + * @var bool + */ + private $nullable; + + /** + * @var int + */ + private $default; + + /** + * @var int + */ + private $length; + + /** + * Constructor. + * + * @param string $name + * @param string $type + * @param Table $table + * @param int $length + * @param bool $nullable + * @param string $default + * @param string|null $comment + * @param string|null $onCreate + */ + public function __construct( + string $name, + string $type, + Table $table, + int $length, + bool $nullable = true, + string $default = null, + string $comment = null, + string $onCreate = null + ) { + parent::__construct($name, $type, $table, $comment, $onCreate); + $this->nullable = $nullable; + $this->default = $default; + $this->length = $length; + } + + /** + * Check whether column can be nullable. + * + * @return bool + */ + public function isNullable() + { + return $this->nullable; + } + + /** + * Return default value. + * Note: default value should be string. + * + * @return string | null + */ + public function getDefault() + { + return $this->default; + } + + /** + * Length can be integer value from 0 to 255. + * + * @return int + */ + public function getLength() + { + return $this->length; + } + + /** + * @inheritdoc + */ + public function getDiffSensitiveParams() + { + return [ + 'type' => $this->getType(), + 'nullable' => $this->isNullable(), + 'default' => $this->getDefault(), + 'length' => $this->getLength(), + 'comment' => $this->getComment() + ]; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Text.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Text.php new file mode 100644 index 0000000000000..b127d5d50e08c --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Text.php @@ -0,0 +1,68 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Text column. + * Declared in SQL, like: TEXT, TINYTEXT, MEDIUMTEXT, LONGTEXT. + */ +class Text extends Column implements + ElementDiffAwareInterface, + ColumnNullableAwareInterface +{ + /** + * @var bool + */ + private $nullable; + + /** + * Constructor. + * + * @param string $name + * @param string $type + * @param Table $table + * @param bool $nullable + * @param string|null $comment + * @param string|null $onCreate + */ + public function __construct( + string $name, + string $type, + Table $table, + bool $nullable = true, + string $comment = null, + string $onCreate = null + ) { + parent::__construct($name, $type, $table, $comment, $onCreate); + $this->nullable = $nullable; + } + + /** + * Check whether column can be nullable. + * + * @return bool + */ + public function isNullable() + { + return $this->nullable; + } + + /** + * @inheritdoc + */ + public function getDiffSensitiveParams() + { + return [ + 'type' => $this->getType(), + 'nullable' => $this->isNullable(), + 'comment' => $this->getComment() + ]; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Timestamp.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Timestamp.php new file mode 100644 index 0000000000000..240a4bd755dbe --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Columns/Timestamp.php @@ -0,0 +1,105 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Columns; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Timestamp column. + * Declared in SQL, like Timestamp. + * Has 2 additional params: default and on_update. + */ +class Timestamp extends Column implements + ElementDiffAwareInterface, + ColumnDefaultAwareInterface, + ColumnNullableAwareInterface +{ + /** + * @var string + */ + private $default; + + /** + * @var null|string + */ + private $onUpdate; + + /** + * @var bool + */ + private $nullable; + + /** + * Constructor. + * + * @param string $name + * @param string $type + * @param Table $table + * @param string $default + * @param bool $nullable + * @param string|null $onUpdate + * @param string|null $comment + * @param string|null $onCreate + */ + public function __construct( + string $name, + string $type, + Table $table, + string $default, + bool $nullable = true, + string $onUpdate = null, + string $comment = null, + string $onCreate = null + ) { + parent::__construct($name, $type, $table, $comment, $onCreate); + $this->default = $default; + $this->onUpdate = $onUpdate; + $this->nullable = $nullable; + } + + /** + * Return default value. + * + * @return int|null + */ + public function getDefault() + { + return $this->default; + } + + /** + * Retrieve on_update param. + * + * @return string + */ + public function getOnUpdate() + { + return $this->onUpdate; + } + + /** + * @inheritdoc + */ + public function getDiffSensitiveParams() + { + return [ + 'type' => $this->getType(), + 'default' => $this->getDefault(), + 'onUpdate' => $this->getOnUpdate(), + 'comment' => $this->getComment() + ]; + } + + /** + * {@inheritdoc} + */ + public function isNullable(): bool + { + return $this->nullable; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Constraint.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Constraint.php similarity index 95% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Constraint.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Constraint.php index 211965385cf99..a7f7fcb2e6656 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Constraint.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Constraint.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto; +namespace Magento\Framework\Setup\Declaration\Schema\Dto; /** * Constraint structural element. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Constraints/Internal.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Constraints/Internal.php new file mode 100644 index 0000000000000..e15407a4a837d --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Constraints/Internal.php @@ -0,0 +1,82 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Constraints; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraint; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Internal key constraint is constraint that add KEY onto table columns, on which it is declared. + * All columns that are holded in this constraint are represented as unique vector. + */ +class Internal extends Constraint implements ElementDiffAwareInterface +{ + /** + * As we can have only one primary key. It name should be always PRIMARY/ + */ + const PRIMARY_NAME = "PRIMARY"; + + /** + * @var array + */ + private $columns; + + /** + * Internal constructor. + * + * @param string $name + * @param string $type + * @param Table $table + * @param array $columns + */ + public function __construct( + $name, + $type, + Table $table, + array $columns + ) { + parent::__construct($name, $type, $table); + $this->columns = $columns; + } + + /** + * Get key columns. + * + * @return Column[] + */ + public function getColumns() + { + return $this->columns; + } + + /** + * Retrieve column names. + * + * @return array + */ + public function getColumnNames() + { + return array_map( + function (Column $column) { + return $column->getName(); + }, + $this->getColumns() + ); + } + + /** + * @inheritdoc + */ + public function getDiffSensitiveParams() + { + return [ + 'type' => $this->getType(), + 'columns' => $this->getColumnNames() + ]; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Constraints/Reference.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Constraints/Reference.php similarity index 87% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Constraints/Reference.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Constraints/Reference.php index 5050cde16b45b..b79e8fdd3cc2f 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Constraints/Reference.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Constraints/Reference.php @@ -3,12 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Constraints; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Constraints; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraint; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraint; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementDiffAwareInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; /** * Reference (Foreign Key) constraint. @@ -51,6 +51,7 @@ class Reference extends Constraint implements ElementDiffAwareInterface * @param Table $referenceTable * @param Column $referenceColumn * @param string $onDelete + * @SuppressWarnings(Magento.TypeDuplication) */ public function __construct( string $name, diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/ElementDiffAwareInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/ElementDiffAwareInterface.php similarity index 92% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/ElementDiffAwareInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/ElementDiffAwareInterface.php index 4fa23955685d7..54413cc7234f5 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/ElementDiffAwareInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/ElementDiffAwareInterface.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto; +namespace Magento\Framework\Setup\Declaration\Schema\Dto; /** * Element diff provider interface. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/ElementFactory.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/ElementFactory.php similarity index 94% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/ElementFactory.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/ElementFactory.php index 0976f48da887b..ff770e2d0dcd8 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/ElementFactory.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/ElementFactory.php @@ -3,10 +3,10 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto; +namespace Magento\Framework\Setup\Declaration\Schema\Dto; use Magento\Framework\Stdlib\BooleanUtils; -use Magento\Setup\Model\Declaration\Schema\Dto\Factories\FactoryInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Factories\FactoryInterface; /** * DTO Element factory. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/ElementInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/ElementInterface.php similarity index 94% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/ElementInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/ElementInterface.php index 0fd0a9e4a674d..1471dba2dfb84 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/ElementInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/ElementInterface.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto; +namespace Magento\Framework\Setup\Declaration\Schema\Dto; /** * Generic DTO Element interface. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Blob.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Blob.php new file mode 100644 index 0000000000000..739f42fd1710e --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Blob.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Blob factory. + */ +class Blob implements FactoryInterface +{ + /** + * Default blob length. + */ + const DEFAULT_BLOB_LENGTH = 65536; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $className; + + /** + * Constructor. + * + * @param ObjectManagerInterface $objectManager + * @param string $className + */ + public function __construct( + ObjectManagerInterface $objectManager, + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Blob::class + ) { + $this->objectManager = $objectManager; + $this->className = $className; + } + + /** + * {@inheritdoc} + */ + public function create(array $data) + { + if (!isset($data['length'])) { + $data['length'] = self::DEFAULT_BLOB_LENGTH; + } + + return $this->objectManager->create($this->className, $data); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Boolean.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Boolean.php new file mode 100644 index 0000000000000..5e22fa70f6f60 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Boolean.php @@ -0,0 +1,65 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Stdlib\BooleanUtils; + +/** + * Boolean factory. + */ +class Boolean implements FactoryInterface +{ + /** + * Default value for boolean xsi:type. + */ + const DEFAULT_BOOLEAN = false; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $className; + + /** + * @var BooleanUtils + */ + private $booleanUtils; + + /** + * Constructor. + * + * @param ObjectManagerInterface $objectManager + * @param BooleanUtils $booleanUtils + * @param string $className + */ + public function __construct( + ObjectManagerInterface $objectManager, + BooleanUtils $booleanUtils, + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Boolean::class + ) { + $this->objectManager = $objectManager; + $this->className = $className; + $this->booleanUtils = $booleanUtils; + } + + /** + * {@inheritdoc} + */ + public function create(array $data) + { + if (isset($data['default'])) { + $data['default'] = $this->booleanUtils->toBoolean($data['default']); + } + + return $this->objectManager->create($this->className, $data); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Date.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Date.php new file mode 100644 index 0000000000000..f5e3271c5ff2a --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Date.php @@ -0,0 +1,47 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Date factory. + * Remove default and nullable attributes, as date type must not have any attributes. + */ +class Date implements FactoryInterface +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $className; + + /** + * Constructor. + * + * @param ObjectManagerInterface $objectManager + * @param string $className + */ + public function __construct( + ObjectManagerInterface $objectManager, + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Date::class + ) { + $this->objectManager = $objectManager; + $this->className = $className; + } + + /** + * {@inheritdoc} + */ + public function create(array $data) + { + return $this->objectManager->create($this->className, $data); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/FactoryInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/FactoryInterface.php new file mode 100644 index 0000000000000..26ed3e8a4d277 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/FactoryInterface.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; + +/** + * DTO Element Factory Interface. + */ +interface FactoryInterface +{ + /** + * Create element using definition data array. + * + * @param array $data + * @return ElementInterface + */ + public function create(array $data); +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Foreign.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Foreign.php similarity index 86% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Foreign.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Foreign.php index 76febc2b09d68..030f2a49d81df 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Foreign.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Foreign.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; use Magento\Framework\ObjectManagerInterface; @@ -35,7 +35,7 @@ class Foreign implements FactoryInterface */ public function __construct( ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference::class + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference::class ) { $this->objectManager = $objectManager; $this->className = $className; diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Index.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Index.php new file mode 100644 index 0000000000000..919aa05634512 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Index.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Index element factory. + */ +class Index implements FactoryInterface +{ + /** + * Default index type. + */ + const DEFAULT_INDEX_TYPE = "BTREE"; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $className; + + /** + * Constructor. + * + * @param ObjectManagerInterface $objectManager + * @param string $className + */ + public function __construct( + ObjectManagerInterface $objectManager, + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Index::class + ) { + $this->objectManager = $objectManager; + $this->className = $className; + } + + /** + * {@inheritdoc} + */ + public function create(array $data) + { + if (!isset($data['indexType'])) { + $data['indexType'] = self::DEFAULT_INDEX_TYPE; + } + + return $this->objectManager->create($this->className, $data); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Integer.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Integer.php new file mode 100644 index 0000000000000..5cd7bcac39736 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Integer.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Integer DTO element factory. + */ +class Integer implements FactoryInterface +{ + /** + * Describe default for different integer types. + * + * @var array + */ + private static $defaultPadding = [ + 'int' => '11', + 'tinyint' => '2', + 'smallint' => '5', + 'bigint' => '20' + ]; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $className; + + /** + * Constructor. + * + * @param ObjectManagerInterface $objectManager + * @param string $className + */ + public function __construct( + ObjectManagerInterface $objectManager, + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer::class + ) { + $this->objectManager = $objectManager; + $this->className = $className; + } + + /** + * {@inheritdoc} + */ + public function create(array $data) + { + if (!isset($data['padding'])) { + $data['padding'] = self::$defaultPadding[$data['type']]; + } + //Auto increment field can`t be null + if (isset($data['identity']) && $data['identity']) { + $data['nullable'] = false; + } + + if (isset($data['default'])) { + $data['default'] = (int) $data['default']; + } + + return $this->objectManager->create($this->className, $data); + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/LongBlob.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/LongBlob.php similarity index 87% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/LongBlob.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/LongBlob.php index b6507151cd5c7..17c0c9d27dc4c 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/LongBlob.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/LongBlob.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; use Magento\Framework\ObjectManagerInterface; @@ -35,7 +35,7 @@ class LongBlob implements FactoryInterface */ public function __construct( ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Blob::class + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Blob::class ) { $this->objectManager = $objectManager; $this->className = $className; diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/LongText.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/LongText.php similarity index 87% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/LongText.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/LongText.php index 790a8bb573cb9..2e364a40a4bf5 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/LongText.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/LongText.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; use Magento\Framework\ObjectManagerInterface; @@ -35,7 +35,7 @@ class LongText implements FactoryInterface */ public function __construct( ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Text::class + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Text::class ) { $this->objectManager = $objectManager; $this->className = $className; diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/MediumBlob.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/MediumBlob.php similarity index 87% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/MediumBlob.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/MediumBlob.php index 5520d32a2da4c..ae771d6e378fe 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/MediumBlob.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/MediumBlob.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; use Magento\Framework\ObjectManagerInterface; @@ -35,7 +35,7 @@ class MediumBlob implements FactoryInterface */ public function __construct( ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Blob::class + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Blob::class ) { $this->objectManager = $objectManager; $this->className = $className; diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/MediumText.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/MediumText.php similarity index 87% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/MediumText.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/MediumText.php index 63254aead32e9..36c0207460126 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/MediumText.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/MediumText.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; use Magento\Framework\ObjectManagerInterface; @@ -35,7 +35,7 @@ class MediumText implements FactoryInterface */ public function __construct( ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Text::class + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Text::class ) { $this->objectManager = $objectManager; $this->className = $className; diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Primary.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Primary.php similarity index 81% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Primary.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Primary.php index 3327f9818de78..ca87ab34f007d 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Primary.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Primary.php @@ -3,10 +3,10 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; use Magento\Framework\ObjectManagerInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Internal; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal; /** * Primary key DTO element factory. @@ -33,7 +33,7 @@ class Primary implements FactoryInterface */ public function __construct( ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Internal::class + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal::class ) { $this->objectManager = $objectManager; $this->className = $className; diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Real.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Real.php new file mode 100644 index 0000000000000..cdb740ea0a92d --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Real.php @@ -0,0 +1,71 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Real type DTO element factory. + * + * Used for real numbers DTO elements like decimal, float or double. + * Decimal type is highly recommended for business math. + */ +class Real implements FactoryInterface +{ + /** + * Default SQL precision. + */ + const DEFAULT_PRECISION = "10"; + + /** + * Default SQL scale. + */ + const DEFAULT_SCALE = "0"; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $className; + + /** + * Constructor. + * + * @param ObjectManagerInterface $objectManager + * @param string $className + */ + public function __construct( + ObjectManagerInterface $objectManager, + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Real::class + ) { + $this->objectManager = $objectManager; + $this->className = $className; + } + + /** + * {@inheritdoc} + */ + public function create(array $data) + { + if (!isset($data['precision'])) { + $data['precision'] = ($data['type'] === 'decimal') ? self::DEFAULT_PRECISION : 0; + } + + if (!isset($data['scale'])) { + $data['scale'] = ($data['type'] === 'decimal') ? self::DEFAULT_SCALE : 0; + } + + if (isset($data['default'])) { + $data['default'] = floatval($data['default']); + } + + return $this->objectManager->create($this->className, $data); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/StringBinary.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/StringBinary.php new file mode 100644 index 0000000000000..71b955ad7364c --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/StringBinary.php @@ -0,0 +1,54 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\ObjectManagerInterface; + +/** + * StringBinary DTO element factory. + * + * Used for char, varchar, binary, varbinary types. + */ +class StringBinary implements FactoryInterface +{ + /** + * Default data length. + */ + const DEFAULT_TEXT_LENGTH = 255; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $className; + + /** + * Constructor. + * + * @param ObjectManagerInterface $objectManager + * @param string $className + */ + public function __construct( + ObjectManagerInterface $objectManager, + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\StringBinary::class + ) { + $this->objectManager = $objectManager; + $this->className = $className; + } + + /** + * {@inheritdoc} + */ + public function create(array $data) + { + $data['length'] = isset($data['length']) ? (int) $data['length'] : self::DEFAULT_TEXT_LENGTH; + return $this->objectManager->create($this->className, $data); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Table.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Table.php new file mode 100644 index 0000000000000..807b5b83db121 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Table.php @@ -0,0 +1,74 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\ObjectManagerInterface; + +/** + * Table DTO element factory. + */ +class Table implements FactoryInterface +{ + /** + * Default engine. + * May be redefined for other DBMS. + */ + const DEFAULT_ENGINE = 'innodb'; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $className; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * Constructor. + * + * @param ObjectManagerInterface $objectManager + * @param ResourceConnection $resourceConnection + * @param string $className + */ + public function __construct( + ObjectManagerInterface $objectManager, + ResourceConnection $resourceConnection, + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Table::class + ) { + $this->objectManager = $objectManager; + $this->className = $className; + $this->resourceConnection = $resourceConnection; + } + + /** + * {@inheritdoc} + */ + public function create(array $data) + { + if ($data['engine'] === null) { + $data['engine'] = self::DEFAULT_ENGINE; + } + $tablePrefix = $this->resourceConnection->getTablePrefix(); + $nameWithoutPrefix = $data['name']; + if (!empty($tablePrefix) && strpos($nameWithoutPrefix, $tablePrefix) === 0) { + $data['nameWithoutPrefix'] = str_replace($tablePrefix, "", $data['name']); + } else { + $data['name'] = $tablePrefix . $data['name']; + $data['nameWithoutPrefix'] = $nameWithoutPrefix; + } + + return $this->objectManager->create($this->className, $data); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Text.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Text.php new file mode 100644 index 0000000000000..24b3168d5679a --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Text.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Text DTO element factory. + */ +class Text implements FactoryInterface +{ + /** + * Default text length. + */ + const DEFAULT_TEXT_LENGTH = 65536; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $className; + + /** + * Constructor. + * + * @param ObjectManagerInterface $objectManager + * @param string $className + */ + public function __construct( + ObjectManagerInterface $objectManager, + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Text::class + ) { + $this->objectManager = $objectManager; + $this->className = $className; + } + + /** + * {@inheritdoc} + */ + public function create(array $data) + { + if (!isset($data['length'])) { + $data['length'] = self::DEFAULT_TEXT_LENGTH; + } + + return $this->objectManager->create($this->className, $data); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Timestamp.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Timestamp.php new file mode 100644 index 0000000000000..4a7cca43919a1 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Timestamp.php @@ -0,0 +1,82 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; + +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Stdlib\BooleanUtils; + +/** + * Timestamp DTO element factory. + * + * This format is used to save date (year, month, day). + * Probably your SQL engine will save date in this format: 'YYYY-MM-DD HH:MM::SS' + * Date time in invalid format will be converted to '0000-00-00 00:00:00' string + * MySQL timestamp is similar to UNIX timestamp. You can pass you local time there and it will + * be converted to UTC timezone. Then when you will try to pull your time back it will be converted + * to your local time again. + * Unix range: 1970-01-01 00:00:01' UTC to '2038-01-09 03:14:07' + */ +class Timestamp implements FactoryInterface +{ + /** + * Nullable timestamp value. + */ + const NULL_TIMESTAMP = 'NULL'; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $className; + + /** + * @var BooleanUtils + */ + private $booleanUtils; + + /** + * Constructor. + * + * @param ObjectManagerInterface $objectManager + * @param BooleanUtils $booleanUtils + * @param string $className + */ + public function __construct( + ObjectManagerInterface $objectManager, + BooleanUtils $booleanUtils, + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp::class + ) { + $this->objectManager = $objectManager; + $this->className = $className; + $this->booleanUtils = $booleanUtils; + } + + /** + * {@inheritdoc} + */ + public function create(array $data) + { + $data['onUpdate'] = isset($data['on_update']) ? $data['on_update'] : null; + //OnUpdate is boolean as there is only one possible value for onUpdate statement. + if ($data['onUpdate'] && $data['onUpdate'] !== 'CURRENT_TIMESTAMP') { + if ($this->booleanUtils->toBoolean($data['onUpdate'])) { + $data['onUpdate'] = 'CURRENT_TIMESTAMP'; + } else { + unset($data['onUpdate']); + } + } + //By default default attribute is not used. + if (!isset($data['default'])) { + $data['default'] = self::NULL_TIMESTAMP; + } + + return $this->objectManager->create($this->className, $data); + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Unique.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Unique.php similarity index 84% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Unique.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Unique.php index 506f988dbf909..3709f035fe3a4 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Unique.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Factories/Unique.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; +namespace Magento\Framework\Setup\Declaration\Schema\Dto\Factories; use Magento\Framework\ObjectManagerInterface; @@ -30,7 +30,7 @@ class Unique implements FactoryInterface */ public function __construct( ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Internal::class + $className = \Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal::class ) { $this->objectManager = $objectManager; $this->className = $className; diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/GenericElement.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/GenericElement.php similarity index 94% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/GenericElement.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/GenericElement.php index f2cff40110348..122f1afd6f9cc 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/GenericElement.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/GenericElement.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto; +namespace Magento\Framework\Setup\Declaration\Schema\Dto; /** * Generic element DTO. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Index.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Index.php new file mode 100644 index 0000000000000..ea8c07bf19e4c --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Index.php @@ -0,0 +1,126 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Declaration\Schema\Dto; + +/** + * Index structural element. + * Used to speedup read operations from SQL database. + */ +class Index extends GenericElement implements + ElementInterface, + TableElementInterface, + ElementDiffAwareInterface +{ + /** + * Element type. + */ + const TYPE = 'index'; + + /** + * Fulltext index type. + */ + const FULLTEXT_INDEX = "fulltext"; + + /** + * @var Table + */ + private $table; + + /** + * @var array + */ + private $columns; + + /** + * @var string + */ + private $indexType; + + /** + * Constructor. + * + * @param string $name + * @param string $type + * @param Table $table + * @param array $columns + * @param string $indexType + */ + public function __construct( + string $name, + string $type, + Table $table, + array $columns, + string $indexType + ) { + parent::__construct($name, $type); + $this->table = $table; + $this->columns = $columns; + $this->indexType = $indexType; + } + + /** + * Return columns in order, in which they should go in composite index. + * + * @return Column[] + */ + public function getColumns() + { + return $this->columns; + } + + /** + * {@inheritdoc} + */ + public function getTable() + { + return $this->table; + } + + /** + * {@inheritdoc} + */ + public function getDiffSensitiveParams() + { + return [ + 'type' => $this->getType(), + 'columns' => $this->getColumnNames(), + 'indexType' => $this->getIndexType() + ]; + } + + /** + * Retrieve array with column names from column objects collections. + * + * @return array + */ + public function getColumnNames() + { + return array_map( + function (Column $column) { + return $column->getName(); + }, + $this->getColumns() + ); + } + + /** + * {@inheritdoc} + */ + public function getElementType() + { + return self::TYPE; + } + + /** + * Get index type (FULLTEXT, BTREE, HASH). + * + * @return string + */ + public function getIndexType() + { + return $this->indexType; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Schema.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Schema.php similarity index 96% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Schema.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Schema.php index f524d767f9d62..3e68b985283cf 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Schema.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Schema.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto; +namespace Magento\Framework\Setup\Declaration\Schema\Dto; use Magento\Framework\App\ResourceConnection; diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/SchemaFactory.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/SchemaFactory.php similarity index 86% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/SchemaFactory.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/SchemaFactory.php index e8bb65c55f70b..561ed427e70e4 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/SchemaFactory.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/SchemaFactory.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto; +namespace Magento\Framework\Setup\Declaration\Schema\Dto; use Magento\Framework\ObjectManagerInterface; @@ -35,7 +35,7 @@ public function __construct(ObjectManagerInterface $objectManager) /** * Create class instance with specified parameters. * - * @return \Magento\Setup\Model\Declaration\Schema\Dto\Schema + * @return \Magento\Framework\Setup\Declaration\Schema\Dto\Schema */ public function create() { diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Table.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Table.php new file mode 100644 index 0000000000000..76b87ea8fc886 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/Table.php @@ -0,0 +1,300 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Dto; + +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; + +/** + * Table structural element + * Aggregate inside itself: columns, constraints and indexes + * Resource is also specified on this strucural element + */ +class Table extends GenericElement implements + ElementInterface, + ElementDiffAwareInterface +{ + /** + * In case if we will need to change this object: add, modify or drop, we will need + * to define it by its type + */ + const TYPE = 'table'; + + /** + * @var Constraint[] + */ + private $constraints = []; + + /** + * @var Column[] + */ + private $columns = []; + + /** + * @var string + */ + protected $type = 'table'; + + /** + * @var Index[] + */ + private $indexes = []; + + /** + * @var string + */ + private $resource; + + /** + * @var string + */ + private $engine; + + /** + * @var string + */ + private $nameWithoutPrefix; + + /** + * @var null|string + */ + private $comment; + + /** + * @param string $name + * @param string $nameWithoutPrefix + * @param string $type + * @param string $resource + * @param string $engine + * @param string|null $comment + * @param array $columns + * @param array $indexes + * @param array $constraints + * @internal param string $nameWithPrefix + */ + public function __construct( + string $name, + string $type, + string $nameWithoutPrefix, + string $resource, + string $engine, + string $comment = null, + array $columns = [], + array $indexes = [], + array $constraints = [] + ) { + parent::__construct($name, $type); + $this->columns = $columns; + $this->indexes = $indexes; + $this->constraints = $constraints; + $this->resource = $resource; + $this->engine = $engine; + $this->nameWithoutPrefix = $nameWithoutPrefix; + $this->comment = $comment; + } + + /** + * Return different table constraints. + * It can be constraint like unique key or reference to another table, etc + * + * @return Constraint[] + */ + public function getConstraints() + { + return $this->constraints; + } + + /** + * @param string $name + * @return Constraint | bool + */ + public function getConstraintByName($name) + { + return isset($this->constraints[$name]) ? $this->constraints[$name] : false; + } + + /** + * This method lookup only for foreign keys constraints + * + * @return Reference[] + */ + public function getReferenceConstraints() + { + $constraints = []; + + foreach ($this->getConstraints() as $constraint) { + if ($constraint instanceof Reference) { + $constraints[$constraint->getName()] = $constraint; + } + } + + return $constraints; + } + + /** + * As primary constraint always have one name + * and can be only one for table + * it name is allocated into it constraint + * + * @return bool|Internal + */ + public function getPrimaryConstraint() + { + return isset($this->constraints[Internal::PRIMARY_NAME]) ? + $this->constraints[Internal::PRIMARY_NAME] : + false; + } + + /** + * @param string $name + * @return Index | bool + */ + public function getIndexByName($name) + { + return isset($this->indexes[$name]) ? $this->indexes[$name] : false; + } + + /** + * Return all columns. + * Note, table always must have columns + * + * @return Column[] + */ + public function getColumns() + { + return $this->columns; + } + + /** + * Return all indexes, that are applied to table + * + * @return Index[] + */ + public function getIndexes() + { + return $this->indexes; + } + + /** + * Retrieve shard name, on which table will exists + * + * @return string + */ + public function getResource() + { + return $this->resource; + } + + /** + * This is workaround, as any DTO object couldnt be changed after instantiation. + * However there is case, when we have 2 tables with constraints in different tables, + * that depends to each other table. So we need to setup DTO first and only then pass + * problematic constraints to it, in order to avoid circular dependency. + * + * @param Constraint[] $constraints + */ + public function addConstraints(array $constraints) + { + $this->constraints = array_replace($this->constraints, $constraints); + } + + /** + * Add columns + * + * @param Column[] $columns + */ + public function addColumns(array $columns) + { + $this->columns = array_replace($this->columns, $columns); + } + + /** + * If column exists - retrieve column + * + * @param string $nameOrId + * @return Column | bool + */ + public function getColumnByName($nameOrId) + { + if (isset($this->columns[$nameOrId])) { + return $this->columns[$nameOrId]; + } + + return false; + } + + /** + * Retrieve elements by specific type + * Allowed types: columns, constraints, indexes... + * + * @param string $type + * @return ElementInterface[] + */ + public function getElementsByType($type) + { + if (!isset($this->{$type})) { + throw new \InvalidArgumentException(sprintf("Type %s is not defined", $type)); + } + + return $this->{$type}; + } + + /** + * This is workaround, as any DTO object couldnt be changed after instantiation. + * However there is case, when we depends on column definition we need modify our indexes + * + * @param array $indexes + */ + public function addIndexes(array $indexes) + { + $this->indexes = array_replace($this->indexes, $indexes); + } + + /** + * @inheritdoc + */ + public function getElementType() + { + return self::TYPE; + } + + /** + * @return string + */ + public function getEngine(): string + { + return $this->engine; + } + + /** + * @inheritdoc + */ + public function getDiffSensitiveParams() + { + return [ + 'resource' => $this->getResource(), + 'engine' => $this->getEngine(), + 'comment' => $this->getComment() + ]; + } + + /** + * @return string + */ + public function getNameWithoutPrefix(): string + { + return $this->nameWithoutPrefix; + } + + /** + * @return null|string + */ + public function getComment() + { + return $this->comment; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/TableElementInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/TableElementInterface.php similarity index 86% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Dto/TableElementInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/TableElementInterface.php index 371c756d7c427..630f09b18aa26 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/TableElementInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Dto/TableElementInterface.php @@ -3,7 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Dto; +namespace Magento\Framework\Setup\Declaration\Schema\Dto; /** * Table DTO Element interface. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/ElementHistory.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/ElementHistory.php similarity index 89% rename from setup/src/Magento/Setup/Model/Declaration/Schema/ElementHistory.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/ElementHistory.php index af6f857a5b733..f609d2715d324 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/ElementHistory.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/ElementHistory.php @@ -4,9 +4,9 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema; +namespace Magento\Framework\Setup\Declaration\Schema; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; /** * Element history container. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/ElementHistoryFactory.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/ElementHistoryFactory.php similarity index 94% rename from setup/src/Magento/Setup/Model/Declaration/Schema/ElementHistoryFactory.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/ElementHistoryFactory.php index 5f2cff36a0a33..174e213e75b6e 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/ElementHistoryFactory.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/ElementHistoryFactory.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema; +namespace Magento\Framework\Setup\Declaration\Schema; use Magento\Framework\ObjectManagerInterface; diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/FileSystem/Csv.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/FileSystem/Csv.php new file mode 100644 index 0000000000000..1720938c945b4 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/FileSystem/Csv.php @@ -0,0 +1,177 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\FileSystem; + +use Magento\Framework\App\Filesystem\DirectoryList; + +/** + * CSV file operations wrapper. + */ +class Csv implements \Magento\Framework\Setup\Declaration\Schema\DataSavior\DumpAccessorInterface +{ + /** + * Folder where will be persisted all csv dumps + */ + const DUMP_FOLDER = 'declarative_dumps_csv'; + + /** + * @var int + */ + private $baseBatchSize; + + /** + * @var DirectoryList + */ + private $directoryList; + + /** + * @var \Magento\Framework\Filesystem\Driver\File + */ + private $fileDriver; + + /** + * Csv constructor. + * @param DirectoryList $directoryList + * @param \Magento\Framework\Filesystem\Driver\File $fileDriver + * @param int $baseBatchSize + */ + public function __construct( + DirectoryList $directoryList, + \Magento\Framework\Filesystem\Driver\File $fileDriver, + $baseBatchSize = 15000 + ) { + $this->baseBatchSize = $baseBatchSize; + $this->directoryList = $directoryList; + $this->fileDriver = $fileDriver; + } + + /** + * Save to csv data with batches. + * + * @param string $file + * @param array $data + * @return $this + */ + public function save($file, array $data) + { + $file = $this->prepareFile($file); + if (!count($data) || !$file) { + return $this; + } + + if (!file_exists($file)) { + array_unshift($data, array_keys($data[0])); + } + + $fh = fopen($file, 'a'); + + foreach ($data as $dataRow) { + fputcsv($fh, $dataRow); + } + + fclose($fh); + return $this; + } + + /** + * Prepare CSV file name + * + * @param string $file + * @return string | bool + */ + private function prepareFile($file) + { + $absolutePath = $this->directoryList->getPath(DirectoryList::VAR_DIR); + + if (!$this->fileDriver->isWritable($absolutePath)) { + return false; + } + $dumpsPath = $absolutePath . DIRECTORY_SEPARATOR . self::DUMP_FOLDER; + $this->ensureDirExists($dumpsPath); + $filePath = $dumpsPath . DIRECTORY_SEPARATOR . $file . '.csv'; + return $filePath; + } + + /** + * Create directory if not exists + * + * @param string $dir + */ + private function ensureDirExists($dir) + { + if (!$this->fileDriver->isExists($dir)) { + $this->fileDriver->createDirectory($dir); + } + } + + /** + * File read generator. + * + * This generator allows to load to memory only batch, with which we need to work at the moment + * + * @param string $file + * @return \Generator + */ + public function read($file) + { + $file = $this->prepareFile($file); + + if (!$this->fileDriver->isReadable($file)) { + return []; + } + $data = []; + $iterator = 0; + $fh = fopen($file, 'r'); + $headers = fgetcsv($fh); + $rowData = fgetcsv($fh); + + while ($rowData) { + if ($iterator++ > $this->baseBatchSize) { + $iterator = 0; + $finalData = $data; + $data = []; + yield $this->processCsvData($finalData, $headers); + } + + $data[] = $rowData; + $rowData = fgetcsv($fh); + } + + fclose($fh); + yield $this->processCsvData($data, $headers); + } + + /** + * @param array $csvData + * @param array $headers + * @return array + */ + private function processCsvData(array $csvData, array $headers) + { + $result = []; + + foreach ($csvData as $rowIndex => $csvRow) { + foreach ($csvRow as $index => $item) { + $result[$rowIndex][$headers[$index]] = $item; + } + } + + return $result; + } + + /** + * @inheritdoc + */ + public function destruct($resource) + { + $file = $this->prepareFile($resource); + + if ($this->fileDriver->isExists($file)) { + $this->fileDriver->deleteFile($file); + } + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/FileSystem/XmlReader.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/FileSystem/XmlReader.php similarity index 80% rename from setup/src/Magento/Setup/Model/Declaration/Schema/FileSystem/XmlReader.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/FileSystem/XmlReader.php index a250a742204e1..bd835c35fd890 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/FileSystem/XmlReader.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/FileSystem/XmlReader.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\FileSystem; +namespace Magento\Framework\Setup\Declaration\Schema\FileSystem; use Magento\Framework\Config\FileResolverByModule; use Magento\Framework\Config\ReaderInterface; @@ -33,8 +33,8 @@ class XmlReader extends \Magento\Framework\Config\Reader\Filesystem implements R * XmlReader constructor. * * @param FileResolverByModule $fileResolver - * @param \Magento\Setup\Model\Declaration\Schema\Config\Converter $converter - * @param \Magento\Setup\Model\Declaration\Schema\Config\SchemaLocator $schemaLocator + * @param \Magento\Framework\Setup\Declaration\Schema\Config\Converter $converter + * @param \Magento\Framework\Setup\Declaration\Schema\Config\SchemaLocator $schemaLocator * @param \Magento\Framework\Config\ValidationStateInterface $validationState * @param string $fileName * @param string $domDocumentClass @@ -42,8 +42,8 @@ class XmlReader extends \Magento\Framework\Config\Reader\Filesystem implements R */ public function __construct( FileResolverByModule $fileResolver, - \Magento\Setup\Model\Declaration\Schema\Config\Converter $converter, - \Magento\Setup\Model\Declaration\Schema\Config\SchemaLocator $schemaLocator, + \Magento\Framework\Setup\Declaration\Schema\Config\Converter $converter, + \Magento\Framework\Setup\Declaration\Schema\Config\SchemaLocator $schemaLocator, \Magento\Framework\Config\ValidationStateInterface $validationState, $fileName = 'db_schema.xml', $domDocumentClass = \Magento\Framework\Config\Dom::class, diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/OperationInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/OperationInterface.php new file mode 100644 index 0000000000000..00490a96047df --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/OperationInterface.php @@ -0,0 +1,40 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema; + +/** + * Schema operation interface. + */ +interface OperationInterface +{ + /** + * Retrieve operation identifier key. + * + * @return string + */ + public function getOperationName(); + + /** + * Is operation destructive flag. + * + * Destructive operations can make system unstable. + * + * For example, if operation is destructive it can remove table or column created not with + * declarative schema (for example with old migration script). + * + * @return bool + */ + public function isOperationDestructive(); + + /** + * Apply change of any type. + * + * @param ElementHistory $elementHistory + * @return array + */ + public function doOperation(ElementHistory $elementHistory); +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/AddColumn.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/AddColumn.php similarity index 87% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Operations/AddColumn.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/AddColumn.php index c8a910a2cd463..5810c78a2093c 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/AddColumn.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/AddColumn.php @@ -4,22 +4,23 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Operations; - -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DDLTriggerInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DefinitionAggregator; -use Magento\Setup\Model\Declaration\Schema\Db\Statement; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementFactory; -use Magento\Setup\Model\Declaration\Schema\Dto\Index; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\ElementHistoryFactory; -use Magento\Setup\Model\Declaration\Schema\OperationInterface; +namespace Magento\Framework\Setup\Declaration\Schema\Operations; + +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DDLTriggerInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DefinitionAggregator; +use Magento\Framework\Setup\Declaration\Schema\Db\Statement; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementFactory; +use Magento\Framework\Setup\Declaration\Schema\Dto\Index; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\ElementHistoryFactory; +use Magento\Framework\Setup\Declaration\Schema\OperationInterface; /** * Add column to table operation. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class AddColumn implements OperationInterface { @@ -192,7 +193,7 @@ public function doOperation(ElementHistory $elementHistory) */ $element = $elementHistory->getNew(); $definition = $this->definitionAggregator->toDefinition($element); - + $statement = $this->dbSchemaWriter->addElement( $element->getName(), $element->getTable()->getResource(), diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/AddComplexElement.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/AddComplexElement.php similarity index 79% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Operations/AddComplexElement.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/AddComplexElement.php index f333eca43e84f..7e1d94eeed8f5 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/AddComplexElement.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/AddComplexElement.php @@ -4,14 +4,14 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Operations; +namespace Magento\Framework\Setup\Declaration\Schema\Operations; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DefinitionAggregator; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\TableElementInterface; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\OperationInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DefinitionAggregator; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\TableElementInterface; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\OperationInterface; /** * Add complex element operation. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/CreateTable.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/CreateTable.php similarity index 79% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Operations/CreateTable.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/CreateTable.php index 338c0f52e5522..18726001c19f6 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/CreateTable.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/CreateTable.php @@ -4,18 +4,18 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Operations; +namespace Magento\Framework\Setup\Declaration\Schema\Operations; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DDLTriggerInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DefinitionAggregator; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraint; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Index; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\OperationInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DDLTriggerInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DefinitionAggregator; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraint; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Index; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\OperationInterface; /** * Create table operation. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/DropElement.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/DropElement.php new file mode 100644 index 0000000000000..97fb53597839d --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/DropElement.php @@ -0,0 +1,88 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Operations; + +use Magento\Framework\Setup\Declaration\Schema\Db\AdapterMediator; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DefinitionAggregator; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\TableElementInterface; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\OperationInterface; + +/** + * Drop element operation. + * + * Drops structural element. + */ +class DropElement implements OperationInterface +{ + /** + * Operation name. + */ + const OPERATION_NAME = 'drop_element'; + + /** + * @var DbSchemaWriterInterface + */ + private $dbSchemaWriter; + + /** + * @var DefinitionAggregator + */ + private $definitionAggregator; + + /** + * Constructor. + * + * @param DbSchemaWriterInterface $dbSchemaWriter + * @param DefinitionAggregator $definitionAggregator + */ + public function __construct( + DbSchemaWriterInterface $dbSchemaWriter, + DefinitionAggregator $definitionAggregator + ) { + $this->dbSchemaWriter = $dbSchemaWriter; + $this->definitionAggregator = $definitionAggregator; + } + + /** + * {@inheritdoc} + */ + public function getOperationName() + { + return self::OPERATION_NAME; + } + + /** + * {@inheritdoc} + */ + public function isOperationDestructive() + { + return true; + } + + /** + * {@inheritdoc} + */ + public function doOperation(ElementHistory $elementHistory) + { + /** + * @var TableElementInterface | ElementInterface $element + */ + $element = $elementHistory->getNew(); + + return [ + $this->dbSchemaWriter->dropElement( + $element->getTable()->getResource(), + $element->getName(), + $element->getTable()->getName(), + $element->getType() + ) + ]; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/DropReference.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/DropReference.php similarity index 84% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Operations/DropReference.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/DropReference.php index c5a1b3a67f23d..4a5f651a10815 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/DropReference.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/DropReference.php @@ -4,10 +4,10 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Operations; +namespace Magento\Framework\Setup\Declaration\Schema\Operations; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\OperationInterface; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\OperationInterface; /** * Drop foreign key operation. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/DropTable.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/DropTable.php similarity index 77% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Operations/DropTable.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/DropTable.php index 9b7249e636606..759fd15903fa1 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/DropTable.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/DropTable.php @@ -4,13 +4,13 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Operations; +namespace Magento\Framework\Setup\Declaration\Schema\Operations; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DefinitionAggregator; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\OperationInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DefinitionAggregator; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\OperationInterface; /** * Drop table operation. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/ModifyColumn.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/ModifyColumn.php similarity index 79% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Operations/ModifyColumn.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/ModifyColumn.php index 285b44bcdbee9..6bafc790c3455 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/ModifyColumn.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/ModifyColumn.php @@ -4,13 +4,13 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Operations; +namespace Magento\Framework\Setup\Declaration\Schema\Operations; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DefinitionAggregator; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\OperationInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DefinitionAggregator; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\OperationInterface; /** * Modify column in table operation. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/ModifyTable.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/ModifyTable.php new file mode 100644 index 0000000000000..d30b3271106f4 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/ModifyTable.php @@ -0,0 +1,76 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema\Operations; + +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DefinitionAggregator; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\OperationInterface; + +/** + * Modify table operation. + * + * Used to change table options. + */ +class ModifyTable implements OperationInterface +{ + /** + * Operation name. + */ + const OPERATION_NAME = 'modify_table'; + + /** + * @var DbSchemaWriterInterface + */ + private $dbSchemaWriter; + + /** + * Constructor. + * + * @param DbSchemaWriterInterface $dbSchemaWriter + */ + public function __construct( + DbSchemaWriterInterface $dbSchemaWriter + ) { + $this->dbSchemaWriter = $dbSchemaWriter; + } + + /** + * {@inheritdoc} + */ + public function getOperationName() + { + return self::OPERATION_NAME; + } + + /** + * {@inheritdoc} + */ + public function isOperationDestructive() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function doOperation(ElementHistory $elementHistory) + { + /** @var Table $table */ + $table = $elementHistory->getNew(); + return [ + $this->dbSchemaWriter->modifyTableOption( + $table->getName(), + $table->getResource(), + 'comment', + $table->getComment() + ) + ]; + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/ReCreateTable.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/ReCreateTable.php similarity index 86% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Operations/ReCreateTable.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/ReCreateTable.php index ba5ad86b4c2ee..a06c7c10325f5 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/ReCreateTable.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Operations/ReCreateTable.php @@ -4,10 +4,10 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema\Operations; +namespace Magento\Framework\Setup\Declaration\Schema\Operations; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\OperationInterface; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\OperationInterface; /** * Recreate table operation. diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/OperationsExecutor.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/OperationsExecutor.php new file mode 100644 index 0000000000000..ed1baff1d3323 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/OperationsExecutor.php @@ -0,0 +1,270 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Declaration\Schema; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Setup\Declaration\Schema\DataSavior\DataSaviorInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\StatementAggregatorFactory; +use Magento\Framework\Setup\Declaration\Schema\Db\StatementFactory; +use Magento\Framework\Setup\Declaration\Schema\Diff\DiffInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Operations\AddColumn; +use Magento\Framework\Setup\Declaration\Schema\Operations\CreateTable; +use Magento\Framework\Setup\Declaration\Schema\Operations\ReCreateTable; + +/** + * Schema operations executor. + * + * Go through all available SQL operations and execute each one with data from change registry. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class OperationsExecutor +{ + /** + * Request keys. + */ + const KEY_SAFE_MODE = 'safe-mode'; + const KEY_DATA_RESTORE = 'data-restore'; + + /** + * @var OperationInterface[] + */ + private $operations; + + /** + * @var Sharding + */ + private $sharding; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var StatementFactory + */ + private $statementFactory; + + /** + * @var DbSchemaWriterInterface + */ + private $dbSchemaWriter; + + /** + * @var StatementAggregatorFactory + */ + private $statementAggregatorFactory; + + /** + * @var DataSaviorInterface[] + */ + private $dataSaviorsCollection; + + /** + * @var DryRunLogger + */ + private $dryRunLogger; + + /** + * Constructor. + * + * @param array $operations + * @param array $dataSaviorsCollection + * @param Sharding $sharding + * @param ResourceConnection $resourceConnection + * @param StatementFactory $statementFactory + * @param DbSchemaWriterInterface $dbSchemaWriter + * @param StatementAggregatorFactory $statementAggregatorFactory + * @param DryRunLogger $dryRunLogger + */ + public function __construct( + array $operations, + array $dataSaviorsCollection, + Sharding $sharding, + ResourceConnection $resourceConnection, + StatementFactory $statementFactory, + DbSchemaWriterInterface $dbSchemaWriter, + StatementAggregatorFactory $statementAggregatorFactory, + DryRunLogger $dryRunLogger + ) { + $this->operations = $operations; + $this->sharding = $sharding; + $this->resourceConnection = $resourceConnection; + $this->statementFactory = $statementFactory; + $this->dbSchemaWriter = $dbSchemaWriter; + $this->statementAggregatorFactory = $statementAggregatorFactory; + $this->dataSaviorsCollection = $dataSaviorsCollection; + $this->dryRunLogger = $dryRunLogger; + } + + /** + * Retrieve only destructive operation names. + * + * For example, drop_table, recreate_table, etc. + * + * @return array + */ + public function getDestructiveOperations() + { + $operations = []; + + foreach ($this->operations as $operation) { + if ($operation->isOperationDestructive()) { + $operations[$operation->getOperationName()] = $operation->getOperationName(); + } + } + + return $operations; + } + + /** + * In order to successfully run all operations we need to start setup for all + * connections first. + * + * @return void + */ + private function startSetupForAllConnections() + { + foreach ($this->sharding->getResources() as $resource) { + $this->resourceConnection->getConnection($resource) + ->startSetup(); + $this->resourceConnection->getConnection($resource) + ->query('SET UNIQUE_CHECKS=0'); + } + } + + /** + * In order to revert previous state we need to end setup for all connections + * connections first. + * + * @return void + */ + private function endSetupForAllConnections() + { + foreach ($this->sharding->getResources() as $resource) { + $this->resourceConnection->getConnection($resource) + ->endSetup(); + } + } + + /** + * Check if during this operation we need to restore data + * + * @param OperationInterface $operation + * @return bool + */ + private function operationIsOppositeToDestructive(OperationInterface $operation) + { + return $operation instanceof AddColumn || + $operation instanceof CreateTable || + $operation instanceof ReCreateTable; + } + + /** + * Loop through all operations that are configured in di.xml + * and execute them with elements from Diff. + * + * @see OperationInterface + * @param DiffInterface $diff + * @param array $requestData + * @return void + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ + public function execute(DiffInterface $diff, array $requestData) + { + $this->startSetupForAllConnections(); + $tableHistories = $diff->getAll(); + $dryRun = isset($requestData[DryRunLogger::INPUT_KEY_DRY_RUN_MODE]) && + $requestData[DryRunLogger::INPUT_KEY_DRY_RUN_MODE]; + + if ($dryRun) { + $this->dryRunLogger->prepareToDryRun(); + } + + if (is_array($tableHistories)) { + foreach ($tableHistories as $tableHistory) { + $destructiveElements = []; + $oppositeToDestructiveElements = []; + $statementAggregator = $this->statementAggregatorFactory->create(); + + foreach ($this->operations as $operation) { + if (isset($tableHistory[$operation->getOperationName()])) { + /** @var ElementHistory $elementHistory */ + foreach ($tableHistory[$operation->getOperationName()] as $elementHistory) { + $statementAggregator->addStatements($operation->doOperation($elementHistory)); + + if ($operation->isOperationDestructive()) { + $destructiveElements[] = $elementHistory->getOld(); + } elseif ($this->operationIsOppositeToDestructive($operation)) { + $oppositeToDestructiveElements[] = $elementHistory->getNew(); + } + } + } + } + + $this->doDump($destructiveElements, $requestData); + $this->dbSchemaWriter->compile($statementAggregator, $dryRun); + $this->doRestore($oppositeToDestructiveElements, $requestData); + } + } + + $this->endSetupForAllConnections(); + } + + /** + * Do restore of destructive operations + * + * @param array $elements + * @param array $requestData + */ + private function doRestore(array $elements, array $requestData) + { + $restoreMode = isset($requestData[self::KEY_DATA_RESTORE]) && $requestData[self::KEY_DATA_RESTORE]; + + if ($restoreMode) { + /** + * @var ElementInterface $element + */ + foreach ($elements as $element) { + foreach ($this->dataSaviorsCollection as $dataSavior) { + if ($dataSavior->isAcceptable($element)) { + $dataSavior->restore($element); + break; + } + } + } + } + } + + /** + * Do dump of destructive operations + * + * @param array $elements + * @param array $requestData + */ + private function doDump(array $elements, array $requestData) + { + $safeMode = isset($requestData[self::KEY_SAFE_MODE]) && $requestData[self::KEY_SAFE_MODE]; + + if ($safeMode) { + /** + * @var ElementInterface $element + */ + foreach ($elements as $element) { + foreach ($this->dataSaviorsCollection as $dataSavior) { + if ($dataSavior->isAcceptable($element)) { + $dataSavior->dump($element); + break; + } + } + } + } + } +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Request.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Request.php similarity index 93% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Request.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Request.php index 4d1e13944dd59..2ffe29cc76962 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Request.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Request.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema; +namespace Magento\Framework\Setup\Declaration\Schema; /** * CLI or Ui params transport object. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/RequestFactory.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/RequestFactory.php similarity index 93% rename from setup/src/Magento/Setup/Model/Declaration/Schema/RequestFactory.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/RequestFactory.php index 9a62aa34db9b4..8f76815d4dc12 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/RequestFactory.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/RequestFactory.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema; +namespace Magento\Framework\Setup\Declaration\Schema; use Zend\Di\Di; diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/SchemaConfig.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/SchemaConfig.php similarity index 83% rename from setup/src/Magento/Setup/Model/Declaration/Schema/SchemaConfig.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/SchemaConfig.php index 2b693f59cc38b..4cd90cb35b236 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/SchemaConfig.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/SchemaConfig.php @@ -4,13 +4,13 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema; +namespace Magento\Framework\Setup\Declaration\Schema; use Magento\Framework\Config\FileResolverByModule; -use Magento\Setup\Model\Declaration\Schema\Db\SchemaBuilder as DbSchemaBuilder; -use Magento\Setup\Model\Declaration\Schema\Declaration\SchemaBuilder as DeclarativeSchemaBuilder; -use Magento\Setup\Model\Declaration\Schema\Declaration\ReaderComposite; -use Magento\Setup\Model\Declaration\Schema\Dto\SchemaFactory; +use Magento\Framework\Setup\Declaration\Schema\Db\SchemaBuilder as DbSchemaBuilder; +use Magento\Framework\Setup\Declaration\Schema\Declaration\SchemaBuilder as DeclarativeSchemaBuilder; +use Magento\Framework\Setup\Declaration\Schema\Declaration\ReaderComposite; +use Magento\Framework\Setup\Declaration\Schema\Dto\SchemaFactory; /** * {@inheritdoc} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/SchemaConfigInterface.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/SchemaConfigInterface.php similarity index 83% rename from setup/src/Magento/Setup/Model/Declaration/Schema/SchemaConfigInterface.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/SchemaConfigInterface.php index cc0b5319fdf6a..1e6c5d63c8b3c 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/SchemaConfigInterface.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/SchemaConfigInterface.php @@ -4,9 +4,9 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema; +namespace Magento\Framework\Setup\Declaration\Schema; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; /** * Schema configuration interface. diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Sharding.php b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Sharding.php similarity index 97% rename from setup/src/Magento/Setup/Model/Declaration/Schema/Sharding.php rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/Sharding.php index a04540cb6d9e6..eff8d7c3c03bc 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Sharding.php +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/Sharding.php @@ -4,7 +4,7 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Model\Declaration\Schema; +namespace Magento\Framework\Setup\Declaration\Schema; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\Config\ConfigOptionsListConstants; diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/constraint.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/constraint.xsd similarity index 80% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/constraint.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/constraint.xsd index 06b99c88e43dc..61540ecc616b0 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/constraint.xsd +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/constraint.xsd @@ -6,7 +6,7 @@ */ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/operations.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/operations.xsd" /> <xs:attributeGroup name="baseConstraint"> <xs:attributeGroup ref="basicOperations" /> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/foreign.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/foreign.xsd similarity index 92% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/foreign.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/foreign.xsd index 32cd05caa3ffb..950fbf66f90cf 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/foreign.xsd +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/foreign.xsd @@ -6,7 +6,7 @@ */ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/constraints/constraint.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/constraints/constraint.xsd" /> <!--@TODO: why we need to specify table?--> <xs:complexType name="foreign"> <xs:annotation> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/primary.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/primary.xsd similarity index 89% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/primary.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/primary.xsd index 826f30c2fd87b..f6d1e09823aba 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/primary.xsd +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/primary.xsd @@ -6,7 +6,7 @@ */ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/constraints/constraint.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/constraints/constraint.xsd" /> <xs:complexType name="primary"> <xs:annotation> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/unique.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/unique.xsd similarity index 87% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/unique.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/unique.xsd index 76c3c39dad0eb..e2d24ea65749c 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/constraints/unique.xsd +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/constraints/unique.xsd @@ -6,7 +6,7 @@ */ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/constraints/constraint.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/constraints/constraint.xsd" /> <xs:complexType name="unique"> <xs:annotation> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/index.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/index.xsd similarity index 100% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/index.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/index.xsd diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/name.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/name.xsd similarity index 100% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/name.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/name.xsd diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/operations.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/operations.xsd similarity index 100% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/operations.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/operations.xsd diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/schema.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/schema.xsd new file mode 100644 index 0000000000000..fa1894bb486cf --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/schema.xsd @@ -0,0 +1,78 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** +* Copyright © Magento, Inc. All rights reserved. +* See COPYING.txt for license details. +*/ +--> + +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <!--Types--> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/name.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/real/decimal.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/real/float.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/real/double.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/integers/integer.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/integers/biginteger.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/integers/smallinteger.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/integers/tinyinteger.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/texts/text.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/texts/longtext.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/texts/mediumtext.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/texts/varchar.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/binaries/blob.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/binaries/mediumblob.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/binaries/longblob.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/binaries/varbinary.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/datetime/timestamp.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/datetime/datetime.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/datetime/date.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/boolean.xsd" /> + <!--Constraints--> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/constraints/foreign.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/constraints/unique.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/constraints/primary.xsd" /> + <!--Indexes--> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/index.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd" /> + + <xs:element name="schema"> + <xs:complexType> + <xs:sequence minOccurs="0" maxOccurs="unbounded"> + <xs:element name="table" type="table"/> + </xs:sequence> + </xs:complexType> + </xs:element> + + <xs:complexType name="table"> + <xs:annotation> + <xs:documentation> + Table definition. Here we can found column, constraints and indexes + </xs:documentation> + </xs:annotation> + <xs:choice minOccurs="0" maxOccurs="unbounded"> + <xs:element name="column" type="abstractColumnType"/> + <xs:element name="constraint" /> + <xs:element name="index" type="index" /> + </xs:choice> + <xs:attribute name="name" type="xs:string" /> + <xs:attribute name="resource" type="resourceType" /> + <xs:attribute name="engine" type="engineType" /> + <xs:attribute name="comment" type="xs:string" /> + </xs:complexType> + + <xs:simpleType name="resourceType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="default" /> + <xs:enumeration value="quote" /> + <xs:enumeration value="sales" /> + </xs:restriction> + </xs:simpleType> + + <xs:simpleType name="engineType"> + <xs:restriction base="xs:string"> + <xs:enumeration value="innodb" /> + <xs:enumeration value="memory" /> + </xs:restriction> + </xs:simpleType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/blob.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/blob.xsd new file mode 100644 index 0000000000000..b3812cedeb63e --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/blob.xsd @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="blob"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + Can be used as binary source + </xs:documentation> + </xs:annotation> + + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/longblob.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/longblob.xsd new file mode 100644 index 0000000000000..f69ea7c71641e --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/longblob.xsd @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="longblob"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + Can be used as binary source. Different types can be used depends on data size + you want to persist + </xs:documentation> + </xs:annotation> + + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/mediumblob.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/mediumblob.xsd new file mode 100644 index 0000000000000..ac81024f3181d --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/mediumblob.xsd @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="mediumblob"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + Can be used as binary source + </xs:documentation> + </xs:annotation> + + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/varbinary.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/varbinary.xsd new file mode 100644 index 0000000000000..0ee79199c29ae --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/binaries/varbinary.xsd @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="varbinary"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + Can be used as binary source + </xs:documentation> + </xs:annotation> + + <xs:attribute name="length"> + <xs:simpleType> + <xs:restriction base="xs:integer"> + <xs:maxInclusive value="255"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="default" type="xs:string" /> + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/boolean.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/boolean.xsd new file mode 100644 index 0000000000000..65dec3ae2183a --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/boolean.xsd @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd" /> + + <xs:complexType name="boolean"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:attribute name="default" type="xs:boolean" /> + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/column.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/column.xsd similarity index 78% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/column.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/column.xsd index 2fcf6c59e12f6..df485e38869bb 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/column.xsd +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/column.xsd @@ -6,8 +6,7 @@ */ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/operations.xsd" /> - + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/operations.xsd" /> <xs:attributeGroup name="baseColumn"> <xs:attributeGroup ref="basicOperations" /> <xs:attribute name="name" type="nameType" use="required" /> @@ -20,4 +19,8 @@ </xs:annotation> </xs:attribute> </xs:attributeGroup> + + <xs:complexType name="abstractColumnType"> + <xs:attributeGroup ref="baseColumn" /> + </xs:complexType> </xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/date.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/date.xsd new file mode 100644 index 0000000000000..aeb6f34c41ae4 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/date.xsd @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd" /> + + <xs:complexType name="date"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + This format is used to save date (year, month, day). + Probably your SQL engine will save date in this format: 'YYYY-MM-DD' + Dates in invalid format will be converted to '0000-00-00' string + </xs:documentation> + </xs:annotation> + + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/datetime.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/datetime.xsd new file mode 100644 index 0000000000000..c9c9d4052e12e --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/datetime.xsd @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/datetime/default.xsd"/> + + <xs:complexType name="datetime"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + This format is used to save date (year, month, day). + Probably your SQL engine will save date in this format: 'YYYY-MM-DD HH:MM::SS' + Date time in invalid format will be converted to '0000-00-00 00:00:00' string + Supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59' + DateTime format save date and time in your local time zone + </xs:documentation> + </xs:annotation> + + <xs:attributeGroup ref="default" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/default.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/default.xsd similarity index 100% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/default.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/default.xsd diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/timestamp.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/timestamp.xsd new file mode 100644 index 0000000000000..0fd94540bae52 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/datetime/timestamp.xsd @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd" /> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/datetime/default.xsd"/> + + <xs:complexType name="timestamp"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + This format is used to save date (year, month, day). + Probably your SQL engine will save date in this format: 'YYYY-MM-DD HH:MM::SS' + Date time in invalid format will be converted to '0000-00-00 00:00:00' string + MySQL timestamp is similar to UNIX timestamp. You can pass you local time there and it will + be converted to UTC timezone. Then when you will try to pull your time back it will be converted + to your local time again. + Unix range: 1970-01-01 00:00:01' UTC to '2038-01-09 03:14:07' + </xs:documentation> + </xs:annotation> + + <xs:attributeGroup ref="default" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/biginteger.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/biginteger.xsd similarity index 78% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/biginteger.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/biginteger.xsd index 186779afb5382..df222eb93a3dc 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/biginteger.xsd +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/biginteger.xsd @@ -6,7 +6,7 @@ */ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/integers/integer.xsd"/> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/integers/integer.xsd"/> <xs:complexType name="bigint"> <xs:complexContent> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/integer.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/integer.xsd new file mode 100644 index 0000000000000..e264060cba63d --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/integer.xsd @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="int"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + Serves needs in integer digits. Default padding is 11. + Size is 4 bytes. + </xs:documentation> + </xs:annotation> + <xs:attribute name="default" type="xs:integer" /> + <xs:attribute name="padding"> + <xs:annotation> + <xs:documentation> + We can use padding only from 2, because padding 1 used for boolean type. + And we need to distinguish boolean and integer + </xs:documentation> + </xs:annotation> + <xs:simpleType> + <xs:restriction base="xs:integer"> + <xs:maxInclusive value="255" /> + <xs:minInclusive value="2" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="unsigned" type="xs:boolean" /> + <xs:attribute name="identity" type="xs:boolean" /> + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/smallinteger.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/smallinteger.xsd similarity index 84% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/smallinteger.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/smallinteger.xsd index 7c77d738f9b68..5306fbc1d9f5b 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/smallinteger.xsd +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/smallinteger.xsd @@ -6,7 +6,7 @@ */ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/integers/integer.xsd"/> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/integers/integer.xsd"/> <xs:complexType name="smallint"> <xs:annotation> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/tinyinteger.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/tinyinteger.xsd similarity index 78% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/tinyinteger.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/tinyinteger.xsd index e35d4b27921ec..32d8294d9dc72 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/tinyinteger.xsd +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/integers/tinyinteger.xsd @@ -6,7 +6,7 @@ */ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/integers/integer.xsd"/> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/integers/integer.xsd"/> <xs:complexType name="tinyint"> <xs:complexContent> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/real/decimal.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/real/decimal.xsd new file mode 100644 index 0000000000000..2aa5387df497d --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/real/decimal.xsd @@ -0,0 +1,46 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="decimal"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + A fixed point decimal fraction equal to SQL DECIMAL(PRECISION,SCALE) type, where + - SCALE is a size of number in fractional part, + - PRECISION is a whole size of decimal fraction. + Please use this type for business oriented math like price or qty storages. + </xs:documentation> + </xs:annotation> + + <xs:attribute name="default" type="xs:decimal" /> + <!--Note that scale must not be more than precision--> + <xs:attribute name="precision"> + <xs:simpleType> + <xs:restriction base="xs:integer"> + <xs:minInclusive value="0" /> + <xs:maxInclusive value="65" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="unsigned" type="xs:boolean" /> + <xs:attribute name="scale"> + <xs:simpleType> + <xs:restriction base="xs:integer"> + <xs:minInclusive value="0" /> + <xs:maxInclusive value="30" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/real/double.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/real/double.xsd similarity index 86% rename from setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/real/double.xsd rename to lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/real/double.xsd index be83da3016b27..652626ee9c144 100644 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/real/double.xsd +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/real/double.xsd @@ -6,7 +6,7 @@ */ --> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/real/float.xsd"/> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/real/float.xsd"/> <xs:complexType name="double"> <xs:annotation> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/real/float.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/real/float.xsd new file mode 100644 index 0000000000000..3ddaed993a649 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/real/float.xsd @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="float"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + A floating point binary value with single precision. Has rounding issues. + Float is good for scientific calculations. + For business oriented math like price or qty storages please use decimal type. + </xs:documentation> + </xs:annotation> + + <xs:attribute name="default" type="xs:float" /> + <!--Note that scale must not be more than precision--> + <xs:attribute name="precision"> + <xs:simpleType> + <xs:restriction base="xs:integer"> + <xs:minInclusive value="0" /> + <xs:maxInclusive value="255" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="scale"> + <xs:simpleType> + <xs:restriction base="xs:integer"> + <xs:minInclusive value="0" /> + <xs:maxInclusive value="253" /> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="nullable" type="xs:boolean" /> + <xs:attribute name="unsigned" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/longtext.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/longtext.xsd new file mode 100644 index 0000000000000..90b1b910c06ea --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/longtext.xsd @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="longtext"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + Here plain text can be persisted. Length of this field is more than more than 16777216 + </xs:documentation> + </xs:annotation> + + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/mediumtext.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/mediumtext.xsd new file mode 100644 index 0000000000000..652d4b5cf4616 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/mediumtext.xsd @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="mediumtext"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + Here plain text can be persisted. Length of this field is more than 65536 characters + and less than 16777216 + </xs:documentation> + </xs:annotation> + + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/text.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/text.xsd new file mode 100644 index 0000000000000..d1efce612489e --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/text.xsd @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="text"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + Here plain text can be persisted. Length of this field is more than 255 characters + and less than 65536 + </xs:documentation> + </xs:annotation> + + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/varchar.xsd b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/varchar.xsd new file mode 100644 index 0000000000000..a667b0b2481c4 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Declaration/Schema/etc/types/texts/varchar.xsd @@ -0,0 +1,35 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +--> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> + <xs:include schemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/types/column.xsd"/> + + <xs:complexType name="varchar"> + <xs:complexContent> + <xs:extension base="abstractColumnType"> + <xs:annotation> + <xs:documentation> + Varchar is the small text field. It do not have max length. But we suppose, that this field can be used for + string columns that are in role of some key, like customer email or product sku. We add limitation for 1024 characters + on this type. This limitation is justified by SQL engine limitations, like {max sort size} or {max index size}. + For example, in MySQL, default max sort size (max_sort_length) is 1024 symbols. + </xs:documentation> + </xs:annotation> + + <xs:attribute name="length"> + <xs:simpleType> + <xs:restriction base="xs:integer"> + <xs:maxInclusive value="1024"/> + </xs:restriction> + </xs:simpleType> + </xs:attribute> + <xs:attribute name="default" type="xs:string" /> + <xs:attribute name="nullable" type="xs:boolean" /> + </xs:extension> + </xs:complexContent> + </xs:complexType> +</xs:schema> diff --git a/lib/internal/Magento/Framework/Setup/Exception.php b/lib/internal/Magento/Framework/Setup/Exception.php new file mode 100644 index 0000000000000..c21bd1c503295 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Exception.php @@ -0,0 +1,16 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup; + +use Magento\Framework\Exception\LocalizedException; + +/** + * Exception thrown if an error occurs on setup process. + */ +class Exception extends LocalizedException +{ +} diff --git a/lib/internal/Magento/Framework/Setup/Lists.php b/lib/internal/Magento/Framework/Setup/Lists.php index ce0dd8348acc3..1ee5baf28658e 100644 --- a/lib/internal/Magento/Framework/Setup/Lists.php +++ b/lib/internal/Magento/Framework/Setup/Lists.php @@ -21,12 +21,20 @@ class Lists */ protected $allowedLocales; + /** + * List of allowed currencies + * + * @var array + */ + private $allowedCurrencies; + /** * @param ConfigInterface $localeConfig */ public function __construct(ConfigInterface $localeConfig) { $this->allowedLocales = $localeConfig->getAllowedLocales(); + $this->allowedCurrencies = $localeConfig->getAllowedCurrencies(); } /** @@ -64,6 +72,10 @@ public function getCurrencyList() $currencies = (new CurrencyBundle())->get(Resolver::DEFAULT_LOCALE)['Currencies']; $list = []; foreach ($currencies as $code => $data) { + $isAllowedCurrency = array_search($code, $this->allowedCurrencies) !== false; + if (!$isAllowedCurrency) { + continue; + } $list[$code] = $data[1] . ' (' . $code . ')'; } asort($list); diff --git a/lib/internal/Magento/Framework/Setup/Patch/DataPatchInterface.php b/lib/internal/Magento/Framework/Setup/Patch/DataPatchInterface.php new file mode 100644 index 0000000000000..e768d045e83be --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/DataPatchInterface.php @@ -0,0 +1,14 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Patch; + +/** + * This interface describe script, that atomic operations with data (DML, DQL) in SQL database + * This is wrapper for @see PatchInterface in order to define what kind of patch we have + */ +interface DataPatchInterface extends PatchInterface +{ +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/DependentPatchInterface.php b/lib/internal/Magento/Framework/Setup/Patch/DependentPatchInterface.php new file mode 100644 index 0000000000000..abda94a0e6f8e --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/DependentPatchInterface.php @@ -0,0 +1,33 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Patch; + +/** + * Each patch can have dependecies, that should be applied before such patch + * + * / Patch2 --- Patch3 + * / + * / + * Patch1 + * + * Here you see dependency of Patch1 to Patch2 + */ +interface DependentPatchInterface +{ + /** + * Get array of patches that have to be executed prior to this. + * + * example of implementation: + * + * [ + * \Vendor_Name\Module_Name\Setup\Patch\Patch1::class, + * \Vendor_Name\Module_Name\Setup\Patch\Patch2::class + * ] + * + * @return string[] + */ + public static function getDependencies(); +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/NonTransactionableInterface.php b/lib/internal/Magento/Framework/Setup/Patch/NonTransactionableInterface.php new file mode 100644 index 0000000000000..30800b3c89323 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/NonTransactionableInterface.php @@ -0,0 +1,13 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Patch; + +/** + * Means that patch can`t be run in transaction + */ +interface NonTransactionableInterface +{ +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchApplier.php b/lib/internal/Magento/Framework/Setup/Patch/PatchApplier.php new file mode 100644 index 0000000000000..4ffc4f1828354 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchApplier.php @@ -0,0 +1,280 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Patch; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Module\ModuleResource; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Phrase; +use Magento\Framework\Setup\Exception; +use Magento\Framework\Setup\ModuleDataSetupInterface; + +/** + * Apply patches per specific module + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class PatchApplier +{ + /** + * @var PatchRegistryFactory + */ + private $patchRegistryFactory; + + /** + * @var PatchReader + */ + private $dataPatchReader; + + /** + * @var PatchReader + */ + private $schemaPatchReader; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * @var ModuleResource + */ + private $moduleResource; + + /** + * @var PatchHistory + */ + private $patchHistory; + + /** + * @var PatchFactory + */ + private $patchFactory; + + /** + * @var \Magento\Framework\Setup\SetupInterface + */ + private $schemaSetup; + + /** + * @var ModuleDataSetupInterface + */ + private $moduleDataSetup; + + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * PatchApplier constructor. + * @param PatchReader $dataPatchReader + * @param PatchReader $schemaPatchReader + * @param PatchRegistryFactory $patchRegistryFactory + * @param ResourceConnection $resourceConnection + * @param ModuleResource $moduleResource + * @param PatchHistory $patchHistory + * @param PatchFactory $patchFactory + * @param ObjectManagerInterface $objectManager + * @param \Magento\Framework\Setup\SchemaSetupInterface $schemaSetup + * @param ModuleDataSetupInterface $moduleDataSetup + * @SuppressWarnings(PHPMD.ExcessiveParameterList) + * @SuppressWarnings(Magento.TypeDuplication) + */ + public function __construct( + PatchReader $dataPatchReader, + PatchReader $schemaPatchReader, + PatchRegistryFactory $patchRegistryFactory, + ResourceConnection $resourceConnection, + ModuleResource $moduleResource, + PatchHistory $patchHistory, + PatchFactory $patchFactory, + ObjectManagerInterface $objectManager, + \Magento\Framework\Setup\SchemaSetupInterface $schemaSetup, + \Magento\Framework\Setup\ModuleDataSetupInterface $moduleDataSetup + ) { + $this->patchRegistryFactory = $patchRegistryFactory; + $this->dataPatchReader = $dataPatchReader; + $this->schemaPatchReader = $schemaPatchReader; + $this->resourceConnection = $resourceConnection; + $this->moduleResource = $moduleResource; + $this->patchHistory = $patchHistory; + $this->patchFactory = $patchFactory; + $this->schemaSetup = $schemaSetup; + $this->moduleDataSetup = $moduleDataSetup; + $this->objectManager = $objectManager; + } + + /** + * Check is patch skipable by data setup version in DB + * + * @param string $patchClassName + * @param string $moduleName + * @return bool + */ + private function isSkipableByDataSetupVersion(string $patchClassName, $moduleName) + { + $dbVersion = $this->moduleResource->getDataVersion($moduleName); + return in_array(PatchVersionInterface::class, class_implements($patchClassName)) && + version_compare(call_user_func([$patchClassName, 'getVersion']), $dbVersion) <= 0; + } + + /** + * Check is patch skipable by schema setup version in DB + * + * @param string $patchClassName + * @param string $moduleName + * @return bool + */ + private function isSkipableBySchemaSetupVersion(string $patchClassName, $moduleName) + { + $dbVersion = $this->moduleResource->getDbVersion($moduleName); + return in_array(PatchVersionInterface::class, class_implements($patchClassName)) && + version_compare(call_user_func([$patchClassName, 'getVersion']), $dbVersion) <= 0; + } + + /** + * Apply all patches for one module + * + * @param null | string $moduleName + * @throws Exception + */ + public function applyDataPatch($moduleName = null) + { + $dataPatches = $this->dataPatchReader->read($moduleName); + $registry = $this->prepareRegistry($dataPatches); + foreach ($registry as $dataPatch) { + /** + * Due to bacward compatabilities reasons some patches should be skipped + */ + if ($this->isSkipableByDataSetupVersion($dataPatch, $moduleName)) { + $this->patchHistory->fixPatch($dataPatch); + continue; + } + + $dataPatch = $this->objectManager->create( + '\\' . $dataPatch, + ['moduleDataSetup' => $this->moduleDataSetup] + ); + if (!$dataPatch instanceof DataPatchInterface) { + throw new Exception( + new Phrase("Patch %1 should implement DataPatchInterface", [get_class($dataPatch)]) + ); + } + if ($dataPatch instanceof NonTransactionableInterface) { + $dataPatch->apply(); + $this->patchHistory->fixPatch(get_class($dataPatch)); + } else { + try { + $this->moduleDataSetup->getConnection()->beginTransaction(); + $dataPatch->apply(); + $this->patchHistory->fixPatch(get_class($dataPatch)); + $this->moduleDataSetup->getConnection()->commit(); + } catch (\Exception $e) { + $this->moduleDataSetup->getConnection()->rollBack(); + throw new Exception(new Phrase($e->getMessage())); + } finally { + unset($dataPatch); + } + } + } + } + + /** + * Register all patches in registry in order to manipulate chains and dependencies of patches + * of patches + * + * @param array $patchNames + * @return PatchRegistry + */ + private function prepareRegistry(array $patchNames) + { + $registry = $this->patchRegistryFactory->create(); + + foreach ($patchNames as $patchName) { + $registry->registerPatch($patchName); + } + + return $registry; + } + + /** + * Apply all patches for one module + * + * @param null | string $moduleName + * @throws Exception + */ + public function applySchemaPatch($moduleName = null) + { + $schemaPatches = $this->schemaPatchReader->read($moduleName); + $registry = $this->prepareRegistry($schemaPatches); + + foreach ($registry as $schemaPatch) { + try { + /** + * Skip patches that were applied in old style + */ + if ($this->isSkipableBySchemaSetupVersion($schemaPatch, $moduleName)) { + $this->patchHistory->fixPatch($schemaPatch); + continue; + } + /** + * @var SchemaPatchInterface $schemaPatch + */ + $schemaPatch = $this->patchFactory->create($schemaPatch, ['schemaSetup' => $this->schemaSetup]); + $schemaPatch->apply(); + $this->patchHistory->fixPatch(get_class($schemaPatch)); + } catch (\Exception $e) { + throw new Exception( + new Phrase( + 'Unable to apply patch %1 for module %2. Original exception message: %3', + [ + get_class($schemaPatch), + $moduleName, + $e->getMessage() + ] + ) + ); + } finally { + unset($schemaPatch); + } + } + } + + /** + * Revert data patches for specific module + * + * @param null | string $moduleName + * @throws Exception + */ + public function revertDataPatches($moduleName = null) + { + $dataPatches = $this->dataPatchReader->read($moduleName); + $registry = $this->prepareRegistry($dataPatches); + $adapter = $this->moduleDataSetup->getConnection(); + + foreach ($registry->getReverseIterator() as $dataPatch) { + $dataPatch = $this->objectManager->create( + '\\' . $dataPatch, + ['moduleDataSetup' => $this->moduleDataSetup] + ); + if ($dataPatch instanceof PatchRevertableInterface) { + try { + $adapter->beginTransaction(); + /** @var PatchRevertableInterface|DataPatchInterface $dataPatch */ + $dataPatch->revert(); + $this->patchHistory->revertPatchFromHistory(get_class($dataPatch)); + $adapter->commit(); + } catch (\Exception $e) { + $adapter->rollBack(); + throw new Exception(new Phrase($e->getMessage())); + } finally { + unset($dataPatch); + } + } + } + } +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchApplierFactory.php b/lib/internal/Magento/Framework/Setup/Patch/PatchApplierFactory.php new file mode 100644 index 0000000000000..deb7c91c976ae --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchApplierFactory.php @@ -0,0 +1,39 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Patch; + +use Magento\Framework\ObjectManagerInterface; + +/** + * This factory allows to create data patches applier + */ +class PatchApplierFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @param ObjectManagerInterface $objectManager + */ + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * Create new instance of patch applier + * + * @param array $arguments + * @return PatchInterface + */ + public function create($arguments = []) + { + return $this->objectManager->create(\Magento\Framework\Setup\Patch\PatchApplier::class, $arguments); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchFactory.php b/lib/internal/Magento/Framework/Setup/Patch/PatchFactory.php new file mode 100644 index 0000000000000..e6c4832887efd --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchFactory.php @@ -0,0 +1,52 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Patch; + +use Magento\Framework\ObjectManagerInterface; + +/** + * This factory allows to create data patches: + * @see PatchInterface + */ +class PatchFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @param ObjectManagerInterface $objectManager + */ + public function __construct(ObjectManagerInterface $objectManager) + { + $this->objectManager = $objectManager; + } + + /** + * Create new instance of patch + * + * @param string $instanceName + * @param array $arguments + * @return PatchInterface + */ + public function create($instanceName, $arguments = []) + { + $patchInstance = $this->objectManager->create('\\' . $instanceName, $arguments); + if (!$patchInstance instanceof PatchInterface) { + throw new \InvalidArgumentException( + sprintf( + "%s should implement %s interface", + $instanceName, + PatchInterface::class + ) + ); + } + + return $patchInstance; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchHistory.php b/lib/internal/Magento/Framework/Setup/Patch/PatchHistory.php new file mode 100644 index 0000000000000..34b7c226185e3 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchHistory.php @@ -0,0 +1,123 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Patch; + +use Magento\Framework\App\ResourceConnection; + +/** + * This is registry of all patches, that are already applied on database + */ +class PatchHistory +{ + /** + * Table name where patche names will be persisted + */ + const TABLE_NAME = 'patch_list'; + + /** + * Name of a patch + */ + const CLASS_NAME = "patch_name"; + + /** + * Patch type for schema patches + */ + const SCHEMA_PATCH_TYPE = 'schema'; + + /** + * Patch type for data patches + */ + const DATA_PATCH_TYPE = 'data'; + + /** + * @var array + */ + private $patchesRegistry = null; + + /** + * @var ResourceConnection + */ + private $resourceConnection; + + /** + * PatchHistory constructor. + * @param ResourceConnection $resourceConnection + */ + public function __construct(ResourceConnection $resourceConnection) + { + $this->resourceConnection = $resourceConnection; + } + + /** + * Read and cache data patches from db + * + * All patches are store in patch_list table + * @see self::TABLE_NAME + * + * @return array + */ + private function getAppliedPatches() + { + if ($this->patchesRegistry === null) { + $adapter = $this->resourceConnection->getConnection(); + $filterSelect = $adapter + ->select() + ->from($this->resourceConnection->getTableName(self::TABLE_NAME), self::CLASS_NAME); + $this->patchesRegistry = $adapter->fetchCol($filterSelect); + } + + return $this->patchesRegistry; + } + + /** + * Fix patch in patch table in order to avoid reapplying of patch + * + * @param string $patchName + * @return void + */ + public function fixPatch($patchName) + { + if ($this->isApplied($patchName)) { + throw new \LogicException(sprintf("Patch %s cannot be applied twice", $patchName)); + } + + $adapter = $this->resourceConnection->getConnection(); + $adapter->insert($this->resourceConnection->getTableName(self::TABLE_NAME), [self::CLASS_NAME => $patchName]); + } + + /** + * Revert patch from history + * + * @param $patchName + * @return void + */ + public function revertPatchFromHistory($patchName) + { + if (!$this->isApplied($patchName)) { + throw new \LogicException( + sprintf("Patch %s should be applied, before you can revert it", $patchName) + ); + } + + $adapter = $this->resourceConnection->getConnection(); + $adapter->delete( + $this->resourceConnection->getTableName(self::TABLE_NAME), + [self::CLASS_NAME . "= ?" => $patchName] + ); + } + + /** + * Check whether patch was applied on the system or not + * + * @param string $patchName + * @return bool + */ + public function isApplied($patchName) + { + return in_array($patchName, $this->getAppliedPatches()); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchInterface.php b/lib/internal/Magento/Framework/Setup/Patch/PatchInterface.php new file mode 100644 index 0000000000000..c69f754d4b978 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchInterface.php @@ -0,0 +1,30 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Patch; + +/** + * This interface describe script, that is presented by atomic operations for data and schema + */ +interface PatchInterface extends DependentPatchInterface +{ + /** + * Get aliases (previous names) for the patch. + * + * @return string[] + */ + public function getAliases(); + + /** + * Run code inside patch + * If code fails, patch must be reverted, in case when we are speaking about schema - than under revert + * means run PatchInterface::revert() + * + * If we speak about data, under revert means: $transaction->rollback() + * + * @return $this + */ + public function apply(); +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchReader.php b/lib/internal/Magento/Framework/Setup/Patch/PatchReader.php new file mode 100644 index 0000000000000..845716abcf49e --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchReader.php @@ -0,0 +1,122 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Patch; + +use Magento\Framework\Component\ComponentRegistrar; +use Magento\Framework\Config\ReaderInterface; +use Magento\Framework\Filesystem\Glob; +use Magento\Framework\Module\Dir; + +/** + * Allows to read all patches through the whole system + */ +class PatchReader implements ReaderInterface +{ + /** + * Folder name, where patches are + */ + const SETUP_PATCH_FOLDER = 'Patch'; + + /** + * @var ComponentRegistrar + */ + private $componentRegistrar; + + /** + * @var string + */ + private $type; + + /** + * @param ComponentRegistrar $componentRegistrar + * @param string $type + */ + public function __construct( + ComponentRegistrar $componentRegistrar, + $type + ) { + $this->componentRegistrar = $componentRegistrar; + $this->type = $type; + } + + /** + * Retrieve absolute path to modules patch folder + * + * @param string $modulePath + * @return string + */ + private function getPatchFolder($modulePath) + { + return $modulePath . DIRECTORY_SEPARATOR . Dir::MODULE_SETUP_DIR . + DIRECTORY_SEPARATOR . self::SETUP_PATCH_FOLDER; + } + + /** + * Retrieve module name prepared to usage in namespaces + * + * @param string $moduleName + * @return string + */ + private function getModuleNameForNamespace($moduleName) + { + return str_replace('_', '\\', $moduleName); + } + + /** + * Depends on type we want to handle schema and data patches in different folders + * + * @return string + */ + private function getTypeFolder() + { + return ucfirst($this->type); + } + + /** + * Create array of class patch names from module name + * + * @param string $moduleName + * @param string $modulePath + * @return array + */ + private function getPatchClassesPerModule($moduleName, $modulePath) + { + $patchClasses = []; + $patchesPath = $this->getPatchFolder($modulePath); + $specificPatchPath = $patchesPath . DIRECTORY_SEPARATOR . $this->getTypeFolder(); + $patchesMask = $specificPatchPath . DIRECTORY_SEPARATOR . '*.php'; + + foreach (Glob::glob($patchesMask) as $patchPath) { + $moduleName = $this->getModuleNameForNamespace($moduleName); + $patchClasses[] = $moduleName . '\\Setup\\' . + self::SETUP_PATCH_FOLDER . '\\' . + $this->getTypeFolder() . '\\' . + basename($patchPath, '.php'); + } + + return $patchClasses; + } + + /** + * @param null $moduleName + * @return array + */ + public function read($moduleName = null) + { + $patches = []; + if ($moduleName === null) { + foreach ($this->componentRegistrar->getPaths(ComponentRegistrar::MODULE) as $moduleName => $modulePath) { + $patches += $this->getPatchClassesPerModule($moduleName, $modulePath); + } + } else { + $modulePath = $this->componentRegistrar->getPath(ComponentRegistrar::MODULE, $moduleName); + $patches = $this->getPatchClassesPerModule($moduleName, $modulePath); + } + + return $patches; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchRegistry.php b/lib/internal/Magento/Framework/Setup/Patch/PatchRegistry.php new file mode 100644 index 0000000000000..0d0d9abf2925b --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchRegistry.php @@ -0,0 +1,223 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Patch; + +/** + * Allows to read all patches through the whole system + */ +class PatchRegistry implements \IteratorAggregate +{ + /** + * + * @var array + */ + private $dependents = []; + + /** + * @var string[] + */ + private $patches = []; + + /** + * @var PatchFactory + */ + private $patchFactory; + + /** + * This classes need to do revert + * + * @var string[] + */ + private $appliedPatches = []; + + /** + * @var PatchHistory + */ + private $patchHistory; + + /** + * @var \Iterator + */ + private $iterator = null; + + /** + * @var \Iterator + */ + private $reverseIterator = null; + + /** + * @var array + */ + private $cyclomaticStack = []; + + /** + * PatchRegistry constructor. + * @param PatchFactory $patchFactory + * @param PatchHistory $patchHistory + */ + public function __construct(PatchFactory $patchFactory, PatchHistory $patchHistory) + { + $this->patchFactory = $patchFactory; + $this->patchHistory = $patchHistory; + } + + /** + * Register all dependents to patch + * + * @param string | DependentPatchInterface $patchName + */ + private function registerDependents(string $patchName) + { + $dependencies = $patchName::getDependencies(); + + foreach ($dependencies as $dependency) { + $this->dependents[$dependency][] = $patchName; + } + } + + /** + * Register patch and create chain of patches + * + * @param string $patchName + * @return PatchInterface | bool + */ + public function registerPatch(string $patchName) + { + if ($this->patchHistory->isApplied($patchName)) { + $this->appliedPatches[$patchName] = $patchName; + $this->registerDependents($patchName); + return false; + } + + if (isset($this->patches[$patchName])) { + return $this->patches[$patchName]; + } + + $patch = $patchName; + $this->patches[$patchName] = $patch; + return $patch; + } + + /** + * Retrieve all patches, that depends on current one + * + * @param string $patch + * @return string[] + */ + private function getDependentPatches(string $patch) + { + $patches = []; + $patchName = $patch; + + /** + * Let`s check if patch is dependency for other patches + */ + if (isset($this->dependents[$patchName])) { + foreach ($this->dependents[$patchName] as $dependent) { + if (isset($this->appliedPatches[$dependent])) { + $dependent = $this->appliedPatches[$dependent]; + $patches = array_replace($patches, $this->getDependentPatches($dependent)); + $patches[$dependent] = $dependent; + unset($this->appliedPatches[$dependent]); + } + } + } + + return $patches; + } + + /** + * @param string $patch + * @return string[] + */ + private function getDependencies(string $patch) + { + $depInstances = []; + $deps = call_user_func([$patch, 'getDependencies']); + $this->cyclomaticStack[$patch] = true; + + foreach ($deps as $dep) { + if (isset($this->cyclomaticStack[$dep])) { + throw new \LogicException("Cyclomatic dependency during patch installation"); + } + + $depInstance = $this->registerPatch($dep); + /** + * If a patch already have applied dependency - than we definently know + * that all other dependencies in dependency chain are applied too, so we can skip this dep + */ + if (!$depInstance) { + continue; + } + + $depInstances = array_replace($depInstances, $this->getDependencies($this->patches[$dep])); + $depInstances[$depInstance] = $depInstance; + } + + unset($this->cyclomaticStack[$patch]); + return $depInstances; + } + + /** + * If you want to uninstall system, there you will run all patches in reverse order + * + * But note, that patches also have dependencies, and if patch is dependency to any other patch + * you will to revert it dependencies first and only then patch + * + * @return \ArrayIterator + */ + public function getReverseIterator() + { + if ($this->reverseIterator === null) { + $reversePatches = []; + + while (!empty($this->appliedPatches)) { + $patch = array_pop($this->appliedPatches); + $reversePatches = array_replace($reversePatches, $this->getDependentPatches($patch)); + $reversePatches[$patch] = $patch; + } + + $this->reverseIterator = new \ArrayIterator($reversePatches); + } + + return $this->reverseIterator; + } + + /** + * Retrieve iterator of all patch instances + * + * If patch have dependencies, than first of all dependencies should be installed and only then desired patch + * + * @return \ArrayIterator + */ + public function getIterator() + { + if ($this->iterator === null) { + $installPatches = []; + $patchInstances = $this->patches; + + while (!empty($patchInstances)) { + $firstPatch = array_shift($patchInstances); + $deps = $this->getDependencies($firstPatch); + + /** + * Remove deps from patchInstances + */ + foreach ($deps as $dep) { + unset($patchInstances[$dep]); + } + + $installPatches = array_replace($installPatches, $deps); + $installPatches[$firstPatch] = $firstPatch; + } + + $this->iterator = new \ArrayIterator($installPatches); + } + + return $this->iterator; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchRegistryFactory.php b/lib/internal/Magento/Framework/Setup/Patch/PatchRegistryFactory.php new file mode 100644 index 0000000000000..0d8e242226700 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchRegistryFactory.php @@ -0,0 +1,46 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Patch; + +use Magento\Framework\ObjectManagerInterface; + +/** + * Create instance of patch registry + */ +class PatchRegistryFactory +{ + /** + * @var ObjectManagerInterface + */ + private $objectManager; + + /** + * @var string + */ + private $instanceName; + + /** + * @param ObjectManagerInterface $objectManager + * @param string $instanceName + */ + public function __construct( + ObjectManagerInterface $objectManager, + $instanceName = PatchRegistry::class + ) { + + $this->objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * @return PatchRegistry + */ + public function create() + { + return $this->objectManager->create($this->instanceName); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchRevertableInterface.php b/lib/internal/Magento/Framework/Setup/Patch/PatchRevertableInterface.php new file mode 100644 index 0000000000000..a69e0c61ad22f --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchRevertableInterface.php @@ -0,0 +1,25 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Patch; + +/** + * Revertable means, that patch can be reverted + * + * All patches (@see PatchInterface) that implement this interfaces should have next values: + * - do not use application layer: like Serilizer, Collections, etc + * - use only some DML operations: INSERT, UPDATE + * - DELETE DML operation is prohibited, because it can cause triggering foreign keys constraints + * - all schema patches are not revertable + */ +interface PatchRevertableInterface +{ + /** + * Rollback all changes, done by this patch + * + * @return void + */ + public function revert(); +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/PatchVersionInterface.php b/lib/internal/Magento/Framework/Setup/Patch/PatchVersionInterface.php new file mode 100644 index 0000000000000..9fca3ffc364f9 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/PatchVersionInterface.php @@ -0,0 +1,26 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Patch; + +/** + * For backward compatibility with versioned style module installation. Deprecated since creation. + * + * @deprecated + */ +interface PatchVersionInterface +{ + /** + * This version associate patch with Magento setup version. + * For example, if Magento current setup version is 2.0.3 and patch version is 2.0.2 than + * this patch will be added to registry, but will not be applied, because it is already applied + * by old mechanism of UpgradeData.php script + * + * + * @return string + * @deprecated since appearance, required for backward compatibility + */ + public static function getVersion(); +} diff --git a/lib/internal/Magento/Framework/Setup/Patch/SchemaPatchInterface.php b/lib/internal/Magento/Framework/Setup/Patch/SchemaPatchInterface.php new file mode 100644 index 0000000000000..ebc7c6f631c81 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Patch/SchemaPatchInterface.php @@ -0,0 +1,14 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Patch; + +/** + * This interface describe script, that atomic operations with schema (DDL) in SQL database + * This is wrapper for @see PatchInterface in order to define what kind of patch we have + */ +interface SchemaPatchInterface extends PatchInterface +{ +} diff --git a/lib/internal/Magento/Framework/Setup/SchemaPersistor.php b/lib/internal/Magento/Framework/Setup/SchemaPersistor.php index 10a1faa2728ae..f3af56b8ac2ca 100644 --- a/lib/internal/Magento/Framework/Setup/SchemaPersistor.php +++ b/lib/internal/Magento/Framework/Setup/SchemaPersistor.php @@ -45,7 +45,8 @@ private function initEmptyDom() return new \SimpleXMLElement( '<schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"></schema>' + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + </schema>' ); } diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Config/ConverterTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Config/ConverterTest.php new file mode 100644 index 0000000000000..2bb4bbcdb8d06 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Config/ConverterTest.php @@ -0,0 +1,93 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Config; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Setup\Declaration\Schema\Config\Converter; + +/** + * Test for Converter class. + * + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Config. + */ +class ConverterTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var Converter + */ + private $converter; + + /** + * @var ObjectManager + */ + private $objectManager; + + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + $this->converter = $this->objectManager->getObject( + Converter::class + ); + } + + /** + * Test converting table schema to array. + */ + public function testConvert() + { + $dom = new \DOMDocument(); + $dom->loadXML( + '<?xml version="1.0"?> + <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> + <table name="test_table" resource="default"> + <column xsi:type="int" name="id" nullable="false" identity="true" comment="Id"/> + <column xsi:type="varchar" name="data" length="100" identity="false" comment="Data"/> + <constraint xsi:type="primary" name="PRIMARY"> + <column name="id"/> + </constraint> + </table> + </schema>' + ); + $result = $this->converter->convert($dom); + $this->assertEquals( + [ + 'table' => [ + 'test_table' => [ + 'column' => [ + 'id' => [ + 'type' => 'int', + 'name' => 'id', + 'nullable' => 'false', + 'identity' => 'true', + 'comment' => 'Id', + ], + 'data' => [ + 'type' => 'varchar', + 'name' => 'data', + 'length' => '100', + 'identity' => 'false', + 'comment' => 'Data', + ], + ], + 'constraint' => [ + 'PRIMARY' => [ + 'column' => [ + 'id' => 'id', + ], + 'type' => 'primary', + 'name' => 'PRIMARY', + ], + ], + 'name' => 'test_table', + 'resource' => 'default', + ], + ], + ], + $result + ); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/DefinitionAggregatorTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/DefinitionAggregatorTest.php similarity index 91% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/DefinitionAggregatorTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/DefinitionAggregatorTest.php index f939ea93dd164..393b10d3e5033 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/DefinitionAggregatorTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/DefinitionAggregatorTest.php @@ -3,17 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DefinitionAggregator; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DbDefinitionProcessorInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DefinitionAggregator; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; /** * Test for Definition Aggregator. * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Db + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db */ class DefinitionAggregatorTest extends \PHPUnit\Framework\TestCase { diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/BlobTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/BlobTest.php similarity index 90% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/BlobTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/BlobTest.php index 0b35af1b99e1f..9693aceac394e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/BlobTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/BlobTest.php @@ -3,14 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\App\ResourceConnection; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Blob; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Blob; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; class BlobTest extends \PHPUnit\Framework\TestCase { diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/BooleanTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/BooleanTest.php similarity index 88% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/BooleanTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/BooleanTest.php index 0cff91d6469d8..8e28df4f6d4e3 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/BooleanTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/BooleanTest.php @@ -3,14 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\App\ResourceConnection; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Boolean as BooleanColumn; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Boolean as BooleanColumn; class BooleanTest extends \PHPUnit\Framework\TestCase { @@ -20,7 +20,7 @@ class BooleanTest extends \PHPUnit\Framework\TestCase private $objectManager; /** - * @var \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean + * @var \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean */ private $boolean; diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/CommentTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/CommentTest.php similarity index 76% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/CommentTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/CommentTest.php index 828be4860f9b0..1c2b3ccd9785b 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/CommentTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/CommentTest.php @@ -3,11 +3,11 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; class CommentTest extends \PHPUnit\Framework\TestCase { @@ -17,7 +17,7 @@ class CommentTest extends \PHPUnit\Framework\TestCase private $objectManager; /** - * @var \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Comment + * @var \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Comment */ private $comment; diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/DateTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/DateTest.php similarity index 85% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/DateTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/DateTest.php index fb0a08a6584a7..2c13795af2b9b 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/DateTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/DateTest.php @@ -3,14 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\App\ResourceConnection; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Date; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Boolean as BooleanColumn; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Date; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Boolean as BooleanColumn; class DateTest extends \PHPUnit\Framework\TestCase { @@ -20,7 +20,7 @@ class DateTest extends \PHPUnit\Framework\TestCase private $objectManager; /** - * @var \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Date + * @var \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Date */ private $date; diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/IdentityTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/IdentityTest.php similarity index 75% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/IdentityTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/IdentityTest.php index 78839efeeae7b..7e872a73ca5d9 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/IdentityTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/IdentityTest.php @@ -3,15 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Identity; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Identity; /** * Test for Identity DTO class. * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns */ class IdentityTest extends \PHPUnit\Framework\TestCase { @@ -21,19 +21,19 @@ class IdentityTest extends \PHPUnit\Framework\TestCase private $objectManager; /** - * @var \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Comment + * @var \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Comment */ private $identity; /** - * @var \Magento\Setup\Model\Declaration\Schema\Dto\Column|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Setup\Declaration\Schema\Dto\Column|\PHPUnit_Framework_MockObject_MockObject */ private $columnMock; protected function setUp() { $this->objectManager = new ObjectManager($this); - $this->columnMock = $this->getMockBuilder(\Magento\Setup\Model\Declaration\Schema\Dto\Column::class) + $this->columnMock = $this->getMockBuilder(\Magento\Framework\Setup\Declaration\Schema\Dto\Column::class) ->disableOriginalConstructor() ->setMethods(['isIdentity']) ->getMock(); diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/IntegerTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/IntegerTest.php similarity index 88% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/IntegerTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/IntegerTest.php index a1b9b201fb594..823a587fd48f4 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/IntegerTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/IntegerTest.php @@ -3,17 +3,17 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\App\ResourceConnection; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Identity; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Integer; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Unsigned; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer as IntegerColumnDto; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Identity; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Integer; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Unsigned; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer as IntegerColumnDto; class IntegerTest extends \PHPUnit\Framework\TestCase { @@ -23,7 +23,7 @@ class IntegerTest extends \PHPUnit\Framework\TestCase private $objectManager; /** - * @var \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Integer + * @var \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Integer */ private $integer; diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/NullableTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/NullableTest.php similarity index 87% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/NullableTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/NullableTest.php index ffa66408c945f..43dda0271eaf8 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/NullableTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/NullableTest.php @@ -3,12 +3,12 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Boolean as BooleanColumnDto; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Boolean as BooleanColumnDto; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementInterface; class NullableTest extends \PHPUnit\Framework\TestCase { diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdateTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdateTest.php similarity index 82% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdateTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdateTest.php index 8ae2b114e0f80..f92795364b26a 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdateTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdateTest.php @@ -3,14 +3,14 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\OnUpdate; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Boolean; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Boolean as BooleanColumnDto; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\OnUpdate; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Boolean; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Boolean as BooleanColumnDto; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp; class OnUpdateTest extends \PHPUnit\Framework\TestCase { diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/RealTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/RealTest.php similarity index 91% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/RealTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/RealTest.php index 9e33a974d7e90..348152cfae48c 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/RealTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/RealTest.php @@ -3,18 +3,18 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\App\ResourceConnection; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Identity; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Integer; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Real; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Unsigned; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Real as RealColumnDto; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Identity; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Integer; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Real; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Unsigned; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Real as RealColumnDto; class RealTest extends \PHPUnit\Framework\TestCase { @@ -24,7 +24,7 @@ class RealTest extends \PHPUnit\Framework\TestCase private $objectManager; /** - * @var \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Real + * @var \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Real */ private $real; diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinaryTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinaryTest.php similarity index 88% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinaryTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinaryTest.php index 333cff613a479..c266acfd32277 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinaryTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinaryTest.php @@ -3,19 +3,19 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\App\ResourceConnection; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\StringBinary; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\StringBinary as StringBinaryColumn; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\StringBinary; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\StringBinary as StringBinaryColumn; /** * Test for StringBinary class. * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns */ class StringBinaryTest extends \PHPUnit\Framework\TestCase { diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/TimestampTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/TimestampTest.php similarity index 90% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/TimestampTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/TimestampTest.php index 695a48e948f55..7d82fb889d308 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/TimestampTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/TimestampTest.php @@ -3,15 +3,15 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\App\ResourceConnection; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Timestamp; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\OnUpdate; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Boolean as BooleanColumn; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Timestamp; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Comment; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Nullable; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\OnUpdate; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Boolean as BooleanColumn; class TimestampTest extends \PHPUnit\Framework\TestCase { @@ -21,7 +21,7 @@ class TimestampTest extends \PHPUnit\Framework\TestCase private $objectManager; /** - * @var \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Timestamp + * @var \Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Timestamp */ private $timestamp; diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/UnsignedTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/UnsignedTest.php similarity index 90% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/UnsignedTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/UnsignedTest.php index 18d8a56b954b0..298d055218cb9 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Columns/UnsignedTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Columns/UnsignedTest.php @@ -3,11 +3,11 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Columns; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Columns; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Unsigned; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer as IntegerColumnDto; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Columns\Unsigned; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer as IntegerColumnDto; class UnsignedTest extends \PHPUnit\Framework\TestCase { diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKeyTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKeyTest.php similarity index 94% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKeyTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKeyTest.php index 3f69992296757..90bd32712285e 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKeyTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Constraints/ForeignKeyTest.php @@ -3,20 +3,20 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Constraints; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Constraints; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Constraints\ForeignKey; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Constraints\ForeignKey; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; /** * Test for Foreign Key constraint definition. * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Constraints + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Constraints */ class ForeignKeyTest extends \PHPUnit\Framework\TestCase { diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/InternalTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Constraints/InternalTest.php similarity index 91% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/InternalTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Constraints/InternalTest.php index f9d1ed10db6ab..62c76715b510c 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/InternalTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/Constraints/InternalTest.php @@ -3,19 +3,19 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Constraints; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Constraints; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Constraints\Internal; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Internal as InternalConstraintDto; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Constraints\Internal; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal as InternalConstraintDto; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; /** * Test for internal (primary key, unique key) constraint definition. * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Constraints + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Constraints */ class InternalTest extends \PHPUnit\Framework\TestCase { diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/IndexTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/IndexTest.php new file mode 100644 index 0000000000000..51ee068ef3063 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/MySQL/Definition/IndexTest.php @@ -0,0 +1,175 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Adapter\AdapterInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\Definition\Index; +use Magento\Framework\Setup\Declaration\Schema\Dto\Index as IndexDto; + +/** + * Test for index (key) definition. + * + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db\MySQL\Definition\Constraints + */ +class IndexTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var ObjectManager + */ + private $objectManager; + + /** + * @var Index + */ + private $index; + + /** + * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject + */ + private $resourceConnectionMock; + + protected function setUp() + { + $this->objectManager = new ObjectManager($this); + $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + $this->index = $this->objectManager->getObject( + Index::class, + [ + 'resourceConnection' => $this->resourceConnectionMock + ] + ); + } + + /** + * Test conversion to definition. + * + * @dataProvider toDefinitionDataProvider() + */ + public function testToDefinition($name, $type, $columns, $expectedExpression) + { + /** @var IndexDto|\PHPUnit_Framework_MockObject_MockObject $index */ + $index = $this->getMockBuilder(IndexDto::class) + ->disableOriginalConstructor() + ->getMock(); + $adapterMock = $this->getMockBuilder(AdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resourceConnectionMock->expects($this->once()) + ->method('getConnection') + ->willReturn($adapterMock); + + $index->expects($this->any())->method('getName')->willReturn($name); + $index->expects($this->any())->method('getIndexType')->willReturn($type); + $index->expects($this->any())->method('getColumnNames')->willReturn($columns); + $adapterMock->expects($this->any()) + ->method('quoteIdentifier') + ->willReturnCallback( + function ($name) { + return '`' . $name . '`'; + } + ); + + $this->assertEquals( + $expectedExpression, + $this->index->toDefinition($index) + ); + } + + public function toDefinitionDataProvider() + { + return [ + [ + 'name' => 'ft_index', + 'type' => IndexDto::FULLTEXT_INDEX, + 'columns' => ['title', 'content'], + 'expectedExpression' => "FULLTEXT INDEX `ft_index` (`title`,`content`)" + ], + [ + 'name' => 'ft_index', + 'type' => IndexDto::FULLTEXT_INDEX, + 'columns' => ['title'], + 'expectedExpression' => "FULLTEXT INDEX `ft_index` (`title`)" + ], + [ + 'name' => 'ft_index', + 'type' => 'btree', + 'columns' => ['title'], + 'expectedExpression' => "INDEX `ft_index` (`title`)" + ], + [ + 'name' => 'ft_index', + 'type' => 'HASH', + 'columns' => ['title'], + 'expectedExpression' => "INDEX `ft_index` (`title`)" + ], + ]; + } + + /** + * Test from definition conversion. + * + * @param array $definition + * @param array $expectedDefinition + * @dataProvider definitionDataProvider() + */ + public function testFromDefinition($definition, $expectedDefinition) + { + $result = $this->index->fromDefinition($definition); + $this->assertEquals($expectedDefinition, $result); + } + + /** + * @return array + */ + public function definitionDataProvider() + { + return [ + [ + 'definition' => [ + 'Index_type' => 'FULLTEXT', + 'Key_name' => 'ft_index', + 'Column_name' => 'text', + ], + 'excpectedDefiniton' => [ + 'indexType' => 'fulltext', + 'name' => 'ft_index', + 'column' => ['text' => 'text'], + 'type' => 'index', + ], + ], + [ + 'definition' => [ + 'Index_type' => 'BTREE', + 'Key_name' => 'bt_index', + 'Column_name' => 'text', + ], + 'excpectedDefiniton' => [ + 'indexType' => 'btree', + 'name' => 'bt_index', + 'column' => ['text' => 'text'], + 'type' => 'index', + ], + ], + [ + 'definition' => [ + 'Index_type' => 'HASH', + 'Key_name' => 'ht_index', + 'Column_name' => 'text', + ], + 'excpectedDefiniton' => [ + 'indexType' => 'hash', + 'name' => 'ht_index', + 'column' => ['text' => 'text'], + 'type' => 'index', + ], + ] + ]; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/SchemaBuilderTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/SchemaBuilderTest.php new file mode 100644 index 0000000000000..593f6d5b4339d --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/SchemaBuilderTest.php @@ -0,0 +1,479 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaReaderInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementFactory; +use Magento\Framework\Setup\Declaration\Schema\Dto\Index; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Sharding; + +/** + * Test for SchemaBuilder. + * + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class SchemaBuilderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\Setup\Declaration\Schema\Db\SchemaBuilder + */ + private $model; + + /** + * @var ObjectManagerHelper + */ + private $objectManagerHelper; + + /** + * @var ElementFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $elementFactoryMock; + + /** + * @var DbSchemaReaderInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $dbSchemaReaderMock; + + /** + * @var Sharding|\PHPUnit_Framework_MockObject_MockObject + */ + private $shardingMock; + + protected function setUp() + { + $this->elementFactoryMock = $this->getMockBuilder(ElementFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->dbSchemaReaderMock = $this->getMockBuilder(DbSchemaReaderInterface::class) + ->getMockForAbstractClass(); + $this->shardingMock = $this->getMockBuilder(Sharding::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->model = $this->objectManagerHelper->getObject( + \Magento\Framework\Setup\Declaration\Schema\Db\SchemaBuilder::class, + [ + 'elementFactory' => $this->elementFactoryMock, + 'dbSchemaReader' => $this->dbSchemaReaderMock, + 'sharding' => $this->shardingMock + ] + ); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function dataProvider() + { + return [ + [ + 'columns' => [ + 'first_table' => [ + 'first_column' => [ + 'name' => 'first_column', + 'type' => 'int', + 'padding' => 10, + 'identity' => true, + 'nullable' => false + ], + 'foreign_column' => [ + 'name' => 'foreign_column', + 'type' => 'int', + 'padding' => 10, + 'nullable' => false + ], + 'second_column' => [ + 'name' => 'second_column', + 'type' => 'timestamp', + 'default' => 'CURRENT_TIMESTAMP', + 'on_update' => true + ], + ], + 'second_table' => [ + 'ref_column' => [ + 'name' => 'ref_column', + 'type' => 'int', + 'padding' => 10, + 'nullable' => false + ], + ] + ], + 'references' => [ + 'first_table' => [ + 'some_foreign_key' => [ + 'name' => 'some_foreign_key', + 'type' => 'foreign', + 'column' => 'foreign_column', + 'table' => 'first_table', + 'referenceTable' => 'second_table', + 'referenceColumn' => 'ref_column' + ], + ] + ], + 'constraints' => [ + 'first_table' => [ + 'PRIMARY' => [ + 'name' => 'PRIMARY', + 'type' => 'primary', + 'column' => [ + 'first_column' + ] + ] + ] + ], + 'indexes' => [ + 'second_table' => [ + 'FIRST_INDEX' => [ + 'name' => 'FIRST_INDEX', + 'column' => [ + 'ref_column' + ] + ] + ] + ] + ] + ]; + } + + /** + * Create table. + * + * @param string $name + * @return Table + */ + private function createTable($name) + { + return new Table( + $name, + $name, + 'table', + 'default', + 'resource' + ); + } + + /** + * Create integer column with autoincrement. + * + * @param string $name + * @param Table $table + * @return \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer + */ + private function createIntegerAIColumn($name, Table $table) + { + return new Integer( + $name, + 'int', + $table, + 10, + true, + false, + true + ); + } + + /** + * Create integer column. + * + * @param string $name + * @param Table $table + * @return \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer + */ + private function createIntegerColumn($name, Table $table) + { + return new Integer( + $name, + 'int', + $table, + 10 + ); + } + + /** + * Create primary key constraint. + * + * @param Table $table + * @param array $columns + * @return Internal + */ + private function createPrimaryConstraint(Table $table, array $columns) + { + return new Internal( + 'PRIMARY', + 'primary', + $table, + $columns + ); + } + + /** + * Create index. + * + * @param string $indexName + * @param Table $table + * @param array $columns + * @return Index + */ + private function createIndex($indexName, Table $table, array $columns) + { + return new Index( + $indexName, + 'index', + $table, + $columns, + 'btree' + ); + } + + /** + * Create timestamp column. + * + * @param string $name + * @param Table $table + * @return \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp + */ + private function createTimestampColumn($name, Table $table) + { + return new Timestamp( + $name, + 'timestamp', + $table, + 'CURRENT_TIMESTAMP', + false, + true + ); + } + + /** + * @dataProvider dataProvider + * @param array $columns + * @param array $references + * @param array $constraints + * @param array $indexes + */ + public function testBuild(array $columns, array $references, array $constraints, array $indexes) + { + $this->prepareSchemaMocks($columns, $references, $constraints, $indexes); + $resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + /** @var Schema $schema */ + $schema = $this->objectManagerHelper->getObject( + Schema::class, + ['resourceConnection' => $resourceConnectionMock] + ); + $this->model->build($schema); + } + + /** + * WARNING! The expected exception type may differ depending on PHPUnit version. + * + * @dataProvider dataProvider + * @param array $columns + * @param array $references + * @param array $constraints + * @param array $indexes + * @expectedException \Exception + * @expectedExceptionMessage + * User Warning: Column unknown_column does not exist for index/constraint FIRST_INDEX in table second_table + */ + public function testBuildUnknownIndexColumn(array $columns, array $references, array $constraints, array $indexes) + { + $indexes['second_table']['FIRST_INDEX']['column'][] = 'unknown_column'; + $this->prepareSchemaMocks($columns, $references, $constraints, $indexes); + $resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + /** @var Schema $schema */ + $schema = $this->objectManagerHelper->getObject( + Schema::class, + ['resourceConnection' => $resourceConnectionMock] + ); + $this->model->build($schema); + } + + /** + * Prepare mocks for test. + * + * @param array $columns + * @param array $references + * @param array $constraints + * @param array $indexes + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + private function prepareSchemaMocks(array $columns, array $references, array $constraints, array $indexes) + { + $withContext = [['first_table', 'default'], ['second_table', 'default']]; + $this->shardingMock->expects(self::once()) + ->method('getResources') + ->willReturn(['default']); + $this->dbSchemaReaderMock->expects(self::once()) + ->method('readTables') + ->with('default') + ->willReturn(['first_table', 'second_table']); + $this->dbSchemaReaderMock->expects($this->any()) + ->method('getTableOptions') + ->withConsecutive(...array_values($withContext)) + ->willReturnOnConsecutiveCalls( + ['Engine' => 'innodb', 'Comment' => ''], + ['Engine' => 'innodb', 'Comment' => 'Not null comment'] + ); + $this->dbSchemaReaderMock->expects($this->any()) + ->method('readColumns') + ->withConsecutive(...array_values($withContext)) + ->willReturnOnConsecutiveCalls($columns['first_table'], $columns['second_table']); + $this->dbSchemaReaderMock->expects($this->any()) + ->method('readIndexes') + ->withConsecutive(...array_values($withContext)) + ->willReturnOnConsecutiveCalls([], $indexes['second_table']); + $this->dbSchemaReaderMock->expects($this->any()) + ->method('readConstraints') + ->withConsecutive(...array_values($withContext)) + ->willReturnOnConsecutiveCalls($constraints['first_table'], []); + $this->dbSchemaReaderMock->expects($this->any()) + ->method('readReferences') + ->withConsecutive(...array_values($withContext)) + ->willReturnOnConsecutiveCalls($references['first_table'], []); + $table = $this->createTable('first_table'); + $refTable = $this->createTable('second_table'); + $refColumn = $this->createIntegerColumn('ref_column', $refTable); + $index = $this->createIndex('FIRST_INDEX', $table, [$refColumn]); + $refTable->addColumns([$refColumn]); + $refTable->addIndexes([$index]); + $firstColumn = $this->createIntegerAIColumn('first_column', $table); + $foreignColumn = $this->createIntegerColumn('foreign_column', $table); + $timestampColumn = $this->createTimestampColumn('second_column', $table); + $primaryKey = $this->createPrimaryConstraint($table, [$firstColumn]); + $foreignKey = new Reference( + 'some_foreign_key', + 'foreign', + $table, + $foreignColumn, + $refTable, + $refColumn, + 'CASCADE' + ); + $table->addColumns([$firstColumn, $foreignColumn, $timestampColumn]); + $table->addConstraints([$foreignKey, $primaryKey]); + $this->elementFactoryMock->expects($this->any()) + ->method('create') + ->withConsecutive( + [ + 'table', + [ + 'name' =>'first_table', + 'resource' => 'default', + 'engine' => 'innodb', + 'comment' => null + ] + ], + [ + 'int', + [ + 'name' => 'first_column', + 'type' => 'int', + 'table' => $table, + 'padding' => 10, + 'identity' => true, + 'nullable' => false, + ] + ], + [ + 'int', + [ + 'name' => 'foreign_column', + 'type' => 'int', + 'table' => $table, + 'padding' => 10, + 'nullable' => false, + ] + ], + [ + 'timestamp', + [ + 'name' => 'second_column', + 'type' => 'timestamp', + 'table' => $table, + 'default' => 'CURRENT_TIMESTAMP', + 'on_update' => true, + ] + ], + [ + 'primary', + [ + 'name' => 'PRIMARY', + 'type' => 'primary', + 'columns' => [$firstColumn], + 'table' => $table, + 'column' => ['first_column'], + ] + ], + [ + 'table', + [ + 'name' =>'second_table', + 'resource' => 'default', + 'engine' => 'innodb', + 'comment' => 'Not null comment' + ] + ], + [ + 'int', + [ + 'name' => 'ref_column', + 'type' => 'int', + 'table' => $refTable, + 'padding' => 10, + 'nullable' => false, + ] + ], + [ + 'index', + [ + 'name' => 'FIRST_INDEX', + 'table' => $refTable, + 'column' => ['ref_column'], + 'columns' => [$refColumn], + ] + ], + [ + 'foreign', + [ + 'name' => 'some_foreign_key', + 'type' => 'foreign', + 'column' => $foreignColumn, + 'table' => $table, + 'referenceTable' => $refTable, + 'referenceColumn' => $refColumn, + ] + ] + ) + ->willReturnOnConsecutiveCalls( + $table, + $firstColumn, + $foreignColumn, + $timestampColumn, + $primaryKey, + $refTable, + $refColumn, + $index, + $foreignKey + ); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/StatementAggregatorTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/StatementAggregatorTest.php similarity index 93% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/StatementAggregatorTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/StatementAggregatorTest.php index f91c0dd152368..904b1791bc088 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/StatementAggregatorTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Db/StatementAggregatorTest.php @@ -4,22 +4,22 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use Magento\Setup\Model\Declaration\Schema\Db\ReferenceStatement; -use Magento\Setup\Model\Declaration\Schema\Db\Statement; -use Magento\Setup\Model\Declaration\Schema\Db\StatementAggregator; +use Magento\Framework\Setup\Declaration\Schema\Db\ReferenceStatement; +use Magento\Framework\Setup\Declaration\Schema\Db\Statement; +use Magento\Framework\Setup\Declaration\Schema\Db\StatementAggregator; /** * Test for StatementAggregator. * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Db + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Db */ class StatementAggregatorTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Setup\Model\Declaration\Schema\Db\StatementAggregator + * @var \Magento\Framework\Setup\Declaration\Schema\Db\StatementAggregator */ private $model; diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Declaration/SchemaBuilderTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Declaration/SchemaBuilderTest.php new file mode 100644 index 0000000000000..523784ccb4fe9 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Declaration/SchemaBuilderTest.php @@ -0,0 +1,462 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Declaration; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\Stdlib\BooleanUtils; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationComposite; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Internal; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementFactory; +use Magento\Framework\Setup\Declaration\Schema\Dto\Index; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Sharding; + +/** + * Test for SchemaBuilder. + * + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Declaration + * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class SchemaBuilderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\Setup\Declaration\Schema\Declaration\SchemaBuilder + */ + private $model; + + /** + * @var ObjectManagerHelper + */ + private $objectManagerHelper; + + /** + * @var ElementFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $elementFactoryMock; + + /** + * @var BooleanUtils|\PHPUnit_Framework_MockObject_MockObject + */ + private $booleanUtilsMock; + + /** + * @var Sharding|\PHPUnit_Framework_MockObject_MockObject + */ + private $shardingMock; + + /** + * @var ValidationComposite|\PHPUnit_Framework_MockObject_MockObject + */ + private $validationCompositeMock; + + /** + * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject + */ + private $resourceConnectionMock; + + protected function setUp() + { + $this->elementFactoryMock = $this->getMockBuilder(ElementFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->booleanUtilsMock = $this->getMockBuilder(BooleanUtils::class) + ->disableOriginalConstructor() + ->getMock(); + $this->shardingMock = $this->getMockBuilder(Sharding::class) + ->disableOriginalConstructor() + ->getMock(); + $this->validationCompositeMock = $this->getMockBuilder(ValidationComposite::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->model = $this->objectManagerHelper->getObject( + \Magento\Framework\Setup\Declaration\Schema\Declaration\SchemaBuilder::class, + [ + 'elementFactory' => $this->elementFactoryMock, + 'booleanUtils' => new BooleanUtils(), + 'sharding' => $this->shardingMock, + 'validationComposite' => $this->validationCompositeMock, + 'resourceConnection' => $this->resourceConnectionMock + ] + ); + } + + /** + * @return array + */ + public function tablesProvider() + { + return [ + [ + [ + 'first_table' => [ + 'name' => 'first_table', + 'engine' => 'innodb', + 'resource' => 'default', + 'column' => [ + 'first_column' => [ + 'name' => 'first_column', + 'type' => 'int', + 'padding' => 10, + 'identity' => true, + 'nullable' => false + ], + 'foreign_column' => [ + 'name' => 'foreign_column', + 'type' => 'int', + 'padding' => 10, + 'nullable' => false + ], + 'some_disabled_column' => [ + 'name' => 'some_disabled_column', + 'disabled' => 'true', + 'type' => 'int', + 'padding' => 10, + 'nullable' => false + ], + 'second_column' => [ + 'name' => 'second_column', + 'type' => 'timestamp', + 'default' => 'CURRENT_TIMESTAMP', + 'on_update' => true + ], + ], + 'constraint' => [ + 'some_foreign_key' => [ + 'name' => 'some_foreign_key', + 'type' => 'foreign', + 'column' => 'foreign_column', + 'table' => 'first_table', + 'referenceTable' => 'second_table', + 'referenceColumn' => 'ref_column' + ], + 'PRIMARY' => [ + 'name' => 'PRIMARY', + 'type' => 'primary', + 'column' => [ + 'first_column' + ] + ] + ] + ], + 'second_table' => [ + 'name' => 'second_table', + 'engine' => 'innodb', + 'resource' => 'default', + 'column' => [ + 'ref_column' => [ + 'name' => 'ref_column', + 'type' => 'int', + 'padding' => 10, + 'nullable' => false + ], + ], + 'index' => [ + 'FIRST_INDEX' => [ + 'name' => 'FIRST_INDEX', + 'column' => [ + 'ref_column' + ] + ] + ], + ] + ] + ] + ]; + } + + /** + * Create table + * + * @param string $name + * @return Table + */ + private function createTable($name) + { + return new Table( + $name, + $name, + 'table', + 'default', + 'resource' + ); + } + + /** + * Create integer column with autoincrement. + * + * @param string $name + * @param Table $table + * @return \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer + */ + private function createIntegerAIColumn($name, Table $table) + { + return new Integer( + $name, + 'int', + $table, + 10, + true, + false, + true + ); + } + + /** + * Create integer column. + * + * @param string $name + * @param Table $table + * @return \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer + */ + private function createIntegerColumn($name, Table $table) + { + return new Integer( + $name, + 'int', + $table, + 10 + ); + } + + /** + * Create PK constraint. + * + * @param Table $table + * @param array $columns + * @return Internal + */ + private function createPrimaryConstraint(Table $table, array $columns) + { + return new Internal( + 'PRIMARY', + 'primary', + $table, + $columns + ); + } + + /** + * Create index. + * + * @param string $indexName + * @param Table $table + * @param array $columns + * @return Index + */ + private function createIndex($indexName, Table $table, array $columns) + { + return new Index( + $indexName, + 'index', + $table, + $columns, + 'btree' + ); + } + + /** + * Create timestamp column. + * + * @param string $name + * @param Table $table + * @return \Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Timestamp + */ + private function createTimestampColumn($name, Table $table) + { + return new Timestamp( + $name, + 'timestamp', + $table, + 'CURRENT_TIMESTAMP', + false, + true + ); + } + + /** + * @dataProvider tablesProvider + * @param array $tablesData + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function testBuild(array $tablesData) + { + $table = $this->createTable('first_table'); + $refTable = $this->createTable('second_table'); + $refColumn = $this->createIntegerColumn('ref_column', $refTable); + $index = $this->createIndex('FIRST_INDEX', $table, [$refColumn]); + $refTable->addColumns([$refColumn]); + $refTable->addIndexes([$index]); + $firstColumn = $this->createIntegerAIColumn('first_column', $table); + $foreignColumn = $this->createIntegerColumn('foreign_column', $table); + $timestampColumn = $this->createTimestampColumn('second_column', $table); + $primaryKey = $this->createPrimaryConstraint($table, [$firstColumn]); + $foreignKey = new Reference( + 'some_foreign_key', + 'foreign', + $table, + $foreignColumn, + $refTable, + $refColumn, + 'CASCADE' + ); + $table->addColumns([$firstColumn, $foreignColumn, $timestampColumn]); + $table->addConstraints([$foreignKey, $primaryKey]); + $this->elementFactoryMock->expects(self::exactly(9)) + ->method('create') + ->withConsecutive( + [ + 'table', + [ + 'name' =>'first_table', + 'resource' => 'default', + 'engine' => 'innodb', + 'comment' => null + ] + ], + [ + 'int', + [ + 'name' => 'first_column', + 'type' => 'int', + 'table' => $table, + 'padding' => 10, + 'identity' => true, + 'nullable' => false, + 'resource' => 'default' + ] + ], + [ + 'int', + [ + 'name' => 'foreign_column', + 'type' => 'int', + 'table' => $table, + 'padding' => 10, + 'nullable' => false, + 'resource' => 'default' + ] + ], + [ + 'timestamp', + [ + 'name' => 'second_column', + 'type' => 'timestamp', + 'table' => $table, + 'default' => 'CURRENT_TIMESTAMP', + 'on_update' => true, + 'resource' => 'default' + ] + ], + [ + 'table', + [ + 'name' =>'second_table', + 'resource' => 'default', + 'engine' => 'innodb', + 'comment' => null + ] + ], + [ + 'int', + [ + 'name' => 'ref_column', + 'type' => 'int', + 'table' => $refTable, + 'padding' => 10, + 'nullable' => false, + 'resource' => 'default' + ] + ], + [ + 'index', + [ + 'name' => 'FIRST_INDEX', + 'table' => $refTable, + 'column' => ['ref_column'], + 'columns' => [$refColumn], + 'resource' => 'default' + ] + ], + [ + 'foreign', + [ + 'name' => 'some_foreign_key', + 'type' => 'foreign', + 'column' => $foreignColumn, + 'table' => $table, + 'referenceTable' => $refTable, + 'referenceColumn' => $refColumn, + 'resource' => 'default' + ] + ], + [ + 'primary', + [ + 'name' => 'PRIMARY', + 'type' => 'primary', + 'columns' => [$firstColumn], + 'table' => $table, + 'column' => ['first_column'], + 'resource' => 'default' + ] + ] + ) + ->willReturnOnConsecutiveCalls( + $table, + $firstColumn, + $foreignColumn, + $timestampColumn, + $refTable, + $refColumn, + $index, + $foreignKey, + $primaryKey + ); + $resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + /** @var Schema $schema */ + $schema = $this->objectManagerHelper->getObject( + Schema::class, + ['resourceConnection' => $resourceConnectionMock] + ); + $this->resourceConnectionMock->expects(self::once()) + ->method('getTableName') + ->willReturn('second_table'); + $resourceConnectionMock->expects(self::exactly(6)) + ->method('getTableName') + ->withConsecutive( + ['first_table'], + ['first_table'], + ['second_table'], + ['second_table'], + ['first_table'], + ['second_table'] + ) + ->willReturnOnConsecutiveCalls( + 'first_table', + 'first_table', + 'second_table', + 'second_table', + 'first_table', + 'second_table' + ); + $this->model->addTablesData($tablesData); + $this->model->build($schema); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Diff/DiffManagerTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Diff/DiffManagerTest.php similarity index 88% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Diff/DiffManagerTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Diff/DiffManagerTest.php index 4e791f70916e8..b88ad608c89ff 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Diff/DiffManagerTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Diff/DiffManagerTest.php @@ -4,19 +4,19 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Diff; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Diff; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use Magento\Setup\Model\Declaration\Schema\Diff\Diff; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; -use Magento\Setup\Model\Declaration\Schema\Dto\Index; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Diff\Diff; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\Dto\Index; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; class DiffManagerTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Setup\Model\Declaration\Schema\Diff\DiffManager + * @var \Magento\Framework\Setup\Declaration\Schema\Diff\DiffManager */ private $model; @@ -26,18 +26,18 @@ class DiffManagerTest extends \PHPUnit\Framework\TestCase private $objectManagerHelper; /** - * @var \Magento\Setup\Model\Declaration\Schema\Comparator|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Setup\Declaration\Schema\Comparator|\PHPUnit_Framework_MockObject_MockObject */ private $comparatorMock; protected function setUp() { - $this->comparatorMock = $this->getMockBuilder(\Magento\Setup\Model\Declaration\Schema\Comparator::class) + $this->comparatorMock = $this->getMockBuilder(\Magento\Framework\Setup\Declaration\Schema\Comparator::class) ->getMockForAbstractClass(); $this->objectManagerHelper = new ObjectManagerHelper($this); $this->model = $this->objectManagerHelper->getObject( - \Magento\Setup\Model\Declaration\Schema\Diff\DiffManager::class, + \Magento\Framework\Setup\Declaration\Schema\Diff\DiffManager::class, [ 'comparator' => $this->comparatorMock ] diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Dto/Factories/TableTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Dto/Factories/TableTest.php new file mode 100644 index 0000000000000..9562d38d74cf3 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Dto/Factories/TableTest.php @@ -0,0 +1,84 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Dto\Factories; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +class TableTest extends \PHPUnit\Framework\TestCase +{ + /** @var \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Table */ + protected $model; + + /** @var ObjectManagerHelper */ + protected $objectManagerHelper; + + /** @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject */ + protected $objectManagerMock; + + /** @var \Magento\Framework\App\ResourceConnection|\PHPUnit_Framework_MockObject_MockObject */ + protected $resourceConnectionMock; + + protected function setUp() + { + $this->objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resourceConnectionMock = $this->getMockBuilder(\Magento\Framework\App\ResourceConnection::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->model = $this->objectManagerHelper->getObject( + \Magento\Framework\Setup\Declaration\Schema\Dto\Factories\Table::class, + [ + 'objectManager' => $this->objectManagerMock, + 'resourceConnection' => $this->resourceConnectionMock + ] + ); + } + + public function testCreate() + { + $this->resourceConnectionMock->expects(self::once()) + ->method('getTablePrefix') + ->willReturn('pf_'); + $data = [ + 'name' => 'some_table', + 'engine' => null, + ]; + $expectedData = [ + 'name' => 'pf_some_table', + 'engine' => 'innodb', + 'nameWithoutPrefix' => 'some_table' + ]; + $this->objectManagerMock->expects(self::once()) + ->method('create') + ->with(Table::class, $expectedData); + $this->model->create($data); + } + + public function testCreateWithPrefix() + { + $this->resourceConnectionMock->expects(self::once()) + ->method('getTablePrefix') + ->willReturn('pf_'); + $data = [ + 'name' => 'pf_some_table', + 'engine' => 'memory', + 'nameWithoutPrefix' => 'some_table' + ]; + $expectedData = [ + 'name' => 'pf_some_table', + 'engine' => 'memory', + 'nameWithoutPrefix' => 'some_table' + ]; + $this->objectManagerMock->expects(self::once()) + ->method('create') + ->with(Table::class, $expectedData); + $this->model->create($data); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Operations/AddColumnTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Operations/AddColumnTest.php similarity index 85% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Operations/AddColumnTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Operations/AddColumnTest.php index a6c3ebc399f2d..38e16152c4156 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Operations/AddColumnTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/Operations/AddColumnTest.php @@ -4,28 +4,28 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Operations; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\Operations; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DefinitionAggregator; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\DDL\Triggers\MigrateDataFrom; -use Magento\Setup\Model\Declaration\Schema\Db\Statement; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementFactory; -use Magento\Setup\Model\Declaration\Schema\Dto\Index; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\ElementHistoryFactory; -use Magento\Setup\Model\Declaration\Schema\Operations\AddColumn; -use Magento\Setup\Model\Declaration\Schema\Operations\AddComplexElement; -use Magento\Setup\Model\Declaration\Schema\Operations\DropElement; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\DefinitionAggregator; +use Magento\Framework\Setup\Declaration\Schema\Db\MySQL\DDL\Triggers\MigrateDataFrom; +use Magento\Framework\Setup\Declaration\Schema\Db\Statement; +use Magento\Framework\Setup\Declaration\Schema\Dto\Column; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer; +use Magento\Framework\Setup\Declaration\Schema\Dto\ElementFactory; +use Magento\Framework\Setup\Declaration\Schema\Dto\Index; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\ElementHistoryFactory; +use Magento\Framework\Setup\Declaration\Schema\Operations\AddColumn; +use Magento\Framework\Setup\Declaration\Schema\Operations\AddComplexElement; +use Magento\Framework\Setup\Declaration\Schema\Operations\DropElement; /** * Test for AddColumn. * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Operations + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema\Operations * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/OperationsExecutorTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/OperationsExecutorTest.php similarity index 83% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/OperationsExecutorTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/OperationsExecutorTest.php index f14413ab169dc..50fff290da182 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/OperationsExecutorTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/OperationsExecutorTest.php @@ -4,34 +4,34 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema; use Magento\Framework\App\ResourceConnection; use Magento\Framework\DB\Adapter\Pdo\Mysql; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\StatementAggregator; -use Magento\Setup\Model\Declaration\Schema\Db\StatementAggregatorFactory; -use Magento\Setup\Model\Declaration\Schema\Db\StatementFactory; -use Magento\Setup\Model\Declaration\Schema\Diff\DiffInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\Operations\CreateTable; -use Magento\Setup\Model\Declaration\Schema\Operations\DropElement; -use Magento\Setup\Model\Declaration\Schema\Sharding; +use Magento\Framework\Setup\Declaration\Schema\Db\DbSchemaWriterInterface; +use Magento\Framework\Setup\Declaration\Schema\Db\StatementAggregator; +use Magento\Framework\Setup\Declaration\Schema\Db\StatementAggregatorFactory; +use Magento\Framework\Setup\Declaration\Schema\Db\StatementFactory; +use Magento\Framework\Setup\Declaration\Schema\Diff\DiffInterface; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Integer; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\ElementHistory; +use Magento\Framework\Setup\Declaration\Schema\Operations\CreateTable; +use Magento\Framework\Setup\Declaration\Schema\Operations\DropElement; +use Magento\Framework\Setup\Declaration\Schema\Sharding; /** * Test for OperationsExecutor. * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema + * @package Magento\Framework\Setup\Test\Unit\Declaration\Schema * * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class OperationsExecutorTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Setup\Model\Declaration\Schema\OperationsExecutor + * @var \Magento\Framework\Setup\Declaration\Schema\OperationsExecutor */ private $model; @@ -102,12 +102,13 @@ protected function setUp() ->getMock(); $this->objectManagerHelper = new ObjectManagerHelper($this); $this->model = $this->objectManagerHelper->getObject( - \Magento\Setup\Model\Declaration\Schema\OperationsExecutor::class, + \Magento\Framework\Setup\Declaration\Schema\OperationsExecutor::class, [ 'operations' => [ 'create_table' => $this->createTableOperation, 'drop_element' => $this->dropElement ], + 'dataSaviorsCollection' => [], 'sharding' => $this->shardingMock, 'resourceConnection' => $this->resourceConnectionMock, 'statementFactory' => $this->statementFactoryMock, @@ -178,6 +179,6 @@ public function testExecute() ->willReturn($tablesHistories); $this->dropElement->expects(self::at(0)) ->method('doOperation'); - $this->model->execute($diff); + $this->model->execute($diff, []); } } diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/ShardingTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ShardingTest.php similarity index 88% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/ShardingTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ShardingTest.php index 09ea145d458d3..4a73816ba89ff 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/ShardingTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ShardingTest.php @@ -4,14 +4,14 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; class ShardingTest extends \PHPUnit\Framework\TestCase { - /** @var \Magento\Setup\Model\Declaration\Schema\Sharding */ + /** @var \Magento\Framework\Setup\Declaration\Schema\Sharding */ private $model; /** @var ObjectManagerHelper */ @@ -28,7 +28,7 @@ protected function setUp() $this->objectManagerHelper = new ObjectManagerHelper($this); $this->model = $this->objectManagerHelper->getObject( - \Magento\Setup\Model\Declaration\Schema\Sharding::class, + \Magento\Framework\Setup\Declaration\Schema\Sharding::class, [ 'deploymentConfig' => $this->deploymentConfigMock, 'resources' => ['default', 'checkout', 'sales'] diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/ValidationRules/CheckReferenceColumnHasIndexTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ValidationRules/CheckReferenceColumnHasIndexTest.php similarity index 82% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/ValidationRules/CheckReferenceColumnHasIndexTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ValidationRules/CheckReferenceColumnHasIndexTest.php index 77a4d93d7ff97..573fc483a19ca 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/ValidationRules/CheckReferenceColumnHasIndexTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ValidationRules/CheckReferenceColumnHasIndexTest.php @@ -4,14 +4,14 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\ValidationRules; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\ValidationRules; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use Magento\Setup\Model\Declaration\Schema\Declaration\ValidationRules\CheckReferenceColumnHasIndex; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Real; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules\CheckReferenceColumnHasIndex; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Real; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; class CheckReferenceColumnHasIndexTest extends \PHPUnit\Framework\TestCase { diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/ValidationRules/RealTypesTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ValidationRules/RealTypesTest.php similarity index 82% rename from setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/ValidationRules/RealTypesTest.php rename to lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ValidationRules/RealTypesTest.php index 90df6f0d03d7c..573cacae322f7 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/ValidationRules/RealTypesTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ValidationRules/RealTypesTest.php @@ -4,13 +4,13 @@ * See COPYING.txt for license details. */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\ValidationRules; +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\ValidationRules; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use Magento\Setup\Model\Declaration\Schema\Declaration\ValidationRules\RealTypes; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Real; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; +use Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules\RealTypes; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Real; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; class RealTypesTest extends \PHPUnit\Framework\TestCase { diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ValidationRules/ValidationRulesTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ValidationRules/ValidationRulesTest.php new file mode 100644 index 0000000000000..d1ae5e7c9127d --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Declaration/Schema/ValidationRules/ValidationRulesTest.php @@ -0,0 +1,81 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Test\Unit\Declaration\Schema\ValidationRules; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; +use Magento\Framework\Setup\Declaration\Schema\Declaration\ValidationRules\CheckReferenceColumnHasIndex; +use Magento\Framework\Setup\Declaration\Schema\Dto\Columns\Real; +use Magento\Framework\Setup\Declaration\Schema\Dto\Constraints\Reference; +use Magento\Framework\Setup\Declaration\Schema\Dto\Schema; +use Magento\Framework\Setup\Declaration\Schema\Dto\Table; + +/** + * Class ValidationRulesTest + * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\ValidationRules + */ +class ValidationRulesTest extends \PHPUnit\Framework\TestCase +{ + /** @var CheckReferenceColumnHasIndex */ + private $model; + + /** @var ObjectManagerHelper */ + private $objectManagerHelper; + + protected function setUp() + { + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->model = $this->objectManagerHelper->getObject( + CheckReferenceColumnHasIndex::class, + [ + ] + ); + } + + public function testValidate() + { + $table = new Table('name', 'name', 'table', 'default', 'innodb'); + $refTable = new Table( + 'ref_table', + 'name', + 'table', + 'default', + 'innodb' + ); + + $column = new Real('decimal', 'decimal', $table, 10, 5); + $refColumn = new Real('ref_decimal', 'decimal', $refTable, 10, 5); + $reference = new Reference( + 'ref', + 'foreign', + $table, + $column, + $refTable, + $refColumn, + 'CASCADE' + ); + + $table->addColumns([$column]); + $refTable->addColumns([$refColumn]); + $table->addConstraints([$reference]); + /** @var Schema|\PHPUnit_Framework_MockObject_MockObject $schemaMock */ + $schemaMock = $this->getMockBuilder(Schema::class) + ->disableOriginalConstructor() + ->getMock(); + $schemaMock->expects(self::once()) + ->method('getTables') + ->willReturn([$table]); + self::assertEquals( + [ + [ + 'column' => 'ref_decimal', + 'message' => 'Reference column ref_decimal in reference table ref_table do not have index', + ], + ], + $this->model->validate($schemaMock) + ); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/ListsTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/ListsTest.php index 6e7ca3ece43b1..a25771b4519f2 100644 --- a/lib/internal/Magento/Framework/Setup/Test/Unit/ListsTest.php +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/ListsTest.php @@ -58,6 +58,9 @@ protected function setUp() $this->mockConfig->expects($this->any()) ->method('getAllowedLocales') ->willReturn($this->expectedLocales); + $this->mockConfig->expects($this->any()) + ->method('getAllowedCurrencies') + ->willReturn($this->expectedCurrencies); $this->lists = new Lists($this->mockConfig); } @@ -73,4 +76,13 @@ public function testGetLocaleList() $locales = array_intersect($this->expectedLocales, array_keys($this->lists->getLocaleList())); $this->assertEquals($this->expectedLocales, $locales); } + + /** + * Test Lists:getCurrencyList() considering allowed currencies config values. + */ + public function testGetCurrencyList() + { + $currencies = array_intersect($this->expectedCurrencies, array_keys($this->lists->getCurrencyList())); + $this->assertEquals($this->expectedCurrencies, $currencies); + } } diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchApplierTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchApplierTest.php new file mode 100644 index 0000000000000..76d40a983de78 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchApplierTest.php @@ -0,0 +1,547 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Test\Unit\Patch; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Adapter\AdapterInterface; +use Magento\Framework\Module\ModuleResource; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\SchemaSetupInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Setup\Patch\PatchApplier; +use Magento\Framework\Setup\Patch\PatchFactory; +use Magento\Framework\Setup\Patch\PatchHistory; +use Magento\Framework\Setup\Patch\PatchReader; +use Magento\Framework\Setup\Patch\PatchRegistry; +use Magento\Framework\Setup\Patch\PatchRegistryFactory; + +/** + * Class PatchApplierTest + * @package Magento\Framework\Setup\Test\Unit\Patch + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class PatchApplierTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var PatchRegistryFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $patchRegistryFactoryMock; + + /** + * @var PatchReader|\PHPUnit_Framework_MockObject_MockObject + */ + private $dataPatchReaderMock; + + /** + * @var PatchReader|\PHPUnit_Framework_MockObject_MockObject + */ + private $schemaPatchReaderMock; + + /** + * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject + */ + private $resourceConnectionMock; + + /** + * @var ModuleResource|\PHPUnit_Framework_MockObject_MockObject + */ + private $moduleResourceMock; + + /** + * @var PatchHistory|\PHPUnit_Framework_MockObject_MockObject + */ + private $patchHistoryMock; + + /** + * @var PatchFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $patchFactoryMock; + + /** + * @var \Magento\Framework\Setup\SetupInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $schemaSetupMock; + + /** + * @var ModuleDataSetupInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $moduleDataSetupMock; + + /** + * @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $objectManagerMock; + + /** + * @var PatchApplier + */ + private $patchApllier; + + /** + * @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $connectionMock; + + protected function setUp() + { + $this->patchRegistryFactoryMock = $this->createMock(PatchRegistryFactory::class); + $this->dataPatchReaderMock = $this->createMock(PatchReader::class); + $this->schemaPatchReaderMock = $this->createMock(PatchReader::class); + $this->resourceConnectionMock = $this->createMock(ResourceConnection::class); + $this->moduleResourceMock = $this->createMock(ModuleResource::class); + $this->patchHistoryMock = $this->createMock(PatchHistory::class); + $this->patchFactoryMock = $this->createMock(PatchFactory::class); + $this->schemaSetupMock = $this->createMock(SchemaSetupInterface::class); + $this->moduleDataSetupMock = $this->createMock(ModuleDataSetupInterface::class); + $this->objectManagerMock = $this->createMock(ObjectManagerInterface::class); + $this->connectionMock = $this->createMock(AdapterInterface::class); + $this->moduleDataSetupMock->expects($this->any())->method('getConnection')->willReturn($this->connectionMock); + + $objectManager = new ObjectManager($this); + $this->patchApllier = $objectManager->getObject( + PatchApplier::class, + [ + 'patchRegistryFactory' => $this->patchRegistryFactoryMock, + 'dataPatchReader' => $this->dataPatchReaderMock, + 'schemaPatchReader' => $this->schemaPatchReaderMock, + 'resourceConnection' => $this->resourceConnectionMock, + 'moduleResource' => $this->moduleResourceMock, + 'patchHistory' => $this->patchHistoryMock, + 'patchFactory' => $this->patchFactoryMock, + 'objectManager' => $this->objectManagerMock, + 'schemaSetup' => $this->schemaSetupMock, + 'moduleDataSetup' => $this->moduleDataSetupMock, + ] + ); + require_once __DIR__ . '/../_files/data_patch_classes.php'; + require_once __DIR__ . '/../_files/schema_patch_classes.php'; + } + + /** + * @param $moduleName + * @param $dataPatches + * @param $moduleVersionInDb + * + * @dataProvider applyDataPatchDataNewModuleProvider() + */ + public function testApplyDataPatchForNewlyInstalledModule($moduleName, $dataPatches, $moduleVersionInDb) + { + $this->dataPatchReaderMock->expects($this->once()) + ->method('read') + ->with($moduleName) + ->willReturn($dataPatches); + + $this->moduleResourceMock->expects($this->any())->method('getDataVersion')->willReturnMap( + [ + [$moduleName, $moduleVersionInDb] + ] + ); + + $patches = [ + \SomeDataPatch::class, + \OtherDataPatch::class + ]; + $patchRegistryMock = $this->createAggregateIteratorMock(PatchRegistry::class, $patches, ['registerPatch']); + $patchRegistryMock->expects($this->exactly(2)) + ->method('registerPatch'); + + $this->patchRegistryFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($patchRegistryMock); + + $patch1 = $this->createMock(\SomeDataPatch::class); + $patch1->expects($this->once())->method('apply'); + $patch2 = $this->createMock(\OtherDataPatch::class); + $patch2->expects($this->once())->method('apply'); + $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap( + [ + ['\\' . \SomeDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch1], + ['\\' . \OtherDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch2], + ] + ); + $this->connectionMock->expects($this->exactly(2))->method('beginTransaction'); + $this->connectionMock->expects($this->exactly(2))->method('commit'); + $this->patchHistoryMock->expects($this->any())->method('fixPatch')->willReturnMap( + [ + [get_class($patch1)], + [get_class($patch2)], + ] + ); + $this->patchApllier->applyDataPatch($moduleName); + } + + /** + * @return array + */ + public function applyDataPatchDataNewModuleProvider() + { + return [ + 'newly installed module' => [ + 'moduleName' => 'Module1', + 'dataPatches' => [ + \SomeDataPatch::class, + \OtherDataPatch::class + ], + 'moduleVersionInDb' => null, + ], + ]; + } + + /** + * @param $moduleName + * @param $dataPatches + * @param $moduleVersionInDb + * + * @dataProvider applyDataPatchDataInstalledModuleProvider() + */ + public function testApplyDataPatchForInstalledModule($moduleName, $dataPatches, $moduleVersionInDb) + { + $this->dataPatchReaderMock->expects($this->once()) + ->method('read') + ->with($moduleName) + ->willReturn($dataPatches); + + $this->moduleResourceMock->expects($this->any())->method('getDataVersion')->willReturnMap( + [ + [$moduleName, $moduleVersionInDb] + ] + ); + + $patches = [ + \SomeDataPatch::class, + \OtherDataPatch::class + ]; + $patchRegistryMock = $this->createAggregateIteratorMock(PatchRegistry::class, $patches, ['registerPatch']); + $patchRegistryMock->expects($this->exactly(2)) + ->method('registerPatch'); + + $this->patchRegistryFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($patchRegistryMock); + + $patch1 = $this->createMock(\SomeDataPatch::class); + $patch1->expects($this->never())->method('apply'); + $patch2 = $this->createMock(\OtherDataPatch::class); + $patch2->expects($this->once())->method('apply'); + $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap( + [ + ['\\' . \SomeDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch1], + ['\\' . \OtherDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch2], + ] + ); + $this->connectionMock->expects($this->exactly(1))->method('beginTransaction'); + $this->connectionMock->expects($this->exactly(1))->method('commit'); + $this->patchHistoryMock->expects($this->exactly(2))->method('fixPatch'); + $this->patchApllier->applyDataPatch($moduleName); + } + + public function applyDataPatchDataInstalledModuleProvider() + { + return [ + 'upgrade module iwth only OtherDataPatch' => [ + 'moduleName' => 'Module1', + 'dataPatches' => [ + \SomeDataPatch::class, + \OtherDataPatch::class + ], + 'moduleVersionInDb' => '2.0.0', + ] + ]; + } + + /** + * @param $moduleName + * @param $dataPatches + * @param $moduleVersionInDb + * + * @expectedException \Magento\Framework\Setup\Exception + * @expectedExceptionMessage Patch Apply Error + * + * @dataProvider applyDataPatchDataInstalledModuleProvider() + */ + public function testApplyDataPatchRollback($moduleName, $dataPatches, $moduleVersionInDb) + { + $this->dataPatchReaderMock->expects($this->once()) + ->method('read') + ->with($moduleName) + ->willReturn($dataPatches); + + $this->moduleResourceMock->expects($this->any())->method('getDataVersion')->willReturnMap( + [ + [$moduleName, $moduleVersionInDb] + ] + ); + + $patches = [ + \SomeDataPatch::class, + \OtherDataPatch::class + ]; + $patchRegistryMock = $this->createAggregateIteratorMock(PatchRegistry::class, $patches, ['registerPatch']); + $patchRegistryMock->expects($this->exactly(2)) + ->method('registerPatch'); + + $this->patchRegistryFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($patchRegistryMock); + + $patch1 = $this->createMock(\SomeDataPatch::class); + $patch1->expects($this->never())->method('apply'); + $patch2 = $this->createMock(\OtherDataPatch::class); + $exception = new \Exception('Patch Apply Error'); + $patch2->expects($this->once())->method('apply')->willThrowException($exception); + $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap( + [ + ['\\' . \SomeDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch1], + ['\\' . \OtherDataPatch::class, ['moduleDataSetup' => $this->moduleDataSetupMock], $patch2], + ] + ); + $this->connectionMock->expects($this->exactly(1))->method('beginTransaction'); + $this->connectionMock->expects($this->never())->method('commit'); + $this->connectionMock->expects($this->exactly(1))->method('rollback'); + $this->patchHistoryMock->expects($this->exactly(1))->method('fixPatch'); + $this->patchApllier->applyDataPatch($moduleName); + } + + /** + * @expectedException \Magento\Framework\Setup\Exception + * @expectedExceptionMessageRegExp "Patch [a-zA-Z0-9\_]+ should implement DataPatchInterface" + */ + public function testNonDataPatchApply() + { + $this->dataPatchReaderMock->expects($this->once()) + ->method('read') + ->with('module1') + ->willReturn([\stdClass::class]); + $patchRegistryMock = $this->createAggregateIteratorMock( + PatchRegistry::class, + [\stdClass::class], + ['registerPatch'] + ); + $patchRegistryMock->expects($this->exactly(1)) + ->method('registerPatch'); + + $this->patchRegistryFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($patchRegistryMock); + + $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap( + [ + [ + '\\' . \stdClass::class, + ['moduleDataSetup' => $this->moduleDataSetupMock], + $this->createMock(\stdClass::class) + ], + ] + ); + + $this->patchApllier->applyDataPatch('module1'); + } + + public function testNonTransactionablePatch() + { + $patches = [\NonTransactionableDataPatch::class]; + $this->dataPatchReaderMock->expects($this->once()) + ->method('read') + ->with('module1') + ->willReturn($patches); + $patchRegistryMock = $this->createAggregateIteratorMock( + PatchRegistry::class, + $patches, + ['registerPatch'] + ); + $patchRegistryMock->expects($this->exactly(1)) + ->method('registerPatch'); + + $this->patchRegistryFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($patchRegistryMock); + + $patch1 = $this->createMock($patches[0]); + $patch1->expects($this->exactly(1))->method('apply'); + $this->connectionMock->expects($this->never())->method('beginTransaction'); + $this->connectionMock->expects($this->never())->method('commit'); + $this->connectionMock->expects($this->never())->method('rollback'); + $this->patchHistoryMock->expects($this->once())->method('fixPatch')->with(get_class($patch1)); + $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap( + [ + [ + '\\' . $patches[0], + ['moduleDataSetup' => $this->moduleDataSetupMock], + $patch1 + ], + ] + ); + + $this->patchApllier->applyDataPatch('module1'); + } + + /** + * @param $moduleName + * @param $schemaPatches + * @param $moduleVersionInDb + * + * @dataProvider schemaPatchDataProvider() + */ + public function testSchemaPatchAplly($moduleName, $schemaPatches, $moduleVersionInDb) + { + $this->schemaPatchReaderMock->expects($this->once()) + ->method('read') + ->with($moduleName) + ->willReturn($schemaPatches); + + $this->moduleResourceMock->expects($this->any())->method('getDbVersion')->willReturnMap( + [ + [$moduleName, $moduleVersionInDb] + ] + ); + + $patches = [ + \SomeSchemaPatch::class, + \OtherSchemaPatch::class + ]; + $patchRegistryMock = $this->createAggregateIteratorMock(PatchRegistry::class, $patches, ['registerPatch']); + $patchRegistryMock->expects($this->exactly(2)) + ->method('registerPatch'); + + $this->patchRegistryFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($patchRegistryMock); + + $patch1 = $this->createMock(\SomeSchemaPatch::class); + $patch1->expects($this->never())->method('apply'); + $patch2 = $this->createMock(\OtherSchemaPatch::class); + $patch2->expects($this->once())->method('apply'); + $this->patchFactoryMock->expects($this->any())->method('create')->willReturnMap( + [ + [\SomeSchemaPatch::class, ['schemaSetup' => $this->schemaSetupMock], $patch1], + [\OtherSchemaPatch::class, ['schemaSetup' => $this->schemaSetupMock], $patch2], + ] + ); + $this->connectionMock->expects($this->never())->method('beginTransaction'); + $this->connectionMock->expects($this->never())->method('commit'); + $this->patchHistoryMock->expects($this->exactly(2))->method('fixPatch'); + $this->patchApllier->applySchemaPatch($moduleName); + } + + public function testRevertDataPatches() + { + $patches = [\RevertableDataPatch::class]; + $this->dataPatchReaderMock->expects($this->once()) + ->method('read') + ->with('module1') + ->willReturn($patches); + $patchRegistryMock = $this->createAggregateIteratorMock( + PatchRegistry::class, + $patches, + ['registerPatch', 'getReverseIterator'] + ); + $patchRegistryMock->expects($this->exactly(1)) + ->method('registerPatch'); + $patchRegistryMock->expects($this->once())->method('getReverseIterator') + ->willReturn(array_reverse($patches)); + + $this->patchRegistryFactoryMock->expects($this->any()) + ->method('create') + ->willReturn($patchRegistryMock); + + $patch1 = $this->createMock($patches[0]); + $patch1->expects($this->exactly(1))->method('revert'); + $this->connectionMock->expects($this->once())->method('beginTransaction'); + $this->connectionMock->expects($this->once())->method('commit'); + $this->connectionMock->expects($this->never())->method('rollback'); + $this->patchHistoryMock->expects($this->once())->method('revertPatchFromHistory')->with(get_class($patch1)); + $this->objectManagerMock->expects($this->any())->method('create')->willReturnMap( + [ + [ + '\\' . $patches[0], + ['moduleDataSetup' => $this->moduleDataSetupMock], + $patch1 + ], + ] + ); + + $this->patchApllier->revertDataPatches('module1'); + } + + /** + * @return array + */ + public function schemaPatchDataProvider() + { + return [ + 'upgrade module iwth only OtherSchemaPatch' => [ + 'moduleName' => 'Module1', + 'schemaPatches' => [ + \SomeSchemaPatch::class, + \OtherSchemaPatch::class + ], + 'moduleVersionInDb' => '2.0.0', + ] + ]; + } + /** + * Create mock of class that implements IteratorAggregate + * + * @param string $className + * @param array $items + * @param array $methods + * @return \PHPUnit_Framework_MockObject_MockObject|\IteratorAggregate + * @throws \Exception + */ + private function createAggregateIteratorMock($className, array $items = [], array $methods = []) + { + if (!in_array(ltrim(\IteratorAggregate::class, '\\'), class_implements($className))) { + throw new \Exception('Mock possible only for classes that implement IteratorAggregate interface.'); + } + /** + * PHPUnit_Framework_MockObject_MockObject + */ + $someIterator = $this->createMock(\ArrayIterator::class); + + $mockIteratorAggregate = $this->getMockBuilder($className) + ->disableOriginalConstructor() + ->setMethods(array_merge($methods, ['getIterator'])) + ->getMock(); + + $mockIteratorAggregate->expects($this->any())->method('getIterator')->willReturn($someIterator); + + $iterator = new \ArrayIterator($items); + + $someIterator->expects($this->any()) + ->method('rewind') + ->willReturnCallback(function () use ($iterator) { + $iterator->rewind(); + }); + + $someIterator->expects($this->any()) + ->method('current') + ->willReturnCallback(function () use ($iterator) { + return $iterator->current(); + }); + + $someIterator->expects($this->any()) + ->method('key') + ->willReturnCallback(function () use ($iterator) { + return $iterator->key(); + }); + + $someIterator->expects($this->any()) + ->method('next') + ->willReturnCallback(function () use ($iterator) { + $iterator->next(); + }); + + $someIterator->expects($this->any()) + ->method('valid') + ->willReturnCallback(function () use ($iterator) { + return $iterator->valid(); + }); + + return $mockIteratorAggregate; + } +} diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchFactoryTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchFactoryTest.php new file mode 100644 index 0000000000000..b9f45d09a3b38 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchFactoryTest.php @@ -0,0 +1,59 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Test\Unit\Patch; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Adapter\AdapterInterface; +use Magento\Framework\ObjectManagerInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Setup\Patch\PatchFactory; +use Magento\Framework\Setup\Patch\PatchHistory; +use Magento\Framework\Setup\Patch\PatchInterface; + +/** + * Class PatchFactoryTest + * @package Magento\Framework\Setup\Test\Unit\Patch + */ +class PatchFactoryTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var PatchFactory + */ + private $patchFactory; + + /** + * @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $objectManagerMock; + + protected function setUp() + { + $objectManager = new ObjectManager($this); + $this->objectManagerMock = $this->createMock(ObjectManagerInterface::class); + $this->patchFactory = $objectManager->getObject( + PatchFactory::class, + [ + 'objectManager' => $this->objectManagerMock, + ] + ); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage stdClass should implement Magento\Framework\Setup\Patch\PatchInterface interface + */ + public function testCreateNonPatchInterface() + { + $patchNonPatchInterface = $this->createMock(\stdClass::class); + $this->objectManagerMock->expects($this->any()) + ->method('create') + ->with('\\stdClass') + ->willReturn($patchNonPatchInterface); + + $this->patchFactory->create(\stdClass::class); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchHistoryTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchHistoryTest.php new file mode 100644 index 0000000000000..5d9631fe27f12 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchHistoryTest.php @@ -0,0 +1,86 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Test\Unit\Patch; + +use Magento\Framework\App\ResourceConnection; +use Magento\Framework\DB\Adapter\AdapterInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Setup\Patch\PatchHistory; +use Magento\Framework\Setup\Patch\PatchInterface; + +/** + * Class PatchHistoryTest + * @package Magento\Framework\Setup\Test\Unit\Patch + */ +class PatchHistoryTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var PatchHistory + */ + private $patchHistory; + + /** + * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject + */ + private $resourceConnectionMock; + + protected function setUp() + { + $objectManager = new ObjectManager($this); + $this->resourceConnectionMock = $this->createMock(ResourceConnection::class); + $this->patchHistory = $objectManager->getObject( + PatchHistory::class, + [ + 'resourceConnection' => $this->resourceConnectionMock, + ] + ); + } + + /** + * Test fix non-applied patch + */ + public function testFixPatch() + { + /** @var PatchInterface|\PHPUnit_Framework_MockObject_MockObject $patch1 */ + $patch1 = $this->createMock(PatchInterface::class); + /** @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject $adapterMock */ + $adapterMock = $this->createMock(AdapterInterface::class); + $this->resourceConnectionMock->expects($this->any())->method('getConnection')->willReturn($adapterMock); + $selectMock = $this->createMock(\Magento\Framework\DB\Select::class); + $selectMock->expects($this->once())->method('from'); + $adapterMock->expects($this->any())->method('select')->willReturn($selectMock); + $adapterMock->expects($this->once())->method('fetchCol')->willReturn([]); + $this->resourceConnectionMock->expects($this->any()) + ->method('getTableName') + ->willReturn(PatchHistory::TABLE_NAME); + $adapterMock->expects($this->once())->method('insert') + ->with(PatchHistory::TABLE_NAME, [PatchHistory::CLASS_NAME => get_class($patch1)]); + $this->patchHistory->fixPatch(get_class($patch1)); + } + + /** + * @expectedException \LogicException + * @expectedExceptionMessageRegExp "Patch [a-zA-Z0-9\_]+ cannot be applied twice" + */ + public function testFixAppliedPatch() + { + /** @var PatchInterface|\PHPUnit_Framework_MockObject_MockObject $patch1 */ + $patch1 = $this->createMock(PatchInterface::class); + /** @var AdapterInterface|\PHPUnit_Framework_MockObject_MockObject $adapterMock */ + $adapterMock = $this->createMock(AdapterInterface::class); + $this->resourceConnectionMock->expects($this->any())->method('getConnection')->willReturn($adapterMock); + $selectMock = $this->createMock(\Magento\Framework\DB\Select::class); + $selectMock->expects($this->once())->method('from'); + $adapterMock->expects($this->any())->method('select')->willReturn($selectMock); + $adapterMock->expects($this->once())->method('fetchCol')->willReturn([get_class($patch1)]); + $this->resourceConnectionMock->expects($this->any()) + ->method('getTableName') + ->willReturn(PatchHistory::TABLE_NAME); + $adapterMock->expects($this->never())->method('insert'); + $this->patchHistory->fixPatch(get_class($patch1)); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchRegirtryTest.php b/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchRegirtryTest.php new file mode 100644 index 0000000000000..25c4c4730e7c4 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/Patch/PatchRegirtryTest.php @@ -0,0 +1,100 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Framework\Setup\Test\Unit\Patch; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Framework\Setup\Patch\PatchFactory; +use Magento\Framework\Setup\Patch\PatchHistory; +use Magento\Framework\Setup\Patch\PatchRegistry; + +/** + * Class PatchRegirtryTest + * @package Magento\Framework\Setup\Test\Unit\Patch + */ +class PatchRegirtryTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var PatchRegistry + */ + private $patchRegistry; + + /** + * @var PatchFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $patchFactoryMock; + + /** + * @var PatchHistory|\PHPUnit_Framework_MockObject_MockObject + */ + private $patchHistoryMock; + + protected function setUp() + { + $objectManager = new ObjectManager($this); + $this->patchFactoryMock = $this->getMockBuilder(PatchFactory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->patchHistoryMock = $this->getMockBuilder(PatchHistory::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->patchRegistry = $objectManager->getObject( + PatchRegistry::class, + [ + 'patchHistory' => $this->patchHistoryMock, + 'patchFactory' => $this->patchFactoryMock, + ] + ); + require_once __DIR__ . '/../_files/data_patch_classes.php'; + } + + public function testRegisterAppliedPatch() + { + $this->patchHistoryMock->expects($this->once()) + ->method('isApplied') + ->with(\SomeDataPatch::class) + ->willReturn(false); + + $this->assertEquals(\SomeDataPatch::class, $this->patchRegistry->registerPatch(\SomeDataPatch::class)); + } + + public function testRegisterNonAplliedPatch() + { + $this->patchHistoryMock->expects($this->once()) + ->method('isApplied') + ->with(\SomeDataPatch::class) + ->willReturn(true); + + $this->assertEquals(false, $this->patchRegistry->registerPatch(\SomeDataPatch::class)); + } + + public function testGetIterator() + { + $this->patchHistoryMock->expects($this->any()) + ->method('isApplied') + ->willReturnMap( + [ + [\SomeDataPatch::class, false], + [\OtherDataPatch::class, false] + ] + ); + + $this->assertEquals(\SomeDataPatch::class, $this->patchRegistry->registerPatch(\SomeDataPatch::class)); + + $actualPatches = []; + foreach ($this->patchRegistry->getIterator() as $patch) { + $actualPatches[] = $patch; + } + // assert that all dependencies are present and placed in valid sequence + $this->assertEquals( + [\OtherDataPatch::class, \SomeDataPatch::class], + $actualPatches, + 'Failed to assert that actual non-apllied patches sequence is valid.' + ); + } +} diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/_files/data_patch_classes.php b/lib/internal/Magento/Framework/Setup/Test/Unit/_files/data_patch_classes.php new file mode 100644 index 0000000000000..b259f55b94407 --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/_files/data_patch_classes.php @@ -0,0 +1,136 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +// @codingStandardsIgnoreFile - as of namespace absence + +class OtherDataPatch implements \Magento\Framework\Setup\Patch\DataPatchInterface +{ + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + } +} + +class SomeDataPatch implements + \Magento\Framework\Setup\Patch\DataPatchInterface, + \Magento\Framework\Setup\Patch\PatchVersionInterface +{ + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + OtherDataPatch::class, + ]; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + return $this; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } +} + +class NonTransactionableDataPatch implements + \Magento\Framework\Setup\Patch\DataPatchInterface, + \Magento\Framework\Setup\Patch\NonTransactionableInterface +{ + + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + } +} + +class RevertableDataPatch implements + \Magento\Framework\Setup\Patch\DataPatchInterface, + \Magento\Framework\Setup\Patch\PatchRevertableInterface +{ + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + } + + /** + * {@inheritdoc} + */ + public function revert() + { + } +} diff --git a/lib/internal/Magento/Framework/Setup/Test/Unit/_files/schema_patch_classes.php b/lib/internal/Magento/Framework/Setup/Test/Unit/_files/schema_patch_classes.php new file mode 100644 index 0000000000000..0f44d7a13346e --- /dev/null +++ b/lib/internal/Magento/Framework/Setup/Test/Unit/_files/schema_patch_classes.php @@ -0,0 +1,72 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +// @codingStandardsIgnoreFile - as of namespace absence + +class OtherSchemaPatch implements \Magento\Framework\Setup\Patch\SchemaPatchInterface +{ + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + } +} + +class SomeSchemaPatch implements + \Magento\Framework\Setup\Patch\SchemaPatchInterface, + \Magento\Framework\Setup\Patch\PatchVersionInterface +{ + /** + * {@inheritdoc} + */ + public static function getDependencies() + { + return [ + OtherDataPatch::class, + ]; + } + + /** + * {@inheritdoc} + */ + public function getAliases() + { + return []; + } + + /** + * {@inheritdoc} + */ + public function apply() + { + return $this; + } + + /** + * {@inheritdoc} + */ + public static function getVersion() + { + return '2.0.0'; + } +} diff --git a/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php b/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php index de5503c144647..dff31a897e1ac 100644 --- a/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php +++ b/lib/internal/Magento/Framework/Stdlib/Cookie/PhpCookieManager.php @@ -204,14 +204,14 @@ private function checkAbilityToSendCookie($name, $value) $sizeOfCookie = $this->sizeOfCookie($name, $value); - if ($numCookies > PhpCookieManager::MAX_NUM_COOKIES) { + if ($numCookies > static::MAX_NUM_COOKIES) { $this->logger->warning( new Phrase('Unable to send the cookie. Maximum number of cookies would be exceeded.'), array_merge($_COOKIE, ['user-agent' => $this->httpHeader->getHttpUserAgent()]) ); } - if ($sizeOfCookie > PhpCookieManager::MAX_COOKIE_SIZE) { + if ($sizeOfCookie > static::MAX_COOKIE_SIZE) { throw new CookieSizeLimitReachedException( new Phrase( 'Unable to send the cookie. Size of \'%name\' is %size bytes.', diff --git a/lib/internal/Magento/Framework/Stdlib/DateTime.php b/lib/internal/Magento/Framework/Stdlib/DateTime.php index 7f25620fdc736..36db84860b373 100644 --- a/lib/internal/Magento/Framework/Stdlib/DateTime.php +++ b/lib/internal/Magento/Framework/Stdlib/DateTime.php @@ -79,6 +79,9 @@ public function isEmptyDate($date) * @param int $time * @return string The given time in given format * + * @deprecated + * @see Use Intl library for datetime handling: http://php.net/manual/en/book.intl.php + * * @codeCoverageIgnore */ public function gmDate($format, $time) @@ -92,6 +95,9 @@ public function gmDate($format, $time) * @param string $timeStr * @return int * + * @deprecated + * @see Use Intl library for datetime handling: http://php.net/manual/en/book.intl.php + * * @codeCoverageIgnore */ public function strToTime($timeStr) diff --git a/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php b/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php index 879332f148e31..9f182f3dc00a4 100644 --- a/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php +++ b/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php @@ -12,7 +12,6 @@ use Magento\Framework\Exception\LocalizedException; use Magento\Framework\Locale\ResolverInterface; use Magento\Framework\Phrase; -use Magento\Framework\Stdlib\DateTime; /** * Timezone library @@ -42,7 +41,7 @@ class Timezone implements TimezoneInterface protected $_scopeResolver; /** - * @var DateTime + * @var \Magento\Framework\Stdlib\DateTime */ protected $_dateTime; @@ -64,7 +63,7 @@ class Timezone implements TimezoneInterface /** * @param ScopeResolverInterface $scopeResolver * @param ResolverInterface $localeResolver - * @param DateTime $dateTime + * @param \Magento\Framework\Stdlib\DateTime $dateTime * @param ScopeConfigInterface $scopeConfig * @param string $scopeType * @param string $defaultTimezonePath @@ -72,7 +71,7 @@ class Timezone implements TimezoneInterface public function __construct( ScopeResolverInterface $scopeResolver, ResolverInterface $localeResolver, - DateTime $dateTime, + \Magento\Framework\Stdlib\DateTime $dateTime, ScopeConfigInterface $scopeConfig, $scopeType, $defaultTimezonePath diff --git a/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php b/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php index 75b8eb2cec8d6..1ea942f5e9013 100644 --- a/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php +++ b/lib/internal/Magento/Framework/Stdlib/Test/Unit/Cookie/PhpCookieManagerTest.php @@ -47,8 +47,6 @@ class PhpCookieManagerTest extends \PHPUnit\Framework\TestCase const COOKIE_HTTP_ONLY = true; const COOKIE_NOT_HTTP_ONLY = false; const COOKIE_EXPIRE_END_OF_SESSION = 0; - const MAX_NUM_COOKIES = 50; - const MAX_COOKIE_SIZE = 4096; /** * Mapping from constant names to functions that handle the assertions. @@ -499,7 +497,9 @@ public function testSetCookieSizeTooLarge() ); $cookieValue = ''; - for ($i = 0; $i < self::MAX_COOKIE_SIZE + 1; $i++) { + + $cookieManager = $this->cookieManager; + for ($i = 0; $i < $cookieManager::MAX_COOKIE_SIZE + 1; $i++) { $cookieValue = $cookieValue . 'a'; } @@ -527,8 +527,9 @@ public function testSetTooManyCookies() $userAgent = 'some_user_agent'; - // Set self::MAX_NUM_COOKIES number of cookies in superglobal $_COOKIE. - for ($i = count($_COOKIE); $i < self::MAX_NUM_COOKIES; $i++) { + $cookieManager = $this->cookieManager; + // Set $cookieManager::MAX_NUM_COOKIES number of cookies in superglobal $_COOKIE. + for ($i = count($_COOKIE); $i < $cookieManager::MAX_NUM_COOKIES; $i++) { $_COOKIE['test_cookie_' . $i] = self::COOKIE_VALUE . '_' . $i; } diff --git a/lib/internal/Magento/Framework/Test/Unit/App/ResourceConnectionTest.php b/lib/internal/Magento/Framework/Test/Unit/App/ResourceConnectionTest.php index d0bb0b9d73470..686c09e947509 100644 --- a/lib/internal/Magento/Framework/Test/Unit/App/ResourceConnectionTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/App/ResourceConnectionTest.php @@ -61,6 +61,31 @@ protected function setUp() ); } + public function testGetTablePrefixWithInjectedPrefix() + { + /** @var ResourceConnection $resourceConnection */ + $resourceConnection = $this->objectManager->getObject( + ResourceConnection::class, + [ + 'deploymentConfig' => $this->deploymentConfigMock, + 'connectionFactory' => $this->connectionFactoryMock, + 'config' => $this->configMock, + 'tablePrefix' => 'some_prefix' + ] + ); + + self::assertEquals($resourceConnection->getTablePrefix(), 'some_prefix'); + } + + public function testGetTablePrefix() + { + $this->deploymentConfigMock->expects(self::once()) + ->method('get') + ->with(ConfigOptionsListConstants::CONFIG_PATH_DB_PREFIX) + ->willReturn('pref_'); + self::assertEquals('pref_', $this->unit->getTablePrefix()); + } + public function testGetConnectionByName() { $this->deploymentConfigMock->expects(self::once())->method('get') diff --git a/lib/internal/Magento/Framework/Test/Unit/Config/FileResolverByModuleTest.php b/lib/internal/Magento/Framework/Test/Unit/Config/FileResolverByModuleTest.php new file mode 100644 index 0000000000000..1a1f3391f0170 --- /dev/null +++ b/lib/internal/Magento/Framework/Test/Unit/Config/FileResolverByModuleTest.php @@ -0,0 +1,232 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ +namespace Magento\Framework\Test\Unit\Config; + +use Magento\Framework\Config\FileIterator; +use Magento\Framework\Filesystem\DriverInterface; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; + +class FileResolverByModuleTest extends \PHPUnit\Framework\TestCase +{ + /** + * @var \Magento\Framework\Config\FileResolverByModule + */ + private $model; + + /** + * @var ObjectManagerHelper + */ + private $objectManagerHelper; + + /** + * @var \Magento\Framework\Module\Dir\Reader|\PHPUnit_Framework_MockObject_MockObject + */ + private $readerMock; + + /** + * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject + */ + private $filesystemMock; + + /** + * @var \Magento\Framework\Config\FileIteratorFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $fileIteratorFactoryMock; + + /** + * @var \Magento\Framework\Component\ComponentRegistrar|\PHPUnit_Framework_MockObject_MockObject + */ + private $componentRegistrarMock; + + /** + * @var \Magento\Framework\Filesystem\Driver\File|\PHPUnit_Framework_MockObject_MockObject + */ + private $fileDriver; + + protected function setUp() + { + $this->readerMock = $this->getMockBuilder(\Magento\Framework\Module\Dir\Reader::class) + ->disableOriginalConstructor() + ->getMock(); + $this->filesystemMock = $this->getMockBuilder(\Magento\Framework\Filesystem::class) + ->disableOriginalConstructor() + ->getMock(); + $this->fileIteratorFactoryMock = $this->getMockBuilder(\Magento\Framework\Config\FileIteratorFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->componentRegistrarMock = $this->getMockBuilder(\Magento\Framework\Component\ComponentRegistrar::class) + ->disableOriginalConstructor() + ->getMock(); + $this->fileDriver = $this->getMockBuilder(\Magento\Framework\Filesystem\Driver\File::class) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManagerHelper = new ObjectManagerHelper($this); + $this->model = $this->objectManagerHelper->getObject( + \Magento\Framework\Config\FileResolverByModule::class, + [ + 'moduleReader' => $this->readerMock, + 'filesystem' => $this->filesystemMock, + 'iteratorFactory' => $this->fileIteratorFactoryMock, + 'componentRegistrar' => $this->componentRegistrarMock, + 'driver' => $this->fileDriver + ] + ); + } + + public function testGet() + { + $iterator = $this->getMockBuilder(FileIterator::class) + ->disableOriginalConstructor() + ->getMock(); + $iterator->expects(self::once()) + ->method('toArray') + ->willReturn([ + 'some_path' => '<xml>Some Content</xml>' + ]); + $primaryIterator = $this->getMockBuilder(FileIterator::class) + ->disableOriginalConstructor() + ->getMock(); + $primaryIterator->expects(self::once()) + ->method('toArray') + ->willReturn([ + '/www/app/etc/db_schema.xml' => '<xml>Primary Content</xml>' + ]); + $directoryMock = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\ReadInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $directoryMock->expects(self::once()) + ->method('search') + ->with('{db_schema.xml,*/db_schema.xml}') + ->willReturn(['app/etc/db_schema.xml']); + $directoryMock->expects(self::once()) + ->method('getAbsolutePath') + ->willReturn('/www/app/etc/db_schema.xml'); + $this->readerMock->expects(self::once()) + ->method('getConfigurationFiles') + ->willReturn($iterator); + $this->fileIteratorFactoryMock->expects(self::once()) + ->method('create') + ->with(['/www/app/etc/db_schema.xml']) + ->willReturn($primaryIterator); + $this->fileDriver->expects(self::once()) + ->method('isFile') + ->with('/www/app/etc/db_schema.xml') + ->willReturn(true); + $this->filesystemMock->expects(self::once()) + ->method('getDirectoryRead') + ->willReturn($directoryMock); + self::assertEquals( + $this->model->get('db_schema.xml', 'all'), + [ + 'some_path' => '<xml>Some Content</xml>', + '/www/app/etc/db_schema.xml' => '<xml>Primary Content</xml>' + ] + ); + } + + /** + * @expectedExceptionMessage Primary db_schema file doesn`t exist + */ + public function testGetWithException() + { + $iterator = $this->getMockBuilder(FileIterator::class) + ->disableOriginalConstructor() + ->getMock(); + $iterator->expects(self::once()) + ->method('toArray') + ->willReturn([ + 'some_path' => '<xml>Some Content</xml>' + ]); + $primaryIterator = $this->getMockBuilder(FileIterator::class) + ->disableOriginalConstructor() + ->getMock(); + $primaryIterator->expects(self::once()) + ->method('toArray') + ->willReturn([ + '/www/app/etc/db_schema.xml' => '<xml>Primary Content</xml>' + ]); + $directoryMock = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\ReadInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $directoryMock->expects(self::once()) + ->method('search') + ->with('{db_schema.xml,*/db_schema.xml}') + ->willReturn(['app/etc/db_schema.xml']); + $directoryMock->expects(self::once()) + ->method('getAbsolutePath') + ->willReturn('/www/app/etc/db_schema.xml'); + $this->readerMock->expects(self::once()) + ->method('getConfigurationFiles') + ->willReturn($iterator); + $this->fileIteratorFactoryMock->expects(self::once()) + ->method('create') + ->with(['/www/app/etc/db_schema.xml']) + ->willReturn($primaryIterator); + $this->fileDriver->expects(self::once()) + ->method('isFile') + ->with('/www/app/etc/db_schema.xml') + ->willReturn(true); + $this->filesystemMock->expects(self::once()) + ->method('getDirectoryRead') + ->willReturn($directoryMock); + $this->model->get('db_schema.xml', 'all'); + } + + public function testGetOneModule() + { + $iterator = $this->getMockBuilder(FileIterator::class) + ->disableOriginalConstructor() + ->getMock(); + $iterator->expects(self::once()) + ->method('toArray') + ->willReturn([ + 'some_path/etc/db_schema.xml' => '<xml>Some Content</xml>' + ]); + $primaryIterator = $this->getMockBuilder(FileIterator::class) + ->disableOriginalConstructor() + ->getMock(); + $primaryIterator->expects(self::once()) + ->method('toArray') + ->willReturn([ + '/www/app/etc/db_schema.xml' => '<xml>Primary Content</xml>' + ]); + $directoryMock = $this->getMockBuilder(\Magento\Framework\Filesystem\Directory\ReadInterface::class) + ->disableOriginalConstructor() + ->getMock(); + $directoryMock->expects(self::once()) + ->method('search') + ->with('{db_schema.xml,*/db_schema.xml}') + ->willReturn(['app/etc/db_schema.xml']); + $directoryMock->expects(self::once()) + ->method('getAbsolutePath') + ->willReturn('/www/app/etc/db_schema.xml'); + $this->readerMock->expects(self::once()) + ->method('getConfigurationFiles') + ->willReturn($iterator); + $this->fileIteratorFactoryMock->expects(self::once()) + ->method('create') + ->with(['/www/app/etc/db_schema.xml']) + ->willReturn($primaryIterator); + $this->fileDriver->expects(self::once()) + ->method('isFile') + ->with('/www/app/etc/db_schema.xml') + ->willReturn(true); + $this->filesystemMock->expects(self::once()) + ->method('getDirectoryRead') + ->willReturn($directoryMock); + $this->componentRegistrarMock->expects(self::once()) + ->method('getPath') + ->with('module', 'Magento_Some') + ->willReturn('some_path'); + self::assertEquals( + [ + 'some_path/etc/db_schema.xml' => '<xml>Some Content</xml>', + '/www/app/etc/db_schema.xml' => '<xml>Primary Content</xml>' + ], + $this->model->get('db_schema.xml', 'Magento_Some') + ); + } +} diff --git a/lib/internal/Magento/Framework/View/Asset/Minification.php b/lib/internal/Magento/Framework/View/Asset/Minification.php index 686f794d6318a..33c82a1810db6 100644 --- a/lib/internal/Magento/Framework/View/Asset/Minification.php +++ b/lib/internal/Magento/Framework/View/Asset/Minification.php @@ -143,7 +143,8 @@ public function getExcludes($contentType) if (!isset($this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType])) { $this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType] = []; $key = sprintf(self::XML_PATH_MINIFICATION_EXCLUDES, $contentType); - foreach (explode("\n", $this->scopeConfig->getValue($key, $this->scope)) as $exclude) { + $excludeValues = $this->getMinificationExcludeValues($key); + foreach ($excludeValues as $exclude) { if (trim($exclude) != '') { $this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType][] = trim($exclude); } @@ -151,4 +152,17 @@ public function getExcludes($contentType) } return $this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType]; } + + /** + * Get minification exclude values from configuration + * + * @param string $key + * @return string[] + */ + private function getMinificationExcludeValues($key) + { + $configValues = $this->scopeConfig->getValue($key, $this->scope) ?? []; + + return array_values($configValues); + } } diff --git a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/TemplateFile.php b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/TemplateFile.php index 8150b386eddef..09f87d878ad1c 100644 --- a/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/TemplateFile.php +++ b/lib/internal/Magento/Framework/View/Design/FileResolution/Fallback/TemplateFile.php @@ -10,6 +10,9 @@ use Magento\Framework\View\Asset\ConfigInterface; use Magento\Framework\View\Design\ThemeInterface; use Magento\Framework\View\Template\Html\MinifierInterface; +use Magento\Framework\App\DeploymentConfig; +use Magento\Framework\App\ObjectManager; +use Magento\Framework\Config\ConfigOptionsListConstants; /** * Provider of template view files @@ -31,21 +34,29 @@ class TemplateFile extends File */ protected $assetConfig; + /** + * @var DeploymentConfig + */ + private $deploymentConfig; + /** * @param ResolverInterface $resolver * @param MinifierInterface $templateMinifier * @param State $appState * @param ConfigInterface $assetConfig + * @param DeploymentConfig $deploymentConfig */ public function __construct( ResolverInterface $resolver, MinifierInterface $templateMinifier, State $appState, - ConfigInterface $assetConfig + ConfigInterface $assetConfig, + DeploymentConfig $deploymentConfig = null ) { $this->appState = $appState; $this->templateMinifier = $templateMinifier; $this->assetConfig = $assetConfig; + $this->deploymentConfig = $deploymentConfig ?: ObjectManager::getInstance()->get(DeploymentConfig::class); parent::__construct($resolver); } @@ -73,7 +84,7 @@ public function getFile($area, ThemeInterface $themeModel, $file, $module = null if ($template && $this->assetConfig->isMinifyHtml()) { switch ($this->appState->getMode()) { case State::MODE_PRODUCTION: - return $this->templateMinifier->getPathToMinified($template); + return $this->getMinifiedTemplateInProduction($template); case State::MODE_DEFAULT: return $this->templateMinifier->getMinified($template); case State::MODE_DEVELOPER: @@ -83,4 +94,24 @@ public function getFile($area, ThemeInterface $themeModel, $file, $module = null } return $template; } + + /** + * Returns path to minified template file + * + * If SCD on demand in production is disabled - returns the path to minified template file. + * Otherwise returns the path to minified template file, + * or minify if file not exist and returns path. + * + * @param string $template + * @return string + */ + private function getMinifiedTemplateInProduction($template) + { + if ($this->deploymentConfig->getConfigData( + ConfigOptionsListConstants::CONFIG_PATH_SCD_ON_DEMAND_IN_PRODUCTION + )) { + return $this->templateMinifier->getMinified($template); + } + return $this->templateMinifier->getPathToMinified($template); + } } diff --git a/lib/internal/Magento/Framework/View/Element/Html/Link.php b/lib/internal/Magento/Framework/View/Element/Html/Link.php index 71b73918120f8..6c5761f8cea25 100644 --- a/lib/internal/Magento/Framework/View/Element/Html/Link.php +++ b/lib/internal/Magento/Framework/View/Element/Html/Link.php @@ -11,6 +11,8 @@ * @method string getLabel() * @method string getPath() * @method string getTitle() + * + * @api */ class Link extends \Magento\Framework\View\Element\Template { diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php index 2f6305f1cc73c..1cc2a3dd7e2b7 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php @@ -203,10 +203,10 @@ public function testGetExcludes() ->expects($this->once()) ->method('getValue') ->with('dev/js/minify_exclude') - ->willReturn( - " /tiny_mce/ \n" . - " /tiny_mce2/ " - ); + ->willReturn([ + 'tiny_mce' => '/tiny_mce/', + 'some_other_unique_name' => '/tiny_mce2/' + ]); $expected = ['/tiny_mce/', '/tiny_mce2/']; $this->assertEquals($expected, $this->minification->getExcludes('js')); diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/TemplateFileTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/TemplateFileTest.php index 478a8a4d214e0..7e94d7e80a97f 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/TemplateFileTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Design/FileResolution/Fallback/TemplateFileTest.php @@ -10,6 +10,10 @@ use Magento\Framework\View\Design\Fallback\RulePool; use Magento\Framework\View\Design\FileResolution\Fallback\TemplateFile; use Magento\Framework\View\Design\FileResolution\Fallback\ResolverInterface; +use Magento\Framework\View\Template\Html\MinifierInterface; +use Magento\Framework\View\Asset\ConfigInterface; +use Magento\Framework\App\DeploymentConfig; +use Magento\Framework\Config\ConfigOptionsListConstants; class TemplateFileTest extends \PHPUnit\Framework\TestCase { @@ -19,12 +23,12 @@ class TemplateFileTest extends \PHPUnit\Framework\TestCase protected $resolver; /** - * @var \Magento\Framework\View\Template\Html\MinifierInterface|\PHPUnit_Framework_MockObject_MockObject + * @var MinifierInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $minifier; /** - * @var \Magento\Framework\App\State|\PHPUnit_Framework_MockObject_MockObject + * @var State|\PHPUnit_Framework_MockObject_MockObject */ protected $state; @@ -34,26 +38,29 @@ class TemplateFileTest extends \PHPUnit\Framework\TestCase protected $object; /** - * @var \Magento\Framework\View\Asset\ConfigInterface|\PHPUnit_Framework_MockObject_MockObject + * @var DeploymentConfig|\PHPUnit_Framework_MockObject_MockObject + */ + private $deploymentConfigMock; + + /** + * @var ConfigInterface|\PHPUnit_Framework_MockObject_MockObject */ protected $assetConfig; protected function setUp() { - $this->resolver = $this->createMock( - \Magento\Framework\View\Design\FileResolution\Fallback\ResolverInterface::class - ); - $this->minifier = $this->createMock(\Magento\Framework\View\Template\Html\MinifierInterface::class); - $this->state = $this->getMockBuilder( - \Magento\Framework\App\State::class - )->disableOriginalConstructor()->getMock(); - $this->assetConfig = $this->getMockForAbstractClass( - \Magento\Framework\View\Asset\ConfigInterface::class, - [], - '', - false + $this->resolver = $this->getMockForAbstractClass(ResolverInterface::class); + $this->minifier = $this->getMockForAbstractClass(MinifierInterface::class); + $this->state = $this->createMock(State::class); + $this->assetConfig = $this->getMockForAbstractClass(ConfigInterface::class); + $this->deploymentConfigMock = $this->createMock(DeploymentConfig::class); + $this->object = new TemplateFile( + $this->resolver, + $this->minifier, + $this->state, + $this->assetConfig, + $this->deploymentConfigMock ); - $this->object = new TemplateFile($this->resolver, $this->minifier, $this->state, $this->assetConfig); } /** @@ -75,7 +82,7 @@ public function testGetFileWhenStateDeveloper() $this->resolver->expects($this->once()) ->method('resolve') ->with(RulePool::TYPE_TEMPLATE_FILE, 'file.ext', 'frontend', $theme, null, 'Magento_Module') - ->will($this->returnValue($expected)); + ->willReturn($expected); $actual = $this->object->getFile('frontend', $theme, 'file.ext', 'Magento_Module'); $this->assertSame($expected, $actual); @@ -84,10 +91,11 @@ public function testGetFileWhenStateDeveloper() /** * Cover getFile when mode is default * @param string $mode + * @param integer $onDemandInProduction * @param string $method * @dataProvider getMinifiedDataProvider */ - public function testGetFileWhenModifiedNeeded($mode, $method) + public function testGetFileWhenModifiedNeeded($mode, $onDemandInProduction, $method) { $this->assetConfig ->expects($this->once()) @@ -98,13 +106,17 @@ public function testGetFileWhenModifiedNeeded($mode, $method) $expected = 'some/file.ext'; $expectedMinified = '/path/to/minified/some/file.ext'; + $this->deploymentConfigMock->expects($this->any()) + ->method('getConfigData') + ->with(ConfigOptionsListConstants::CONFIG_PATH_SCD_ON_DEMAND_IN_PRODUCTION) + ->willReturn($onDemandInProduction); $this->state->expects($this->once()) ->method('getMode') ->willReturn($mode); $this->resolver->expects($this->once()) ->method('resolve') ->with(RulePool::TYPE_TEMPLATE_FILE, 'file.ext', 'frontend', $theme, null, 'Magento_Module') - ->will($this->returnValue($expected)); + ->willReturn($expected); $this->minifier->expects($this->once()) ->method($method) ->with($expected) @@ -127,9 +139,10 @@ public function testGetFileIfMinificationIsDisabled() $this->resolver->expects($this->once()) ->method('resolve') ->with(RulePool::TYPE_TEMPLATE_FILE, 'file.ext', 'frontend', $theme, null, 'Magento_Module') - ->will($this->returnValue($expected)); + ->willReturn($expected); - $this->state->expects($this->never())->method('getMode'); + $this->state->expects($this->never()) + ->method('getMode'); $actual = $this->object->getFile('frontend', $theme, 'file.ext', 'Magento_Module'); $this->assertSame($expected, $actual); @@ -143,8 +156,10 @@ public function testGetFileIfMinificationIsDisabled() public function getMinifiedDataProvider() { return [ - 'default' => [State::MODE_DEFAULT, 'getMinified'], - 'production' => [State::MODE_PRODUCTION, 'getPathToMinified'], + 'default with on demand' => [State::MODE_DEFAULT, 1, 'getMinified'], + 'default without on demand' => [State::MODE_DEFAULT, 0, 'getMinified'], + 'production with on demand' => [State::MODE_PRODUCTION, 1, 'getMinified'], + 'production without on demand' => [State::MODE_PRODUCTION, 0, 'getPathToMinified'], ]; } } diff --git a/lib/internal/Magento/Framework/composer.json b/lib/internal/Magento/Framework/composer.json index 785ff07a60f39..b442effe5ffda 100644 --- a/lib/internal/Magento/Framework/composer.json +++ b/lib/internal/Magento/Framework/composer.json @@ -23,7 +23,7 @@ "ext-spl": "*", "ext-xsl": "*", "lib-libxml": "*", - "colinmollenhour/php-redis-session-abstract": "~1.2.2", + "colinmollenhour/php-redis-session-abstract": "~1.3.8", "composer/composer": "1.4.1", "magento/zendframework1": "~1.13.0", "monolog/monolog": "^1.17", diff --git a/lib/web/mage/adminhtml/browser.js b/lib/web/mage/adminhtml/browser.js index 232019d1b0916..26d6679bb3ce5 100644 --- a/lib/web/mage/adminhtml/browser.js +++ b/lib/web/mage/adminhtml/browser.js @@ -265,6 +265,7 @@ define([ node: this.activeNode.id, store: this.options.storeId, 'as_is': targetEl.is('textarea') ? 1 : 0, + 'force_static_path': targetEl.data('force_static_path') ? 1 : 0, 'form_key': FORM_KEY }, context: this, @@ -273,7 +274,11 @@ define([ if (targetEl.is('textarea')) { this.insertAtCursor(targetEl.get(0), data); } else { - targetEl.val(data).trigger('change'); + targetEl + .val(data) + .data('size', fileRow.data('size')) + .data('mime-type', fileRow.data('mime-type')) + .trigger('change'); } MediabrowserUtility.closeDialog(); targetEl.focus(); @@ -472,4 +477,6 @@ define([ breadcrumbs.insertAfter(this.element.find('#content_header')); } }); + + return window.MediabrowserUtility; }); diff --git a/lib/web/mage/adminhtml/form.js b/lib/web/mage/adminhtml/form.js index 86866f0b00149..e136e8c0f7354 100644 --- a/lib/web/mage/adminhtml/form.js +++ b/lib/web/mage/adminhtml/form.js @@ -386,7 +386,7 @@ define([ * @param {Object} config */ initialize: function (elementsMap, config) { - var idTo, idFrom; + var idTo, idFrom, values, fromId, radioFrom; if (config) { this._config = config; @@ -400,10 +400,21 @@ define([ 'change', this.trackChange.bindAsEventListener(this, idTo, elementsMap[idTo]) ); - this.trackChange(null, idTo, elementsMap[idTo]); } else { - this.trackChange(null, idTo, elementsMap[idTo]); + // Check if radio button + values = elementsMap[idTo][idFrom].values; + fromId = $(idFrom + values[0]); + radioFrom = fromId ? $$('[name="' + fromId.name + '"]') : false; + + if (radioFrom) { + radioFrom.invoke( + 'on', + 'change', + this.trackChange.bindAsEventListener(this, idTo, elementsMap[idTo]) + ); + } } + this.trackChange(null, idTo, elementsMap[idTo]); } } }, @@ -428,7 +439,7 @@ define([ // define whether the target should show up var shouldShowUp = true, idFrom, from, values, isInArray, isNegative, headElement, isInheritCheckboxChecked, target, inputs, - isAnInputOrSelect, currentConfig,rowElement; + isAnInputOrSelect, currentConfig, rowElement, fromId, radioFrom; for (idFrom in valuesFrom) { //eslint-disable-line guard-for-in from = $(idFrom); @@ -441,6 +452,20 @@ define([ if (!from || isInArray && isNegative || !isInArray && !isNegative) { shouldShowUp = false; } + // Check if radio button + } else { + values = valuesFrom[idFrom].values; + fromId = $(idFrom + values[0]); + + if (fromId) { + radioFrom = $$('[name="' + fromId.name + '"]:checked'); + isInArray = radioFrom.length > 0 && values.indexOf(radioFrom[0].value) !== -1; + isNegative = valuesFrom[idFrom].negative; + + if (!radioFrom || isInArray && isNegative || !isInArray && !isNegative) { + shouldShowUp = false; + } + } } } diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index 834981402f67f..86d98181724cd 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -629,6 +629,9 @@ define([ return; } + // remove the active state class from the siblings + this.active.siblings().children('.ui-state-active').removeClass('ui-state-active'); + this._open(newItem.parent()); // Delay so Firefox will not hide activedescendant change in expanding submenu from AT diff --git a/phpserver/README.md b/phpserver/README.md index 63436c8af7883..6bb814fe5f5f2 100644 --- a/phpserver/README.md +++ b/phpserver/README.md @@ -31,7 +31,7 @@ For more informations about the installation process using the CLI, you can cons ### How to run Magento -Example usage: ```php -S 127.0.0.1:8082 -t ./pub/ ./phpserver/router.php``` +Example usage: ```php -S 127.0.0.1:8082 -t ./pub/ ../phpserver/router.php``` ### What exactly the script does diff --git a/phpserver/router.php b/phpserver/router.php index a12e9178ecad4..06c23ecdfe3cd 100644 --- a/phpserver/router.php +++ b/phpserver/router.php @@ -103,6 +103,7 @@ } else { $debug('file does not exist'); if (strpos($route, 'static/') === 0) { + $route = preg_replace('#static/#', '', $route, 1); $_GET['resource'] = $route; $debug("static: $route"); include($magentoPackagePubDir.'/static.php'); diff --git a/pub/static/.htaccess b/pub/static/.htaccess index 21fe6a63e64ba..a10e234e07ff2 100644 --- a/pub/static/.htaccess +++ b/pub/static/.htaccess @@ -12,6 +12,9 @@ Options -MultiViews <IfModule mod_rewrite.c> RewriteEngine On + ## you can put here your pub/static folder path relative to web root + #RewriteBase /magento/pub/static/ + # Remove signature of the static files that is used to overcome the browser cache RewriteRule ^version.+?/(.+)$ $1 [L] diff --git a/setup/config/di.config.php b/setup/config/di.config.php index 77a1ea7cdbf81..97d5b46c8f9c4 100644 --- a/setup/config/di.config.php +++ b/setup/config/di.config.php @@ -56,7 +56,7 @@ \Magento\Framework\Component\ComponentRegistrarInterface::class => \Magento\Framework\Component\ComponentRegistrar::class, ], - \Magento\Setup\Model\Declaration\Schema\SchemaConfig::class => [ + \Magento\Framework\Setup\Declaration\Schema\SchemaConfig::class => [ 'parameters' => [ 'connectionScopes' => [ 'default', diff --git a/setup/src/Magento/Setup/Console/Command/AbstractDependenciesCommand.php b/setup/src/Magento/Setup/Console/Command/AbstractDependenciesCommand.php index f115277654fae..2c91d2d2f37c3 100644 --- a/setup/src/Magento/Setup/Console/Command/AbstractDependenciesCommand.php +++ b/setup/src/Magento/Setup/Console/Command/AbstractDependenciesCommand.php @@ -107,5 +107,6 @@ protected function execute(InputInterface $input, OutputInterface $output) // we must have an exit code higher than zero to indicate something was wrong return \Magento\Framework\Console\Cli::RETURN_FAILURE; } + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/AbstractMaintenanceCommand.php b/setup/src/Magento/Setup/Console/Command/AbstractMaintenanceCommand.php index ae6611273cb6b..85ae008adf366 100644 --- a/setup/src/Magento/Setup/Console/Command/AbstractMaintenanceCommand.php +++ b/setup/src/Magento/Setup/Console/Command/AbstractMaintenanceCommand.php @@ -99,6 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output) . '</info>' ); } + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } /** diff --git a/setup/src/Magento/Setup/Console/Command/AbstractModuleManageCommand.php b/setup/src/Magento/Setup/Console/Command/AbstractModuleManageCommand.php index eab1ce79f5b3d..5d7eedfa66c2a 100644 --- a/setup/src/Magento/Setup/Console/Command/AbstractModuleManageCommand.php +++ b/setup/src/Magento/Setup/Console/Command/AbstractModuleManageCommand.php @@ -12,6 +12,7 @@ use Symfony\Component\Console\Input\InputOption; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\Module\Status; +use Magento\Framework\Console\Cli; abstract class AbstractModuleManageCommand extends AbstractModuleCommand { @@ -77,14 +78,14 @@ protected function execute(InputInterface $input, OutputInterface $output) if (!empty($messages)) { $output->writeln(implode(PHP_EOL, $messages)); // we must have an exit code higher than zero to indicate something was wrong - return \Magento\Framework\Console\Cli::RETURN_FAILURE; + return Cli::RETURN_FAILURE; } try { $modulesToChange = $this->getStatus()->getModulesToChange($isEnable, $modules); } catch (\LogicException $e) { $output->writeln('<error>' . $e->getMessage() . '</error>'); // we must have an exit code higher than zero to indicate something was wrong - return \Magento\Framework\Console\Cli::RETURN_FAILURE; + return Cli::RETURN_FAILURE; } if (!empty($modulesToChange)) { $force = $input->getOption(self::INPUT_KEY_FORCE); @@ -96,7 +97,7 @@ protected function execute(InputInterface $input, OutputInterface $output) ); $output->writeln('<error>' . implode("</error>\n<error>", $constraints) . '</error>'); // we must have an exit code higher than zero to indicate something was wrong - return \Magento\Framework\Console\Cli::RETURN_FAILURE; + return Cli::RETURN_FAILURE; } } $this->setIsEnabled($isEnable, $modulesToChange, $output); @@ -111,6 +112,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } else { $output->writeln('<info>No modules were changed.</info>'); } + return Cli::RETURN_SUCCESS; } /** diff --git a/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php b/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php index 4ad8e7c229bfd..00fa272e74962 100644 --- a/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php +++ b/setup/src/Magento/Setup/Console/Command/AdminUserCreateCommand.php @@ -159,6 +159,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln( '<info>Created Magento administrator user named ' . $input->getOption(AdminAccount::KEY_USER) . '</info>' ); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } /** diff --git a/setup/src/Magento/Setup/Console/Command/ConfigSetCommand.php b/setup/src/Magento/Setup/Console/Command/ConfigSetCommand.php index 4192d22524ad1..aa96e9fdc7e71 100644 --- a/setup/src/Magento/Setup/Console/Command/ConfigSetCommand.php +++ b/setup/src/Magento/Setup/Console/Command/ConfigSetCommand.php @@ -126,6 +126,7 @@ function ($value) { $output->writeln('<info>You made no changes to the configuration.</info>'); } } + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } /** diff --git a/setup/src/Magento/Setup/Console/Command/DbDataUpgradeCommand.php b/setup/src/Magento/Setup/Console/Command/DbDataUpgradeCommand.php index 36b010d6d1e38..ae0c2f5c4e27f 100644 --- a/setup/src/Magento/Setup/Console/Command/DbDataUpgradeCommand.php +++ b/setup/src/Magento/Setup/Console/Command/DbDataUpgradeCommand.php @@ -67,5 +67,6 @@ protected function execute(InputInterface $input, OutputInterface $output) } $installer = $this->installFactory->create(new ConsoleLogger($output)); $installer->installDataFixtures(); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/DbSchemaUpgradeCommand.php b/setup/src/Magento/Setup/Console/Command/DbSchemaUpgradeCommand.php index c3b7778cdcb9d..3ef9a441b868f 100644 --- a/setup/src/Magento/Setup/Console/Command/DbSchemaUpgradeCommand.php +++ b/setup/src/Magento/Setup/Console/Command/DbSchemaUpgradeCommand.php @@ -81,6 +81,6 @@ protected function execute(InputInterface $input, OutputInterface $output) } $installer = $this->installFactory->create(new ConsoleLogger($output)); $installer->installSchema($input->getOptions()); - return null; + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/DeployStaticContentCommand.php b/setup/src/Magento/Setup/Console/Command/DeployStaticContentCommand.php index 4217c9ea5c650..6a4231259a1ca 100644 --- a/setup/src/Magento/Setup/Console/Command/DeployStaticContentCommand.php +++ b/setup/src/Magento/Setup/Console/Command/DeployStaticContentCommand.php @@ -127,7 +127,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $logger = $this->consoleLoggerFactory->getLogger($output, $verbose); if (!$refreshOnly) { - $logger->alert(PHP_EOL . "Deploy using {$options[Options::STRATEGY]} strategy"); + $logger->notice(PHP_EOL . "Deploy using {$options[Options::STRATEGY]} strategy"); } $this->mockCache(); @@ -140,7 +140,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $deployService->deploy($options); if (!$refreshOnly) { - $logger->alert(PHP_EOL . "Execution time: " . (microtime(true) - $time)); + $logger->notice(PHP_EOL . "Execution time: " . (microtime(true) - $time)); } return \Magento\Framework\Console\Cli::RETURN_SUCCESS; diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php index 904840869fdeb..68e26ec83c3f7 100644 --- a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php +++ b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php @@ -21,6 +21,7 @@ use Magento\Setup\Module\Di\App\Task\OperationInterface; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\ProgressBar; +use Magento\Framework\Console\Cli; /** * Command to run compile in single-tenant mode @@ -141,7 +142,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $output->writeln($line); } // we must have an exit code higher than zero to indicate something was wrong - return \Magento\Framework\Console\Cli::RETURN_FAILURE; + return Cli::RETURN_FAILURE; } $modulePaths = $this->componentRegistrar->getPaths(ComponentRegistrar::MODULE); @@ -211,8 +212,9 @@ function (OperationInterface $operation) use ($progressBar) { } catch (OperationException $e) { $output->writeln('<error>' . $e->getMessage() . '</error>'); // we must have an exit code higher than zero to indicate something was wrong - return \Magento\Framework\Console\Cli::RETURN_FAILURE; + return Cli::RETURN_FAILURE; } + return Cli::RETURN_SUCCESS; } /** @@ -239,7 +241,7 @@ private function getExcludedModulePaths(array $modulePaths) $vendorPathsRegExps[] = $vendorDir . '/(?:' . join('|', $vendorModules) . ')'; } - $basePathsRegExps[] = $basePath + $basePathsRegExps[] = preg_quote($basePath, '#') . '/(?:' . join('|', $vendorPathsRegExps) . ')'; } @@ -258,6 +260,10 @@ private function getExcludedModulePaths(array $modulePaths) */ private function getExcludedLibraryPaths(array $libraryPaths) { + $libraryPaths = array_map(function ($libraryPath) { + return preg_quote($libraryPath, '#'); + }, $libraryPaths); + $excludedLibraryPaths = [ '#^(?:' . join('|', $libraryPaths) . ')/([\\w]+/)?Test#', '#^(?:' . join('|', $libraryPaths) . ')/([\\w]+/)?tests#', @@ -274,7 +280,7 @@ private function getExcludedLibraryPaths(array $libraryPaths) private function getExcludedSetupPaths($setupPath) { return [ - '#^(?:' . $setupPath . ')(/[\\w]+)*/Test#' + '#^(?:' . preg_quote($setupPath, '#') . ')(/[\\w]+)*/Test#' ]; } diff --git a/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php b/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php index d4f192255c209..e084cd8ff6cad 100644 --- a/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php +++ b/setup/src/Magento/Setup/Console/Command/GenerateFixturesCommand.php @@ -133,6 +133,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // we must have an exit code higher than zero to indicate something was wrong return \Magento\Framework\Console\Cli::RETURN_FAILURE; } + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } /** diff --git a/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php b/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php index 1151ba7630d5d..bb8ab4e4cc49a 100644 --- a/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php +++ b/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php @@ -77,5 +77,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $input->getOption(self::INPUT_KEY_MAGENTO) ); $output->writeln('<info>Dictionary successfully processed.</info>'); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/I18nPackCommand.php b/setup/src/Magento/Setup/Console/Command/I18nPackCommand.php index 0fa3f474500db..7c5cc89387dcf 100644 --- a/setup/src/Magento/Setup/Console/Command/I18nPackCommand.php +++ b/setup/src/Magento/Setup/Console/Command/I18nPackCommand.php @@ -91,5 +91,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $input->getOption(self::INPUT_KEY_ALLOW_DUPLICATES) ); $output->writeln("<info>Successfully saved $locale language package.</info>"); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/InfoAdminUriCommand.php b/setup/src/Magento/Setup/Console/Command/InfoAdminUriCommand.php index 290a62d661cac..006afc27a0826 100644 --- a/setup/src/Magento/Setup/Console/Command/InfoAdminUriCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InfoAdminUriCommand.php @@ -53,5 +53,6 @@ protected function execute(InputInterface $input, OutputInterface $output) . $this->deploymentConfig->get(BackendConfigOptionsList::CONFIG_PATH_BACKEND_FRONTNAME) . "\n" ); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/InfoBackupsListCommand.php b/setup/src/Magento/Setup/Console/Command/InfoBackupsListCommand.php index c22367bded29a..178102aa0b3b7 100644 --- a/setup/src/Magento/Setup/Console/Command/InfoBackupsListCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InfoBackupsListCommand.php @@ -87,7 +87,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } if (empty($tempTable)) { $output->writeln('<info>No backup files found.</info>'); - return; + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } $output->writeln("<info>Showing backup files in $backupsDir.</info>"); /** @var \Symfony\Component\Console\Helper\Table $table */ @@ -101,5 +101,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } else { $output->writeln('<info>No backup files found.</info>'); } + + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/InfoCurrencyListCommand.php b/setup/src/Magento/Setup/Console/Command/InfoCurrencyListCommand.php index b9734807e3522..d673fc85c1ef1 100644 --- a/setup/src/Magento/Setup/Console/Command/InfoCurrencyListCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InfoCurrencyListCommand.php @@ -56,5 +56,6 @@ protected function execute(InputInterface $input, OutputInterface $output) } $table->render($output); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/InfoLanguageListCommand.php b/setup/src/Magento/Setup/Console/Command/InfoLanguageListCommand.php index 171ee32266a7f..88d1bdd5601d5 100644 --- a/setup/src/Magento/Setup/Console/Command/InfoLanguageListCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InfoLanguageListCommand.php @@ -56,5 +56,6 @@ protected function execute(InputInterface $input, OutputInterface $output) } $table->render($output); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/InfoTimezoneListCommand.php b/setup/src/Magento/Setup/Console/Command/InfoTimezoneListCommand.php index 587334a7e1dfd..95b4cd27bbd3a 100644 --- a/setup/src/Magento/Setup/Console/Command/InfoTimezoneListCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InfoTimezoneListCommand.php @@ -56,5 +56,6 @@ protected function execute(InputInterface $input, OutputInterface $output) } $table->render($output); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/InstallCommand.php b/setup/src/Magento/Setup/Console/Command/InstallCommand.php index f978d4a6f5c7f..65eb047a5c77e 100644 --- a/setup/src/Magento/Setup/Console/Command/InstallCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InstallCommand.php @@ -6,14 +6,16 @@ namespace Magento\Setup\Console\Command; use Magento\Deploy\Console\Command\App\ConfigImportCommand; -use Symfony\Component\Console\Input\ArrayInput; -use Magento\Setup\Model\Declaration\Schema\Request; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Output\OutputInterface; +use Magento\Framework\Setup\Declaration\Schema\DryRunLogger; +use Magento\Framework\Setup\Declaration\Schema\OperationsExecutor; +use Magento\Framework\Setup\Declaration\Schema\Request; +use Magento\Setup\Model\ConfigModel; use Magento\Setup\Model\InstallerFactory; use Magento\Framework\Setup\ConsoleLogger; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Input\InputOption; -use Magento\Setup\Model\ConfigModel; +use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Helper\QuestionHelper; @@ -46,6 +48,7 @@ class InstallCommand extends AbstractSetupCommand const INPUT_KEY_ENABLE_MODULES = 'enable_modules'; /** + * List of comma-separated module names. That must be avoided during installation. * List of comma-separated module names. That must be avoided during installation. * Avaiable magic param all. */ @@ -67,6 +70,16 @@ class InstallCommand extends AbstractSetupCommand */ const INPUT_KEY_INTERACTIVE_SETUP_SHORTCUT = 'i'; + /** + * Parameter says that in this mode all destructive operations, like column removal will be dumped + */ + const INPUT_KEY_SAFE_INSTALLER_MODE = 'safe-mode'; + + /** + * Parameter allows to restore data, that was dumped with safe mode before + */ + const INPUT_KEY_DATA_RESTORE = 'data-restore'; + /** * Regex for sales_order_increment_prefix validation. */ @@ -175,6 +188,25 @@ protected function configure() InputOption::VALUE_NONE, 'Interactive Magento instalation' ), + new InputOption( + OperationsExecutor::KEY_SAFE_MODE, + null, + InputOption::VALUE_OPTIONAL, + 'Safe installation of Magento with dumps on destructive operations, like column removal' + ), + new InputOption( + OperationsExecutor::KEY_DATA_RESTORE, + null, + InputOption::VALUE_OPTIONAL, + 'Restore removed data from dumps' + ), + new InputOption( + DryRunLogger::INPUT_KEY_DRY_RUN_MODE, + null, + InputOption::VALUE_OPTIONAL, + 'Magento Installation will be run in dry-run mode', + false + ), ]); $this->setName('setup:install') ->setDescription('Installs the Magento application') diff --git a/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php b/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php index fdfd0af451aa2..7eb8aec274888 100644 --- a/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php +++ b/setup/src/Magento/Setup/Console/Command/InstallStoreConfigurationCommand.php @@ -127,6 +127,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } $installer = $this->installerFactory->create(new ConsoleLogger($output)); $installer->installUserConfig($input->getOptions()); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } /** diff --git a/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php b/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php index 3df2825dfec1d..09f33cf85062c 100644 --- a/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php +++ b/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php @@ -24,6 +24,7 @@ class MaintenanceAllowIpsCommand extends AbstractSetupCommand */ const INPUT_KEY_IP = 'ip'; const INPUT_KEY_NONE = 'none'; + const INPUT_KEY_ADD = 'add'; /** * @var MaintenanceMode @@ -69,6 +70,12 @@ protected function configure() InputOption::VALUE_NONE, 'Clear allowed IP addresses' ), + new InputOption( + self::INPUT_KEY_ADD, + null, + InputOption::VALUE_NONE, + 'Add the IP address to existing list' + ), ]; $this->setName('maintenance:allow-ips') ->setDescription('Sets maintenance mode exempt IPs') @@ -91,9 +98,12 @@ protected function execute(InputInterface $input, OutputInterface $output) } if (!empty($addresses)) { + if ($input->getOption(self::INPUT_KEY_ADD)) { + $addresses = array_unique(array_merge($this->maintenanceMode->getAddressInfo(), $addresses)); + } $this->maintenanceMode->setAddresses(implode(',', $addresses)); $output->writeln( - '<info>Set exempt IP-addresses: ' . implode(', ', $this->maintenanceMode->getAddressInfo()) . + '<info>Set exempt IP-addresses: ' . implode(' ', $this->maintenanceMode->getAddressInfo()) . '</info>' ); } @@ -101,6 +111,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $this->maintenanceMode->setAddresses(''); $output->writeln('<info>Set exempt IP-addresses: none</info>'); } + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } /** diff --git a/setup/src/Magento/Setup/Console/Command/MaintenanceStatusCommand.php b/setup/src/Magento/Setup/Console/Command/MaintenanceStatusCommand.php index 9162cc47f6bd9..f2d3d2bf30caa 100644 --- a/setup/src/Magento/Setup/Console/Command/MaintenanceStatusCommand.php +++ b/setup/src/Magento/Setup/Console/Command/MaintenanceStatusCommand.php @@ -54,7 +54,8 @@ protected function execute(InputInterface $input, OutputInterface $output) ($this->maintenanceMode->isOn() ? 'active' : 'not active') . '</info>' ); $addressInfo = $this->maintenanceMode->getAddressInfo(); - $addresses = implode(', ', $addressInfo); + $addresses = implode(' ', $addressInfo); $output->writeln('<info>List of exempt IP-addresses: ' . ($addresses ? $addresses : 'none') . '</info>'); + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/ModuleStatusCommand.php b/setup/src/Magento/Setup/Console/Command/ModuleStatusCommand.php index d4305c9572a66..85af8f3caeb1a 100644 --- a/setup/src/Magento/Setup/Console/Command/ModuleStatusCommand.php +++ b/setup/src/Magento/Setup/Console/Command/ModuleStatusCommand.php @@ -65,5 +65,6 @@ protected function execute(InputInterface $input, OutputInterface $output) } else { $output->writeln(join("\n", $disabledModules)); } + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/ModuleUninstallCommand.php b/setup/src/Magento/Setup/Console/Command/ModuleUninstallCommand.php index 1d2d202a9590a..5754bbca986c8 100644 --- a/setup/src/Magento/Setup/Console/Command/ModuleUninstallCommand.php +++ b/setup/src/Magento/Setup/Console/Command/ModuleUninstallCommand.php @@ -10,6 +10,7 @@ use Magento\Framework\App\MaintenanceMode; use Magento\Framework\Backup\Factory; use Magento\Framework\Composer\ComposerInformation; +use Magento\Framework\Console\Cli; use Magento\Framework\Module\DependencyChecker; use Magento\Framework\Module\FullModuleList; use Magento\Framework\Module\PackageInfo; @@ -17,6 +18,7 @@ use Magento\Setup\Model\ModuleRegistryUninstaller; use Magento\Setup\Model\ModuleUninstaller; use Magento\Setup\Model\ObjectManagerProvider; +use Magento\Framework\Setup\Patch\PatchApplier; use Magento\Setup\Model\UninstallCollector; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -38,6 +40,7 @@ class ModuleUninstallCommand extends AbstractModuleCommand const INPUT_KEY_BACKUP_CODE = 'backup-code'; const INPUT_KEY_BACKUP_MEDIA = 'backup-media'; const INPUT_KEY_BACKUP_DB = 'backup-db'; + const INPUT_KEY_NON_COMPOSER_MODULE = 'non-composer'; /** * Deployment Configuration @@ -107,6 +110,11 @@ class ModuleUninstallCommand extends AbstractModuleCommand */ private $maintenanceModeEnabler; + /** + * @var PatchApplier + */ + private $patchApplier; + /** * Constructor * @@ -147,6 +155,19 @@ public function __construct( $maintenanceModeEnabler ?: $this->objectManager->get(MaintenanceModeEnabler::class); } + /** + * @return PatchApplier + */ + private function getPatchApplier() + { + if (!$this->patchApplier) { + $this->patchApplier = $this + ->objectManager->get(PatchApplier::class); + } + + return $this->patchApplier; + } + /** * {@inheritdoc} */ @@ -177,6 +198,12 @@ protected function configure() InputOption::VALUE_NONE, 'Take complete database backup' ), + new InputOption( + self::INPUT_KEY_NON_COMPOSER_MODULE, + null, + InputOption::VALUE_NONE, + 'All modules, that will be past here will be non composer based' + ) ]; $this->setName('module:uninstall') ->setDescription('Uninstalls modules installed by composer') @@ -195,6 +222,7 @@ protected function isModuleRequired() /** * {@inheritdoc} * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) */ protected function execute(InputInterface $input, OutputInterface $output) { @@ -203,16 +231,25 @@ protected function execute(InputInterface $input, OutputInterface $output) '<error>You cannot run this command because the Magento application is not installed.</error>' ); // we must have an exit code higher than zero to indicate something was wrong - return \Magento\Framework\Console\Cli::RETURN_FAILURE; + return Cli::RETURN_FAILURE; } $modules = $input->getArgument(self::INPUT_KEY_MODULES); + + if ($input->getOption(self::INPUT_KEY_NON_COMPOSER_MODULE)) { + foreach ($modules as $moduleName) { + $this->getPatchApplier()->revertDataPatches($moduleName); + } + + return Cli::RETURN_SUCCESS; + } + // validate modules input $messages = $this->validate($modules); if (!empty($messages)) { $output->writeln($messages); // we must have an exit code higher than zero to indicate something was wrong - return \Magento\Framework\Console\Cli::RETURN_FAILURE; + return Cli::RETURN_FAILURE; } // check dependencies @@ -220,7 +257,7 @@ protected function execute(InputInterface $input, OutputInterface $output) if (!empty($dependencyMessages)) { $output->writeln($dependencyMessages); // we must have an exit code higher than zero to indicate something was wrong - return \Magento\Framework\Console\Cli::RETURN_FAILURE; + return Cli::RETURN_FAILURE; } $helper = $this->getHelper('question'); @@ -229,7 +266,7 @@ protected function execute(InputInterface $input, OutputInterface $output) false ); if (!$helper->ask($input, $output, $question) && $input->isInteractive()) { - return \Magento\Framework\Console\Cli::RETURN_FAILURE; + return Cli::RETURN_FAILURE; } $result = $this->maintenanceModeEnabler->executeInMaintenanceMode( @@ -261,11 +298,11 @@ function () use ($input, $output, $modules, $helper) { $this->moduleUninstaller->uninstallCode($output, $modules); $this->cleanup($input, $output); - return \Magento\Framework\Console\Cli::RETURN_SUCCESS; + return Cli::RETURN_SUCCESS; } catch (\Exception $e) { $output->writeln('<error>' . $e->getMessage() . '</error>'); $output->writeln('<error>Please disable maintenance mode after you resolved above issues</error>'); - return \Magento\Framework\Console\Cli::RETURN_FAILURE; + return Cli::RETURN_FAILURE; } }, $output, diff --git a/setup/src/Magento/Setup/Console/Command/UninstallCommand.php b/setup/src/Magento/Setup/Console/Command/UninstallCommand.php index f321117422adf..0163ef3846c83 100644 --- a/setup/src/Magento/Setup/Console/Command/UninstallCommand.php +++ b/setup/src/Magento/Setup/Console/Command/UninstallCommand.php @@ -50,5 +50,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $installer = $this->installerFactory->create(new ConsoleLogger($output)); $installer->uninstall(); } + return \Magento\Framework\Console\Cli::RETURN_SUCCESS; } } diff --git a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php index da19c776fb205..bd7be01a0b2fe 100644 --- a/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php +++ b/setup/src/Magento/Setup/Console/Command/UpgradeCommand.php @@ -10,6 +10,8 @@ use Magento\Framework\App\DeploymentConfig; use Magento\Framework\App\ObjectManager; use Magento\Framework\Setup\ConsoleLogger; +use Magento\Framework\Setup\Declaration\Schema\DryRunLogger; +use Magento\Framework\Setup\Declaration\Schema\OperationsExecutor; use Magento\Setup\Model\InstallerFactory; use Symfony\Component\Console\Input\ArrayInput; use Symfony\Component\Console\Input\InputInterface; @@ -81,7 +83,26 @@ protected function configure() InputOption::VALUE_OPTIONAL, 'Allows to convert old scripts (InstallSchema, UpgradeSchema) to db_schema.xml format', false - ) + ), + new InputOption( + OperationsExecutor::KEY_SAFE_MODE, + null, + InputOption::VALUE_OPTIONAL, + 'Safe installation of Magento with dumps on destructive operations, like column removal' + ), + new InputOption( + OperationsExecutor::KEY_DATA_RESTORE, + null, + InputOption::VALUE_OPTIONAL, + 'Restore removed data from dumps' + ), + new InputOption( + DryRunLogger::INPUT_KEY_DRY_RUN_MODE, + null, + InputOption::VALUE_OPTIONAL, + 'Magento Installation will be run in dry-run mode', + false + ), ]; $this->setName('setup:upgrade') ->setDescription('Upgrades the Magento application, DB data, and schema') @@ -100,7 +121,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $installer = $this->installerFactory->create(new ConsoleLogger($output)); $installer->updateModulesSequence($keepGenerated); $installer->installSchema($request); - $installer->installDataFixtures(); + $installer->installDataFixtures($request); if ($this->deploymentConfig->isAvailable()) { $importConfigCommand = $this->getApplication()->find(ConfigImportCommand::COMMAND_NAME); diff --git a/setup/src/Magento/Setup/Console/InputValidationException.php b/setup/src/Magento/Setup/Console/InputValidationException.php new file mode 100755 index 0000000000000..efa8a03bcfe49 --- /dev/null +++ b/setup/src/Magento/Setup/Console/InputValidationException.php @@ -0,0 +1,14 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Console; + +use Symfony\Component\Console\Exception\RuntimeException; + +class InputValidationException extends RuntimeException +{ + +} diff --git a/setup/src/Magento/Setup/Console/Style/MagentoStyle.php b/setup/src/Magento/Setup/Console/Style/MagentoStyle.php new file mode 100755 index 0000000000000..4dec01f9497e1 --- /dev/null +++ b/setup/src/Magento/Setup/Console/Style/MagentoStyle.php @@ -0,0 +1,602 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Console\Style; + +use Magento\Setup\Console\InputValidationException; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Exception\RuntimeException; +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Helper\Helper; +use Symfony\Component\Console\Helper\ProgressBar; +use Symfony\Component\Console\Helper\SymfonyQuestionHelper; +use Symfony\Component\Console\Helper\Table; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Question\ConfirmationQuestion; +use Symfony\Component\Console\Question\Question; +use Symfony\Component\Console\Style\OutputStyle; + +/** + * Magento console output decorator. + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ +class MagentoStyle extends OutputStyle implements MagentoStyleInterface +{ + /** + * Default console line max length(use for limitation in case terminal width greater than 120 characters). + */ + const MAX_LINE_LENGTH = 120; + + /** + * Console input provider. + * + * @var InputInterface + */ + private $input; + + /** + * Style Guide compliant question helper. + * + * @var SymfonyQuestionHelper + */ + private $questionHelper; + + /** + * Progress output provider. + * + * @var ProgressBar + */ + private $progressBar; + + /** + * Calculated output line length. + * + * @var int + */ + private $lineLength; + + /** + * Console output buffer provider. + * + * @var BufferedOutput + */ + private $bufferedOutput; + + /** + * MagentoStyle constructor. + * + * @param InputInterface $input + * @param OutputInterface $output + */ + public function __construct(InputInterface $input, OutputInterface $output) + { + $this->input = $input; + $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter()); + // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not. + $currentLength = $this->getTerminalWidth() - (int)(DIRECTORY_SEPARATOR === '\\'); + $this->lineLength = min($currentLength, self::MAX_LINE_LENGTH); + parent::__construct($output); + } + + /** + * Formats a message as a block of text. + * + * @param string|array $messages The message to write in the block + * @param string|null $type The block type (added in [] on first line) + * @param string|null $style The style to apply to the whole block + * @param string $prefix The prefix for the block + * @param bool $padding Whether to add vertical padding + * @return void + */ + public function block( + $messages, + string $type = null, + string $style = null, + string $prefix = ' ', + bool $padding = false + ) { + $messages = is_array($messages) ? array_values($messages) : [$messages]; + $this->autoPrependBlock(); + $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding)); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function title($message) + { + $this->autoPrependBlock(); + $bar = str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message)); + $this->writeln([ + sprintf(' <options=bold>%s</>', OutputFormatter::escapeTrailingBackslash($message)), + sprintf(' <options=bold>%s</>', $bar), + ]); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function section($message) + { + $this->autoPrependBlock(); + $bar = str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message)); + $this->writeln([ + sprintf(' <fg=white>%s</>', OutputFormatter::escapeTrailingBackslash($message)), + sprintf(' <fg=white>%s</>', $bar), + ]); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function listing(array $elements) + { + $this->autoPrependText(); + $elements = array_map(function ($element) { + return sprintf(' * %s', $element); + }, $elements); + + $this->writeln($elements); + $this->newLine(); + } + + /** + * {@inheritdoc} + */ + public function text($message) + { + $this->autoPrependText(); + $messages = is_array($message) ? array_values($message) : [$message]; + foreach ($messages as $singleMessage) { + $this->writeln(sprintf(' %s', $singleMessage)); + } + } + + /** + * Formats a command comment. + * + * @param string|array $message + * @param bool $padding + * @return void + */ + public function comment($message, $padding = false) + { + $this->block($message, null, 'comment', ' ', $padding); + } + + /** + * {@inheritdoc} + */ + public function success($message, $padding = true) + { + $this->block($message, 'SUCCESS', 'fg=black;bg=green', ' ', $padding); + } + + /** + * {@inheritdoc} + */ + public function error($message, $padding = true) + { + $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', $padding); + } + + /** + * {@inheritdoc} + */ + public function warning($message, $padding = true) + { + $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', $padding); + } + + /** + * {@inheritdoc} + */ + public function note($message, $padding = false) + { + $this->block($message, 'NOTE', 'fg=yellow', ' ', $padding); + } + + /** + * {@inheritdoc} + */ + public function caution($message, $padding = true) + { + $this->block($message, 'CAUTION', 'fg=black;bg=yellow', ' ! ', $padding); + } + + /** + * {@inheritdoc} + */ + public function table(array $headers, array $rows) + { + $style = clone Table::getStyleDefinition('symfony-style-guide'); + $style->setCellHeaderFormat('<info>%s</info>'); + + $table = new Table($this); + $table->setHeaders($headers); + $table->setRows($rows); + $table->setStyle($style); + + $table->render(); + $this->newLine(); + } + + /** + * {@inheritdoc} + * @throws \Symfony\Component\Console\Exception\InvalidArgumentException + */ + public function ask($question, $default = null, $validator = null, $maxAttempts = null) + { + $question = new Question($question, $default); + $question->setValidator($validator); + $question->setMaxAttempts($maxAttempts); + + return $this->askQuestion($question); + } + + /** + * {@inheritdoc} + * @throws \Symfony\Component\Console\Exception\LogicException + */ + public function askHidden($question, $validator = null) + { + $question = new Question($question); + + $question->setHidden(true); + $question->setValidator($validator); + + return $this->askQuestion($question); + } + + /** + * {@inheritdoc} + */ + public function confirm($question, $default = true) + { + return $this->askQuestion(new ConfirmationQuestion($question, $default)); + } + + /** + * {@inheritdoc} + */ + public function choice($question, array $choices, $default = null) + { + if (null !== $default) { + $values = array_flip($choices); + $default = $values[$default]; + } + + return $this->askQuestion(new ChoiceQuestion($question, $choices, $default)); + } + + /** + * {@inheritdoc} + */ + public function progressStart($max = 0) + { + $this->progressBar = $this->createProgressBar($max); + $this->progressBar->start(); + } + + /** + * {@inheritdoc} + * @throws \Symfony\Component\Console\Exception\LogicException + * @throws \Symfony\Component\Console\Exception\RuntimeException + */ + public function progressAdvance($step = 1) + { + $this->getProgressBar()->advance($step); + } + + /** + * {@inheritdoc} + * @throws \Symfony\Component\Console\Exception\RuntimeException + */ + public function progressFinish() + { + $this->getProgressBar()->finish(); + $this->newLine(2); + $this->progressBar = null; + } + + /** + * {@inheritdoc} + */ + public function createProgressBar($max = 0) + { + $progressBar = parent::createProgressBar($max); + $progressBar->setEmptyBarCharacter(' '); + $progressBar->setProgressCharacter('>'); + $progressBar->setBarCharacter('='); + + return $progressBar; + } + + /** + * Ask user question. + * + * @param Question $question + * + * @return string + */ + public function askQuestion(Question $question) + { + if ($this->input->isInteractive()) { + $this->autoPrependBlock(); + } + + if (!$this->questionHelper) { + $this->questionHelper = new SymfonyQuestionHelper(); + } + + $answer = $this->questionHelper->ask($this->input, $this, $question); + + if ($this->input->isInteractive()) { + $this->newLine(); + $this->bufferedOutput->write(PHP_EOL); + } + + return $answer; + } + + /** + * Ask for an missing argument. + * + * @param string $argument + * @param string $question + * @param string|null $default + * @param callable|null $validator + * @param int|null $maxAttempts + * @param bool $comment + * @param string $commentFormat + * @throws \Symfony\Component\Console\Exception\InvalidArgumentException + */ + public function askForMissingArgument( + string $argument, + string $question, + string $default = null, + callable $validator = null, + int $maxAttempts = null, + bool $comment = null, + string $commentFormat = 'Argument [%s] set to: %s' + ) { + try { + if ($this->input->getArgument($argument) === null) { + $this->input->setArgument($argument, $this->ask($question, $default, $validator, $maxAttempts)); + } + $argumentValue = $this->input->getArgument($argument); + $validated = (is_callable($validator) ? $validator($argumentValue) : $argumentValue); + if ((bool)($comment ?? $this->isDebug())) { + $this->comment(sprintf($commentFormat, $argument, $validated)); + } + } catch (InputValidationException $e) { + $this->error('Validation Error: ' . $e->getMessage()); + $this->askForMissingArgument( + $argument, + $question, + $default, + $validator, + $maxAttempts, + $comment, + $commentFormat + ); + } + } + + /** + * Ask for an missing option. + * + * @param string $option + * @param string $question + * @param string|null $default + * @param callable|null $validator + * @param int|null $maxAttempts + * @param bool $comment + * @param string $commentFormat + * @throws \Symfony\Component\Console\Exception\InvalidArgumentException + */ + public function askForMissingOption( + string $option, + string $question, + string $default = null, + callable $validator = null, + int $maxAttempts = null, + bool $comment = null, + string $commentFormat = 'Option [%s] set to: %s' + ) { + try { + if (null === $this->input->getOption($option)) { + $this->input->setOption($option, $this->ask($question, $default, $validator, $maxAttempts)); + } + $optionValue = $this->input->getOption($option); + $validated = (is_callable($validator) ? $validator($optionValue) : $optionValue); + if ((bool)($comment ?? $this->isDebug())) { + $this->comment(sprintf($commentFormat, $option, $validated)); + } + } catch (InputValidationException $e) { + $this->error('Validation Error: ' . $e->getMessage()); + $this->askForMissingOption( + $option, + $question, + $default, + $validator, + $maxAttempts, + $comment, + $commentFormat + ); + } + } + + /** + * {@inheritdoc} + */ + public function writeln($messages, $type = self::OUTPUT_NORMAL) + { + parent::writeln($messages, $type); + $this->bufferedOutput->writeln($this->reduceBuffer($messages), $type); + } + + /** + * {@inheritdoc} + */ + public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL) + { + parent::write($messages, $newline, $type); + $this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type); + } + + /** + * {@inheritdoc} + */ + public function newLine($count = 1) + { + parent::newLine($count); + $this->bufferedOutput->write(str_repeat(PHP_EOL, $count)); + } + + /** + * Get progress bar instance. + * + * @return ProgressBar + * @throws RuntimeException in case progress bar hasn't been instantiated yet. + */ + private function getProgressBar() + { + if (!$this->progressBar) { + throw new RuntimeException('The ProgressBar is not started.'); + } + + return $this->progressBar; + } + + /** + * @return int + */ + private function getTerminalWidth() + { + $application = new Application(); + $dimensions = $application->getTerminalDimensions(); + + return $dimensions[0] ?: self::MAX_LINE_LENGTH; + } + + /** + * Add empty line before output element in case there were no empty lines before. + * + * @return void + */ + private function autoPrependBlock() + { + $chars = substr($this->bufferedOutput->fetch(), -2); + if (!isset($chars[0])) { + $this->newLine(); //empty history, so we should start with a new line. + } + //Prepend new line for each non LF chars (This means no blank line was output before) + $this->newLine(2 - substr_count($chars, PHP_EOL)); + } + + /** + * Add empty line before text(listing) output element. + * + * @return void + */ + private function autoPrependText() + { + $fetched = $this->bufferedOutput->fetch(); + //Prepend new line if last char isn't EOL: + if (PHP_EOL !== substr($fetched, -1)) { + $this->newLine(); + } + } + + private function reduceBuffer($messages) + { + // We need to know if the two last chars are PHP_EOL + // Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer + return array_map(function ($value) { + return substr($value, -4); + }, array_merge([$this->bufferedOutput->fetch()], (array)$messages)); + } + + /** + * Build output in block style. + * + * @param array $messages + * @param string|null $type + * @param string|null $style + * @param string $prefix + * @param bool $padding + * @return array + */ + private function createBlock( + array $messages, + string $type = null, + string $style = null, + string $prefix = ' ', + bool $padding = false + ) { + $indentLength = 0; + $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix); + if (null !== $type) { + $type = sprintf('[%s] ', $type); + $indentLength = strlen($type); + $lineIndentation = str_repeat(' ', $indentLength); + } + $lines = $this->getBlockLines($messages, $prefixLength, $indentLength); + $firstLineIndex = 0; + if ($padding && $this->isDecorated()) { + $firstLineIndex = 1; + array_unshift($lines, ''); + $lines[] = ''; + } + foreach ($lines as $i => &$line) { + if (null !== $type) { + $line = $firstLineIndex === $i ? $type . $line : $lineIndentation . $line; + } + $line = $prefix . $line; + $multiplier = $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line); + $line .= str_repeat(' ', $multiplier); + if ($style) { + $line = sprintf('<%s>%s</>', $style, $line); + } + } + + return $lines; + } + + /** + * Wrap and add new lines for each element. + * + * @param array $messages + * @param int $prefixLength + * @param int $indentLength + * @return array + */ + private function getBlockLines( + array $messages, + int $prefixLength, + int $indentLength + ) { + $lines = [[]]; + foreach ($messages as $key => $message) { + $message = OutputFormatter::escape($message); + $wordwrap = wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true); + $lines[] = explode(PHP_EOL, $wordwrap); + if (count($messages) > 1 && $key < count($messages) - 1) { + $lines[][] = ''; + } + } + $lines = array_merge(...$lines); + + return $lines; + } +} diff --git a/setup/src/Magento/Setup/Console/Style/MagentoStyleInterface.php b/setup/src/Magento/Setup/Console/Style/MagentoStyleInterface.php new file mode 100755 index 0000000000000..a7aba31549699 --- /dev/null +++ b/setup/src/Magento/Setup/Console/Style/MagentoStyleInterface.php @@ -0,0 +1,17 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Console\Style; + +use Symfony\Component\Console\Style\StyleInterface; + +/** + * Interface for output decorator. + */ +interface MagentoStyleInterface extends StyleInterface +{ + +} diff --git a/setup/src/Magento/Setup/Model/ConfigGenerator.php b/setup/src/Magento/Setup/Model/ConfigGenerator.php index 00ed16db74d8a..7e5b0c162a393 100644 --- a/setup/src/Magento/Setup/Model/ConfigGenerator.php +++ b/setup/src/Magento/Setup/Model/ConfigGenerator.php @@ -6,13 +6,14 @@ namespace Magento\Setup\Model; +use Magento\Framework\App\ObjectManager; use Magento\Framework\Config\Data\ConfigData; +use Magento\Framework\Config\Data\ConfigDataFactory; use Magento\Framework\Config\File\ConfigFilePool; -use Magento\Framework\Math\Random; use Magento\Framework\App\DeploymentConfig; use Magento\Framework\Config\ConfigOptionsListConstants; use Magento\Framework\App\State; -use Magento\Framework\App\ObjectManagerFactory; +use Magento\Framework\Math\Random; /** * Creates deployment config data based on user input array @@ -26,39 +27,58 @@ class ConfigGenerator * @var array */ private static $paramMap = [ - ConfigOptionsListConstants::INPUT_KEY_DB_HOST => ConfigOptionsListConstants::KEY_HOST, - ConfigOptionsListConstants::INPUT_KEY_DB_NAME => ConfigOptionsListConstants::KEY_NAME, - ConfigOptionsListConstants::INPUT_KEY_DB_USER => ConfigOptionsListConstants::KEY_USER, - ConfigOptionsListConstants::INPUT_KEY_DB_PASSWORD => ConfigOptionsListConstants::KEY_PASSWORD, - ConfigOptionsListConstants::INPUT_KEY_DB_PREFIX => ConfigOptionsListConstants::KEY_PREFIX, - ConfigOptionsListConstants::INPUT_KEY_DB_MODEL => ConfigOptionsListConstants::KEY_MODEL, - ConfigOptionsListConstants::INPUT_KEY_DB_ENGINE => ConfigOptionsListConstants::KEY_ENGINE, + ConfigOptionsListConstants::INPUT_KEY_DB_HOST => ConfigOptionsListConstants::KEY_HOST, + ConfigOptionsListConstants::INPUT_KEY_DB_NAME => ConfigOptionsListConstants::KEY_NAME, + ConfigOptionsListConstants::INPUT_KEY_DB_USER => ConfigOptionsListConstants::KEY_USER, + ConfigOptionsListConstants::INPUT_KEY_DB_PASSWORD => ConfigOptionsListConstants::KEY_PASSWORD, + ConfigOptionsListConstants::INPUT_KEY_DB_PREFIX => ConfigOptionsListConstants::KEY_PREFIX, + ConfigOptionsListConstants::INPUT_KEY_DB_MODEL => ConfigOptionsListConstants::KEY_MODEL, + ConfigOptionsListConstants::INPUT_KEY_DB_ENGINE => ConfigOptionsListConstants::KEY_ENGINE, ConfigOptionsListConstants::INPUT_KEY_DB_INIT_STATEMENTS => ConfigOptionsListConstants::KEY_INIT_STATEMENTS, - ConfigOptionsListConstants::INPUT_KEY_ENCRYPTION_KEY => ConfigOptionsListConstants::KEY_ENCRYPTION_KEY, - ConfigOptionsListConstants::INPUT_KEY_SESSION_SAVE => ConfigOptionsListConstants::KEY_SAVE, - ConfigOptionsListConstants::INPUT_KEY_RESOURCE => ConfigOptionsListConstants::KEY_RESOURCE, + ConfigOptionsListConstants::INPUT_KEY_ENCRYPTION_KEY => ConfigOptionsListConstants::KEY_ENCRYPTION_KEY, + ConfigOptionsListConstants::INPUT_KEY_SESSION_SAVE => ConfigOptionsListConstants::KEY_SAVE, + ConfigOptionsListConstants::INPUT_KEY_RESOURCE => ConfigOptionsListConstants::KEY_RESOURCE, ]; + /** + * @var DeploymentConfig + */ + protected $deploymentConfig; + /** * @var Random + * @deprecated 100.2.0 */ protected $random; /** - * @var DeploymentConfig + * @var ConfigDataFactory */ - protected $deploymentConfig; + private $configDataFactory; + + /** + * @var CryptKeyGeneratorInterface + */ + private $cryptKeyGenerator; /** * Constructor * - * @param Random $random + * @param Random $random Deprecated since 100.2.0 * @param DeploymentConfig $deploymentConfig + * @param ConfigDataFactory|null $configDataFactory + * @param CryptKeyGeneratorInterface|null $cryptKeyGenerator */ - public function __construct(Random $random, DeploymentConfig $deploymentConfig) - { + public function __construct( + Random $random, + DeploymentConfig $deploymentConfig, + ConfigDataFactory $configDataFactory = null, + CryptKeyGeneratorInterface $cryptKeyGenerator = null + ) { $this->random = $random; $this->deploymentConfig = $deploymentConfig; + $this->configDataFactory = $configDataFactory ?? ObjectManager::getInstance()->get(ConfigDataFactory::class); + $this->cryptKeyGenerator = $cryptKeyGenerator ?? ObjectManager::getInstance()->get(CryptKeyGenerator::class); } /** @@ -70,23 +90,17 @@ public function createCryptConfig(array $data) { $currentKey = $this->deploymentConfig->get(ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY); - $configData = new ConfigData(ConfigFilePool::APP_ENV); - if (isset($data[ConfigOptionsListConstants::INPUT_KEY_ENCRYPTION_KEY])) { - if ($currentKey !== null) { - $key = $currentKey . "\n" . $data[ConfigOptionsListConstants::INPUT_KEY_ENCRYPTION_KEY]; - } else { - $key = $data[ConfigOptionsListConstants::INPUT_KEY_ENCRYPTION_KEY]; - } + $configData = $this->configDataFactory->create(ConfigFilePool::APP_ENV); - $configData->set(ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY, $key); - } else { - if ($currentKey === null) { - $configData->set( - ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY, - md5($this->random->getRandomString(ConfigOptionsListConstants::STORE_KEY_RANDOM_STRING_SIZE)) - ); - } - } + // Use given key if set, else use current + $key = $data[ConfigOptionsListConstants::INPUT_KEY_ENCRYPTION_KEY] ?? $currentKey; + + // If there is no key given or currently set, generate a new one + $key = $key ?? $this->cryptKeyGenerator->generate(); + + // Chaining of ".. ?? .." is not used to keep it simpler to understand + + $configData->set(ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY, $key); return $configData; } @@ -99,7 +113,7 @@ public function createCryptConfig(array $data) */ public function createSessionConfig(array $data) { - $configData = new ConfigData(ConfigFilePool::APP_ENV); + $configData = $this->configDataFactory->create(ConfigFilePool::APP_ENV); if (isset($data[ConfigOptionsListConstants::INPUT_KEY_SESSION_SAVE])) { $configData->set( @@ -132,7 +146,7 @@ public function createDefinitionsConfig(array $data) */ public function createDbConfig(array $data) { - $configData = new ConfigData(ConfigFilePool::APP_ENV); + $configData = $this->configDataFactory->create(ConfigFilePool::APP_ENV); $optional = [ ConfigOptionsListConstants::INPUT_KEY_DB_HOST, @@ -151,25 +165,18 @@ public function createDbConfig(array $data) ); } + $dbConnectionPrefix = ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTION_DEFAULT . '/'; + foreach ($optional as $key) { if (isset($data[$key])) { - $configData->set( - ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTION_DEFAULT . '/' . self::$paramMap[$key], - $data[$key] - ); + $configData->set($dbConnectionPrefix . self::$paramMap[$key], $data[$key]); } } - $currentStatus = $this->deploymentConfig->get( - ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTION_DEFAULT . '/' . ConfigOptionsListConstants::KEY_ACTIVE - ); + $currentStatus = $this->deploymentConfig->get($dbConnectionPrefix . ConfigOptionsListConstants::KEY_ACTIVE); if ($currentStatus === null) { - $configData->set( - ConfigOptionsListConstants::CONFIG_PATH_DB_CONNECTION_DEFAULT - . '/' . ConfigOptionsListConstants::KEY_ACTIVE, - '1' - ); + $configData->set($dbConnectionPrefix . ConfigOptionsListConstants::KEY_ACTIVE, '1'); } return $configData; @@ -182,7 +189,7 @@ public function createDbConfig(array $data) */ public function createResourceConfig() { - $configData = new ConfigData(ConfigFilePool::APP_ENV); + $configData = $this->configDataFactory->create(ConfigFilePool::APP_ENV); if ($this->deploymentConfig->get(ConfigOptionsListConstants::CONFIG_PATH_RESOURCE_DEFAULT_SETUP) === null) { $configData->set(ConfigOptionsListConstants::CONFIG_PATH_RESOURCE_DEFAULT_SETUP, 'default'); @@ -198,10 +205,12 @@ public function createResourceConfig() */ public function createXFrameConfig() { - $configData = new ConfigData(ConfigFilePool::APP_ENV); + $configData = $this->configDataFactory->create(ConfigFilePool::APP_ENV); + if ($this->deploymentConfig->get(ConfigOptionsListConstants::CONFIG_PATH_X_FRAME_OPT) === null) { $configData->set(ConfigOptionsListConstants::CONFIG_PATH_X_FRAME_OPT, 'SAMEORIGIN'); } + return $configData; } @@ -212,10 +221,12 @@ public function createXFrameConfig() */ public function createModeConfig() { - $configData = new ConfigData(ConfigFilePool::APP_ENV); + $configData = $this->configDataFactory->create(ConfigFilePool::APP_ENV); + if ($this->deploymentConfig->get(State::PARAM_MODE) === null) { $configData->set(State::PARAM_MODE, State::MODE_DEFAULT); } + return $configData; } @@ -227,21 +238,29 @@ public function createModeConfig() */ public function createCacheHostsConfig(array $data) { - $configData = new ConfigData(ConfigFilePool::APP_ENV); + $configData = $this->configDataFactory->create(ConfigFilePool::APP_ENV); + if (isset($data[ConfigOptionsListConstants::INPUT_KEY_CACHE_HOSTS])) { - $hostData = explode(',', $data[ConfigOptionsListConstants::INPUT_KEY_CACHE_HOSTS]); - $hosts = []; - foreach ($hostData as $data) { - $dataArray = explode(':', trim($data)); - $host = []; - $host['host'] = $dataArray[0]; - if (isset($dataArray[1])) { - $host['port'] = $dataArray[1]; - } - $hosts[] = $host; - } + $hosts = explode(',', $data[ConfigOptionsListConstants::INPUT_KEY_CACHE_HOSTS]); + + $hosts = array_map( + function ($hostData) { + $hostDataParts = explode(':', trim($hostData)); + + $tmp = ['host' => $hostDataParts[0]]; + + if (isset($hostDataParts[1])) { + $tmp['port'] = $hostDataParts[1]; + } + + return $tmp; + }, + $hosts + ); + $configData->set(ConfigOptionsListConstants::CONFIG_PATH_CACHE_HOSTS, $hosts); } + $configData->setOverrideWhenSave(true); return $configData; } diff --git a/setup/src/Magento/Setup/Model/ConfigOptionsList/Session.php b/setup/src/Magento/Setup/Model/ConfigOptionsList/Session.php index 3b3fbf33a02e2..c0ec78f046e23 100644 --- a/setup/src/Magento/Setup/Model/ConfigOptionsList/Session.php +++ b/setup/src/Magento/Setup/Model/ConfigOptionsList/Session.php @@ -37,6 +37,10 @@ class Session implements ConfigOptionsListInterface const INPUT_KEY_SESSION_REDIS_DISABLE_LOCKING = 'session-save-redis-disable-locking'; const INPUT_KEY_SESSION_REDIS_MIN_LIFETIME = 'session-save-redis-min-lifetime'; const INPUT_KEY_SESSION_REDIS_MAX_LIFETIME = 'session-save-redis-max-lifetime'; + const INPUT_KEY_SESSION_REDIS_SENTINEL_SERVERS = 'session-save-redis-sentinel-servers'; + const INPUT_KEY_SESSION_REDIS_SENTINEL_MASTER = 'session-save-redis-sentinel-master'; + const INPUT_KEY_SESSION_REDIS_SENTINEL_VERIFY_MASTER = 'session-save-redis-sentinel-verify-master'; + const INPUT_KEY_SESSION_REDIS_SENTINEL_CONNECT_RETRIES = 'session-save-redis-sentinel-connect-retires'; const CONFIG_PATH_SESSION_REDIS = 'session/redis'; const CONFIG_PATH_SESSION_REDIS_HOST = 'session/redis/host'; @@ -57,6 +61,10 @@ class Session implements ConfigOptionsListInterface const CONFIG_PATH_SESSION_REDIS_DISABLE_LOCKING = 'session/redis/disable_locking'; const CONFIG_PATH_SESSION_REDIS_MIN_LIFETIME = 'session/redis/min_lifetime'; const CONFIG_PATH_SESSION_REDIS_MAX_LIFETIME = 'session/redis/max_lifetime'; + const CONFIG_PATH_SESSION_REDIS_SENTINEL_SERVERS = 'session/redis/sentinel_servers'; + const CONFIG_PATH_SESSION_REDIS_SENTINEL_MASTER = 'session/redis/sentinel_master'; + const CONFIG_PATH_SESSION_REDIS_SENTINEL_VERIFY_MASTER = 'session/redis/sentinel_verify_master'; + const CONFIG_PATH_SESSION_REDIS_SENTINEL_CONNECT_RETRIES = 'session/redis/sentinel_connect_retries'; /** * @var array @@ -80,7 +88,9 @@ class Session implements ConfigOptionsListInterface self::INPUT_KEY_SESSION_REDIS_BOT_LIFETIME => '7200', self::INPUT_KEY_SESSION_REDIS_DISABLE_LOCKING => '0', self::INPUT_KEY_SESSION_REDIS_MIN_LIFETIME => '60', - self::INPUT_KEY_SESSION_REDIS_MAX_LIFETIME => '2592000' + self::INPUT_KEY_SESSION_REDIS_MAX_LIFETIME => '2592000', + self::INPUT_KEY_SESSION_REDIS_SENTINEL_VERIFY_MASTER => '0', + self::INPUT_KEY_SESSION_REDIS_SENTINEL_CONNECT_RETRIES => '5', ]; /** @@ -121,6 +131,11 @@ class Session implements ConfigOptionsListInterface self::INPUT_KEY_SESSION_REDIS_DISABLE_LOCKING => self::CONFIG_PATH_SESSION_REDIS_DISABLE_LOCKING, self::INPUT_KEY_SESSION_REDIS_MIN_LIFETIME => self::CONFIG_PATH_SESSION_REDIS_MIN_LIFETIME, self::INPUT_KEY_SESSION_REDIS_MAX_LIFETIME => self::CONFIG_PATH_SESSION_REDIS_MAX_LIFETIME, + self::INPUT_KEY_SESSION_REDIS_SENTINEL_MASTER => self::CONFIG_PATH_SESSION_REDIS_SENTINEL_MASTER, + self::INPUT_KEY_SESSION_REDIS_SENTINEL_SERVERS => self::CONFIG_PATH_SESSION_REDIS_SENTINEL_SERVERS, + self::INPUT_KEY_SESSION_REDIS_SENTINEL_CONNECT_RETRIES => + self::CONFIG_PATH_SESSION_REDIS_SENTINEL_CONNECT_RETRIES, + self::INPUT_KEY_SESSION_REDIS_SENTINEL_VERIFY_MASTER => self::CONFIG_PATH_SESSION_REDIS_SENTINEL_VERIFY_MASTER, ]; /** @@ -246,6 +261,30 @@ public function getOptions() self::CONFIG_PATH_SESSION_REDIS_MAX_LIFETIME, 'Redis max session lifetime, in seconds' ), + new TextConfigOption( + self::INPUT_KEY_SESSION_REDIS_SENTINEL_MASTER, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_SESSION_REDIS_SENTINEL_MASTER, + 'Redis Sentinel master' + ), + new TextConfigOption( + self::INPUT_KEY_SESSION_REDIS_SENTINEL_SERVERS, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::INPUT_KEY_SESSION_REDIS_SENTINEL_SERVERS, + 'Redis Sentinel servers, comma separated' + ), + new TextConfigOption( + self::INPUT_KEY_SESSION_REDIS_SENTINEL_VERIFY_MASTER, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_SESSION_REDIS_SENTINEL_VERIFY_MASTER, + 'Redis Sentinel verify master. Values: false (default), true' + ), + new TextConfigOption( + self::INPUT_KEY_SESSION_REDIS_SENTINEL_CONNECT_RETRIES, + TextConfigOption::FRONTEND_WIZARD_TEXT, + self::CONFIG_PATH_SESSION_REDIS_SENTINEL_CONNECT_RETRIES, + 'Redis Sentinel connect retries.' + ), ]; } diff --git a/setup/src/Magento/Setup/Model/CryptKeyGenerator.php b/setup/src/Magento/Setup/Model/CryptKeyGenerator.php new file mode 100644 index 0000000000000..ec9d3f028126a --- /dev/null +++ b/setup/src/Magento/Setup/Model/CryptKeyGenerator.php @@ -0,0 +1,55 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Model; + +use Magento\Framework\Config\ConfigOptionsListConstants; +use Magento\Framework\Math\Random; + +/** + * Generates a crypt. + */ +class CryptKeyGenerator implements CryptKeyGeneratorInterface +{ + /** + * @var Random + */ + private $random; + + /** + * CryptKeyGenerator constructor. + * + * @param Random $random + */ + public function __construct(Random $random) + { + $this->random = $random; + } + + /** + * Generates & returns a string to be used as crypt key. + * The key length is not a parameter, but an implementation detail. + * + * @return string + * + * @throws \Magento\Framework\Exception\LocalizedException + */ + public function generate() + { + return md5($this->getRandomString()); + } + + /** + * Returns a random string. + * + * @return string + * @throws \Magento\Framework\Exception\LocalizedException + */ + private function getRandomString() + { + return $this->random->getRandomString(ConfigOptionsListConstants::STORE_KEY_RANDOM_STRING_SIZE); + } +} diff --git a/setup/src/Magento/Setup/Model/CryptKeyGeneratorInterface.php b/setup/src/Magento/Setup/Model/CryptKeyGeneratorInterface.php new file mode 100644 index 0000000000000..f96f9b37ac9a7 --- /dev/null +++ b/setup/src/Magento/Setup/Model/CryptKeyGeneratorInterface.php @@ -0,0 +1,22 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Model; + +/** + * Interface for crypt key generators. + */ +interface CryptKeyGeneratorInterface +{ + /** + * Generates & returns a string to be used as crypt key. + * + * The key length is not a parameter, but an implementation detail. + * + * @return string + */ + public function generate(); +} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Config/Converter.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Config/Converter.php deleted file mode 100644 index 839c4d17c342c..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Config/Converter.php +++ /dev/null @@ -1,124 +0,0 @@ -<?php -/** - * Attributes configuration converter - * - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Config; - -/** - * This converter is required for Declaration Filesystem reader: - * - * @see \Magento\Setup\Model\Declaration\Schema\FileSystem\XmlReader - * - * Allows to convert declarative schema to raw array and add default values - * for column types and for constraints. - */ -class Converter implements \Magento\Framework\Config\ConverterInterface -{ - /** - * Convert config from XML to array. - * - * @param \DOMDocument $source - * @return array - */ - public function convert($source) - { - $output = $this->recursiveConvert($this->getTablesNode($source)); - return $output; - } - - /** - * We exactly know, that our schema is consists from tables. - * So we do not need root elements in result, only table names. - * So proposed to select only tables from all DOMDocument. - * - * @param \DOMDocument $element - * @return \DOMNodeList - */ - private function getTablesNode(\DOMDocument $element) - { - return $element->getElementsByTagName('table'); - } - - /** - * Convert elements. - * - * @param \Traversable $source - * @return array - */ - private function recursiveConvert(\Traversable $source) - { - $output = []; - foreach ($source as $element) { - if ($element instanceof \DOMElement) { - $key = $element->getAttribute('name'); - - if ($element->hasChildNodes()) { - $output[$element->tagName][$key] = - array_replace( - $this->recursiveConvert($element->childNodes), - $this->interpretateAttributes($element) - ); - } else if ($this->hasAttributesExceptName($element)) { - $output[$element->tagName][$key] = $this->interpretateAttributes($element); - } else { - $output[$element->tagName][$key] = $key; - } - } - } - - return $output; - } - - /** - * Check whether we have any attributes except name XSI:TYPE is in another namespace. - * Note: name is mandatory attribute. - * - * @param \DOMElement $element - * @return bool - */ - private function hasAttributesExceptName(\DOMElement $element) - { - return $element->hasAttribute('xsi:type') || $element->attributes->length >= 2; - } - - /** - * Mix attributes that comes from XML schema with default ones. - * So if you will not have some attribute in schema - it will be taken from default one. - * - * @param \DOMElement $domElement - * @return mixed - */ - private function interpretateAttributes(\DOMElement $domElement) - { - $attributes = $this->getAttributes($domElement); - $xsiType = $domElement->getAttribute('xsi:type'); - - if ($xsiType) { - $attributes['type'] = $xsiType; - } - - return $attributes; - } - - /** - * Convert XML attributes into raw array with attributes. - * - * @param \DOMElement $element - * @return array - */ - private function getAttributes(\DOMElement $element) - { - $attributes = []; - $attributeNodes = $element->attributes; - - /** @var \DOMAttr $attribute */ - foreach ($attributeNodes as $domAttr) { - $attributes[$domAttr->name] = $domAttr->value; - } - - return $attributes; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Config/SchemaLocator.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Config/SchemaLocator.php deleted file mode 100644 index df6779122c4f0..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Config/SchemaLocator.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Config; - -/** - * This is system class that provides .xsd file for validation XML schema. - */ -class SchemaLocator implements \Magento\Framework\Config\SchemaLocatorInterface -{ - /** - * Path to corresponding XSD file with validation rules for merged config. - * - * @var string - */ - protected $_schema = null; - - /** - * Path to corresponding XSD file with validation rules for separate config files. - * - * @var string - */ - protected $_perFileSchema = null; - - /** - * Constructor. - * - * @param \Magento\Framework\Config\Dom\UrnResolver $urnResolver - * @param string $schemaUrn - */ - public function __construct( - \Magento\Framework\Config\Dom\UrnResolver $urnResolver, - $schemaUrn = 'urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd' - ) { - $this->_schema = $urnResolver->getRealPath($schemaUrn); - $this->_perFileSchema = $this->_schema; - } - - /** - * Get path to merged config schema. - * - * @return string|null - */ - public function getSchema() - { - return $this->_schema; - } - - /** - * Get path to pre file validation schema. - * - * @return string|null - */ - public function getPerFileSchema() - { - return $this->_perFileSchema; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DDL/Triggers/MigrateDataFromAnotherTable.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DDL/Triggers/MigrateDataFromAnotherTable.php deleted file mode 100644 index 237d93fc004db..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/DDL/Triggers/MigrateDataFromAnotherTable.php +++ /dev/null @@ -1,79 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\DDL\Triggers; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DDLTriggerInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Used to migrate data from one column to another in scope of one table. - * Can add statement in case when data can`t be migrate easily. - */ -class MigrateDataFromAnotherTable implements DDLTriggerInterface -{ - /** - * Pattern with which we can match whether we can apply and use this trigger or not. - */ - const MATCH_PATTERN = '/migrateDataFromAnotherTable\(([^\)]+)\,([^\)]+)\)/'; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * Constructor. - * - * @param ResourceConnection $resourceConnection - */ - public function __construct(ResourceConnection $resourceConnection) - { - $this->resourceConnection = $resourceConnection; - } - - /** - * @inheritdoc - */ - public function isApplicable($statement) - { - return preg_match(self::MATCH_PATTERN, $statement); - } - - /** - * @param Column $column - * @inheritdoc - */ - public function getCallback(ElementInterface $column) - { - preg_match(self::MATCH_PATTERN, $column->getOnCreate(), $matches); - return function () use ($column, $matches) { - $tableName = $column->getTable()->getName(); - $tableMigrateFrom = $matches[1]; - $columnMigrateFrom = $matches[2]; - $adapter = $this->resourceConnection->getConnection( - $column->getTable()->getResource() - ); - $select = $adapter->select() - ->setPart('disable_staging_preview', true) - ->from( - $this->resourceConnection->getTableName($tableMigrateFrom), - [$column->getName() => $columnMigrateFrom] - ); - //Update only if table exists - if ($adapter->isTableExists($tableMigrateFrom)) { - $adapter->query( - $adapter->insertFromSelect( - $select, - $this->resourceConnection->getTableName($tableName) - ) - ); - } - }; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Blob.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Blob.php deleted file mode 100644 index fd0209241e52e..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Blob.php +++ /dev/null @@ -1,77 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Process blob and text types. - * - * @inheritdoc - */ -class Blob implements DbDefinitionProcessorInterface -{ - /** - * @var Nullable - */ - private $nullable; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - /** - * @var Comment - */ - private $comment; - - /** - * Blob constructor. - * - * @param Nullable $nullable - * @param Comment $comment - * @param ResourceConnection $resourceConnection - */ - public function __construct( - Nullable $nullable, - Comment $comment, - ResourceConnection $resourceConnection - ) { - $this->nullable = $nullable; - $this->resourceConnection = $resourceConnection; - $this->comment = $comment; - } - - /** - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - return sprintf( - '%s %s %s %s', - $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), - $column->getType(), - $this->nullable->toDefinition($column), - $this->comment->toDefinition($column) - ); - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - $matches = []; - if (preg_match('/^text\s*\((\d+)\)/', $data['definition'], $matches) && isset($matches[1])) { - $data['length'] = $matches[1]; - } - - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Boolean.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Boolean.php deleted file mode 100644 index f81db3464f22a..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Boolean.php +++ /dev/null @@ -1,103 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * As all MySQL aliases as BOOL or BOOLEAN are converted to TINYINT(1) - * proposed to processed tinyint as boolean. - * - * @inheritdoc - */ -class Boolean implements DbDefinitionProcessorInterface -{ - /** - * Type the column is persisted with. - */ - const TYPE = 'BOOLEAN'; - - /** - * Type of integer that is used in MySQL for boolean. - */ - const INTEGER_TYPE = 'tinyint'; - - /** - * Padding for integer described below. - */ - const INTEGER_PADDING = '1'; - - /** - * @var Nullable - */ - private $nullable; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var Comment - */ - private $comment; - - /** - * Constructor. - * - * @param Nullable $nullable - * @param ResourceConnection $resourceConnection - * @param Comment $comment - */ - public function __construct( - Nullable $nullable, - ResourceConnection $resourceConnection, - Comment $comment - ) { - $this->nullable = $nullable; - $this->resourceConnection = $resourceConnection; - $this->comment = $comment; - } - - /** - * @param \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Boolean $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - return sprintf( - '%s %s %s %s %s', - $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), - self::TYPE, - $this->nullable->toDefinition($column), - $column->getDefault() !== null ? - sprintf('DEFAULT %s', $column->getDefault() ? 1 : 0) : '', - $this->comment->toDefinition($column) - ); - } - - /** - * Boolean is presented as tinyint(1). - * - * @inheritdoc - */ - public function fromDefinition(array $data) - { - if ($data['type'] === self::INTEGER_TYPE && $data['padding'] === self::INTEGER_PADDING) { - $data['type'] = strtolower(self::TYPE); - if (isset($data['default'])) { - $data['default'] = $data['default'] === null ? null : (bool) $data['default']; - } - $data['unsigned'] = false; //Not signed for boolean - unset($data['padding']); - } - - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Comment.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Comment.php deleted file mode 100644 index a3147f53b41ef..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Comment.php +++ /dev/null @@ -1,37 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\ColumnNullableAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Comment definition processor. - * - * @inheritdoc - */ -class Comment implements DbDefinitionProcessorInterface -{ - /** - * @param Column $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - return $column->getComment() !== null ? sprintf('COMMENT "%s"', $column->getComment()) : ''; - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Date.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Date.php deleted file mode 100644 index 536b5e8f34b2e..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Date.php +++ /dev/null @@ -1,72 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Date type processor. - * - * @inheritdoc - */ -class Date implements DbDefinitionProcessorInterface -{ - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var Comment - */ - private $comment; - - /** - * @var Nullable - */ - private $nullable; - - /** - * Constructor. - * - * @param ResourceConnection $resourceConnection - * @param Nullable $nullable - * @param Comment $comment - */ - public function __construct(ResourceConnection $resourceConnection, Nullable $nullable, Comment $comment) - { - $this->resourceConnection = $resourceConnection; - $this->comment = $comment; - $this->nullable = $nullable; - } - - /** - * @param \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - return sprintf( - '%s %s %s %s', - $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), - $column->getType(), - $this->nullable->toDefinition($column), - $this->comment->toDefinition($column) - ); - } - - /** - * @inheritdoc - * @codeCoverageIgnore - */ - public function fromDefinition(array $data) - { - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Identity.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Identity.php deleted file mode 100644 index 2b1f876c9b6d6..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Identity.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\ColumnIdentityAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Identity (auto_increment) column processor. - * - * @inheritdoc - */ -class Identity implements DbDefinitionProcessorInterface -{ - /** - * Auto increment flag. - */ - const IDENTITY_FLAG = 'auto_increment'; - - /** - * @param ColumnIdentityAwareInterface $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - return $column->isIdentity() ? strtoupper(self::IDENTITY_FLAG) : ''; - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - if (!empty($data['extra']) && stripos($data['extra'], self::IDENTITY_FLAG) !== false) { - $data['identity'] = true; - } - - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Integer.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Integer.php deleted file mode 100644 index 68ed3d4d1016e..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Integer.php +++ /dev/null @@ -1,119 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Integer type processor. - * - * Processes integer type and separate it on type and padding. - * - * @inheritdoc - */ -class Integer implements DbDefinitionProcessorInterface -{ - /** - * @var Unsigned - */ - private $unsigned; - - /** - * @var \Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns\Boolean - */ - private $boolean; - - /** - * @var Nullable - */ - private $nullable; - - /** - * @var Identity - */ - private $identity; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var Comment - */ - private $comment; - - /** - * Constructor. - * - * @param Unsigned $unsigned - * @param bool $boolean - * @param Nullable $nullable - * @param Identity $identity - * @param Comment $comment - * @param ResourceConnection $resourceConnection - */ - public function __construct( - Unsigned $unsigned, - Boolean $boolean, - Nullable $nullable, - Identity $identity, - Comment $comment, - ResourceConnection $resourceConnection - ) { - $this->unsigned = $unsigned; - $this->boolean = $boolean; - $this->nullable = $nullable; - $this->identity = $identity; - $this->resourceConnection = $resourceConnection; - $this->comment = $comment; - } - - /** - * @param \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - return sprintf( - '%s %s(%s) %s %s %s %s %s', - $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), - $column->getType(), - $column->getPadding(), - $this->unsigned->toDefinition($column), - $this->nullable->toDefinition($column), - $column->getDefault() !== null ? - sprintf('DEFAULT %s', (string) intval($column->getDefault())) : '', - $this->identity->toDefinition($column), - $this->comment->toDefinition($column) - ); - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - $matches = []; - if (preg_match('/^(big|small|tiny|medium)?int\((\d+)\)/', $data['definition'], $matches)) { - /** - * match[1] - prefix - * match[2] - padding, like 5 or 11 - */ - //Use shortcut for mediuminteger - $data['padding'] = $matches[2]; - $data = $this->unsigned->fromDefinition($data); - $data = $this->nullable->fromDefinition($data); - $data = $this->identity->fromDefinition($data); - $data = $this->boolean->fromDefinition($data); - } - - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Nullable.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Nullable.php deleted file mode 100644 index 8439c32116fcd..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Nullable.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\ColumnNullableAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Nullable columns processor. - * - * @inheritdoc - */ -class Nullable implements DbDefinitionProcessorInterface -{ - /** - * @param ColumnNullableAwareInterface $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - if ($column instanceof ColumnNullableAwareInterface) { - return $column->isNullable() ? 'NULL' : 'NOT NULL'; - } - - return ''; - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdate.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdate.php deleted file mode 100644 index f8c8822ba3fea..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/OnUpdate.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * On update statement processor. - * - * @inheritdoc - */ -class OnUpdate implements DbDefinitionProcessorInterface -{ - /** - * @param \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - if ($column instanceof \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp) { - return $column->getOnUpdate() ? - 'ON UPDATE CURRENT_TIMESTAMP' : ''; - } - - return ''; - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - $matches = []; - if (preg_match('/^(?:on update)\s([\_\-\s\w\d]+)/', $data['extra'], $matches)) { - $data['on_update'] = true; - } - - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Real.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Real.php deleted file mode 100644 index d3a0e3038d43c..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Real.php +++ /dev/null @@ -1,106 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Process real types and separate them into type, scale and precision. - * See https://dev.mysql.com/doc/refman/5.7/en/precision-math-decimal-characteristics.html - * - * @inheritdoc - */ -class Real implements DbDefinitionProcessorInterface -{ - /** - * @var Nullable - */ - private $nullable; - - /** - * @var Unsigned - */ - private $unsigned; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var Comment - */ - private $comment; - - /** - * @param Nullable $nullable - * @param Unsigned $unsigned - * @param Comment $comment - * @param ResourceConnection $resourceConnection - */ - public function __construct( - Nullable $nullable, - Unsigned $unsigned, - Comment $comment, - ResourceConnection $resourceConnection - ) { - $this->nullable = $nullable; - $this->unsigned = $unsigned; - $this->resourceConnection = $resourceConnection; - $this->comment = $comment; - } - - /** - * @param \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Real $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - if ($column->getPrecision() === 0 && $column->getScale() === 0) { - $type = $column->getType(); - } else { - $type = sprintf('%s(%s, %s)', $column->getType(), $column->getPrecision(), $column->getScale()); - } - - return sprintf( - '%s %s %s %s %s %s', - $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), - $type, - $this->unsigned->toDefinition($column), - $this->nullable->toDefinition($column), - $column->getDefault() !== null ? - sprintf('DEFAULT %s', $column->getDefault()) : '', - $this->comment->toDefinition($column) - ); - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - $matches = []; - if (preg_match('/^(float|decimal|double)\s*\((\d+)\s*,\s*(\d+)\)/i', $data['definition'], $matches)) { - /** - * match[1] - type - * match[2] - precision - * match[3] - scale - */ - $data['precision'] = $matches[2]; - $data['scale'] = $matches[3]; - $data = $this->nullable->fromDefinition($data); - $data = $this->unsigned->fromDefinition($data); - } elseif (preg_match('/^decimal\s*\(\s*(\d+)\s*\)/i', $data['definition'], $matches)) { - $data['precision'] = $matches[1]; - $data['scale'] = 0; - } - - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinary.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinary.php deleted file mode 100644 index 44286e7a953ef..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/StringBinary.php +++ /dev/null @@ -1,81 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Processor for following types: char, varchar, varbinary, binary. - * - * @inheritdoc - */ -class StringBinary implements DbDefinitionProcessorInterface -{ - /** - * @var Nullable - */ - private $nullable; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var Comment - */ - private $comment; - - /** - * @param Nullable $nullable - * @param ResourceConnection $resourceConnection - * @param Comment $comment - */ - public function __construct(Nullable $nullable, ResourceConnection $resourceConnection, Comment $comment) - { - $this->nullable = $nullable; - $this->resourceConnection = $resourceConnection; - $this->comment = $comment; - } - - /** - * @param \Magento\Setup\Model\Declaration\Schema\Dto\Columns\StringBinary $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - if ($column->getDefault() !== null) { - $default = sprintf('DEFAULT "%s"', $column->getDefault()); - } else { - $default = ''; - } - - return sprintf( - '%s %s(%s) %s %s %s', - $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), - $column->getType(), - $column->getLength(), - $this->nullable->toDefinition($column), - $default, - $this->comment->toDefinition($column) - ); - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - $matches = []; - if (preg_match('/^(char|binary|varchar|varbinary)\s*\((\d+)\)/', $data['definition'], $matches)) { - $data['length'] = $matches[2]; - } - - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Timestamp.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Timestamp.php deleted file mode 100644 index 7df37fd28a988..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Timestamp.php +++ /dev/null @@ -1,99 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Processor for timestamp/datetime types. - * - * @inheritdoc - */ -class Timestamp implements DbDefinitionProcessorInterface -{ - /** - * This date and time can be used, when const value as DEFAULT 0 was passed for datetime type. - */ - const CONST_DEFAULT_TIMESTAMP = '0000-00-00 00:00:00'; - - /** - * @var OnUpdate - */ - private $onUpdate; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var Nullable - */ - private $nullable; - - /** - * @var Comment - */ - private $comment; - - /** - * Constructor. - * - * @param OnUpdate $onUpdate - * @param Nullable $nullable - * @param Comment $comment - * @param ResourceConnection $resourceConnection - */ - public function __construct( - OnUpdate $onUpdate, - Nullable $nullable, - Comment $comment, - ResourceConnection $resourceConnection - ) { - $this->onUpdate = $onUpdate; - $this->resourceConnection = $resourceConnection; - $this->nullable = $nullable; - $this->comment = $comment; - } - - /** - * @param \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - $nullable = $this->nullable->toDefinition($column); - $default = $column->getDefault() === 'NULL' - ? '' - : sprintf('DEFAULT %s', $column->getDefault()); - - return sprintf( - '%s %s %s %s %s %s', - $this->resourceConnection->getConnection()->quoteIdentifier($column->getName()), - $column->getType(), - $nullable, - $default, - $this->onUpdate->toDefinition($column), - $this->comment->toDefinition($column) - ); - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - if ($data['default'] === self::CONST_DEFAULT_TIMESTAMP) { - $data['default'] = '0'; - } - $data = $this->nullable->fromDefinition($data); - $data = $this->onUpdate->fromDefinition($data); - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Unsigned.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Unsigned.php deleted file mode 100644 index 9b85fa9862d23..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Columns/Unsigned.php +++ /dev/null @@ -1,43 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Columns; - -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\ColumnUnsignedAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Unsigned flag processor. - * Unsigned can be used for all numeric types. - * - * @inheritdoc - */ -class Unsigned implements DbDefinitionProcessorInterface -{ - /** - * Unsigned flag. Applicable only to numeric types. - */ - const UNSIGNED_FLAG = 'unsigned'; - - /** - * @param ColumnUnsignedAwareInterface $column - * @inheritdoc - */ - public function toDefinition(ElementInterface $column) - { - return $column->isUnsigned() ? strtoupper(self::UNSIGNED_FLAG) : ''; - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - $data['unsigned'] = stripos($data['definition'], self::UNSIGNED_FLAG) !== false; - return $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/Internal.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/Internal.php deleted file mode 100644 index 8a69a591420ad..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Constraints/Internal.php +++ /dev/null @@ -1,91 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Constraints; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Internal key (index) processor. - * - * Detect primary or unique constraints and map them to appropriate format. - * - * @inheritdoc - */ -class Internal implements DbDefinitionProcessorInterface -{ - /** - * Name of Primary Key. - */ - const PRIMARY_NAME = 'PRIMARY'; - - /** - * Primary key statement. - */ - const PRIMARY_KEY_NAME = 'PRIMARY KEY'; - - /** - * Unique key statement. - */ - const UNIQUE_KEY_NAME = 'UNIQUE KEY'; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * Constructor. - * - * @param ResourceConnection $resourceConnection - */ - public function __construct(ResourceConnection $resourceConnection) - { - $this->resourceConnection = $resourceConnection; - } - - /** - * @param \Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Internal $constraint - * @inheritdoc - */ - public function toDefinition(ElementInterface $constraint) - { - $adapter = $this->resourceConnection->getConnection( - $constraint->getTable()->getResource() - ); - $columnsList = array_map( - function ($columnName) use ($adapter) { - return $adapter->quoteIdentifier($columnName); - }, - $constraint->getColumnNames() - ); - $isPrimary = $constraint->getType() === 'primary'; - - return sprintf( - 'CONSTRAINT %s %s (%s)', - $isPrimary ? '' : $adapter->quoteIdentifier($constraint->getName()), - $isPrimary ? 'PRIMARY KEY' : 'UNIQUE KEY', - implode(',', $columnsList) - ); - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - return [ - 'name' => $data['Key_name'], - 'column' => [ - $data['Column_name'] => $data['Column_name'] - ], - 'type' => $data['Key_name'] === self::PRIMARY_NAME ? 'primary' : 'unique' - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Index.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Index.php deleted file mode 100644 index 010de012dd94e..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/MySQL/Definition/Index.php +++ /dev/null @@ -1,84 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbDefinitionProcessorInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * Index (key) processor. - * - * @inheritdoc - */ -class Index implements DbDefinitionProcessorInterface -{ - /** - * Index statement. - */ - const INDEX_KEY_NAME = 'INDEX'; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * Index constructor. - * - * @param ResourceConnection $resourceConnection - */ - public function __construct(ResourceConnection $resourceConnection) - { - $this->resourceConnection = $resourceConnection; - } - - /** - * @param \Magento\Setup\Model\Declaration\Schema\Dto\Index $index - * @inheritdoc - */ - public function toDefinition(ElementInterface $index) - { - $indexType = $index->getIndexType(); - //There is no matter what connection to use -> so use default one - $adapter = $this->resourceConnection->getConnection(); - $isFullText = $indexType === \Magento\Setup\Model\Declaration\Schema\Dto\Index::FULLTEXT_INDEX; - //index types, that are similar to MySQL ones, can just be uppercased. - //[FULLTEXT ]INDEX `name` [USING [BTREE|HASH]] (columns) - return sprintf( - '%sINDEX %s%s (%s)', - $isFullText ? 'FULLTEXT ' : '', - $adapter->quoteIdentifier($index->getName()), - '', // placeholder for USING HASH|BTREE statement for non-fulltext indexes - implode( - ',', - array_map( - function ($columnName) use ($adapter) { - return $adapter->quoteIdentifier($columnName); - }, - $index->getColumnNames() - ) - ) - ); - } - - /** - * @inheritdoc - */ - public function fromDefinition(array $data) - { - return [ - 'indexType' => strtolower($data['Index_type']), - 'name' => $data['Key_name'], - 'column' => [ - $data['Column_name'] => $data['Column_name'] - ], - 'type' => 'index' - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/SchemaBuilder.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Db/SchemaBuilder.php deleted file mode 100644 index b487d7e1a3139..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Db/SchemaBuilder.php +++ /dev/null @@ -1,182 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Db; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementFactory; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\Sharding; - -/** - * This type of builder is responsible for converting ENTIRE data, that comes from db - * into DTO`s format, with aggregation root: Schema. - * - * Note: SchemaBuilder can not be used for one structural element, like column or constraint - * because it should have references to other DTO objects. - * In order to convert build only 1 structural element use directly it factory. - * - * @see Schema - * @inheritdoc - */ -class SchemaBuilder -{ - /** - * @var ElementFactory - */ - private $elementFactory; - - /** - * @var DbSchemaReaderInterface - */ - private $dbSchemaReader; - - /** - * @var Sharding - */ - private $sharding; - - /** - * Constructor. - * - * @param ElementFactory $elementFactory - * @param DbSchemaReaderInterface $dbSchemaReader - * @param Sharding $sharding - */ - public function __construct( - ElementFactory $elementFactory, - DbSchemaReaderInterface $dbSchemaReader, - Sharding $sharding - ) { - $this->elementFactory = $elementFactory; - $this->dbSchemaReader = $dbSchemaReader; - $this->sharding = $sharding; - } - - /** - * @inheritdoc - */ - public function build(Schema $schema) - { - $tables = []; - - foreach ($this->sharding->getResources() as $resource) { - foreach ($this->dbSchemaReader->readTables($resource) as $tableName) { - $columns = []; - $indexes = []; - $constraints = []; - - $tableOptions = $this->dbSchemaReader->getTableOptions($tableName, $resource); - $columnsData = $this->dbSchemaReader->readColumns($tableName, $resource); - $indexesData = $this->dbSchemaReader->readIndexes($tableName, $resource); - $constrainsData = $this->dbSchemaReader->readConstraints($tableName, $resource); - - /** - * @var Table $table - */ - $table = $this->elementFactory->create( - 'table', - [ - 'name' => $tableName, - 'resource' => $resource, - 'engine' => strtolower($tableOptions['Engine']), - 'comment' => $tableOptions['Comment'] === '' ? null : $tableOptions['Comment'] - ] - ); - - // Process columns - foreach ($columnsData as $columnData) { - $columnData['table'] = $table; - $column = $this->elementFactory->create($columnData['type'], $columnData); - $columns[$column->getName()] = $column; - } - - $table->addColumns($columns); - //Process indexes - foreach ($indexesData as $indexData) { - $indexData['columns'] = $this->resolveInternalRelations($columns, $indexData); - $indexData['table'] = $table; - $index = $this->elementFactory->create('index', $indexData); - $indexes[$index->getName()] = $index; - } - //Process internal constraints - foreach ($constrainsData as $constraintData) { - $constraintData['columns'] = $this->resolveInternalRelations($columns, $constraintData); - $constraintData['table'] = $table; - $constraint = $this->elementFactory->create($constraintData['type'], $constraintData); - $constraints[$constraint->getName()] = $constraint; - } - - $table->addIndexes($indexes); - $table->addConstraints($constraints); - $tables[$table->getName()] = $table; - $schema->addTable($table); - } - } - - $this->processReferenceKeys($tables); - return $schema; - } - - /** - * Process references for all tables. Schema validation required. - * - * @param Table[] $tables - * @return Table[] - */ - private function processReferenceKeys(array $tables) - { - foreach ($tables as $table) { - $tableName = $table->getName(); - $referencesData = $this->dbSchemaReader->readReferences($tableName, $table->getResource()); - $references = []; - - foreach ($referencesData as $referenceData) { - //Prepare reference data - $referenceData['table'] = $tables[$tableName]; - $referenceData['column'] = $tables[$tableName]->getColumnByName($referenceData['column']); - $referenceData['referenceTable'] = $tables[$referenceData['referenceTable']]; - $referenceData['referenceColumn'] = $referenceData['referenceTable']->getColumnByName( - $referenceData['referenceColumn'] - ); - - $references[$referenceData['name']] = $this->elementFactory->create('foreign', $referenceData); - } - - $tables[$tableName]->addConstraints($references); - } - - return $tables; - } - - /** - * Retrieve column objects from names. - * - * @param Column[] $columns - * @param array $data - * @return Column[] - */ - private function resolveInternalRelations(array $columns, array $data) - { - if (!is_array($data['column'])) { - throw new \InvalidArgumentException("Cannot find columns for internal index"); - } - - $referenceColumns = []; - foreach ($data['column'] as $columnName) { - if (!isset($columns[$columnName])) { - //Depends on business logic, can either ignore non-existing column - //or throw exception if db is not consistent and there is no column - //that was specified for key - } else { - $referenceColumns[] = $columns[$columnName]; - } - } - - return $referenceColumns; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/SchemaBuilder.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/SchemaBuilder.php deleted file mode 100644 index a724ed2ffdf0b..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Declaration/SchemaBuilder.php +++ /dev/null @@ -1,347 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Declaration; - -use Magento\Framework\Stdlib\BooleanUtils; -use Magento\Setup\Exception; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraint; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementFactory; -use Magento\Setup\Model\Declaration\Schema\Dto\Index; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\Sharding; - -/** - * This type of builder is responsible for converting ENTIRE data, that comes from XML - * into DTO`s format, with aggregation root: Schema. - * - * Note: SchemaBuilder can not be used for one structural element, like column or constraint - * because it should have references to other DTO objects. - * In order to convert build only 1 structural element use directly it factory. - * - * structure - * - table[N,] - * -column - * -constraint - * -internal (unique, primary, check, nullable) - * -reference (referenceTable=<DTO>, referenceColumn=<DTO>, ...) - * -index - */ -class SchemaBuilder -{ - /** - * @var array - */ - private $tablesData = []; - - /** - * @var Sharding - */ - private $sharding; - - /** - * @var ElementFactory - */ - private $elementFactory; - - /** - * @var BooleanUtils - */ - private $booleanUtils; - - /** - * @var ValidationComposite - */ - private $validationComposite; - - /** - * @var \Magento\Framework\App\ResourceConnection - */ - private $resourceConnection; - - /** - * SchemaBuilder constructor. - * - * @param ElementFactory $elementFactory - * @param BooleanUtils $booleanUtils - * @param Sharding $sharding - * @param ValidationComposite $validationComposite - * @param \Magento\Framework\App\ResourceConnection $resourceConnection - * @internal param array $tablesData - */ - public function __construct( - ElementFactory $elementFactory, - BooleanUtils $booleanUtils, - Sharding $sharding, - ValidationComposite $validationComposite, - \Magento\Framework\App\ResourceConnection $resourceConnection - ) { - $this->sharding = $sharding; - $this->elementFactory = $elementFactory; - $this->booleanUtils = $booleanUtils; - $this->validationComposite = $validationComposite; - $this->resourceConnection = $resourceConnection; - } - - /** - * Add tables data to builder. - * Tables data holds tables information: columns, constraints, indexes, attributes. - * - * @param array $tablesData - * @return self - */ - public function addTablesData(array $tablesData) - { - $this->tablesData = $tablesData; - return $this; - } - - /** - * Do schema validation and print all errors. - * - * @param Schema $schema - * @throws Exception - */ - private function validate(Schema $schema) - { - $errors = $this->validationComposite->validate($schema); - - if (!empty($errors)) { - $messages = ''; - foreach ($errors as $error) { - $messages .= sprintf("%s%s", PHP_EOL, $error['message']); - } - - throw new Exception($messages); - } - } - - /** - * Build schema. - * - * @param Schema $schema - * @throws Exception - * @return Schema - */ - public function build(Schema $schema) - { - foreach ($this->tablesData as $tableData) { - if (!$schema->getTableByName($tableData['name'])) { - if (!$this->isDisabled($tableData)) { - $this->processTable($schema, $tableData); - } - } - } - - $this->validate($schema); - - return $schema; - } - - /** - * Get resource for structural elements. - * - * @param array $tableData - * @return string - */ - private function getStructuralElementResource(array $tableData) - { - return isset($tableData['resource']) && $this->sharding->canUseResource($tableData['resource']) ? - $tableData['resource'] : 'default'; - } - - /** - * Check whether element is disabled and should not appear in final declaration. - * - * @param array $structuralElementData - * @return bool - */ - private function isDisabled($structuralElementData) - { - return isset($structuralElementData['disabled']) && - $this->booleanUtils->toBoolean($structuralElementData['disabled']); - } - - /** - * Instantiate column DTO objects from array. - * If column was renamed new key will be associated to it. - * - * @param array $tableData - * @param string $resource - * @param Table $table - * @return array - */ - private function processColumns(array $tableData, $resource, Table $table) - { - $columns = []; - - foreach ($tableData['column'] as $columnData) { - if ($this->isDisabled($columnData)) { - continue; - } - - $columnData = $this->processGenericData($columnData, $resource, $table); - $column = $this->elementFactory->create($columnData['type'], $columnData); - $columns[$column->getName()] = $column; - } - - return $columns; - } - - /** - * Process generic data that is support by all 3 child types: columns, constraints, indexes. - * - * @param array $elementData - * @param Table $table - * @param $resource - * @return array - */ - private function processGenericData(array $elementData, $resource, Table $table) - { - $elementData['table'] = $table; - $elementData['resource'] = $resource; - - return $elementData; - } - - /** - * Process tables and add them to schema. - * If table already exists - then we need to skip it. - * - * @param Schema $schema - * @param array $tableData - * @return \Magento\Setup\Model\Declaration\Schema\Dto\Table - */ - private function processTable(Schema $schema, array $tableData) - { - if (!$schema->getTableByName($tableData['name'])) { - $resource = $this->getStructuralElementResource($tableData); - $tableParams = [ - 'name' => $tableData['name'], - 'resource' => $resource, - 'engine' => $tableData['engine'] ?? null, - 'comment' => $tableData['comment'] ?? null - ]; - /** @var Table $table */ - $table = $this->elementFactory->create('table', $tableParams); - $columns = $this->processColumns($tableData, $resource, $table); - $table->addColumns($columns); - //Add indexes to table - $table->addIndexes($this->processIndexes($tableData, $resource, $table)); - //Add internal and reference constraints - $table->addConstraints($this->processConstraints($tableData, $resource, $schema, $table)); - $schema->addTable($table); - } - - return $schema->getTableByName($tableData['name']); - } - - /** - * Convert column names to objects. - * - * @param array $columnNames - * @param Table $table - * @return array - */ - private function convertColumnNamesToObjects(array $columnNames, Table $table) - { - $columns = []; - - foreach ($columnNames as $columnName) { - $columns[] = $table->getColumnByName($columnName); - } - - return $columns; - } - - /** - * Convert and instantiate index objects. - * - * @param array $tableData - * @param $resource - * @param Table $table - * @return Index[] - */ - private function processIndexes(array $tableData, $resource, Table $table) - { - if (!isset($tableData['index'])) { - return []; - } - - $indexes = []; - - foreach ($tableData['index'] as $indexData) { - if ($this->isDisabled($indexData)) { - continue; - } - - $indexData = $this->processGenericData($indexData, $resource, $table); - $indexData['columns'] = $this->convertColumnNamesToObjects($indexData['column'], $table); - $index = $this->elementFactory->create('index', $indexData); - $indexes[$index->getName()] = $index; - } - - return $indexes; - } - - /** - * Convert and instantiate constraint objects. - * - * @param array $tableData - * @param $resource - * @param Schema $schema - * @param Table $table - * @return Constraint[] - */ - private function processConstraints(array $tableData, $resource, Schema $schema, Table $table) - { - if (!isset($tableData['constraint'])) { - return []; - } - - $constraints = []; - - foreach ($tableData['constraint'] as $constraintData) { - if ($this->isDisabled($constraintData)) { - continue; - } - $constraintData = $this->processGenericData($constraintData, $resource, $table); - //As foreign constraint has different schema we need to process it in different way - if ($constraintData['type'] === 'foreign') { - $constraintData['column'] = $table->getColumnByName($constraintData['column']); - $referenceTableData = $this->tablesData[$constraintData['referenceTable']]; - //If we are referenced to the same table we need to specify it - //Get table name from resource connection regarding prefix settings - $refTableName = $this->resourceConnection->getTableName($referenceTableData['name']); - $referenceTable = $refTableName === $table->getName() ? - $table : - $this->processTable($schema, $referenceTableData); - - if ($referenceTable->getResource() !== $table->getResource()) { - continue; //we should avoid creating foreign keys - //for tables that are on another shard - } - $constraintData['referenceTable'] = $referenceTable; - - if (!$constraintData['referenceTable']) { - throw new \LogicException("Cannot find reference table"); - } - - $constraintData['referenceColumn'] = $constraintData['referenceTable']->getColumnByName( - $constraintData['referenceColumn'] - ); - $constraint = $this->elementFactory->create($constraintData['type'], $constraintData); - $constraints[$constraint->getName()] = $constraint; - } else { - $constraintData['columns'] = $this->convertColumnNamesToObjects($constraintData['column'], $table); - $constraint = $this->elementFactory->create($constraintData['type'], $constraintData); - $constraints[$constraint->getName()] = $constraint; - } - } - - return $constraints; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/DiffInterface.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/DiffInterface.php deleted file mode 100644 index 44ba0212c3688..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Diff/DiffInterface.php +++ /dev/null @@ -1,82 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Diff; - -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\Request; - -/** - * DiffInterface is type of classes, that holds all information - * that need to be changed from one installation to another. - */ -interface DiffInterface -{ - /** - * Retrieve operations by type. - * - * Please note: that we wants to save history and we retrieve next structure: - * [ - * 'column_a' => ElementHistory [ - * 'new' => [ - * ... - * ], - * 'old' => [ - * ... - * ] - * ] - * ] - * - * @return array - */ - public function getAll(); - - /** - * Register operation. - * - * @param ElementInterface|object $dtoObject - * @param string $operation - * @param ElementInterface $oldDtoObject - * @return void - */ - public function register( - ElementInterface $dtoObject, - $operation, - ElementInterface $oldDtoObject = null - ); - - /** - * Register current state of schema to registry. - * - * @param Schema $schema - * @return void - */ - public function registerSchema(Schema $schema); - - /** - * Retrieve current schema object. - * - * @return Schema - */ - public function getCurrentSchemaState(); - - /** - * Return current installation request. - * - * @return Request - */ - public function getCurrentInstallationRequest(); - - /** - * Register installation request with all needed options. - * - * @param Request $request - * @return void - */ - public function registerInstallationRequest(Request $request); -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Blob.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Blob.php deleted file mode 100644 index a31515f10001d..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Blob.php +++ /dev/null @@ -1,69 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; - -/** - * This column represent binary type. - * We can have few binary types: blob, mediumblob, longblob. - * Declared in SQL, like blob. - */ -class Blob extends Column implements - ElementDiffAwareInterface, - ColumnNullableAwareInterface -{ - /** - * @var bool - */ - private $nullable; - - /** - * Constructor. - * - * @param string $name - * @param string $type - * @param Table $table - * @param bool $nullable - * @param string|null $comment - * @param string|null $onCreate - */ - public function __construct( - string $name, - string $type, - Table $table, - bool $nullable = true, - string $comment = null, - string $onCreate = null - ) { - parent::__construct($name, $type, $table, $comment, $onCreate); - $this->nullable = $nullable; - } - - /** - * Check whether column can be nullable. - * - * @return bool - */ - public function isNullable() - { - return $this->nullable; - } - - /** - * @inheritdoc - */ - public function getDiffSensitiveParams() - { - return [ - 'type' => $this->getType(), - 'nullable' => $this->isNullable(), - 'comment' => $this->getComment() - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Boolean.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Boolean.php deleted file mode 100644 index 4b678bf0c0170..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Boolean.php +++ /dev/null @@ -1,88 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; - -/** - * Boolean column. - * Declared in SQL, like TINYINT(1) or BOOL or BOOLEAN. Alias for integer or binary type. - */ -class Boolean extends Column implements - ElementDiffAwareInterface, - ColumnNullableAwareInterface, - ColumnDefaultAwareInterface -{ - /** - * @var bool - */ - private $nullable; - - /** - * @var bool - */ - private $default; - - /** - * Constructor. - * - * @param string $name - * @param string $type - * @param Table $table - * @param bool $nullable - * @param bool $default - * @param string|null $comment - * @param string|null $onCreate - */ - public function __construct( - string $name, - string $type, - Table $table, - bool $nullable = true, - bool $default = null, - string $comment = null, - string $onCreate = null - ) { - parent::__construct($name, $type, $table, $comment, $onCreate); - $this->nullable = $nullable; - $this->default = $default; - } - - /** - * Check whether column can be nullable. - * - * @return bool - */ - public function isNullable() - { - return $this->nullable; - } - - /** - * Return default value. - * Note: default value should be int. - * - * @return int|null - */ - public function getDefault() - { - return $this->default; - } - - /** - * @inheritdoc - */ - public function getDiffSensitiveParams() - { - return [ - 'nullable' => $this->isNullable(), - 'default' => $this->getDefault(), - 'comment' => $this->getComment() - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Date.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Date.php deleted file mode 100644 index 7406a7fb87fed..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Date.php +++ /dev/null @@ -1,68 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; - -/** - * Date column. - * Declared in SQL, like DATE. - * Does not have any additional params. - * Is represented like: YY:MM:DD. - */ -class Date extends Column implements - ElementDiffAwareInterface, - ColumnNullableAwareInterface -{ - /** - * @var bool - */ - private $nullable; - - /** - * Constructor. - * - * @param string $name - * @param string $type - * @param Table $table - * @param bool $nullable - * @param string|null $comment - * @param string|null $onCreate - */ - public function __construct( - string $name, - string $type, - Table $table, - bool $nullable = true, - string $comment = null, - string $onCreate = null - ) { - parent::__construct($name, $type, $table, $comment, $onCreate); - $this->nullable = $nullable; - } - - /** - * @inheritdoc - */ - public function getDiffSensitiveParams() - { - return [ - 'type' => $this->getType(), - 'nullable' => $this->isNullable(), - 'comment' => $this->getComment() - ]; - } - - /** - * {@inheritdoc} - */ - public function isNullable(): bool - { - return $this->nullable; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Integer.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Integer.php deleted file mode 100644 index 116e078da0e3e..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Integer.php +++ /dev/null @@ -1,149 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; - -/** - * Integer column. - * Declared in SQL, like INT(11) or BIGINT(20). - * Where digit is padding, how many zeros should be added before first non-zero digit. - */ -class Integer extends Column implements - ElementDiffAwareInterface, - ColumnUnsignedAwareInterface, - ColumnNullableAwareInterface, - ColumnIdentityAwareInterface, - ColumnDefaultAwareInterface -{ - /** - * @var bool - */ - private $nullable; - - /** - * @var int - */ - private $default; - - /** - * @var bool - */ - private $unsigned; - /** - * @var int - */ - private $padding; - /** - * @var bool - */ - private $identity; - - /** - * Constructor. - * - * @param string $name - * @param string $type - * @param Table $table - * @param int $padding - * @param bool $nullable - * @param bool $unsigned - * @param bool $identity - * @param float|int $default - * @param string|null $comment - * @param string|null $onCreate - * - * @SuppressWarnings(PHPMD.ExcessiveParameterList) - */ - public function __construct( - string $name, - string $type, - Table $table, - int $padding, - bool $nullable = true, - bool $unsigned = false, - bool $identity = false, - int $default = null, - string $comment = null, - string $onCreate = null - ) { - parent::__construct($name, $type, $table, $comment, $onCreate); - $this->nullable = $nullable; - $this->default = $default; - $this->unsigned = $unsigned; - $this->padding = $padding; - $this->identity = $identity; - } - - /** - * Column padding. - * - * @return int - */ - public function getPadding() - { - return $this->padding; - } - - /** - * Check whether column can be nullable. - * - * @return bool - */ - public function isNullable() - { - return $this->nullable; - } - - /** - * Return default value. - * Note: default value should be int. - * - * @return int | null - */ - public function getDefault() - { - return $this->default; - } - - /** - * Check whether element is unsigned or not. - * - * @return bool - */ - public function isUnsigned() - { - return $this->unsigned; - } - - /** - * Define whether column can be autoincrement or not. - * - * @return bool - */ - public function isIdentity() - { - return $this->identity; - } - - /** - * @inheritdoc - */ - public function getDiffSensitiveParams() - { - return [ - 'type' => $this->getType(), - 'nullable' => $this->isNullable(), - 'padding' => $this->getPadding(), - 'unsigned' => $this->isUnsigned(), - 'identity' => $this->isIdentity(), - 'default' => $this->getDefault(), - 'comment' => $this->getComment() - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Real.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Real.php deleted file mode 100644 index 92b83057ba119..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Real.php +++ /dev/null @@ -1,151 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; - -/** - * Real data column. - * Declared in SQL, like FLOAT(P, S), DOUBLE(P, S) or DECIMAL(P, S) - * where S - is scale, P - is precision. - * https://dev.mysql.com/doc/refman/5.7/en/precision-math-decimal-characteristics.html - */ -class Real extends Column implements - ElementDiffAwareInterface, - ColumnUnsignedAwareInterface, - ColumnNullableAwareInterface, - ColumnDefaultAwareInterface -{ - /** - * @var int - */ - private $precision; - - /** - * @var int - */ - private $scale; - - /** - * @var bool - */ - private $nullable; - - /** - * @var float - */ - private $default; - - /** - * @var bool - */ - private $unsigned; - - /** - * Constructor. - * - * @param string $name - * @param string $type - * @param Table $table - * @param int $precision - * @param int $scale - * @param bool $nullable - * @param bool $unsigned - * @param float $default - * @param string|null $comment - * @param string|null $onCreate - * - * @SuppressWarnings(PHPMD.ExcessiveParameterList) - */ - public function __construct( - string $name, - string $type, - Table $table, - int $precision, - int $scale, - bool $nullable = true, - bool $unsigned = false, - float $default = null, - string $comment = null, - string $onCreate = null - ) { - parent::__construct($name, $type, $table, $comment, $onCreate); - $this->precision = $precision; - $this->scale = $scale; - $this->nullable = $nullable; - $this->default = $default; - $this->unsigned = $unsigned; - } - - /** - * Column precision. - * - * @return int - */ - public function getPrecision() - { - return (int)$this->precision; - } - - /** - * Column scale. - * - * @return int - */ - public function getScale() - { - return (int)$this->scale; - } - - /** - * Check whether column can be nullable. - * - * @return bool - */ - public function isNullable() - { - return (bool)$this->nullable; - } - - /** - * Return default value. - * Note: default value should be float. - * - * @return float|null - */ - public function getDefault() - { - return $this->default; - } - - /** - * Check whether element is unsigned or not. - * - * @return bool - */ - public function isUnsigned() - { - return (bool)$this->unsigned; - } - - /** - * @inheritdoc - */ - public function getDiffSensitiveParams() - { - return [ - 'type' => $this->getType(), - 'nullable' => $this->isNullable(), - 'precision' => $this->getPrecision(), - 'scale' => $this->getScale(), - 'unsigned' => $this->isUnsigned(), - 'default' => $this->getDefault(), - 'comment' => $this->getComment() - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/StringBinary.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/StringBinary.php deleted file mode 100644 index 39f83dba17a23..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/StringBinary.php +++ /dev/null @@ -1,109 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; - -/** - * String or Binary column. - * Declared in SQL, like VARCHAR(L), BINARY(L) - * where L - length. - */ -class StringBinary extends Column implements - ElementDiffAwareInterface, - ColumnNullableAwareInterface, - ColumnDefaultAwareInterface -{ - /** - * @var bool - */ - private $nullable; - - /** - * @var int - */ - private $default; - - /** - * @var int - */ - private $length; - - /** - * Constructor. - * - * @param string $name - * @param string $type - * @param Table $table - * @param int $length - * @param bool $nullable - * @param string $default - * @param string|null $comment - * @param string|null $onCreate - */ - public function __construct( - string $name, - string $type, - Table $table, - int $length, - bool $nullable = true, - string $default = null, - string $comment = null, - string $onCreate = null - ) { - parent::__construct($name, $type, $table, $comment, $onCreate); - $this->nullable = $nullable; - $this->default = $default; - $this->length = $length; - } - - /** - * Check whether column can be nullable. - * - * @return bool - */ - public function isNullable() - { - return $this->nullable; - } - - /** - * Return default value. - * Note: default value should be string. - * - * @return string | null - */ - public function getDefault() - { - return $this->default; - } - - /** - * Length can be integer value from 0 to 255. - * - * @return int - */ - public function getLength() - { - return $this->length; - } - - /** - * @inheritdoc - */ - public function getDiffSensitiveParams() - { - return [ - 'type' => $this->getType(), - 'nullable' => $this->isNullable(), - 'default' => $this->getDefault(), - 'length' => $this->getLength(), - 'comment' => $this->getComment() - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Text.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Text.php deleted file mode 100644 index 216c2aadf601b..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Text.php +++ /dev/null @@ -1,68 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; - -/** - * Text column. - * Declared in SQL, like: TEXT, TINYTEXT, MEDIUMTEXT, LONGTEXT. - */ -class Text extends Column implements - ElementDiffAwareInterface, - ColumnNullableAwareInterface -{ - /** - * @var bool - */ - private $nullable; - - /** - * Constructor. - * - * @param string $name - * @param string $type - * @param Table $table - * @param bool $nullable - * @param string|null $comment - * @param string|null $onCreate - */ - public function __construct( - string $name, - string $type, - Table $table, - bool $nullable = true, - string $comment = null, - string $onCreate = null - ) { - parent::__construct($name, $type, $table, $comment, $onCreate); - $this->nullable = $nullable; - } - - /** - * Check whether column can be nullable. - * - * @return bool - */ - public function isNullable() - { - return $this->nullable; - } - - /** - * @inheritdoc - */ - public function getDiffSensitiveParams() - { - return [ - 'type' => $this->getType(), - 'nullable' => $this->isNullable(), - 'comment' => $this->getComment() - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Timestamp.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Timestamp.php deleted file mode 100644 index 30aa212ffca2b..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Columns/Timestamp.php +++ /dev/null @@ -1,105 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Columns; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; - -/** - * Timestamp column. - * Declared in SQL, like Timestamp. - * Has 2 additional params: default and on_update. - */ -class Timestamp extends Column implements - ElementDiffAwareInterface, - ColumnDefaultAwareInterface, - ColumnNullableAwareInterface -{ - /** - * @var string - */ - private $default; - - /** - * @var null|string - */ - private $onUpdate; - - /** - * @var bool - */ - private $nullable; - - /** - * Constructor. - * - * @param string $name - * @param string $type - * @param Table $table - * @param string $default - * @param bool $nullable - * @param string|null $onUpdate - * @param string|null $comment - * @param string|null $onCreate - */ - public function __construct( - string $name, - string $type, - Table $table, - string $default, - bool $nullable = true, - string $onUpdate = null, - string $comment = null, - string $onCreate = null - ) { - parent::__construct($name, $type, $table, $comment, $onCreate); - $this->default = $default; - $this->onUpdate = $onUpdate; - $this->nullable = $nullable; - } - - /** - * Return default value. - * - * @return int|null - */ - public function getDefault() - { - return $this->default; - } - - /** - * Retrieve on_update param. - * - * @return string - */ - public function getOnUpdate() - { - return $this->onUpdate; - } - - /** - * @inheritdoc - */ - public function getDiffSensitiveParams() - { - return [ - 'type' => $this->getType(), - 'default' => $this->getDefault(), - 'onUpdate' => $this->getOnUpdate(), - 'comment' => $this->getComment() - ]; - } - - /** - * {@inheritdoc} - */ - public function isNullable(): bool - { - return $this->nullable; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Constraints/Internal.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Constraints/Internal.php deleted file mode 100644 index 88d0a9a538b6f..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Constraints/Internal.php +++ /dev/null @@ -1,82 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Constraints; - -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraint; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementDiffAwareInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; - -/** - * Internal key constraint is constraint that add KEY onto table columns, on which it is declared. - * All columns that are holded in this constraint are represented as unique vector. - */ -class Internal extends Constraint implements ElementDiffAwareInterface -{ - /** - * As we can have only one primary key. It name should be always PRIMARY/ - */ - const PRIMARY_NAME = "PRIMARY"; - - /** - * @var array - */ - private $columns; - - /** - * Internal constructor. - * - * @param string $name - * @param string $type - * @param Table $table - * @param array $columns - */ - public function __construct( - $name, - $type, - Table $table, - array $columns - ) { - parent::__construct($name, $type, $table); - $this->columns = $columns; - } - - /** - * Get key columns. - * - * @return Column[] - */ - public function getColumns() - { - return $this->columns; - } - - /** - * Retrieve column names. - * - * @return array - */ - public function getColumnNames() - { - return array_map( - function (Column $column) { - return $column->getName(); - }, - $this->getColumns() - ); - } - - /** - * @inheritdoc - */ - public function getDiffSensitiveParams() - { - return [ - 'type' => $this->getType(), - 'columns' => $this->getColumnNames() - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Blob.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Blob.php deleted file mode 100644 index 3a9b1cae06263..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Blob.php +++ /dev/null @@ -1,55 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Framework\ObjectManagerInterface; - -/** - * Blob factory. - */ -class Blob implements FactoryInterface -{ - /** - * Default blob length. - */ - const DEFAULT_BLOB_LENGTH = 65536; - - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $className; - - /** - * Constructor. - * - * @param ObjectManagerInterface $objectManager - * @param string $className - */ - public function __construct( - ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Blob::class - ) { - $this->objectManager = $objectManager; - $this->className = $className; - } - - /** - * {@inheritdoc} - */ - public function create(array $data) - { - if (!isset($data['length'])) { - $data['length'] = self::DEFAULT_BLOB_LENGTH; - } - - return $this->objectManager->create($this->className, $data); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Boolean.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Boolean.php deleted file mode 100644 index 442ab477924cf..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Boolean.php +++ /dev/null @@ -1,65 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Framework\ObjectManagerInterface; -use Magento\Framework\Stdlib\BooleanUtils; - -/** - * Boolean factory. - */ -class Boolean implements FactoryInterface -{ - /** - * Default value for boolean xsi:type. - */ - const DEFAULT_BOOLEAN = false; - - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $className; - - /** - * @var BooleanUtils - */ - private $booleanUtils; - - /** - * Constructor. - * - * @param ObjectManagerInterface $objectManager - * @param BooleanUtils $booleanUtils - * @param string $className - */ - public function __construct( - ObjectManagerInterface $objectManager, - BooleanUtils $booleanUtils, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Boolean::class - ) { - $this->objectManager = $objectManager; - $this->className = $className; - $this->booleanUtils = $booleanUtils; - } - - /** - * {@inheritdoc} - */ - public function create(array $data) - { - if (isset($data['default'])) { - $data['default'] = $this->booleanUtils->toBoolean($data['default']); - } - - return $this->objectManager->create($this->className, $data); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Date.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Date.php deleted file mode 100644 index 4356479f13845..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Date.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Framework\ObjectManagerInterface; - -/** - * Date factory. - * Remove default and nullable attributes, as date type must not have any attributes. - */ -class Date implements FactoryInterface -{ - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $className; - - /** - * Constructor. - * - * @param ObjectManagerInterface $objectManager - * @param string $className - */ - public function __construct( - ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Date::class - ) { - $this->objectManager = $objectManager; - $this->className = $className; - } - - /** - * {@inheritdoc} - */ - public function create(array $data) - { - return $this->objectManager->create($this->className, $data); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/FactoryInterface.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/FactoryInterface.php deleted file mode 100644 index 06bdf2c21c555..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/FactoryInterface.php +++ /dev/null @@ -1,22 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; - -/** - * DTO Element Factory Interface. - */ -interface FactoryInterface -{ - /** - * Create element using definition data array. - * - * @param array $data - * @return ElementInterface - */ - public function create(array $data); -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Index.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Index.php deleted file mode 100644 index d040a7ae00e98..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Index.php +++ /dev/null @@ -1,55 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Framework\ObjectManagerInterface; - -/** - * Index element factory. - */ -class Index implements FactoryInterface -{ - /** - * Default index type. - */ - const DEFAULT_INDEX_TYPE = "BTREE"; - - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $className; - - /** - * Constructor. - * - * @param ObjectManagerInterface $objectManager - * @param string $className - */ - public function __construct( - ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Index::class - ) { - $this->objectManager = $objectManager; - $this->className = $className; - } - - /** - * {@inheritdoc} - */ - public function create(array $data) - { - if (!isset($data['indexType'])) { - $data['indexType'] = self::DEFAULT_INDEX_TYPE; - } - - return $this->objectManager->create($this->className, $data); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Integer.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Integer.php deleted file mode 100644 index e66681fb700de..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Integer.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Framework\ObjectManagerInterface; - -/** - * Integer DTO element factory. - */ -class Integer implements FactoryInterface -{ - /** - * Describe default for different integer types. - * - * @var array - */ - private static $defaultPadding = [ - 'int' => '11', - 'tinyint' => '2', - 'smallint' => '5', - 'bigint' => '20' - ]; - - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $className; - - /** - * Constructor. - * - * @param ObjectManagerInterface $objectManager - * @param string $className - */ - public function __construct( - ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer::class - ) { - $this->objectManager = $objectManager; - $this->className = $className; - } - - /** - * {@inheritdoc} - */ - public function create(array $data) - { - if (!isset($data['padding'])) { - $data['padding'] = self::$defaultPadding[$data['type']]; - } - //Auto increment field can`t be null - if (isset($data['identity']) && $data['identity']) { - $data['nullable'] = false; - } - - if (isset($data['default'])) { - $data['default'] = (int) $data['default']; - } - - return $this->objectManager->create($this->className, $data); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Real.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Real.php deleted file mode 100644 index 9af53fb05b8f6..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Real.php +++ /dev/null @@ -1,71 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Framework\ObjectManagerInterface; - -/** - * Real type DTO element factory. - * - * Used for real numbers DTO elements like decimal, float or double. - * Decimal type is highly recommended for business math. - */ -class Real implements FactoryInterface -{ - /** - * Default SQL precision. - */ - const DEFAULT_PRECISION = "10"; - - /** - * Default SQL scale. - */ - const DEFAULT_SCALE = "0"; - - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $className; - - /** - * Constructor. - * - * @param ObjectManagerInterface $objectManager - * @param string $className - */ - public function __construct( - ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Real::class - ) { - $this->objectManager = $objectManager; - $this->className = $className; - } - - /** - * {@inheritdoc} - */ - public function create(array $data) - { - if (!isset($data['precision'])) { - $data['precision'] = ($data['type'] === 'decimal') ? self::DEFAULT_PRECISION : 0; - } - - if (!isset($data['scale'])) { - $data['scale'] = ($data['type'] === 'decimal') ? self::DEFAULT_SCALE : 0; - } - - if (isset($data['default'])) { - $data['default'] = floatval($data['default']); - } - - return $this->objectManager->create($this->className, $data); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/StringBinary.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/StringBinary.php deleted file mode 100644 index f87e291b6945f..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/StringBinary.php +++ /dev/null @@ -1,54 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Framework\ObjectManagerInterface; - -/** - * StringBinary DTO element factory. - * - * Used for char, varchar, binary, varbinary types. - */ -class StringBinary implements FactoryInterface -{ - /** - * Default data length. - */ - const DEFAULT_TEXT_LENGTH = 255; - - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $className; - - /** - * Constructor. - * - * @param ObjectManagerInterface $objectManager - * @param string $className - */ - public function __construct( - ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\StringBinary::class - ) { - $this->objectManager = $objectManager; - $this->className = $className; - } - - /** - * {@inheritdoc} - */ - public function create(array $data) - { - $data['length'] = isset($data['length']) ? (int) $data['length'] : self::DEFAULT_TEXT_LENGTH; - return $this->objectManager->create($this->className, $data); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Table.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Table.php deleted file mode 100644 index b9655fccdeafe..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Table.php +++ /dev/null @@ -1,67 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\ObjectManagerInterface; - -/** - * Table DTO element factory. - */ -class Table implements FactoryInterface -{ - /** - * Default engine. - * May be overriden for another DBMS. - */ - const DEFAULT_ENGINE = 'innodb'; - - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $className; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * Constructor. - * - * @param ObjectManagerInterface $objectManager - * @param ResourceConnection $resourceConnection - * @param string $className - */ - public function __construct( - ObjectManagerInterface $objectManager, - ResourceConnection $resourceConnection, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Table::class - ) { - $this->objectManager = $objectManager; - $this->className = $className; - $this->resourceConnection = $resourceConnection; - } - - /** - * {@inheritdoc} - */ - public function create(array $data) - { - if ($data['engine'] === null) { - $data['engine'] = self::DEFAULT_ENGINE; - } - $data['nameWithoutPrefix'] = $data['name']; - $data['name'] = $this->resourceConnection->getTableName($data['name']); - return $this->objectManager->create($this->className, $data); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Text.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Text.php deleted file mode 100644 index 32663e9f43a08..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Text.php +++ /dev/null @@ -1,55 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Framework\ObjectManagerInterface; - -/** - * Text DTO element factory. - */ -class Text implements FactoryInterface -{ - /** - * Default text length. - */ - const DEFAULT_TEXT_LENGTH = 65536; - - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $className; - - /** - * Constructor. - * - * @param ObjectManagerInterface $objectManager - * @param string $className - */ - public function __construct( - ObjectManagerInterface $objectManager, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Text::class - ) { - $this->objectManager = $objectManager; - $this->className = $className; - } - - /** - * {@inheritdoc} - */ - public function create(array $data) - { - if (!isset($data['length'])) { - $data['length'] = self::DEFAULT_TEXT_LENGTH; - } - - return $this->objectManager->create($this->className, $data); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Timestamp.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Timestamp.php deleted file mode 100644 index 51ab394d7f082..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Factories/Timestamp.php +++ /dev/null @@ -1,82 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto\Factories; - -use Magento\Framework\ObjectManagerInterface; -use Magento\Framework\Stdlib\BooleanUtils; - -/** - * Timestamp DTO element factory. - * - * This format is used to save date (year, month, day). - * Probably your SQL engine will save date in this format: 'YYYY-MM-DD HH:MM::SS' - * Date time in invalid format will be converted to '0000-00-00 00:00:00' string - * MySQL timestamp is similar to UNIX timestamp. You can pass you local time there and it will - * be converted to UTC timezone. Then when you will try to pull your time back it will be converted - * to your local time again. - * Unix range: 1970-01-01 00:00:01' UTC to '2038-01-09 03:14:07' - */ -class Timestamp implements FactoryInterface -{ - /** - * Nullable timestamp value. - */ - const NULL_TIMESTAMP = 'NULL'; - - /** - * @var ObjectManagerInterface - */ - private $objectManager; - - /** - * @var string - */ - private $className; - - /** - * @var BooleanUtils - */ - private $booleanUtils; - - /** - * Constructor. - * - * @param ObjectManagerInterface $objectManager - * @param BooleanUtils $booleanUtils - * @param string $className - */ - public function __construct( - ObjectManagerInterface $objectManager, - BooleanUtils $booleanUtils, - $className = \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp::class - ) { - $this->objectManager = $objectManager; - $this->className = $className; - $this->booleanUtils = $booleanUtils; - } - - /** - * {@inheritdoc} - */ - public function create(array $data) - { - $data['onUpdate'] = isset($data['on_update']) ? $data['on_update'] : null; - //OnUpdate is boolean as there is only one possible value for onUpdate statement. - if ($data['onUpdate'] && $data['onUpdate'] !== 'CURRENT_TIMESTAMP') { - if ($this->booleanUtils->toBoolean($data['onUpdate'])) { - $data['onUpdate'] = 'CURRENT_TIMESTAMP'; - } else { - unset($data['onUpdate']); - } - } - //By default default attribute is not used. - if (!isset($data['default'])) { - $data['default'] = self::NULL_TIMESTAMP; - } - - return $this->objectManager->create($this->className, $data); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Index.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Index.php deleted file mode 100644 index 0e2ce23e7712c..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Index.php +++ /dev/null @@ -1,126 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Model\Declaration\Schema\Dto; - -/** - * Index structural element. - * Used to speedup read operations from SQL database. - */ -class Index extends GenericElement implements - ElementInterface, - TableElementInterface, - ElementDiffAwareInterface -{ - /** - * Element type. - */ - const TYPE = 'index'; - - /** - * Fulltext index type. - */ - const FULLTEXT_INDEX = "fulltext"; - - /** - * @var Table - */ - private $table; - - /** - * @var array - */ - private $columns; - - /** - * @var string - */ - private $indexType; - - /** - * Constructor. - * - * @param string $name - * @param string $type - * @param Table $table - * @param array $columns - * @param string $indexType - */ - public function __construct( - string $name, - string $type, - Table $table, - array $columns, - string $indexType - ) { - parent::__construct($name, $type); - $this->table = $table; - $this->columns = $columns; - $this->indexType = $indexType; - } - - /** - * Return columns in order, in which they should go in composite index. - * - * @return Column[] - */ - public function getColumns() - { - return $this->columns; - } - - /** - * {@inheritdoc} - */ - public function getTable() - { - return $this->table; - } - - /** - * {@inheritdoc} - */ - public function getDiffSensitiveParams() - { - return [ - 'type' => $this->getType(), - 'columns' => $this->getColumnNames(), - 'indexType' => $this->getIndexType() - ]; - } - - /** - * Retrieve array with column names from column objects collections. - * - * @return array - */ - public function getColumnNames() - { - return array_map( - function (Column $column) { - return $column->getName(); - }, - $this->getColumns() - ); - } - - /** - * {@inheritdoc} - */ - public function getElementType() - { - return self::TYPE; - } - - /** - * Get index type (FULLTEXT, BTREE, HASH). - * - * @return string - */ - public function getIndexType() - { - return $this->indexType; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Table.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Table.php deleted file mode 100644 index 3ff4a7a755563..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Dto/Table.php +++ /dev/null @@ -1,300 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Dto; - -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Internal; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; - -/** - * Table structural element - * Aggregate inside itself: columns, constraints and indexes - * Resource is also specified on this strucural element - */ -class Table extends GenericElement implements - ElementInterface, - ElementDiffAwareInterface -{ - /** - * In case if we will need to change this object: add, modify or drop, we will need - * to define it by its type - */ - const TYPE = 'table'; - - /** - * @var Constraint[] - */ - private $constraints = []; - - /** - * @var Column[] - */ - private $columns = []; - - /** - * @var string - */ - protected $type = 'table'; - - /** - * @var Index[] - */ - private $indexes = []; - - /** - * @var string - */ - private $resource; - - /** - * @var string - */ - private $engine; - - /** - * @var string - */ - private $nameWithoutPrefix; - - /** - * @var null|string - */ - private $comment; - - /** - * @param string $name - * @param string $nameWithoutPrefix - * @param string $type - * @param string $resource - * @param string $engine - * @param string|null $comment - * @param array $columns - * @param array $indexes - * @param array $constraints - * @internal param string $nameWithPrefix - */ - public function __construct( - string $name, - string $nameWithoutPrefix, - string $type, - string $resource, - string $engine, - string $comment = null, - array $columns = [], - array $indexes = [], - array $constraints = [] - ) { - parent::__construct($name, $type); - $this->columns = $columns; - $this->indexes = $indexes; - $this->constraints = $constraints; - $this->resource = $resource; - $this->engine = $engine; - $this->nameWithoutPrefix = $nameWithoutPrefix; - $this->comment = $comment; - } - - /** - * Return different table constraints. - * It can be constraint like unique key or reference to another table, etc - * - * @return Constraint[] - */ - public function getConstraints() - { - return $this->constraints; - } - - /** - * @param string $name - * @return Constraint | bool - */ - public function getConstraintByName($name) - { - return isset($this->constraints[$name]) ? $this->constraints[$name] : false; - } - - /** - * This method lookup only for foreign keys constraints - * - * @return Reference[] - */ - public function getReferenceConstraints() - { - $constraints = []; - - foreach ($this->getConstraints() as $constraint) { - if ($constraint instanceof Reference) { - $constraints[$constraint->getName()] = $constraint; - } - } - - return $constraints; - } - - /** - * As primary constraint always have one name - * and can be only one for table - * it name is allocated into it constraint - * - * @return bool|Constraint - */ - public function getPrimaryConstraint() - { - return isset($this->constraints[Internal::PRIMARY_NAME]) ? - $this->constraints[Internal::PRIMARY_NAME] : - false; - } - - /** - * @param string $name - * @return Index | bool - */ - public function getIndexByName($name) - { - return isset($this->indexes[$name]) ? $this->indexes[$name] : false; - } - - /** - * Return all columns. - * Note, table always must have columns - * - * @return Column[] - */ - public function getColumns() - { - return $this->columns; - } - - /** - * Return all indexes, that are applied to table - * - * @return Index[] - */ - public function getIndexes() - { - return $this->indexes; - } - - /** - * Retrieve shard name, on which table will exists - * - * @return string - */ - public function getResource() - { - return $this->resource; - } - - /** - * This is workaround, as any DTO object couldnt be changed after instantiation. - * However there is case, when we have 2 tables with constraints in different tables, - * that depends to each other table. So we need to setup DTO first and only then pass - * problematic constraints to it, in order to avoid circular dependency. - * - * @param Constraint[] $constraints - */ - public function addConstraints(array $constraints) - { - $this->constraints = array_replace($this->constraints, $constraints); - } - - /** - * Add columns - * - * @param Column[] $columns - */ - public function addColumns(array $columns) - { - $this->columns = array_replace($this->columns, $columns); - } - - /** - * If column exists - retrieve column - * - * @param string $nameOrId - * @return Column - */ - public function getColumnByName($nameOrId) - { - if (isset($this->columns[$nameOrId])) { - return $this->columns[$nameOrId]; - } - - throw new \LogicException(sprintf("Cannot find column with name or id %s", $nameOrId)); - } - - /** - * Retrieve elements by specific type - * Allowed types: columns, constraints, indexes... - * - * @param string $type - * @return ElementInterface[] - */ - public function getElementsByType($type) - { - if (!isset($this->{$type})) { - throw new \InvalidArgumentException(sprintf("Type %s is not defined", $type)); - } - - return $this->{$type}; - } - - /** - * This is workaround, as any DTO object couldnt be changed after instantiation. - * However there is case, when we depends on column definition we need modify our indexes - * - * @param array $indexes - */ - public function addIndexes(array $indexes) - { - $this->indexes = array_replace($this->indexes, $indexes); - } - - /** - * @inheritdoc - */ - public function getElementType() - { - return self::TYPE; - } - - /** - * @return string - */ - public function getEngine(): string - { - return $this->engine; - } - - /** - * @inheritdoc - */ - public function getDiffSensitiveParams() - { - return [ - 'resource' => $this->getResource(), - 'engine' => $this->getEngine(), - 'comment' => $this->getComment() - ]; - } - - /** - * @return string - */ - public function getNameWithoutPrefix(): string - { - return $this->nameWithoutPrefix; - } - - /** - * @return null|string - */ - public function getComment() - { - return $this->comment; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/FileSystem/Csv.php b/setup/src/Magento/Setup/Model/Declaration/Schema/FileSystem/Csv.php deleted file mode 100644 index 01ddd11e963b9..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/FileSystem/Csv.php +++ /dev/null @@ -1,79 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\FileSystem; - -/** - * CSV file operations wrapper. - */ -class Csv -{ - /** - * Default batch size. - * - * @var int - */ - private $batchSize = 15000; - - /** - * Save to csv data with batches. - * - * @param string $file - * @param array $data - * @return $this - */ - public function save($file, array $data) - { - if (!count($data)) { - return $this; - } - - if (!file_exists($file)) { - array_unshift($data, array_keys($data[0])); - } - - $fh = fopen($file, 'a'); - - foreach ($data as $dataRow) { - fputcsv($fh, $dataRow); - } - - fclose($fh); - return $this; - } - - /** - * File read generator. - * - * @param string $file - * @return \Generator - */ - public function readGenerator($file) - { - $data = []; - if (!file_exists($file)) { - return; - } - - $iterator = 0; - $fh = fopen($file, 'r'); - yield fgetcsv($fh); - - while ($rowData = fgetcsv($fh)) { - if ($iterator++ > $this->batchSize) { - $iterator = 0; - $finalData = $data; - $data = []; - yield $finalData; - } - - $data[] = $rowData; - } - - fclose($fh); - yield $data; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/OperationInterface.php b/setup/src/Magento/Setup/Model/Declaration/Schema/OperationInterface.php deleted file mode 100644 index 56f35e274076d..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/OperationInterface.php +++ /dev/null @@ -1,40 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema; - -/** - * Schema operation interface. - */ -interface OperationInterface -{ - /** - * Retrieve operation identifier key. - * - * @return string - */ - public function getOperationName(); - - /** - * Is operation destructive flag. - * - * Destructive operations can make system unstable. - * - * For example, if operation is destructive it can remove table or column created not with - * declarative schema (for example with old migration script). - * - * @return bool - */ - public function isOperationDestructive(); - - /** - * Apply change of any type. - * - * @param ElementHistory $elementHistory - * @return array - */ - public function doOperation(ElementHistory $elementHistory); -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/DropElement.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/DropElement.php deleted file mode 100644 index 9b428c0b38632..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/DropElement.php +++ /dev/null @@ -1,88 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Operations; - -use Magento\Setup\Model\Declaration\Schema\Db\AdapterMediator; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DefinitionAggregator; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\TableElementInterface; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\OperationInterface; - -/** - * Drop element operation. - * - * Drops structural element. - */ -class DropElement implements OperationInterface -{ - /** - * Operation name. - */ - const OPERATION_NAME = 'drop_element'; - - /** - * @var DbSchemaWriterInterface - */ - private $dbSchemaWriter; - - /** - * @var DefinitionAggregator - */ - private $definitionAggregator; - - /** - * Constructor. - * - * @param DbSchemaWriterInterface $dbSchemaWriter - * @param DefinitionAggregator $definitionAggregator - */ - public function __construct( - DbSchemaWriterInterface $dbSchemaWriter, - DefinitionAggregator $definitionAggregator - ) { - $this->dbSchemaWriter = $dbSchemaWriter; - $this->definitionAggregator = $definitionAggregator; - } - - /** - * {@inheritdoc} - */ - public function getOperationName() - { - return self::OPERATION_NAME; - } - - /** - * {@inheritdoc} - */ - public function isOperationDestructive() - { - return true; - } - - /** - * {@inheritdoc} - */ - public function doOperation(ElementHistory $elementHistory) - { - /** - * @var TableElementInterface | ElementInterface $element - */ - $element = $elementHistory->getNew(); - - return [ - $this->dbSchemaWriter->dropElement( - $element->getTable()->getResource(), - $element->getName(), - $element->getTable()->getName(), - $element->getType() - ) - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/ModifyTable.php b/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/ModifyTable.php deleted file mode 100644 index e25d0cf3e6d61..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/Operations/ModifyTable.php +++ /dev/null @@ -1,76 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema\Operations; - -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\DefinitionAggregator; -use Magento\Setup\Model\Declaration\Schema\Dto\Column; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\ElementHistory; -use Magento\Setup\Model\Declaration\Schema\OperationInterface; - -/** - * Modify table operation. - * - * Used to change table options. - */ -class ModifyTable implements OperationInterface -{ - /** - * Operation name. - */ - const OPERATION_NAME = 'modify_table'; - - /** - * @var DbSchemaWriterInterface - */ - private $dbSchemaWriter; - - /** - * Constructor. - * - * @param DbSchemaWriterInterface $dbSchemaWriter - */ - public function __construct( - DbSchemaWriterInterface $dbSchemaWriter - ) { - $this->dbSchemaWriter = $dbSchemaWriter; - } - - /** - * {@inheritdoc} - */ - public function getOperationName() - { - return self::OPERATION_NAME; - } - - /** - * {@inheritdoc} - */ - public function isOperationDestructive() - { - return false; - } - - /** - * {@inheritdoc} - */ - public function doOperation(ElementHistory $elementHistory) - { - /** @var Table $table */ - $table = $elementHistory->getNew(); - return [ - $this->dbSchemaWriter->modifyTableOption( - $table->getName(), - $table->getResource(), - 'comment', - $table->getComment() - ) - ]; - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/OperationsExecutor.php b/setup/src/Magento/Setup/Model/Declaration/Schema/OperationsExecutor.php deleted file mode 100644 index 1f87e43185bca..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/OperationsExecutor.php +++ /dev/null @@ -1,162 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Model\Declaration\Schema; - -use Magento\Framework\App\ResourceConnection; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaWriterInterface; -use Magento\Setup\Model\Declaration\Schema\Db\StatementAggregatorFactory; -use Magento\Setup\Model\Declaration\Schema\Db\StatementFactory; -use Magento\Setup\Model\Declaration\Schema\Diff\DiffInterface; - -/** - * Schema operations executor. - * - * Go through all available SQL operations and execute each one with data from change registry. - */ -class OperationsExecutor -{ - /** - * @var OperationInterface[] - */ - private $operations; - - /** - * @var Sharding - */ - private $sharding; - - /** - * @var ResourceConnection - */ - private $resourceConnection; - - /** - * @var StatementFactory - */ - private $statementFactory; - - /** - * @var DbSchemaWriterInterface - */ - private $dbSchemaWriter; - - /** - * @var StatementAggregatorFactory - */ - private $statementAggregatorFactory; - - /** - * Constructor. - * - * @param array $operations - * @param Sharding $sharding - * @param ResourceConnection $resourceConnection - * @param StatementFactory $statementFactory - * @param DbSchemaWriterInterface $dbSchemaWriter - * @param StatementAggregatorFactory $statementAggregatorFactory - */ - public function __construct( - array $operations, - Sharding $sharding, - ResourceConnection $resourceConnection, - StatementFactory $statementFactory, - DbSchemaWriterInterface $dbSchemaWriter, - StatementAggregatorFactory $statementAggregatorFactory - ) { - $this->operations = $operations; - $this->sharding = $sharding; - $this->resourceConnection = $resourceConnection; - $this->statementFactory = $statementFactory; - $this->dbSchemaWriter = $dbSchemaWriter; - $this->statementAggregatorFactory = $statementAggregatorFactory; - } - - /** - * Retrieve only destructive operation names. - * - * For example, drop_table, recreate_table, etc. - * - * @return array - */ - public function getDestructiveOperations() - { - $operations = []; - - foreach ($this->operations as $operation) { - if ($operation->isOperationDestructive()) { - $operations[$operation->getOperationName()] = $operation->getOperationName(); - } - } - - return $operations; - } - - /** - * In order to successfully run all operations we need to start setup for all - * connections first. - * - * @return void - */ - private function startSetupForAllConnections() - { - foreach ($this->sharding->getResources() as $resource) { - $this->resourceConnection->getConnection($resource) - ->startSetup(); - $this->resourceConnection->getConnection($resource) - ->query('SET UNIQUE_CHECKS=0'); - } - } - - /** - * In order to revert previous state we need to end setup for all connections - * connections first. - * - * @return void - */ - private function endSetupForAllConnections() - { - foreach ($this->sharding->getResources() as $resource) { - $this->resourceConnection->getConnection($resource) - ->endSetup(); - } - } - - /** - * Loop through all operations that are configured in di.xml - * and execute them with elements from ChangeRegistry. - * - * @see OperationInterface - * @param DiffInterface $diff - * @return void - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - public function execute(DiffInterface $diff) - { - $this->startSetupForAllConnections(); - $tableHistories = $diff->getAll(); - if (is_array($tableHistories)) { - foreach ($tableHistories as $tableHistory) { - $statementAggregator = $this->statementAggregatorFactory->create(); - - foreach ($this->operations as $operation) { - if (isset($tableHistory[$operation->getOperationName()])) { - /** @var ElementHistory $elementHistory */ - foreach ($tableHistory[$operation->getOperationName()] as $elementHistory) { - $statementAggregator->addStatements( - $operation->doOperation($elementHistory) - ); - } - } - } - $this->dbSchemaWriter->compile($statementAggregator); - } - } - - $this->endSetupForAllConnections(); - } -} diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/schema.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/schema.xsd deleted file mode 100644 index 6b147e53ea4d4..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/schema.xsd +++ /dev/null @@ -1,77 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** -* Copyright © Magento, Inc. All rights reserved. -* See COPYING.txt for license details. -*/ ---> - -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> - <!--Types--> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/name.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/real/decimal.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/real/float.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/real/double.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/integers/integer.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/integers/biginteger.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/integers/smallinteger.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/integers/tinyinteger.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/texts/text.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/texts/longtext.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/texts/mediumtext.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/texts/varchar.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/binaries/blob.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/binaries/mediumblob.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/binaries/longblob.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/binaries/varbinary.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/datetime/timestamp.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/datetime/datetime.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/datetime/date.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/boolean.xsd" /> - <!--Constraints--> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/constraints/foreign.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/constraints/unique.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/constraints/primary.xsd" /> - <!--Indexes--> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/index.xsd" /> - - <xs:element name="schema"> - <xs:complexType> - <xs:sequence minOccurs="0" maxOccurs="unbounded"> - <xs:element name="table" type="table"/> - </xs:sequence> - </xs:complexType> - </xs:element> - - <xs:complexType name="table"> - <xs:annotation> - <xs:documentation> - Table definition. Here we can found column, constraints and indexes - </xs:documentation> - </xs:annotation> - <xs:choice minOccurs="0" maxOccurs="unbounded"> - <xs:element name="column" /> - <xs:element name="constraint" /> - <xs:element name="index" type="index" /> - </xs:choice> - <xs:attribute name="name" type="xs:string" /> - <xs:attribute name="resource" type="resourceType" /> - <xs:attribute name="engine" type="engineType" /> - <xs:attribute name="comment" type="xs:string" /> - </xs:complexType> - - <xs:simpleType name="resourceType"> - <xs:restriction base="xs:string"> - <xs:enumeration value="default" /> - <xs:enumeration value="quote" /> - <xs:enumeration value="sales" /> - </xs:restriction> - </xs:simpleType> - - <xs:simpleType name="engineType"> - <xs:restriction base="xs:string"> - <xs:enumeration value="innodb" /> - <xs:enumeration value="memory" /> - </xs:restriction> - </xs:simpleType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/blob.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/blob.xsd deleted file mode 100644 index ecb08869ed3df..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/blob.xsd +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="blob"> - <xs:annotation> - <xs:documentation> - Can be used as binary source - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/longblob.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/longblob.xsd deleted file mode 100644 index e23677467db17..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/longblob.xsd +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="longblob"> - <xs:annotation> - <xs:documentation> - Can be used as binary source. Different types can be used depends on data size - you want to persist - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/mediumblob.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/mediumblob.xsd deleted file mode 100644 index 2a693a7c0b131..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/mediumblob.xsd +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="mediumblob"> - <xs:annotation> - <xs:documentation> - Can be used as binary source - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/varbinary.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/varbinary.xsd deleted file mode 100644 index f366cc45a89b2..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/binaries/varbinary.xsd +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="varbinary"> - <xs:annotation> - <xs:documentation> - Can be used as binary source - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="length"> - <xs:simpleType> - <xs:restriction base="xs:integer"> - <xs:maxInclusive value="255"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="default" type="xs:string" /> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/boolean.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/boolean.xsd deleted file mode 100644 index 795ca8095aacb..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/boolean.xsd +++ /dev/null @@ -1,16 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd" /> - - <xs:complexType name="boolean"> - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="default" type="xs:boolean" /> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/date.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/date.xsd deleted file mode 100644 index 616111bea6200..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/date.xsd +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd" /> - - <xs:complexType name="date"> - <xs:annotation> - <xs:documentation> - This format is used to save date (year, month, day). - Probably your SQL engine will save date in this format: 'YYYY-MM-DD' - Dates in invalid format will be converted to '0000-00-00' string - </xs:documentation> - </xs:annotation> - - <xs:attribute name="nullable" type="xs:boolean" /> - <xs:attributeGroup ref="baseColumn" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/datetime.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/datetime.xsd deleted file mode 100644 index 6974ce4ded76a..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/datetime.xsd +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/datetime/default.xsd"/> - - <xs:complexType name="datetime"> - <xs:annotation> - <xs:documentation> - This format is used to save date (year, month, day). - Probably your SQL engine will save date in this format: 'YYYY-MM-DD HH:MM::SS' - Date time in invalid format will be converted to '0000-00-00 00:00:00' string - Supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59' - DateTime format save date and time in your local time zone - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attributeGroup ref="default" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/timestamp.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/timestamp.xsd deleted file mode 100644 index b2e8f77a1b910..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/datetime/timestamp.xsd +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd" /> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/datetime/default.xsd"/> - - <xs:complexType name="timestamp"> - <xs:annotation> - <xs:documentation> - This format is used to save date (year, month, day). - Probably your SQL engine will save date in this format: 'YYYY-MM-DD HH:MM::SS' - Date time in invalid format will be converted to '0000-00-00 00:00:00' string - MySQL timestamp is similar to UNIX timestamp. You can pass you local time there and it will - be converted to UTC timezone. Then when you will try to pull your time back it will be converted - to your local time again. - Unix range: 1970-01-01 00:00:01' UTC to '2038-01-09 03:14:07' - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attributeGroup ref="default" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/integer.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/integer.xsd deleted file mode 100644 index 3ca4992ca5e84..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/integers/integer.xsd +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="int"> - <xs:annotation> - <xs:documentation> - Serves needs in integer digits. Default padding is 11. - Size is 4 bytes. - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="default" type="xs:integer" /> - <xs:attribute name="padding"> - <xs:annotation> - <xs:documentation> - We can use padding only from 2, because padding 1 used for boolean type. - And we need to distinguish boolean and integer - </xs:documentation> - </xs:annotation> - <xs:simpleType> - <xs:restriction base="xs:integer"> - <xs:maxInclusive value="255" /> - <xs:minInclusive value="2" /> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="unsigned" type="xs:boolean" /> - <xs:attribute name="identity" type="xs:boolean" /> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/real/decimal.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/real/decimal.xsd deleted file mode 100644 index 3a5f58792c930..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/real/decimal.xsd +++ /dev/null @@ -1,43 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="decimal"> - <xs:annotation> - <xs:documentation> - A fixed point decimal fraction equal to SQL DECIMAL(PRECISION,SCALE) type, where - - SCALE is a size of number in fractional part, - - PRECISION is a whole size of decimal fraction. - Please use this type for business oriented math like price or qty storages. - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="default" type="xs:decimal" /> - <!--Note that scale must not be more than precision--> - <xs:attribute name="precision"> - <xs:simpleType> - <xs:restriction base="xs:integer"> - <xs:minInclusive value="0" /> - <xs:maxInclusive value="65" /> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="unsigned" type="xs:boolean" /> - <xs:attribute name="scale"> - <xs:simpleType> - <xs:restriction base="xs:integer"> - <xs:minInclusive value="0" /> - <xs:maxInclusive value="30" /> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/real/float.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/real/float.xsd deleted file mode 100644 index 601c29a0e32af..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/real/float.xsd +++ /dev/null @@ -1,42 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="float"> - <xs:annotation> - <xs:documentation> - A floating point binary value with single precision. Has rounding issues. - Float is good for scientific calculations. - For business oriented math like price or qty storages please use decimal type. - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="default" type="xs:float" /> - <!--Note that scale must not be more than precision--> - <xs:attribute name="precision"> - <xs:simpleType> - <xs:restriction base="xs:integer"> - <xs:minInclusive value="0" /> - <xs:maxInclusive value="255" /> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="scale"> - <xs:simpleType> - <xs:restriction base="xs:integer"> - <xs:minInclusive value="0" /> - <xs:maxInclusive value="253" /> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="nullable" type="xs:boolean" /> - <xs:attribute name="unsigned" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/longtext.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/longtext.xsd deleted file mode 100644 index 31980b8b0ea93..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/longtext.xsd +++ /dev/null @@ -1,21 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="longtext"> - <xs:annotation> - <xs:documentation> - Here plain text can be persisted. Length of this field is more than more than 16777216 - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/mediumtext.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/mediumtext.xsd deleted file mode 100644 index aeab7b633ee9a..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/mediumtext.xsd +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="mediumtext"> - <xs:annotation> - <xs:documentation> - Here plain text can be persisted. Length of this field is more than 65536 characters - and less than 16777216 - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/text.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/text.xsd deleted file mode 100644 index 9e2aa1c536ea5..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/text.xsd +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="text"> - <xs:annotation> - <xs:documentation> - Here plain text can be persisted. Length of this field is more than 255 characters - and less than 65536 - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/varchar.xsd b/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/varchar.xsd deleted file mode 100644 index 6ac1c7bfacdba..0000000000000 --- a/setup/src/Magento/Setup/Model/Declaration/Schema/etc/types/texts/varchar.xsd +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ ---> -<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> - <xs:include schemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/types/column.xsd"/> - - <xs:complexType name="varchar"> - <xs:annotation> - <xs:documentation> - Varchar is the small text field. It do not have max length. But we suppose, that this field can be used for - string columns that are in role of some key, like customer email or product sku. We add limitation for 1024 characters - on this type. This limitation is justified by SQL engine limitations, like {max sort size} or {max index size}. - For example, in MySQL, default max sort size (max_sort_length) is 1024 symbols. - </xs:documentation> - </xs:annotation> - - <xs:attributeGroup ref="baseColumn" /> - <xs:attribute name="length"> - <xs:simpleType> - <xs:restriction base="xs:integer"> - <xs:maxInclusive value="1024"/> - </xs:restriction> - </xs:simpleType> - </xs:attribute> - <xs:attribute name="default" type="xs:string" /> - <xs:attribute name="nullable" type="xs:boolean" /> - </xs:complexType> -</xs:schema> diff --git a/setup/src/Magento/Setup/Model/DeclarationInstaller.php b/setup/src/Magento/Setup/Model/DeclarationInstaller.php index 0c58d1dffe45f..52c360251c25a 100644 --- a/setup/src/Magento/Setup/Model/DeclarationInstaller.php +++ b/setup/src/Magento/Setup/Model/DeclarationInstaller.php @@ -5,10 +5,10 @@ */ namespace Magento\Setup\Model; -use Magento\Setup\Model\Declaration\Schema\Diff\SchemaDiff; -use Magento\Setup\Model\Declaration\Schema\OperationsExecutor; -use Magento\Setup\Model\Declaration\Schema\RequestFactory; -use Magento\Setup\Model\Declaration\Schema\SchemaConfigInterface; +use Magento\Framework\Setup\Declaration\Schema\Diff\SchemaDiff; +use Magento\Framework\Setup\Declaration\Schema\OperationsExecutor; +use Magento\Framework\Setup\Declaration\Schema\RequestFactory; +use Magento\Framework\Setup\Declaration\Schema\SchemaConfigInterface; /** * Declaration Installer is facade for installation and upgrade db in declaration mode. @@ -66,10 +66,6 @@ public function installSchema(array $requestData) $declarativeSchema = $this->schemaConfig->getDeclarationConfig(); $dbSchema = $this->schemaConfig->getDbConfig(); $diff = $this->schemaDiff->diff($declarativeSchema, $dbSchema); - $diff->registerSchema($declarativeSchema); - $diff->registerInstallationRequest( - $this->requestFactory->create($requestData) - ); - $this->operationsExecutor->execute($diff); + $this->operationsExecutor->execute($diff, $requestData); } } diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php index 7ae5f170d5b89..a7dc4dd1e6099 100644 --- a/setup/src/Magento/Setup/Model/Installer.php +++ b/setup/src/Magento/Setup/Model/Installer.php @@ -22,11 +22,13 @@ use Magento\Framework\Model\ResourceModel\Db\Context; use Magento\Framework\Module\ModuleList\Loader as ModuleLoader; use Magento\Framework\Module\ModuleListInterface; +use Magento\Framework\Setup\Declaration\Schema\DryRunLogger; use Magento\Framework\Setup\FilePermissions; use Magento\Framework\Setup\InstallDataInterface; use Magento\Framework\Setup\InstallSchemaInterface; use Magento\Framework\Setup\LoggerInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\PatchApplierInterface; use Magento\Framework\Setup\SchemaPersistor; use Magento\Framework\Setup\SchemaSetupInterface; use Magento\Framework\Setup\UpgradeDataInterface; @@ -34,6 +36,8 @@ use Magento\Setup\Console\Command\InstallCommand; use Magento\Setup\Controller\ResponseTypeInterface; use Magento\Setup\Model\ConfigModel as SetupConfigModel; +use Magento\Framework\Setup\Patch\PatchApplier; +use Magento\Framework\Setup\Patch\PatchApplierFactory; use Magento\Setup\Module\ConnectionFactory; use Magento\Setup\Module\DataSetupFactory; use Magento\Setup\Module\SetupFactory; @@ -234,6 +238,11 @@ class Installer */ private $schemaPersistor; + /** + * @var PatchApplierFactory + */ + private $patchApplierFactory; + /** * Constructor * @@ -283,8 +292,7 @@ public function __construct( DataSetupFactory $dataSetupFactory, \Magento\Framework\Setup\SampleData\State $sampleDataState, ComponentRegistrar $componentRegistrar, - PhpReadinessCheck $phpReadinessCheck, - DeclarationInstaller $declarationInstaller = null + PhpReadinessCheck $phpReadinessCheck ) { $this->filePermissions = $filePermissions; $this->deploymentConfigWriter = $deploymentConfigWriter; @@ -308,9 +316,6 @@ public function __construct( $this->sampleDataState = $sampleDataState; $this->componentRegistrar = $componentRegistrar; $this->phpReadinessCheck = $phpReadinessCheck; - $this->declarationInstaller = $declarationInstaller ?: $this->objectManagerProvider->get()->get( - DeclarationInstaller::class - ); $this->schemaPersistor = $this->objectManagerProvider->get()->get(SchemaPersistor::class); } @@ -333,7 +338,7 @@ public function install($request) $script[] = ['Installing database schema:', 'installSchema', [$request]]; $script[] = ['Installing user configuration...', 'installUserConfig', [$request]]; $script[] = ['Enabling caches:', 'enableCaches', []]; - $script[] = ['Installing data...', 'installDataFixtures', []]; + $script[] = ['Installing data...', 'installDataFixtures', [$request]]; if (!empty($request[InstallCommand::INPUT_KEY_SALES_ORDER_INCREMENT_PREFIX])) { $script[] = [ 'Creating sales order increment prefix...', @@ -342,7 +347,10 @@ public function install($request) ]; } $script[] = ['Installing admin user...', 'installAdminUser', [$request]]; - $script[] = ['Caches clearing:', 'cleanCaches', []]; + + if (!$this->isDryRun($request)) { + $script[] = ['Caches clearing:', 'cleanCaches', [$request]]; + } $script[] = ['Disabling Maintenance Mode:', 'setMaintenanceMode', [0]]; $script[] = ['Post installation file permissions check...', 'checkApplicationFilePermissions', []]; $script[] = ['Write installation date...', 'writeInstallationDate', []]; @@ -372,6 +380,21 @@ public function install($request) } } + /** + * Get declaration installer. For upgrade process it must be created after deployment config update. + * + * @return DeclarationInstaller + */ + private function getDeclarationInstaller() + { + if (!$this->declarationInstaller) { + $this->declarationInstaller = $this->objectManagerProvider->get()->get( + DeclarationInstaller::class + ); + } + return $this->declarationInstaller; + } + /** * Writes installation date to the configuration * @@ -580,7 +603,6 @@ private function setupCoreTables(SchemaSetupInterface $setup) { /* @var $connection \Magento\Framework\DB\Adapter\AdapterInterface */ $connection = $setup->getConnection(); - $setup->startSetup(); $this->setupSessionTable($setup, $connection); @@ -782,7 +804,7 @@ private function setupFlagTable( */ public function declarativeInstallSchema(array $request) { - $this->declarationInstaller->installSchema($request); + $this->getDeclarationInstaller()->installSchema($request); } /** @@ -800,7 +822,7 @@ public function installSchema(array $request) $this->setupCoreTables($setup); $this->log->log('Schema creation/updates:'); $this->declarativeInstallSchema($request); - $this->handleDBSchemaData($setup, 'schema'); + $this->handleDBSchemaData($setup, 'schema', $request); /** @var Mysql $adapter */ $adapter = $setup->getConnection(); $schemaListener = $adapter->getSchemaListener(); @@ -826,16 +848,17 @@ private function convertationOfOldScriptsIsAllowed(array $request) /** * Installs data fixtures * + * @param array $request * @return void */ - public function installDataFixtures() + public function installDataFixtures(array $request = []) { $this->assertDbConfigExists(); $this->assertDbAccessible(); $setup = $this->dataSetupFactory->create(); $this->checkFilePermissionsForDbUpgrade(); $this->log->log('Data install/update:'); - $this->handleDBSchemaData($setup, 'data'); + $this->handleDBSchemaData($setup, 'data', $request); } /** @@ -871,12 +894,14 @@ private function throwExceptionForNotWritablePaths(array $paths) * * @param SchemaSetupInterface | ModuleDataSetupInterface $setup * @param string $type + * @param array $request * @return void * @throws \Magento\Setup\Exception * @SuppressWarnings(PHPMD.CyclomaticComplexity) * @SuppressWarnings(PHPMD.NPathComplexity) + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ - private function handleDBSchemaData($setup, $type) + private function handleDBSchemaData($setup, $type, array $request) { if (!(($type === 'schema') || ($type === 'data'))) { throw new \Magento\Setup\Exception("Unsupported operation type $type is requested"); @@ -890,7 +915,28 @@ private function handleDBSchemaData($setup, $type) /** @var Mysql $adapter */ $adapter = $setup->getConnection(); $schemaListener = $adapter->getSchemaListener(); + $this->patchApplierFactory = $this->objectManagerProvider->get()->create( + PatchApplierFactory::class, + [ + 'objectManager' => $this->objectManagerProvider->get() + ] + ); + /** @var PatchApplier $patchApplier */ + if ($type === 'schema') { + $patchApplier = $this->patchApplierFactory->create(['schemaSetup' => $setup]); + } elseif ($type === 'data') { + $patchApplier = $this->patchApplierFactory->create([ + 'moduleDataSetup' => $setup, + 'objectManager' => $this->objectManagerProvider->get() + ]); + } + foreach ($moduleNames as $moduleName) { + if ($this->isDryRun($request)) { + $this->log->log("Module '{$moduleName}':"); + $this->logProgress(); + continue; + } $schemaListener->setModuleName($moduleName); $this->log->log("Module '{$moduleName}':"); $configVer = $this->moduleList->getOne($moduleName)['setup_version']; @@ -903,11 +949,11 @@ private function handleDBSchemaData($setup, $type) if ($upgrader) { $this->log->logInline("Upgrading $type.. "); $upgrader->upgrade($setup, $moduleContextList[$moduleName]); - } - if ($type === 'schema') { - $resource->setDbVersion($moduleName, $configVer); - } elseif ($type === 'data') { - $resource->setDataVersion($moduleName, $configVer); + if ($type === 'schema') { + $resource->setDbVersion($moduleName, $configVer); + } elseif ($type === 'data') { + $resource->setDataVersion($moduleName, $configVer); + } } } } elseif ($configVer) { @@ -921,12 +967,25 @@ private function handleDBSchemaData($setup, $type) $this->log->logInline("Upgrading $type... "); $upgrader->upgrade($setup, $moduleContextList[$moduleName]); } + } + + if ($configVer) { if ($type === 'schema') { $resource->setDbVersion($moduleName, $configVer); } elseif ($type === 'data') { $resource->setDataVersion($moduleName, $configVer); } } + + /** + * Applying data patches after old upgrade data scripts + */ + if ($type === 'schema') { + $patchApplier->applySchemaPatch($moduleName); + } elseif ($type === 'data') { + $patchApplier->applyDataPatch($moduleName); + } + $this->logProgress(); } @@ -938,6 +997,11 @@ private function handleDBSchemaData($setup, $type) $handlerType = 'data-recurring'; } foreach ($moduleNames as $moduleName) { + if ($this->isDryRun($request)) { + $this->log->log("Module '{$moduleName}':"); + $this->logProgress(); + continue; + } $this->log->log("Module '{$moduleName}':"); $modulePostUpdater = $this->getSchemaDataHandler($moduleName, $handlerType); if ($modulePostUpdater) { @@ -962,6 +1026,18 @@ private function assertDbConfigExists() } } + /** + * Check whether Magento setup is run in dry-run mode + * + * @param array $request + * @return bool + */ + private function isDryRun(array $request) + { + return isset($request[DryRunLogger::INPUT_KEY_DRY_RUN_MODE]) && + $request[DryRunLogger::INPUT_KEY_DRY_RUN_MODE]; + } + /** * Installs user configuration * @@ -970,6 +1046,9 @@ private function assertDbConfigExists() */ public function installUserConfig($data) { + if ($this->isDryRun($data)) { + return; + } $userConfig = new StoreConfigurationDataMapper(); /** @var \Magento\Framework\App\State $appState */ $appState = $this->objectManagerProvider->get()->get(\Magento\Framework\App\State::class); @@ -1059,6 +1138,10 @@ private function installOrderIncrementPrefix($orderIncrementPrefix) */ public function installAdminUser($data) { + if ($this->isDryRun($data)) { + return; + } + $adminUserModuleIsInstalled = (bool)$this->deploymentConfig->get('modules/Magento_User'); //Admin user data is not system data, so we need to install it only if schema for admin user was installed if ($adminUserModuleIsInstalled) { diff --git a/setup/src/Magento/Setup/Model/InstallerFactory.php b/setup/src/Magento/Setup/Model/InstallerFactory.php index 15c68408f9564..0fb933dd46cb4 100644 --- a/setup/src/Magento/Setup/Model/InstallerFactory.php +++ b/setup/src/Magento/Setup/Model/InstallerFactory.php @@ -6,11 +6,9 @@ namespace Magento\Setup\Model; -use Magento\Setup\Model\Declaration\Schema\Generated\MysqlDumpSchemaParser; use Zend\ServiceManager\ServiceLocatorInterface; use Magento\Setup\Module\ResourceFactory; use Magento\Framework\App\ErrorHandler; -use Magento\Framework\App\State\CleanupFiles; use Magento\Framework\Setup\LoggerInterface; /** diff --git a/setup/src/Magento/Setup/Model/ModuleUninstaller.php b/setup/src/Magento/Setup/Model/ModuleUninstaller.php index b7d26b09a3754..55b866640b74e 100644 --- a/setup/src/Magento/Setup/Model/ModuleUninstaller.php +++ b/setup/src/Magento/Setup/Model/ModuleUninstaller.php @@ -5,6 +5,7 @@ */ namespace Magento\Setup\Model; +use Magento\Framework\Setup\Patch\PatchApplier; use Symfony\Component\Console\Output\OutputInterface; /** @@ -31,6 +32,10 @@ class ModuleUninstaller * @var \Magento\Setup\Module\SetupFactory */ private $setupFactory; + /** + * @var PatchApplier + */ + private $patchApplier; /** * Constructor @@ -39,6 +44,7 @@ class ModuleUninstaller * @param \Magento\Framework\Composer\Remove $remove * @param UninstallCollector $collector * @param \Magento\Setup\Module\SetupFactory $setupFactory + * @param PatchApplier $patchApplier */ public function __construct( ObjectManagerProvider $objectManagerProvider, @@ -52,6 +58,18 @@ public function __construct( $this->setupFactory = $setupFactory; } + /** + * @return PatchApplier + */ + private function getPatchApplier() + { + if (!$this->patchApplier) { + $this->patchApplier = $this->objectManager->get(PatchApplier::class); + } + + return $this->patchApplier; + } + /** * Invoke remove data routine in each specified module * @@ -71,9 +89,9 @@ public function uninstallData(OutputInterface $output, array $modules) $setupModel, new ModuleContext($resource->getDbVersion($module) ?: '') ); - } else { - $output->writeln("<info>No data to clear in $module</info>"); } + + $this->getPatchApplier()->revertDataPatches($module); } } diff --git a/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php index 6a798f3226570..37388f563e75b 100644 --- a/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php +++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php @@ -30,13 +30,21 @@ public function __construct(\Magento\Setup\Module\Di\Compiler\Log\Log $log) */ public function collectEntities(array $files) { + $virtualTypes = []; $output = []; + $factoriesOutput = []; foreach ($files as $file) { $dom = new \DOMDocument(); $dom->load($file); $xpath = new \DOMXPath($dom); $xpath->registerNamespace("php", "http://php.net/xpath"); $xpath->registerPhpFunctions('preg_match'); + $virtualTypeQuery = "//virtualType/@name"; + + foreach ($xpath->query($virtualTypeQuery) as $virtualNode) { + $virtualTypes[] = $virtualNode->nodeValue; + } + $regex = '/^(.*)\\\(.*)Proxy$/'; $query = "/config/preference[ php:functionString('preg_match', '{$regex}', @type) > 0]/@type | " . "//argument[@xsi:type='object' and php:functionString('preg_match', '{$regex}', text()) > 0] |" . @@ -46,9 +54,33 @@ public function collectEntities(array $files) foreach ($xpath->query($query) as $node) { $output[] = $node->nodeValue; } + + $factoriesOutput = array_merge($factoriesOutput, $this->scanFactories($xpath)); } + $output = array_unique($output); - return $this->_filterEntities($output); + $factoriesOutput = array_unique($factoriesOutput); + $factoriesOutput = array_diff($factoriesOutput, $virtualTypes); + return array_merge($this->_filterEntities($output), $factoriesOutput); + } + + /** + * Scan factories from all di.xml and retrieve non virtual one + * + * @param \DOMXPath $domXpath + * @return array + */ + private function scanFactories(\DOMXPath $domXpath) + { + $output = []; + $regex = '/^(.*)Factory$/'; + $query = "//argument[@xsi:type='object' and php:functionString('preg_match', '{$regex}', text()) > 0] |" . + "//item[@xsi:type='object' and php:functionString('preg_match', '{$regex}', text()) > 0]"; + foreach ($domXpath->query($query) as $node) { + $output[] = $node->nodeValue; + } + + return $output; } /** diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/DeployStaticContentCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/DeployStaticContentCommandTest.php index 772098627fa89..a5dc0d24feb7c 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/DeployStaticContentCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/DeployStaticContentCommandTest.php @@ -102,7 +102,7 @@ public function testExecute($input) $this->consoleLoggerFactory->expects($this->once()) ->method('getLogger')->willReturn($this->logger); - $this->logger->expects($this->exactly(2))->method('alert'); + $this->logger->expects($this->exactly(2))->method('notice'); $this->objectManager->expects($this->once())->method('create')->willReturn($this->deployService); $this->deployService->expects($this->once())->method('deploy'); diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php index 388aa0670e069..20bbb5902d4d2 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php @@ -7,6 +7,7 @@ use Magento\Framework\Component\ComponentRegistrar; use Magento\Setup\Console\Command\DiCompileCommand; +use Magento\Setup\Module\Di\App\Task\OperationFactory; use Symfony\Component\Console\Tester\CommandTester; /** @@ -61,6 +62,10 @@ public function setUp() $this->managerMock = $this->createMock(\Magento\Setup\Module\Di\App\Task\Manager::class); $this->directoryListMock = $this->createMock(\Magento\Framework\App\Filesystem\DirectoryList::class); + $this->directoryListMock->expects($this->any())->method('getPath')->willReturnMap([ + [\Magento\Framework\App\Filesystem\DirectoryList::SETUP, '/path (1)/to/setup/'], + ]); + $this->filesystemMock = $this->getMockBuilder(\Magento\Framework\Filesystem::class) ->disableOriginalConstructor() ->getMock(); @@ -70,8 +75,8 @@ public function setUp() ->getMock(); $this->componentRegistrarMock = $this->createMock(\Magento\Framework\Component\ComponentRegistrar::class); $this->componentRegistrarMock->expects($this->any())->method('getPaths')->willReturnMap([ - [ComponentRegistrar::MODULE, ['/path/to/module/one', '/path/to/module/two']], - [ComponentRegistrar::LIBRARY, ['/path/to/library/one', '/path/to/library/two']], + [ComponentRegistrar::MODULE, ['/path/to/module/one', '/path (1)/to/module/two']], + [ComponentRegistrar::LIBRARY, ['/path/to/library/one', '/path (1)/to/library/two']], ]); $this->command = new DiCompileCommand( @@ -128,7 +133,28 @@ public function testExecute() ->method('create') ->with(\Symfony\Component\Console\Helper\ProgressBar::class) ->willReturn($progressBar); - $this->managerMock->expects($this->exactly(7))->method('addOperation'); + + $this->managerMock->expects($this->exactly(7))->method('addOperation') + ->withConsecutive( + [OperationFactory::PROXY_GENERATOR, []], + [OperationFactory::REPOSITORY_GENERATOR, $this->anything()], + [OperationFactory::DATA_ATTRIBUTES_GENERATOR, []], + [OperationFactory::APPLICATION_CODE_GENERATOR, $this->callback(function ($subject) { + $this->assertEmpty(array_diff($subject['excludePatterns'], [ + "#^(?:/path \(1\)/to/setup/)(/[\w]+)*/Test#", + "#^(?:/path/to/library/one|/path \(1\)/to/library/two)/([\w]+/)?Test#", + "#^(?:/path/to/library/one|/path \(1\)/to/library/two)/([\w]+/)?tests#", + "#^(?:/path/to/(?:module/(?:one))|/path \(1\)/to/(?:module/(?:two)))/Test#", + "#^(?:/path/to/(?:module/(?:one))|/path \(1\)/to/(?:module/(?:two)))/tests#" + ])); + return true; + })], + [OperationFactory::INTERCEPTION, $this->anything()], + [OperationFactory::AREA_CONFIG_GENERATOR, $this->anything()], + [OperationFactory::INTERCEPTION_CACHE, $this->anything()] + ) + ; + $this->managerMock->expects($this->once())->method('process'); $tester = new CommandTester($this->command); $tester->execute([]); diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php index 88038c2e817c1..cce7a2e39adfc 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php @@ -66,6 +66,33 @@ public function testExecute(array $input, array $validatorMessages, $expectedMes $this->assertEquals($expectedMessage, $tester->getDisplay()); } + /** + * @param array $addressInfo + * @param array $input + * @param array $validatorMessages + * @param string $expectedMessage + * @dataProvider executeWithAddDataProvider + */ + public function testExecuteWithAdd(array $addressInfo, array $input, array $validatorMessages, $expectedMessage) + { + $newAddressInfo = array_unique(array_merge($addressInfo, $input['ip'])); + + $this->ipValidator->expects($this->once())->method('validateIps')->willReturn($validatorMessages); + $this->maintenanceMode + ->expects($this->once()) + ->method('setAddresses') + ->with(implode(',', $newAddressInfo)); + + $this->maintenanceMode + ->expects($this->exactly(2)) + ->method('getAddressInfo') + ->willReturnOnConsecutiveCalls($addressInfo, $newAddressInfo); + + $tester = new CommandTester($this->command); + $tester->execute($input); + $this->assertEquals($expectedMessage, $tester->getDisplay()); + } + /** * return array */ @@ -75,7 +102,7 @@ public function executeDataProvider() [ ['ip' => ['127.0.0.1', '127.0.0.2'], '--none' => false], [], - 'Set exempt IP-addresses: 127.0.0.1, 127.0.0.2' . PHP_EOL + 'Set exempt IP-addresses: 127.0.0.1 127.0.0.2' . PHP_EOL ], [ ['--none' => true], @@ -99,4 +126,31 @@ public function executeDataProvider() ] ]; } + + /** + * return array + */ + public function executeWithAddDataProvider() + { + return [ + [ + [], + ['ip' => ['127.0.0.1'], '--add' => true], + [], + 'Set exempt IP-addresses: 127.0.0.1' . PHP_EOL, + ], + [ + ['127.0.0.1'], + ['ip' => ['127.0.0.1'], '--add' => true], + [], + 'Set exempt IP-addresses: 127.0.0.1' . PHP_EOL, + ], + [ + ['127.0.0.1'], + ['ip' => ['127.0.0.2'], '--add' => true], + [], + 'Set exempt IP-addresses: 127.0.0.1 127.0.0.2' . PHP_EOL, + ], + ]; + } } diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceStatusCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceStatusCommandTest.php index 07f9990a0bb6f..0b36c86cf8ada 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceStatusCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceStatusCommandTest.php @@ -50,7 +50,7 @@ public function executeDataProvider() [ [true, ['127.0.0.1', '127.0.0.2']], 'Status: maintenance mode is active' . PHP_EOL . - 'List of exempt IP-addresses: 127.0.0.1, 127.0.0.2' . PHP_EOL + 'List of exempt IP-addresses: 127.0.0.1 127.0.0.2' . PHP_EOL ], [ [true, []], @@ -63,7 +63,7 @@ public function executeDataProvider() [ [false, ['127.0.0.1', '127.0.0.2']], 'Status: maintenance mode is not active' . PHP_EOL . - 'List of exempt IP-addresses: 127.0.0.1, 127.0.0.2' . PHP_EOL + 'List of exempt IP-addresses: 127.0.0.1 127.0.0.2' . PHP_EOL ], ]; } diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleUninstallCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleUninstallCommandTest.php index b6674c9aac986..c00d66eaed134 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleUninstallCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/ModuleUninstallCommandTest.php @@ -8,6 +8,7 @@ use Magento\Framework\App\Console\MaintenanceModeEnabler; use Magento\Setup\Console\Command\ModuleUninstallCommand; use Magento\Setup\Model\ModuleUninstaller; +use Magento\Framework\Setup\Patch\PatchApplier; use Symfony\Component\Console\Tester\CommandTester; /** @@ -96,6 +97,11 @@ class ModuleUninstallCommandTest extends \PHPUnit\Framework\TestCase */ private $tester; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $patchApplierMock; + /** * @SuppressWarnings(PHPMD.UnusedLocalVariable) */ @@ -130,6 +136,9 @@ public function setUp() '', false ); + $this->patchApplierMock = $this->getMockBuilder(PatchApplier::class) + ->disableOriginalConstructor() + ->getMock(); $configLoader->expects($this->any())->method('load')->willReturn([]); $objectManager->expects($this->any()) ->method('get') @@ -143,6 +152,7 @@ public function setUp() $this->createMock(\Magento\Framework\App\State::class) ], [\Magento\Framework\Setup\BackupRollbackFactory::class, $this->backupRollbackFactory], + [PatchApplier::class, $this->patchApplierMock], [\Magento\Framework\ObjectManager\ConfigLoaderInterface::class, $configLoader], ])); $composer = $this->createMock(\Magento\Framework\Composer\ComposerInformation::class); @@ -437,6 +447,18 @@ public function testExecuteRemoveData() $this->tester->execute($input); } + public function testExecuteNonComposerModules() + { + $this->deploymentConfig->expects(self::once()) + ->method('isAvailable') + ->willReturn(true); + $input = ['module' => ['Magento_A'], '-c' => true, '-r' => true, '--non-composer' => true]; + $this->patchApplierMock->expects(self::once()) + ->method('revertDataPatches') + ->with('Magento_A'); + self::assertEquals(0, $this->tester->execute($input)); + } + public function testExecuteAll() { $input = ['module' => ['Magento_A', 'Magento_B'], '-c' => true, '-r' => true]; diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php index 4058eefe0f8c1..6f32a68682606 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/UpgradeCommandTest.php @@ -104,7 +104,7 @@ public function executeDataProvider() [ 'options' => [ '--magento-init-params' => '', - '--convert_old_scripts' => false + '--convert_old_scripts' => false, ], 'deployMode' => \Magento\Framework\App\State::MODE_PRODUCTION, 'expectedString' => 'Please re-run Magento compile command. Use the command "setup:di:compile"' @@ -113,13 +113,16 @@ public function executeDataProvider() 'keep-generated' => false, 'convert_old_scripts' => false, 'magento-init-params' => '', + 'safe-mode' => false, + 'data-restore' => false, + 'dry-run' => false, ] ], [ 'options' => [ '--magento-init-params' => '', '--convert_old_scripts' => false, - '--keep-generated' => true + '--keep-generated' => true, ], 'deployMode' => \Magento\Framework\App\State::MODE_PRODUCTION, 'expectedString' => '', @@ -127,6 +130,9 @@ public function executeDataProvider() 'keep-generated' => true, 'convert_old_scripts' => false, 'magento-init-params' => '', + 'safe-mode' => false, + 'data-restore' => false, + 'dry-run' => false, ] ], [ @@ -137,6 +143,9 @@ public function executeDataProvider() 'keep-generated' => false, 'convert_old_scripts' => false, 'magento-init-params' => '', + 'safe-mode' => false, + 'data-restore' => false, + 'dry-run' => false, ] ], [ @@ -147,6 +156,9 @@ public function executeDataProvider() 'keep-generated' => false, 'convert_old_scripts' => false, 'magento-init-params' => '', + 'safe-mode' => false, + 'data-restore' => false, + 'dry-run' => false, ] ], ]; diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Style/MagentoStyleTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Style/MagentoStyleTest.php new file mode 100755 index 0000000000000..92aa43251ba26 --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Console/Style/MagentoStyleTest.php @@ -0,0 +1,287 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Test\Unit\Console\Style; + +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Setup\Console\Style\MagentoStyle; +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Formatter\OutputFormatter; +use Symfony\Component\Console\Helper\SymfonyQuestionHelper; +use Symfony\Component\Console\Helper\TableCell; +use Symfony\Component\Console\Input\ArrayInput; +use Symfony\Component\Console\Input\InputArgument; +use Symfony\Component\Console\Input\InputDefinition; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + +/** + * Provide tests for MagentoStyle output decorator. + */ +class MagentoStyleTest extends TestCase +{ + /** + * Test subject. + * + * @var MagentoStyle + */ + private $magentoStyle; + + /** + * Auxiliary class replacing console output. + * + * @var TestOutput + */ + private $testOutput; + + /** + * @inheritdoc + */ + protected function setUp() + { + $input = new ArrayInput(['name' => 'foo'], new InputDefinition([new InputArgument('name')])); + $this->testOutput = new TestOutput(); + $this->magentoStyle = new MagentoStyle($input, $this->testOutput); + } + + /** + * Test style decorator will output block with correct style. + * + * @return void + */ + public function testBlockStyle() + { + $this->magentoStyle->block( + ['test first message', 'test second message'], + 'testBlockType', + 'testBlockStyle', + 'testBlockPrefix' + ); + // @codingStandardsIgnoreStart + $expected = PHP_EOL . PHP_EOL . PHP_EOL . + '\<testBlockStyle\>testBlockPrefix\[testBlockType\] test first message\s+' + . PHP_EOL . '\<testBlockStyle\>testBlockPrefix\s+' + . PHP_EOL . '\<testBlockStyle\>testBlockPrefix \s+ test second message\s+' + . PHP_EOL . PHP_EOL; + // @codingStandardsIgnoreEnd + $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Block does not match output'); + } + + /** + * Test style decorator will add title with correct style. + * + * @return void + */ + public function testTitleStyle() + { + $this->magentoStyle->title('My Title'); + $expected = PHP_EOL . PHP_EOL . PHP_EOL . ' My Title' . PHP_EOL . ' ========' . PHP_EOL . PHP_EOL; + $this->assertEquals($expected, $this->testOutput->output, 'Title does not match output'); + } + + /** + * Test style decorator will output section with correct style. + * + * @return void + */ + public function testSectionStyle() + { + $this->magentoStyle->section('My Section'); + $expected = PHP_EOL . PHP_EOL . PHP_EOL . ' My Section' . PHP_EOL . ' ----------' . PHP_EOL . PHP_EOL; + $this->assertEquals($expected, $this->testOutput->output, 'Section does not match output'); + } + + /** + * Test style decorator will output listing with proper style. + * + * @return void + */ + public function testListingStyle() + { + $this->magentoStyle->listing(['test first element', 'test second element']); + $expected = PHP_EOL . ' * test first element' . PHP_EOL . ' * test second element' . PHP_EOL . PHP_EOL; + $this->assertEquals($expected, $this->testOutput->output, 'Listing does not match output'); + } + + /** + * Test style decorator will output text with proper style. + * + * @return void + */ + public function testTextStyle() + { + $this->magentoStyle->text('test message'); + $expected = PHP_EOL . ' test message' . PHP_EOL; + + $this->assertEquals($expected, $this->testOutput->output, 'Text does not match output'); + } + + /** + * Test style decorator will output comment with proper style. + * + * @return void + */ + public function testCommentStyle() + { + $this->magentoStyle->comment('test comment'); + $expected = PHP_EOL . PHP_EOL . PHP_EOL . '\s+test comment\s+' . PHP_EOL . PHP_EOL; + $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Comment does not match output'); + } + + /** + * Test style decorator will output success message with proper style. + * + * @return void + */ + public function testSuccessStyle() + { + $this->magentoStyle->success('test success message'); + $expected = PHP_EOL . PHP_EOL . PHP_EOL . ' \[SUCCESS\] test success message\s+' . PHP_EOL . PHP_EOL; + $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Success message does not match output'); + } + + /** + * Test style decorator will output error message with proper style. + * + * @return void + */ + public function testErrorStyle() + { + $this->magentoStyle->error('test error message'); + $expected = PHP_EOL . PHP_EOL . PHP_EOL . '\s+\[ERROR\] test error message\s+' . PHP_EOL . PHP_EOL; + $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Error message does not match output'); + } + + /** + * Test style decorator will output warning message with proper style. + * + * @return void + */ + public function testWarningStyle() + { + $this->magentoStyle->warning('test warning message'); + $expected = PHP_EOL . PHP_EOL . PHP_EOL . '\s+\[WARNING\] test warning message\s+' . PHP_EOL . PHP_EOL; + $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Warning message does not match output'); + } + + /** + * Test style decorator will output note message with proper style. + * + * @return void + */ + public function testNoteStyle() + { + $this->magentoStyle->note('test note message'); + $expected = PHP_EOL . PHP_EOL . PHP_EOL . '\s+\[NOTE\] test note message\s+' . PHP_EOL . PHP_EOL; + $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Note message does not match output'); + } + + /** + * Test style decorator will output caution message with proper style. + * + * @return void + */ + public function testCautionStyle() + { + $this->magentoStyle->caution('test caution message'); + $expected = PHP_EOL . PHP_EOL . PHP_EOL . '\s+! \[CAUTION\] test caution message\s+' . PHP_EOL . PHP_EOL; + $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Caution message does not match output'); + } + + /** + * Test style decorator will output table with proper style. + * + * @return void + */ + public function testTableStyle() + { + $headers = [ + [new TableCell('Main table title', ['colspan' => 2])], + ['testHeader1', 'testHeader2', 'testHeader3'], + ]; + $rows = [ + [ + 'testValue1', + 'testValue2', + new TableCell('testValue3', ['rowspan' => 2]), + ], + ['testValue4', 'testValue5'], + ]; + $this->magentoStyle->table($headers, $rows); + $expected = ' ------------- ------------- ------------- ' . PHP_EOL . + ' Main table title ' . PHP_EOL . + ' ------------- ------------- ------------- ' . PHP_EOL . + ' testHeader1 testHeader2 testHeader3 ' . PHP_EOL . + ' ------------- ------------- ------------- ' . PHP_EOL . + ' testValue1 testValue2 testValue3 ' . PHP_EOL . + ' testValue4 testValue5 ' . PHP_EOL . + ' ------------- ------------- ------------- ' . PHP_EOL . PHP_EOL; + + $this->assertEquals($expected, $this->testOutput->output, 'Table does not match output'); + } + + /** + * @return void + */ + public function testAsk() + { + $objectManager = new ObjectManager($this); + $formatter = $this->getMockBuilder(OutputFormatter::class) + ->disableOriginalConstructor() + ->getMock(); + $input = $this->getMockBuilder(InputInterface::class) + ->setMethods(['isInteractive']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $input->expects($this->exactly(2)) + ->method('isInteractive') + ->willReturn(false); + $output = $this->getMockBuilder(OutputInterface::class) + ->setMethods(['getVerbosity', 'getFormatter']) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $output->expects($this->once()) + ->method('getVerbosity') + ->willReturn(32); + $output->expects($this->once()) + ->method('getFormatter') + ->willReturn($formatter); + $magentoStyle = $objectManager->getObject( + MagentoStyle::class, + [ + 'input' => $input, + 'output' => $output, + ] + ); + $questionHelper = $this->getMockBuilder(SymfonyQuestionHelper::class) + ->disableOriginalConstructor() + ->getMock(); + $questionHelper->expects($this->once()) + ->method('ask') + ->willReturn('test Answer'); + $objectManager->setBackwardCompatibleProperty($magentoStyle, 'questionHelper', $questionHelper); + + $this->assertEquals( + 'test Answer', + $magentoStyle->ask('test question?', 'test default') + ); + } + + /** + * Test style decorator will output progress with proper style. + * + * @return void + */ + public function testProgress() + { + $this->magentoStyle->progressStart(2); + $this->magentoStyle->progressAdvance(3); + $this->magentoStyle->progressFinish(); + $expected = ' 0/2 [> ] 0%' . PHP_EOL . + ' 3/3 [============================] 100%' . PHP_EOL . PHP_EOL; + $this->assertEquals($expected, $this->testOutput->output, 'Progress does not match output'); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Style/TestOutput.php b/setup/src/Magento/Setup/Test/Unit/Console/Style/TestOutput.php new file mode 100644 index 0000000000000..1407e5ed183e4 --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Console/Style/TestOutput.php @@ -0,0 +1,27 @@ +<?php +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Test\Unit\Console\Style; + +use Symfony\Component\Console\Output\Output; + +/** + * Auxiliary class for MagentoStyleTest. + */ +class TestOutput extends Output +{ + public $output = ''; + + public function clear() + { + $this->output = ''; + } + + protected function doWrite($message, $newline) + { + $this->output .= $message . ($newline ? "\n" : ''); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php index d5bce391f4cd8..be68be8bd8c2d 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigGeneratorTest.php @@ -5,27 +5,57 @@ */ namespace Magento\Setup\Test\Unit\Model; +use Magento\Framework\App\DeploymentConfig; use Magento\Framework\Config\ConfigOptionsListConstants; use Magento\Framework\App\State; +use Magento\Framework\Config\Data\ConfigData; +use Magento\Framework\Config\Data\ConfigDataFactory; +use Magento\Setup\Model\ConfigGenerator; class ConfigGeneratorTest extends \PHPUnit\Framework\TestCase { - /** @var \Magento\Framework\App\DeploymentConfig | \PHPUnit_Framework_MockObject_MockObject */ + /** + * @var DeploymentConfig | \PHPUnit_Framework_MockObject_MockObject + */ private $deploymentConfigMock; - /** @var \Magento\Setup\Model\ConfigGenerator | \PHPUnit_Framework_MockObject_MockObject */ + /** + * @var ConfigGenerator | \PHPUnit_Framework_MockObject_MockObject + */ private $model; + /** + * @var ConfigData|\PHPUnit_Framework_MockObject_MockObject + */ + private $configDataMock; + public function setUp() { $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - $this->deploymentConfigMock = $this->getMockBuilder(\Magento\Framework\App\DeploymentConfig::class) + $this->deploymentConfigMock = $this->getMockBuilder(DeploymentConfig::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->configDataMock = $this->getMockBuilder(ConfigData::class) + ->disableOriginalConstructor() + ->setMethods(['set']) + ->getMock(); + + $configDataFactoryMock = $this->getMockBuilder(ConfigDataFactory::class) ->disableOriginalConstructor() + ->setMethods(['create']) ->getMock(); + + $configDataFactoryMock->method('create') + ->willReturn($this->configDataMock); + $this->model = $objectManager->getObject( - \Magento\Setup\Model\ConfigGenerator::class, - ['deploymentConfig' => $this->deploymentConfigMock] + ConfigGenerator::class, + [ + 'deploymentConfig' => $this->deploymentConfigMock, + 'configDataFactory' => $configDataFactoryMock, + ] ); } @@ -35,8 +65,13 @@ public function testCreateXFrameConfig() ->method('get') ->with(ConfigOptionsListConstants::CONFIG_PATH_X_FRAME_OPT) ->willReturn(null); - $configData = $this->model->createXFrameConfig(); - $this->assertSame('SAMEORIGIN', $configData->getData()[ConfigOptionsListConstants::CONFIG_PATH_X_FRAME_OPT]); + + $this->configDataMock + ->expects($this->once()) + ->method('set') + ->with(ConfigOptionsListConstants::CONFIG_PATH_X_FRAME_OPT, 'SAMEORIGIN'); + + $this->model->createXFrameConfig(); } public function testCreateCacheHostsConfig() @@ -55,8 +90,13 @@ public function testCreateCacheHostsConfig() 'port' => '90', ], ]; - $configData = $this->model->createCacheHostsConfig($data); - $this->assertEquals($expectedData, $configData->getData()[ConfigOptionsListConstants::CONFIG_PATH_CACHE_HOSTS]); + + $this->configDataMock + ->expects($this->once()) + ->method('set') + ->with(ConfigOptionsListConstants::CONFIG_PATH_CACHE_HOSTS, $expectedData); + + $this->model->createCacheHostsConfig($data); } public function testCreateModeConfig() @@ -65,8 +105,13 @@ public function testCreateModeConfig() ->method('get') ->with(State::PARAM_MODE) ->willReturn(null); - $configData = $this->model->createModeConfig(); - $this->assertSame(State::MODE_DEFAULT, $configData->getData()[State::PARAM_MODE]); + + $this->configDataMock + ->expects($this->once()) + ->method('set') + ->with(State::PARAM_MODE, State::MODE_DEFAULT); + + $this->model->createModeConfig(); } public function testCreateModeConfigIfAlreadySet() @@ -78,4 +123,22 @@ public function testCreateModeConfigIfAlreadySet() $configData = $this->model->createModeConfig(); $this->assertSame([], $configData->getData()); } + + public function testCreateCryptKeyConfig() + { + $key = 'my-new-key'; + $data = [ConfigOptionsListConstants::INPUT_KEY_ENCRYPTION_KEY => $key]; + + $this->deploymentConfigMock + ->method('get') + ->with(ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY) + ->willReturn(null); + + $this->configDataMock + ->expects($this->once()) + ->method('set') + ->with(ConfigOptionsListConstants::CONFIG_PATH_CRYPT_KEY, $key); + + $this->model->createCryptConfig($data); + } } diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/SessionTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/SessionTest.php index d37c07e715482..3b1d3e29e4e56 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/SessionTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/SessionTest.php @@ -32,7 +32,7 @@ protected function setUp() public function testGetOptions() { $options = $this->configList->getOptions(); - $this->assertCount(19, $options); + $this->assertCount(23, $options); $this->assertArrayHasKey(0, $options); $this->assertInstanceOf(SelectConfigOption::class, $options[0]); @@ -156,7 +156,11 @@ public function testCreateConfigWithSessionSaveRedis() 'bot_lifetime' => '', 'disable_locking' => '', 'min_lifetime' => '', - 'max_lifetime' => '' + 'max_lifetime' => '', + 'sentinel_master' => '', + 'sentinel_servers' => '', + 'sentinel_connect_retries' => '', + 'sentinel_verify_master' => '', ] ] @@ -209,7 +213,11 @@ public function testCreateConfigWithRedisInput() 'bot_lifetime' => '', 'disable_locking' => '', 'min_lifetime' => '60', - 'max_lifetime' => '3600' + 'max_lifetime' => '3600', + 'sentinel_master' => '', + 'sentinel_servers' => '', + 'sentinel_connect_retries' => '', + 'sentinel_verify_master' => '', ] ], diff --git a/setup/src/Magento/Setup/Test/Unit/Model/CryptKeyGeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Model/CryptKeyGeneratorTest.php new file mode 100644 index 0000000000000..d7a4d477de7b0 --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Model/CryptKeyGeneratorTest.php @@ -0,0 +1,59 @@ +<?php +/*** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +namespace Magento\Setup\Test\Unit\Model; + +use Magento\Framework\Math\Random; +use Magento\Setup\Model\CryptKeyGenerator; +use PHPUnit\Framework\TestCase; + +/** + * Testcase for CryptKeyGenerator + */ +class CryptKeyGeneratorTest extends TestCase +{ + /** + * @var Random|\PHPUnit_Framework_MockObject_MockObject + */ + private $randomMock; + + /** + * @var CryptKeyGenerator + */ + private $cryptKeyGenerator; + + public function setUp() + { + $this->randomMock = $this->getMockBuilder(Random::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->cryptKeyGenerator = new CryptKeyGenerator($this->randomMock); + } + + public function testStringForHashingIsReadFromRandom() + { + $this->randomMock + ->expects($this->once()) + ->method('getRandomString') + ->willReturn(''); + + $this->cryptKeyGenerator->generate(); + } + + public function testReturnsMd5OfRandomString() + { + $expected = 'fdb7594e77f1ad5fbb8e6c917b6012ce'; // == 'magento2' + + $this->randomMock + ->method('getRandomString') + ->willReturn('magento2'); + + $actual = $this->cryptKeyGenerator->generate(); + + $this->assertEquals($expected, $actual); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Config/ConverterTest.php b/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Config/ConverterTest.php deleted file mode 100644 index 37a844409757d..0000000000000 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Config/ConverterTest.php +++ /dev/null @@ -1,93 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Config; - -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Config\Converter; - -/** - * Test for Converter class. - * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Config. - */ -class ConverterTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var Converter - */ - private $converter; - - /** - * @var ObjectManager - */ - private $objectManager; - - protected function setUp() - { - $this->objectManager = new ObjectManager($this); - $this->converter = $this->objectManager->getObject( - Converter::class - ); - } - - /** - * Test converting table schema to array. - */ - public function testConvert() - { - $dom = new \DOMDocument(); - $dom->loadXML( - '<?xml version="1.0"?> - <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:noNamespaceSchemaLocation="urn:magento:setup:Model/Declaration/Schema/etc/schema.xsd"> - <table name="test_table" resource="default"> - <column xsi:type="int" name="id" nullable="false" identity="true" comment="Id"/> - <column xsi:type="varchar" name="data" length="100" identity="false" comment="Data"/> - <constraint xsi:type="primary" name="PRIMARY"> - <column name="id"/> - </constraint> - </table> - </schema>' - ); - $result = $this->converter->convert($dom); - $this->assertEquals( - [ - 'table' => [ - 'test_table' => [ - 'column' => [ - 'id' => [ - 'type' => 'int', - 'name' => 'id', - 'nullable' => 'false', - 'identity' => 'true', - 'comment' => 'Id', - ], - 'data' => [ - 'type' => 'varchar', - 'name' => 'data', - 'length' => '100', - 'identity' => 'false', - 'comment' => 'Data', - ], - ], - 'constraint' => [ - 'PRIMARY' => [ - 'column' => [ - 'id' => 'id', - ], - 'type' => 'primary', - 'name' => 'PRIMARY', - ], - ], - 'name' => 'test_table', - 'resource' => 'default', - ], - ], - ], - $result - ); - } -} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/IndexTest.php b/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/IndexTest.php deleted file mode 100644 index f5ca4ad86cef5..0000000000000 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/MySQL/Definition/IndexTest.php +++ /dev/null @@ -1,175 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\DB\Adapter\AdapterInterface; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Setup\Model\Declaration\Schema\Db\MySQL\Definition\Index; -use Magento\Setup\Model\Declaration\Schema\Dto\Index as IndexDto; - -/** - * Test for index (key) definition. - * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Db\MySQL\Definition\Constraints - */ -class IndexTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var ObjectManager - */ - private $objectManager; - - /** - * @var Index - */ - private $index; - - /** - * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject - */ - private $resourceConnectionMock; - - protected function setUp() - { - $this->objectManager = new ObjectManager($this); - $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - $this->index = $this->objectManager->getObject( - Index::class, - [ - 'resourceConnection' => $this->resourceConnectionMock - ] - ); - } - - /** - * Test conversion to definition. - * - * @dataProvider toDefinitionDataProvider() - */ - public function testToDefinition($name, $type, $columns, $expectedExpression) - { - /** @var IndexDto|\PHPUnit_Framework_MockObject_MockObject $index */ - $index = $this->getMockBuilder(IndexDto::class) - ->disableOriginalConstructor() - ->getMock(); - $adapterMock = $this->getMockBuilder(AdapterInterface::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resourceConnectionMock->expects($this->once()) - ->method('getConnection') - ->willReturn($adapterMock); - - $index->expects($this->any())->method('getName')->willReturn($name); - $index->expects($this->any())->method('getIndexType')->willReturn($type); - $index->expects($this->any())->method('getColumnNames')->willReturn($columns); - $adapterMock->expects($this->any()) - ->method('quoteIdentifier') - ->willReturnCallback( - function ($name) { - return '`' . $name . '`'; - } - ); - - $this->assertEquals( - $expectedExpression, - $this->index->toDefinition($index) - ); - } - - public function toDefinitionDataProvider() - { - return [ - [ - 'name' => 'ft_index', - 'type' => IndexDto::FULLTEXT_INDEX, - 'columns' => ['title', 'content'], - 'expectedExpression' => "FULLTEXT INDEX `ft_index` (`title`,`content`)" - ], - [ - 'name' => 'ft_index', - 'type' => IndexDto::FULLTEXT_INDEX, - 'columns' => ['title'], - 'expectedExpression' => "FULLTEXT INDEX `ft_index` (`title`)" - ], - [ - 'name' => 'ft_index', - 'type' => 'btree', - 'columns' => ['title'], - 'expectedExpression' => "INDEX `ft_index` (`title`)" - ], - [ - 'name' => 'ft_index', - 'type' => 'HASH', - 'columns' => ['title'], - 'expectedExpression' => "INDEX `ft_index` (`title`)" - ], - ]; - } - - /** - * Test from definition conversion. - * - * @param array $definition - * @param array $expectedDefinition - * @dataProvider definitionDataProvider() - */ - public function testFromDefinition($definition, $expectedDefinition) - { - $result = $this->index->fromDefinition($definition); - $this->assertEquals($expectedDefinition, $result); - } - - /** - * @return array - */ - public function definitionDataProvider() - { - return [ - [ - 'definition' => [ - 'Index_type' => 'FULLTEXT', - 'Key_name' => 'ft_index', - 'Column_name' => 'text', - ], - 'excpectedDefiniton' => [ - 'indexType' => 'fulltext', - 'name' => 'ft_index', - 'column' => ['text' => 'text'], - 'type' => 'index', - ], - ], - [ - 'definition' => [ - 'Index_type' => 'BTREE', - 'Key_name' => 'bt_index', - 'Column_name' => 'text', - ], - 'excpectedDefiniton' => [ - 'indexType' => 'btree', - 'name' => 'bt_index', - 'column' => ['text' => 'text'], - 'type' => 'index', - ], - ], - [ - 'definition' => [ - 'Index_type' => 'HASH', - 'Key_name' => 'ht_index', - 'Column_name' => 'text', - ], - 'excpectedDefiniton' => [ - 'indexType' => 'hash', - 'name' => 'ht_index', - 'column' => ['text' => 'text'], - 'type' => 'index', - ], - ] - ]; - } -} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/SchemaBuilderTest.php b/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/SchemaBuilderTest.php deleted file mode 100644 index 8465812dbaf7b..0000000000000 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Db/SchemaBuilderTest.php +++ /dev/null @@ -1,439 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Db; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use Magento\Setup\Model\Declaration\Schema\Db\DbSchemaReaderInterface; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Internal; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementFactory; -use Magento\Setup\Model\Declaration\Schema\Dto\Index; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\Sharding; - -/** - * Test for SchemaBuilder. - * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Db - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class SchemaBuilderTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Setup\Model\Declaration\Schema\Db\SchemaBuilder - */ - private $model; - - /** - * @var ObjectManagerHelper - */ - private $objectManagerHelper; - - /** - * @var ElementFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $elementFactoryMock; - - /** - * @var DbSchemaReaderInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $dbSchemaReaderMock; - - /** - * @var Sharding|\PHPUnit_Framework_MockObject_MockObject - */ - private $shardingMock; - - protected function setUp() - { - $this->elementFactoryMock = $this->getMockBuilder(ElementFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->dbSchemaReaderMock = $this->getMockBuilder(DbSchemaReaderInterface::class) - ->getMockForAbstractClass(); - $this->shardingMock = $this->getMockBuilder(Sharding::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->model = $this->objectManagerHelper->getObject( - \Magento\Setup\Model\Declaration\Schema\Db\SchemaBuilder::class, - [ - 'elementFactory' => $this->elementFactoryMock, - 'dbSchemaReader' => $this->dbSchemaReaderMock, - 'sharding' => $this->shardingMock - ] - ); - } - - /** - * @return array - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function dataProvider() - { - return [ - [ - 'columns' => [ - 'first_table' => [ - 'first_column' => [ - 'name' => 'first_column', - 'type' => 'int', - 'padding' => 10, - 'identity' => true, - 'nullable' => false - ], - 'foreign_column' => [ - 'name' => 'foreign_column', - 'type' => 'int', - 'padding' => 10, - 'nullable' => false - ], - 'second_column' => [ - 'name' => 'second_column', - 'type' => 'timestamp', - 'default' => 'CURRENT_TIMESTAMP', - 'on_update' => true - ], - ], - 'second_table' => [ - 'ref_column' => [ - 'name' => 'ref_column', - 'type' => 'int', - 'padding' => 10, - 'nullable' => false - ], - ] - ], - 'references' => [ - 'first_table' => [ - 'some_foreign_key' => [ - 'name' => 'some_foreign_key', - 'type' => 'foreign', - 'column' => 'foreign_column', - 'table' => 'first_table', - 'referenceTable' => 'second_table', - 'referenceColumn' => 'ref_column' - ], - ] - ], - 'constraints' => [ - 'first_table' => [ - 'PRIMARY' => [ - 'name' => 'PRIMARY', - 'type' => 'primary', - 'column' => [ - 'first_column' - ] - ] - ] - ], - 'indexes' => [ - 'second_table' => [ - 'FIRST_INDEX' => [ - 'name' => 'FIRST_INDEX', - 'column' => [ - 'ref_column' - ] - ] - ] - ] - ] - ]; - } - - /** - * Create table. - * - * @param string $name - * @return Table - */ - private function createTable($name) - { - return new Table( - $name, - $name, - 'table', - 'default', - 'resource' - ); - } - - /** - * Create integer column with autoincrement. - * - * @param string $name - * @param Table $table - * @return \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer - */ - private function createIntegerAIColumn($name, Table $table) - { - return new Integer( - $name, - 'int', - $table, - 10, - true, - false, - true - ); - } - - /** - * Create integer column. - * - * @param string $name - * @param Table $table - * @return \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer - */ - private function createIntegerColumn($name, Table $table) - { - return new Integer( - $name, - 'int', - $table, - 10 - ); - } - - /** - * Create primary key constraint. - * - * @param Table $table - * @param array $columns - * @return Internal - */ - private function createPrimaryConstraint(Table $table, array $columns) - { - return new Internal( - 'PRIMARY', - 'primary', - $table, - $columns - ); - } - - /** - * Create index. - * - * @param string $indexName - * @param Table $table - * @param array $columns - * @return Index - */ - private function createIndex($indexName, Table $table, array $columns) - { - return new Index( - $indexName, - 'index', - $table, - $columns, - 'btree' - ); - } - - /** - * Create timestamp column. - * - * @param string $name - * @param Table $table - * @return \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp - */ - private function createTimestampColumn($name, Table $table) - { - return new Timestamp( - $name, - 'timestamp', - $table, - 'CURRENT_TIMESTAMP', - false, - true - ); - } - - /** - * @dataProvider dataProvider - * @param array $columns - * @param array $references - * @param array $constraints - * @param array $indexes - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testBuild(array $columns, array $references, array $constraints, array $indexes) - { - $withContext = [['first_table', 'default'], ['second_table', 'default']]; - $this->shardingMock->expects(self::once()) - ->method('getResources') - ->willReturn(['default']); - $this->dbSchemaReaderMock->expects(self::once()) - ->method('readTables') - ->with('default') - ->willReturn(['first_table', 'second_table']); - $this->dbSchemaReaderMock->expects(self::exactly(2)) - ->method('getTableOptions') - ->withConsecutive(...array_values($withContext)) - ->willReturnOnConsecutiveCalls( - ['Engine' => 'innodb', 'Comment' => ''], - ['Engine' => 'innodb', 'Comment' => 'Not null comment'] - ); - $this->dbSchemaReaderMock->expects(self::exactly(2)) - ->method('readColumns') - ->withConsecutive(...array_values($withContext)) - ->willReturnOnConsecutiveCalls($columns['first_table'], $columns['second_table']); - $this->dbSchemaReaderMock->expects(self::exactly(2)) - ->method('readIndexes') - ->withConsecutive(...array_values($withContext)) - ->willReturnOnConsecutiveCalls([], $indexes['second_table']); - $this->dbSchemaReaderMock->expects(self::exactly(2)) - ->method('readConstraints') - ->withConsecutive(...array_values($withContext)) - ->willReturnOnConsecutiveCalls($constraints['first_table'], []); - $this->dbSchemaReaderMock->expects(self::exactly(2)) - ->method('readReferences') - ->withConsecutive(...array_values($withContext)) - ->willReturnOnConsecutiveCalls($references['first_table'], []); - $table = $this->createTable('first_table'); - $refTable = $this->createTable('second_table'); - $refColumn = $this->createIntegerColumn('ref_column', $refTable); - $index = $this->createIndex('FIRST_INDEX', $table, [$refColumn]); - $refTable->addColumns([$refColumn]); - $refTable->addIndexes([$index]); - $firstColumn = $this->createIntegerAIColumn('first_column', $table); - $foreignColumn = $this->createIntegerColumn('foreign_column', $table); - $timestampColumn = $this->createTimestampColumn('second_column', $table); - $primaryKey = $this->createPrimaryConstraint($table, [$firstColumn]); - $foreignKey = new Reference( - 'some_foreign_key', - 'foreign', - $table, - $foreignColumn, - $refTable, - $refColumn, - 'CASCADE' - ); - $table->addColumns([$firstColumn, $foreignColumn, $timestampColumn]); - $table->addConstraints([$foreignKey, $primaryKey]); - $this->elementFactoryMock->expects(self::exactly(9)) - ->method('create') - ->withConsecutive( - [ - 'table', - [ - 'name' =>'first_table', - 'resource' => 'default', - 'engine' => 'innodb', - 'comment' => null - ] - ], - [ - 'int', - [ - 'name' => 'first_column', - 'type' => 'int', - 'table' => $table, - 'padding' => 10, - 'identity' => true, - 'nullable' => false, - ] - ], - [ - 'int', - [ - 'name' => 'foreign_column', - 'type' => 'int', - 'table' => $table, - 'padding' => 10, - 'nullable' => false, - ] - ], - [ - 'timestamp', - [ - 'name' => 'second_column', - 'type' => 'timestamp', - 'table' => $table, - 'default' => 'CURRENT_TIMESTAMP', - 'on_update' => true, - ] - ], - [ - 'primary', - [ - 'name' => 'PRIMARY', - 'type' => 'primary', - 'columns' => [$firstColumn], - 'table' => $table, - 'column' => ['first_column'], - ] - ], - [ - 'table', - [ - 'name' =>'second_table', - 'resource' => 'default', - 'engine' => 'innodb', - 'comment' => 'Not null comment' - ] - ], - [ - 'int', - [ - 'name' => 'ref_column', - 'type' => 'int', - 'table' => $refTable, - 'padding' => 10, - 'nullable' => false, - ] - ], - [ - 'index', - [ - 'name' => 'FIRST_INDEX', - 'table' => $refTable, - 'column' => ['ref_column'], - 'columns' => [$refColumn], - ] - ], - [ - 'foreign', - [ - 'name' => 'some_foreign_key', - 'type' => 'foreign', - 'column' => $foreignColumn, - 'table' => $table, - 'referenceTable' => $refTable, - 'referenceColumn' => $refColumn, - ] - ] - ) - ->willReturnOnConsecutiveCalls( - $table, - $firstColumn, - $foreignColumn, - $timestampColumn, - $primaryKey, - $refTable, - $refColumn, - $index, - $foreignKey - ); - $resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - /** @var Schema $schema */ - $schema = $this->objectManagerHelper->getObject( - Schema::class, - ['resourceConnection' => $resourceConnectionMock] - ); - $this->model->build($schema); - } -} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Declaration/SchemaBuilderTest.php b/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Declaration/SchemaBuilderTest.php deleted file mode 100644 index c7795ce6dda7c..0000000000000 --- a/setup/src/Magento/Setup/Test/Unit/Model/Declaration/Schema/Declaration/SchemaBuilderTest.php +++ /dev/null @@ -1,462 +0,0 @@ -<?php -/** - * Copyright © Magento, Inc. All rights reserved. - * See COPYING.txt for license details. - */ - -namespace Magento\Setup\Test\Unit\Model\Declaration\Schema\Declaration; - -use Magento\Framework\App\ResourceConnection; -use Magento\Framework\Stdlib\BooleanUtils; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper; -use Magento\Setup\Model\Declaration\Schema\Declaration\ValidationComposite; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer; -use Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Internal; -use Magento\Setup\Model\Declaration\Schema\Dto\Constraints\Reference; -use Magento\Setup\Model\Declaration\Schema\Dto\ElementFactory; -use Magento\Setup\Model\Declaration\Schema\Dto\Index; -use Magento\Setup\Model\Declaration\Schema\Dto\Schema; -use Magento\Setup\Model\Declaration\Schema\Dto\Table; -use Magento\Setup\Model\Declaration\Schema\Sharding; - -/** - * Test for SchemaBuilder. - * - * @package Magento\Setup\Test\Unit\Model\Declaration\Schema\Declaration - * - * @SuppressWarnings(PHPMD.CouplingBetweenObjects) - */ -class SchemaBuilderTest extends \PHPUnit\Framework\TestCase -{ - /** - * @var \Magento\Setup\Model\Declaration\Schema\Declaration\SchemaBuilder - */ - private $model; - - /** - * @var ObjectManagerHelper - */ - private $objectManagerHelper; - - /** - * @var ElementFactory|\PHPUnit_Framework_MockObject_MockObject - */ - private $elementFactoryMock; - - /** - * @var BooleanUtils|\PHPUnit_Framework_MockObject_MockObject - */ - private $booleanUtilsMock; - - /** - * @var Sharding|\PHPUnit_Framework_MockObject_MockObject - */ - private $shardingMock; - - /** - * @var ValidationComposite|\PHPUnit_Framework_MockObject_MockObject - */ - private $validationCompositeMock; - - /** - * @var ResourceConnection|\PHPUnit_Framework_MockObject_MockObject - */ - private $resourceConnectionMock; - - protected function setUp() - { - $this->elementFactoryMock = $this->getMockBuilder(ElementFactory::class) - ->disableOriginalConstructor() - ->getMock(); - $this->booleanUtilsMock = $this->getMockBuilder(BooleanUtils::class) - ->disableOriginalConstructor() - ->getMock(); - $this->shardingMock = $this->getMockBuilder(Sharding::class) - ->disableOriginalConstructor() - ->getMock(); - $this->validationCompositeMock = $this->getMockBuilder(ValidationComposite::class) - ->disableOriginalConstructor() - ->getMock(); - $this->resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - - $this->objectManagerHelper = new ObjectManagerHelper($this); - $this->model = $this->objectManagerHelper->getObject( - \Magento\Setup\Model\Declaration\Schema\Declaration\SchemaBuilder::class, - [ - 'elementFactory' => $this->elementFactoryMock, - 'booleanUtils' => new BooleanUtils(), - 'sharding' => $this->shardingMock, - 'validationComposite' => $this->validationCompositeMock, - 'resourceConnection' => $this->resourceConnectionMock - ] - ); - } - - /** - * @return array - */ - public function tablesProvider() - { - return [ - [ - [ - 'first_table' => [ - 'name' => 'first_table', - 'engine' => 'innodb', - 'resource' => 'default', - 'column' => [ - 'first_column' => [ - 'name' => 'first_column', - 'type' => 'int', - 'padding' => 10, - 'identity' => true, - 'nullable' => false - ], - 'foreign_column' => [ - 'name' => 'foreign_column', - 'type' => 'int', - 'padding' => 10, - 'nullable' => false - ], - 'some_disabled_column' => [ - 'name' => 'some_disabled_column', - 'disabled' => 'true', - 'type' => 'int', - 'padding' => 10, - 'nullable' => false - ], - 'second_column' => [ - 'name' => 'second_column', - 'type' => 'timestamp', - 'default' => 'CURRENT_TIMESTAMP', - 'on_update' => true - ], - ], - 'constraint' => [ - 'some_foreign_key' => [ - 'name' => 'some_foreign_key', - 'type' => 'foreign', - 'column' => 'foreign_column', - 'table' => 'first_table', - 'referenceTable' => 'second_table', - 'referenceColumn' => 'ref_column' - ], - 'PRIMARY' => [ - 'name' => 'PRIMARY', - 'type' => 'primary', - 'column' => [ - 'first_column' - ] - ] - ] - ], - 'second_table' => [ - 'name' => 'second_table', - 'engine' => 'innodb', - 'resource' => 'default', - 'column' => [ - 'ref_column' => [ - 'name' => 'ref_column', - 'type' => 'int', - 'padding' => 10, - 'nullable' => false - ], - ], - 'index' => [ - 'FIRST_INDEX' => [ - 'name' => 'FIRST_INDEX', - 'column' => [ - 'ref_column' - ] - ] - ], - ] - ] - ] - ]; - } - - /** - * Create table - * - * @param string $name - * @return Table - */ - private function createTable($name) - { - return new Table( - $name, - $name, - 'table', - 'default', - 'resource' - ); - } - - /** - * Create integer column with autoincrement. - * - * @param string $name - * @param Table $table - * @return \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer - */ - private function createIntegerAIColumn($name, Table $table) - { - return new Integer( - $name, - 'int', - $table, - 10, - true, - false, - true - ); - } - - /** - * Create integer column. - * - * @param string $name - * @param Table $table - * @return \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Integer - */ - private function createIntegerColumn($name, Table $table) - { - return new Integer( - $name, - 'int', - $table, - 10 - ); - } - - /** - * Create PK constraint. - * - * @param Table $table - * @param array $columns - * @return Internal - */ - private function createPrimaryConstraint(Table $table, array $columns) - { - return new Internal( - 'PRIMARY', - 'primary', - $table, - $columns - ); - } - - /** - * Create index. - * - * @param string $indexName - * @param Table $table - * @param array $columns - * @return Index - */ - private function createIndex($indexName, Table $table, array $columns) - { - return new Index( - $indexName, - 'index', - $table, - $columns, - 'btree' - ); - } - - /** - * Create timestamp column. - * - * @param string $name - * @param Table $table - * @return \Magento\Setup\Model\Declaration\Schema\Dto\Columns\Timestamp - */ - private function createTimestampColumn($name, Table $table) - { - return new Timestamp( - $name, - 'timestamp', - $table, - 'CURRENT_TIMESTAMP', - false, - true - ); - } - - /** - * @dataProvider tablesProvider - * @param array $tablesData - * @SuppressWarnings(PHPMD.ExcessiveMethodLength) - */ - public function testBuild(array $tablesData) - { - $table = $this->createTable('first_table'); - $refTable = $this->createTable('second_table'); - $refColumn = $this->createIntegerColumn('ref_column', $refTable); - $index = $this->createIndex('FIRST_INDEX', $table, [$refColumn]); - $refTable->addColumns([$refColumn]); - $refTable->addIndexes([$index]); - $firstColumn = $this->createIntegerAIColumn('first_column', $table); - $foreignColumn = $this->createIntegerColumn('foreign_column', $table); - $timestampColumn = $this->createTimestampColumn('second_column', $table); - $primaryKey = $this->createPrimaryConstraint($table, [$firstColumn]); - $foreignKey = new Reference( - 'some_foreign_key', - 'foreign', - $table, - $foreignColumn, - $refTable, - $refColumn, - 'CASCADE' - ); - $table->addColumns([$firstColumn, $foreignColumn, $timestampColumn]); - $table->addConstraints([$foreignKey, $primaryKey]); - $this->elementFactoryMock->expects(self::exactly(9)) - ->method('create') - ->withConsecutive( - [ - 'table', - [ - 'name' =>'first_table', - 'resource' => 'default', - 'engine' => 'innodb', - 'comment' => null - ] - ], - [ - 'int', - [ - 'name' => 'first_column', - 'type' => 'int', - 'table' => $table, - 'padding' => 10, - 'identity' => true, - 'nullable' => false, - 'resource' => 'default' - ] - ], - [ - 'int', - [ - 'name' => 'foreign_column', - 'type' => 'int', - 'table' => $table, - 'padding' => 10, - 'nullable' => false, - 'resource' => 'default' - ] - ], - [ - 'timestamp', - [ - 'name' => 'second_column', - 'type' => 'timestamp', - 'table' => $table, - 'default' => 'CURRENT_TIMESTAMP', - 'on_update' => true, - 'resource' => 'default' - ] - ], - [ - 'table', - [ - 'name' =>'second_table', - 'resource' => 'default', - 'engine' => 'innodb', - 'comment' => null - ] - ], - [ - 'int', - [ - 'name' => 'ref_column', - 'type' => 'int', - 'table' => $refTable, - 'padding' => 10, - 'nullable' => false, - 'resource' => 'default' - ] - ], - [ - 'index', - [ - 'name' => 'FIRST_INDEX', - 'table' => $refTable, - 'column' => ['ref_column'], - 'columns' => [$refColumn], - 'resource' => 'default' - ] - ], - [ - 'foreign', - [ - 'name' => 'some_foreign_key', - 'type' => 'foreign', - 'column' => $foreignColumn, - 'table' => $table, - 'referenceTable' => $refTable, - 'referenceColumn' => $refColumn, - 'resource' => 'default' - ] - ], - [ - 'primary', - [ - 'name' => 'PRIMARY', - 'type' => 'primary', - 'columns' => [$firstColumn], - 'table' => $table, - 'column' => ['first_column'], - 'resource' => 'default' - ] - ] - ) - ->willReturnOnConsecutiveCalls( - $table, - $firstColumn, - $foreignColumn, - $timestampColumn, - $refTable, - $refColumn, - $index, - $foreignKey, - $primaryKey - ); - $resourceConnectionMock = $this->getMockBuilder(ResourceConnection::class) - ->disableOriginalConstructor() - ->getMock(); - /** @var Schema $schema */ - $schema = $this->objectManagerHelper->getObject( - Schema::class, - ['resourceConnection' => $resourceConnectionMock] - ); - $this->resourceConnectionMock->expects(self::once()) - ->method('getTableName') - ->willReturn('second_table'); - $resourceConnectionMock->expects(self::exactly(6)) - ->method('getTableName') - ->withConsecutive( - ['first_table'], - ['first_table'], - ['second_table'], - ['second_table'], - ['first_table'], - ['second_table'] - ) - ->willReturnOnConsecutiveCalls( - 'first_table', - 'first_table', - 'second_table', - 'second_table', - 'first_table', - 'second_table' - ); - $this->model->addTablesData($tablesData); - $this->model->build($schema); - } -} diff --git a/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php index 0f9eb7d136a3b..0ef30b9ab4d6f 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/InstallerFactoryTest.php @@ -10,7 +10,7 @@ use Magento\Framework\Setup\LoggerInterface; use Magento\Framework\Setup\SchemaPersistor; use Magento\Setup\Model\DeclarationInstaller; -use \Magento\Setup\Model\InstallerFactory; +use Magento\Setup\Model\InstallerFactory; use Magento\Setup\Module\ResourceFactory; use Zend\ServiceManager\ServiceLocatorInterface; diff --git a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php index dd5918b477eef..413094a1e0115 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php @@ -10,11 +10,13 @@ use Magento\Framework\Config\ConfigOptionsListConstants; use Magento\Framework\Setup\SchemaListener; use Magento\Setup\Model\DeclarationInstaller; -use \Magento\Setup\Model\Installer; +use Magento\Setup\Model\Installer; use Magento\Framework\App\Filesystem\DirectoryList; use Magento\Framework\Filesystem\DriverPool; use Magento\Framework\Config\File\ConfigFilePool; use Magento\Framework\App\State\CleanupFiles; +use Magento\Framework\Setup\Patch\PatchApplier; +use Magento\Framework\Setup\Patch\PatchApplierFactory; use Magento\Setup\Validator\DbValidator; /** @@ -139,7 +141,7 @@ class InstallerTest extends \PHPUnit\Framework\TestCase private $phpReadinessCheck; /** - * @var \Magento\Setup\Model\DeclarationInstaller|\PHPUnit_Framework_MockObject_MockObject + * @var \Magento\Framework\Setup\DeclarationInstaller|\PHPUnit_Framework_MockObject_MockObject */ private $declarationInstallerMock; @@ -167,6 +169,16 @@ class InstallerTest extends \PHPUnit\Framework\TestCase */ private $contextMock; + /** + * @var PatchApplier|\PHPUnit_Framework_MockObject_MockObject + */ + private $patchApplierMock; + + /** + * @var PatchApplierFactory|\PHPUnit_Framework_MockObject_MockObject + */ + private $patchApplierFactoryMock; + protected function setUp() { $this->filePermissions = $this->createMock(\Magento\Framework\Setup\FilePermissions::class); @@ -204,6 +216,9 @@ protected function setUp() $this->phpReadinessCheck = $this->createMock(\Magento\Setup\Model\PhpReadinessCheck::class); $this->declarationInstallerMock = $this->createMock(DeclarationInstaller::class); $this->schemaListenerMock = $this->createMock(SchemaListener::class); + $this->patchApplierFactoryMock = $this->createMock(PatchApplierFactory::class); + $this->patchApplierMock = $this->createMock(PatchApplier::class); + $this->patchApplierFactoryMock->expects($this->any())->method('create')->willReturn($this->patchApplierMock); $this->object = $this->createObject(); } @@ -308,12 +323,30 @@ public function testInstall() ->will($this->returnValueMap([ [\Magento\Framework\App\Cache\Manager::class, [], $cacheManager], [\Magento\Framework\App\State::class, [], $appState], + [ + PatchApplierFactory::class, + ['objectManager' => $this->objectManager], + $this->patchApplierFactoryMock + ], ])); + $this->patchApplierMock->expects($this->exactly(2))->method('applySchemaPatch')->willReturnMap( + [ + ['Bar_Two'], + ['Foo_One'], + ] + ); + $this->patchApplierMock->expects($this->exactly(2))->method('applyDataPatch')->willReturnMap( + [ + ['Bar_Two'], + ['Foo_One'], + ] + ); $this->objectManager->expects($this->any()) ->method('get') ->will($this->returnValueMap([ [\Magento\Framework\App\State::class, $appState], - [\Magento\Framework\App\Cache\Manager::class, $cacheManager] + [\Magento\Framework\App\Cache\Manager::class, $cacheManager], + [\Magento\Setup\Model\DeclarationInstaller::class, $this->declarationInstallerMock] ])); $this->adminFactory->expects($this->once())->method('create')->willReturn( $this->createMock(\Magento\Setup\Model\AdminAccount::class) diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ModuleUninstallerTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ModuleUninstallerTest.php index 89f7956332aac..73202fdd2b9a4 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/ModuleUninstallerTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/ModuleUninstallerTest.php @@ -6,6 +6,7 @@ namespace Magento\Setup\Test\Unit\Model; use Magento\Setup\Model\ModuleUninstaller; +use Magento\Framework\Setup\Patch\PatchApplier; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -47,6 +48,11 @@ class ModuleUninstallerTest extends \PHPUnit\Framework\TestCase */ private $moduleRegistryUninstaller; + /** + * @var PatchApplier|\PHPUnit_Framework_MockObject_MockObject + */ + private $patchApplierMock; + public function setUp() { $this->moduleRegistryUninstaller = $this->createMock(\Magento\Setup\Model\ModuleRegistryUninstaller::class); @@ -63,6 +69,7 @@ public function setUp() $this->collector = $this->createMock(\Magento\Setup\Model\UninstallCollector::class); $this->setup = $this->createMock(\Magento\Setup\Module\Setup::class); + $this->patchApplierMock = $this->createMock(PatchApplier::class); $setupFactory = $this->createMock(\Magento\Setup\Module\SetupFactory::class); $setupFactory->expects($this->any())->method('create')->willReturn($this->setup); @@ -93,10 +100,20 @@ public function testUninstallRemoveData() $this->output->expects($this->atLeastOnce())->method('writeln'); - $this->objectManager->expects($this->once()) + $this->objectManager->expects($this->any()) ->method('get') - ->with(\Magento\Framework\Module\ModuleResource::class) - ->willReturn($resource); + ->willReturnMap( + [ + [\Magento\Framework\Module\ModuleResource::class, $resource], + [PatchApplier::class, $this->patchApplierMock] + ] + ); + $this->patchApplierMock->expects($this->exactly(2))->method('revertDataPatches')->willReturnMap( + [ + ['moduleA'], + ['moduleB'] + ] + ); $this->uninstaller->uninstallData($this->output, ['moduleA', 'moduleB']); } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/ConfigGeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Module/ConfigGeneratorTest.php index 69f320bccd5ce..65fe4a5f47711 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/ConfigGeneratorTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/ConfigGeneratorTest.php @@ -5,11 +5,18 @@ */ namespace Magento\Setup\Test\Unit\Module; +use Magento\Framework\App\DeploymentConfig; +use Magento\Framework\Config\Data\ConfigData; +use Magento\Framework\Config\Data\ConfigDataFactory; use Magento\Framework\Config\File\ConfigFilePool; +use Magento\Framework\Math\Random; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\Setup\Model\ConfigGenerator; use Magento\Framework\Config\ConfigOptionsListConstants; +use Magento\Setup\Model\CryptKeyGenerator; +use PHPUnit\Framework\TestCase; -class ConfigGeneratorTest extends \PHPUnit\Framework\TestCase +class ConfigGeneratorTest extends TestCase { /** * @var ConfigGenerator @@ -18,11 +25,31 @@ class ConfigGeneratorTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $random = $this->createMock(\Magento\Framework\Math\Random::class); - $random->expects($this->any())->method('getRandomString')->willReturn('key'); - $deployConfig= $this->createMock(\Magento\Framework\App\DeploymentConfig::class); + /** @var DeploymentConfig|\PHPUnit_Framework_MockObject_MockObject $deployConfig */ + $deployConfig = $this->createMock(DeploymentConfig::class); $deployConfig->expects($this->any())->method('isAvailable')->willReturn(false); - $this->configGeneratorObject = new ConfigGenerator($random, $deployConfig); + + /** @var Random|\PHPUnit_Framework_MockObject_MockObject $randomMock */ + $randomMock = $this->createMock(Random::class); + $randomMock->expects($this->any())->method('getRandomString')->willReturn('key'); + + $cryptKeyGenerator = new CryptKeyGenerator($randomMock); + + $objectManagerMock = $this->getMockBuilder(\Magento\Framework\App\ObjectManager::class) + ->disableOriginalConstructor() + ->getMock(); + + $objectManagerMock->method('create')->willReturn(new ConfigData('app_env')); + + $configDataFactoryMock = (new ObjectManager($this)) + ->getObject(ConfigDataFactory::class, ['objectManager' => $objectManagerMock]); + + $this->configGeneratorObject = new ConfigGenerator( + $randomMock, + $deployConfig, + $configDataFactoryMock, + $cryptKeyGenerator + ); } public function testCreateCryptConfigWithInput()