From 3648333e569907c2b2d8c79b4d18641233861163 Mon Sep 17 00:00:00 2001 From: Oleksandr Osadchyi Date: Fri, 27 Jan 2017 15:27:31 +0200 Subject: [PATCH 01/40] MAGETWO-62616: Products are missed and total count is wrong on category page --- .../Category/Product/AbstractAction.php | 3 +- .../Framework/DB/Adapter/Pdo/Mysql.php | 47 +++- .../DB/Query/BatchIteratorFactory.php | 58 ++++- .../Framework/DB/Query/BatchRangeIterator.php | 208 ++++++++++++++++++ .../Magento/Framework/DB/Query/Generator.php | 37 +++- .../Unit/DB/Query/BatchRangeIteratorTest.php | 121 ++++++++++ .../Test/Unit/DB/Query/GeneratorTest.php | 9 +- 7 files changed, 456 insertions(+), 27 deletions(-) create mode 100644 lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php create mode 100644 lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php index c4d8e4fd9be34..dbdd164486fab 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php @@ -314,7 +314,8 @@ protected function prepareSelectsByRange(\Magento\Framework\DB\Select $select, $ return $this->isRangingNeeded() ? $this->connection->selectsByRange( $field, $select, - $range + $range, + \Magento\Framework\DB\Query\BatchIteratorFactory::NON_UNIQUE_FIELD_ITERATOR ) : [ $select ]; diff --git a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php index b4cb60f5a5c74..fa0d081d0a0ea 100644 --- a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php +++ b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php @@ -3374,18 +3374,59 @@ public function insertFromSelect(Select $select, $table, array $fields = [], $mo } /** - * Get insert queries in array for insert by range with step parameter + * Get an array of select for insert by range with step parameter * + * @see selectsByRangeStrategy() * @param string $rangeField * @param \Magento\Framework\DB\Select $select * @param int $stepCount + * @param string $batchStrategy * @return \Magento\Framework\DB\Select[] * @throws LocalizedException * @deprecated */ - public function selectsByRange($rangeField, \Magento\Framework\DB\Select $select, $stepCount = 100) + public function selectsByRange( + $rangeField, + \Magento\Framework\DB\Select $select, + $stepCount = 100, + $batchStrategy = \Magento\Framework\DB\Query\BatchIteratorFactory::UNIQUE_FIELD_ITERATOR + ) { - $iterator = $this->getQueryGenerator()->generate($rangeField, $select, $stepCount); + return $this->selectsByRangeStrategy($rangeField, $select, $stepCount, $batchStrategy); + } + + /** + * Get an array of select queries using the batching strategy + * + * Depending on the $batchStrategy parameter chooses a strategy. This strategy will be used to create + * an array of select queries. By default method use $batchStrategy parameter: + * \Magento\Framework\DB\Query\BatchIteratorFactory::UNIQUE_FIELD_ITERATOR. + * This parameter means that values of $rangeField have relationship + * one-to-one. + * If values of $rangeField is non-unique and have relationship one-to-many, + * than must be used next $batchStrategy parameter: + * \Magento\Framework\DB\Query\BatchIteratorFactory::NON_UNIQUE_FIELD_ITERATOR. + * + * @see BatchIteratorFactory + * @param string $rangeField - Field which is used for the range mechanism in select + * @param Select $select + * @param int $batchSize - Determines on how many parts will be divided + * the number of values in the select. + * @param string $batchStrategy - It determines which strategy is chosen + * @return \Magento\Framework\DB\Select[] + * @throws LocalizedException Throws if incorrect "FROM" part in \Select exists + * @deprecated This is a temporary solution which is made due to the fact that we + * can't change method selectsByRange() in version 2.1 due to a backwards incompatibility. + * In 2.2 version need to use original method selectsByRange() with additional parameter. + */ + public function selectsByRangeStrategy( + $rangeField, + \Magento\Framework\DB\Select $select, + $batchSize = 100, + $batchStrategy = \Magento\Framework\DB\Query\BatchIteratorFactory::UNIQUE_FIELD_ITERATOR + ) { + $iterator = $this->getQueryGenerator()->generate($rangeField, $select, $batchSize, $batchStrategy); + $queries = []; foreach ($iterator as $query) { $queries[] = $query; diff --git a/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php b/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php index 147e65b8df466..f327569bee64c 100644 --- a/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php +++ b/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php @@ -6,10 +6,25 @@ namespace Magento\Framework\DB\Query; /** - * Factory class for @see \Magento\Framework\DB\Query\BatchIterator + * Factory class for \Magento\Framework\DB\Query\BatchIterator, \Magento\Framework\DB\Query\BatchRangeIterator + * + * @see \Magento\Framework\DB\Query\BatchIterator + * @see \Magento\Framework\DB\Query\BatchRangeIterator */ class BatchIteratorFactory { + /** + * Constant which determine strategy to create iterator which will to process + * range field eg. entity_id with unique values. + */ + const UNIQUE_FIELD_ITERATOR = "unique"; + + /** + * Constant which determine strategy to create iterator which will to process + * range field with non-unique values. + */ + const NON_UNIQUE_FIELD_ITERATOR = "non_unqiue"; + /** * Object Manager instance * @@ -18,34 +33,53 @@ class BatchIteratorFactory private $objectManager = null; /** - * Instance name to create - * * @var string */ - private $instanceName = null; + private $uniqueIteratorInstanceName; + + /** + * @var string + */ + private $nonUniqueIteratorInstanceName; /** - * Factory constructor - * * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @param string $instanceName + * @param $uniqueIteratorInstanceName + * @param $nonUniqueIteratorInstanceName */ public function __construct( \Magento\Framework\ObjectManagerInterface $objectManager, - $instanceName = \Magento\Framework\DB\Query\BatchIterator::class + $nonUniqueIteratorInstanceName = \Magento\Framework\DB\Query\BatchRangeIterator::class, + $uniqueIteratorInstanceName = \Magento\Framework\DB\Query\BatchIterator::class + ) { $this->objectManager = $objectManager; - $this->instanceName = $instanceName; + $this->uniqueIteratorInstanceName = $uniqueIteratorInstanceName; + $this->nonUniqueIteratorInstanceName = $nonUniqueIteratorInstanceName; } /** - * Create class instance with specified parameters + * Create iterator instance with specified parameters + * + * Depending on the chosen strategy specified in $data['batchStrategy'] for selects, + * create an instance of iterator. + * By default will be created \Magento\Framework\DB\Query\BatchIterator class. + * This iterator provide interface for accessing sub-selects which was created from main select. * + * If $data['batchStrategy'] == 'non_unqiue' value then we should to create BatchRangeIterator. This Iterator + * allows to operate with rangeField, which has one-to-many relations with other fields and is not unique. + * The main idea is to separate select to few parts in order to reduce the load of SQL server. + * + * @see \Magento\Framework\DB\Query\Generator * @param array $data - * @return \Magento\Framework\DB\Query\BatchIterator + * @return \Iterator */ public function create(array $data = []) { - return $this->objectManager->create($this->instanceName, $data); + if (isset($data['batchStrategy']) && $data['batchStrategy'] == self::NON_UNIQUE_FIELD_ITERATOR) { + return $this->objectManager->create($this->nonUniqueIteratorInstanceName, $data); + } + + return $this->objectManager->create($this->uniqueIteratorInstanceName, $data); } } diff --git a/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php b/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php new file mode 100644 index 0000000000000..8b14acc175822 --- /dev/null +++ b/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php @@ -0,0 +1,208 @@ +batchSize = $batchSize; + $this->select = $select; + $this->correlationName = $correlationName; + $this->rangeField = $rangeField; + $this->rangeFieldAlias = $rangeFieldAlias; + $this->connection = $select->getConnection(); + } + + /** + * Return the current element + * + * If we don't have sub-select we should create and remember it. + * + * @return Select + */ + public function current() + { + if (null == $this->currentSelect) { + $this->isValid = ($this->currentBatch + $this->batchSize) < $this->totalItemCount; + $this->currentSelect = $this->initSelectObject(); + } + return $this->currentSelect; + } + + /** + * Return the key of the current element + * + * Сan return the number of the current sub-select in the iteration. + * + * @return int + */ + public function key() + { + return $this->iteration; + } + + /** + * Move forward to next element + * + * Retrieve the next sub-select and move cursor to the next element. + * Checks that the count of elements more than the sum of limit and offset. + * + * @return Select + */ + public function next() + { + if (null == $this->currentSelect) { + $this->current(); + } + $this->isValid = ($this->batchSize + $this->currentBatch) < $this->totalItemCount; + $select = $this->initSelectObject(); + if ($this->isValid) { + $this->iteration++; + $this->currentSelect = $select; + } else { + $this->currentSelect = null; + } + return $this->currentSelect; + } + + /** + * Rewind the BatchRangeIterator to the first element. + * + * Allows to start iteration from the beginning. + * Move cursor to the start. + * + * @return void + */ + public function rewind() + { + $this->currentSelect = null; + $this->iteration = 0; + $this->isValid = true; + $this->totalItemCount = 0; + } + + /** + * Checks if current position is valid + * + * @return bool + */ + public function valid() + { + return $this->isValid; + } + + /** + * Initialize select object + * + * Return sub-select which is limited by current batch value and return items from n page of SQL request. + * + * @return \Magento\Framework\DB\Select + */ + private function initSelectObject() + { + $object = clone $this->select; + + if (!$this->totalItemCount) { + $wrapperSelect = $this->connection->select(); + $wrapperSelect->from( + $object, + [ + new \Zend_Db_Expr('COUNT(*) as cnt') + ] + ); + $row = $this->connection->fetchRow($wrapperSelect); + + $this->totalItemCount = intval($row['cnt']); + } + /** + * Reset sort order section from origin select object + */ + $object->order($this->correlationName . '.' . $this->rangeField . ' ' . \Magento\Framework\DB\Select::SQL_ASC); + $object->limit($this->currentBatch, $this->batchSize); + $this->currentBatch += $this->batchSize; + + return $object; + } +} diff --git a/lib/internal/Magento/Framework/DB/Query/Generator.php b/lib/internal/Magento/Framework/DB/Query/Generator.php index 909f4752397a3..d6a1546490fc3 100644 --- a/lib/internal/Magento/Framework/DB/Query/Generator.php +++ b/lib/internal/Magento/Framework/DB/Query/Generator.php @@ -28,16 +28,36 @@ public function __construct(BatchIteratorFactory $iteratorFactory) } /** - * Generate select query list with predefined items count in each select item. + * Generate select query list with predefined items count in each select item * - * @param string $rangeField + * Generates select parameters - batchSize, correlationName, rangeField, rangeFieldAlias, batchStrategy + * to obtain instance of iterator. The behavior of the iterator will depend on the parameters passed to it. + * For example: by default for $batchStrategy parameter used + * \Magento\Framework\DB\Query\BatchIteratorFactory::UNIQUE_FIELD_ITERATOR. This parameter is determine, what + * instance of Iterator will be returned. + * + * Other params: + * select - represents the select object, that should be passed into Iterator. + * batchSize - sets the number of items in select. + * correlationName - is the base table involved in the select. + * rangeField - this is the basic field which used to split select. + * rangeFieldAlias - alias of range field. + * + * @see BatchIteratorFactory + * @param string $rangeField - Field which is used for the range mechanism in select * @param \Magento\Framework\DB\Select $select - * @param int $batchSize - * @return BatchIterator - * @throws LocalizedException + * @param int $batchSize - Determines on how many parts will be divided + * the number of values in the select. + * @param string $batchStrategy It determines which strategy is chosen + * @return \Iterator + * @throws LocalizedException Throws if incorrect "FROM" part in \Select exists */ - public function generate($rangeField, \Magento\Framework\DB\Select $select, $batchSize = 100) - { + public function generate( + $rangeField, + \Magento\Framework\DB\Select $select, + $batchSize = 100, + $batchStrategy = \Magento\Framework\DB\Query\BatchIteratorFactory::UNIQUE_FIELD_ITERATOR + ) { $fromSelect = $select->getPart(\Magento\Framework\DB\Select::FROM); if (empty($fromSelect)) { throw new LocalizedException( @@ -72,7 +92,8 @@ public function generate($rangeField, \Magento\Framework\DB\Select $select, $bat 'batchSize' => $batchSize, 'correlationName' => $fieldCorrelationName, 'rangeField' => $rangeField, - 'rangeFieldAlias' => $rangeFieldAlias + 'rangeFieldAlias' => $rangeFieldAlias, + 'batchStrategy' => $batchStrategy ] ); } diff --git a/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php b/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php new file mode 100644 index 0000000000000..6ae87f9856e87 --- /dev/null +++ b/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php @@ -0,0 +1,121 @@ +batchSize = 10; + $this->currentBatch = 0; + $this->correlationName = 'correlationName'; + $this->rangeField = 'rangeField'; + $this->rangeFieldAlias = 'rangeFieldAlias'; + + $this->selectMock = $this->getMock(Select::class, [], [], '', false, false); + $this->wrapperSelectMock = $this->getMock(Select::class, [], [], '', false, false); + $this->connectionMock = $this->getMock(AdapterInterface::class); + $this->connectionMock->expects($this->any())->method('select')->willReturn($this->wrapperSelectMock); + $this->selectMock->expects($this->once())->method('getConnection')->willReturn($this->connectionMock); + $this->connectionMock->expects($this->any())->method('quoteIdentifier')->willReturnArgument(0); + + $this->model = new BatchRangeIterator( + $this->selectMock, + $this->batchSize, + $this->correlationName, + $this->rangeField, + $this->rangeFieldAlias + ); + } + + /** + * Test steps: + * 1. $iterator->current(); + * 2. $iterator->key(); + * @return void + */ + public function testCurrent() + { + $filed = $this->correlationName . '.' . $this->rangeField; + + $this->selectMock->expects($this->once())->method('limit')->with($this->currentBatch, $this->batchSize); + $this->selectMock->expects($this->once())->method('order')->with($filed . ' ASC'); + $this->assertEquals($this->selectMock, $this->model->current()); + $this->assertEquals(0, $this->model->key()); + } + + /** + * Test the separation of batches + */ + public function testIterations() + { + $iterations = 0; + $this->connectionMock->expects($this->once()) + ->method('fetchRow') + ->willReturn(['cnt' => 105]); + + foreach ($this->model as $key => $value) { + $iterations++; + }; + + $this->assertEquals(10, $iterations); + } +} diff --git a/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php b/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php index fcfaa41ffb4e6..b20f14a1d9bee 100644 --- a/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php @@ -70,7 +70,8 @@ public function testGenerate() 'batchSize' => 100, 'correlationName' => 'cp', 'rangeField' => 'entity_id', - 'rangeFieldAlias' => 'product_id' + 'rangeFieldAlias' => 'product_id', + 'batchStrategy' => 'unique' ] )->willReturn($this->iteratorMock); $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100)); @@ -126,7 +127,8 @@ public function testGenerateWithRangeFieldWithoutAlias() 'batchSize' => 100, 'correlationName' => 'cp', 'rangeField' => 'entity_id', - 'rangeFieldAlias' => 'entity_id' + 'rangeFieldAlias' => 'entity_id', + 'batchStrategy' => 'unique' ] )->willReturn($this->iteratorMock); $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100)); @@ -160,7 +162,8 @@ public function testGenerateWithInvalidWithWildcard() 'batchSize' => 100, 'correlationName' => 'cp', 'rangeField' => 'entity_id', - 'rangeFieldAlias' => 'entity_id' + 'rangeFieldAlias' => 'entity_id', + 'batchStrategy' => 'unique' ] )->willReturn($this->iteratorMock); $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100)); From d8ce0cfd3496f23627954fa9cffc95486e12c8ed Mon Sep 17 00:00:00 2001 From: Oleksandr Osadchyi Date: Fri, 27 Jan 2017 16:35:23 +0200 Subject: [PATCH 02/40] MAGETWO-62616: Products are missed and total count is wrong on category page --- .../Magento/Framework/DB/Query/BatchIteratorFactory.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php b/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php index f327569bee64c..565e441246c20 100644 --- a/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php +++ b/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php @@ -44,14 +44,13 @@ class BatchIteratorFactory /** * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @param $uniqueIteratorInstanceName - * @param $nonUniqueIteratorInstanceName + * @param \Magento\Framework\DB\Query\BatchIterator $uniqueIteratorInstanceName + * @param \Magento\Framework\DB\Query\BatchRangeIterator $nonUniqueIteratorInstanceName */ public function __construct( \Magento\Framework\ObjectManagerInterface $objectManager, $nonUniqueIteratorInstanceName = \Magento\Framework\DB\Query\BatchRangeIterator::class, $uniqueIteratorInstanceName = \Magento\Framework\DB\Query\BatchIterator::class - ) { $this->objectManager = $objectManager; $this->uniqueIteratorInstanceName = $uniqueIteratorInstanceName; From c015f8f0a96ad1612abf196391b15272842e756b Mon Sep 17 00:00:00 2001 From: Oleksandr Osadchyi Date: Fri, 27 Jan 2017 18:05:00 +0200 Subject: [PATCH 03/40] MAGETWO-62616: Products are missed and total count is wrong on category page --- lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php b/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php index 8b14acc175822..0718d2cb5b7b7 100644 --- a/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php +++ b/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php @@ -52,6 +52,7 @@ class BatchRangeIterator implements \Iterator * @var int */ private $totalItemCount; + /** * @var int */ @@ -76,6 +77,7 @@ class BatchRangeIterator implements \Iterator * Initialize dependencies. * * @param Select $select + * @param int $batchSize * @param string $correlationName * @param string $rangeField * @param string $rangeFieldAlias From 65b69dc6f0eb5bbb2f45f311d22ea7ba2cf38a78 Mon Sep 17 00:00:00 2001 From: Oleksandr Osadchyi Date: Fri, 27 Jan 2017 18:32:39 +0200 Subject: [PATCH 04/40] MAGETWO-62616: Products are missed and total count is wrong on category page --- .../Test/Unit/DB/Query/BatchRangeIteratorTest.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php b/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php index 6ae87f9856e87..d51ceed1f25eb 100644 --- a/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php @@ -107,15 +107,16 @@ public function testCurrent() */ public function testIterations() { - $iterations = 0; $this->connectionMock->expects($this->once()) ->method('fetchRow') ->willReturn(['cnt' => 105]); - foreach ($this->model as $key => $value) { - $iterations++; - }; + $this->model->rewind(); - $this->assertEquals(10, $iterations); + $this->assertEquals($this->selectMock, $this->model->current()); + $this->assertEquals(0, $this->model->key()); + $this->assertEquals($this->selectMock, $this->model->next()); + $this->assertTrue($this->model->valid()); + $this->assertEquals(1, $this->model->key()); } } From bde30bc21de847b0b20fe983dc90ae7564e554eb Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Sat, 28 Jan 2017 23:40:34 +0200 Subject: [PATCH 05/40] MAGETWO-63403: Auto Generated coupon codes not applying --- .../SalesRule/Model/ResourceModel/Rule/Collection.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php b/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php index b884a39a8bd8a..f3bd4c239ae37 100644 --- a/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php +++ b/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php @@ -158,8 +158,9 @@ public function setValidationFilter( $orWhereConditions = [ $connection->quoteInto( - '(main_table.coupon_type = ? AND rule_coupons.type = 0)', - \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO + '(main_table.coupon_type = ? AND rule_coupons.type = ?)', + \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO, + \Magento\SalesRule\Helper\Coupon::COUPON_TYPE_SPECIFIC_AUTOGENERATED ), $connection->quoteInto( '(main_table.coupon_type = ? AND main_table.use_auto_generation = 1 AND rule_coupons.type = 1)', From 89afdc3a501c6a2335eeb8db242f3914428290a3 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Sun, 29 Jan 2017 01:19:37 +0200 Subject: [PATCH 06/40] MAGETWO-63403: Auto Generated coupon codes not applying --- .../integration/testsuite/Magento/SalesRule/_files/coupons.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupons.php b/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupons.php index 3062683019b03..36f3365f3de91 100644 --- a/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupons.php +++ b/dev/tests/integration/testsuite/Magento/SalesRule/_files/coupons.php @@ -27,4 +27,4 @@ // type AUTO $coupon = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\SalesRule\Model\Coupon::class); -$coupon->setRuleId($items[3]->getId())->setCode('coupon_code_auto')->setType(0)->save(); +$coupon->setRuleId($items[3]->getId())->setCode('coupon_code_auto')->setType(1)->save(); From ec92cc2fad05952ef7d66ec6fd558be2534b498b Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Sun, 29 Jan 2017 01:29:02 +0200 Subject: [PATCH 07/40] MAGETWO-63403: Auto Generated coupon codes not applying --- .../SalesRule/Model/ResourceModel/Rule/Collection.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php b/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php index f3bd4c239ae37..e9181504563d7 100644 --- a/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php +++ b/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php @@ -158,9 +158,8 @@ public function setValidationFilter( $orWhereConditions = [ $connection->quoteInto( - '(main_table.coupon_type = ? AND rule_coupons.type = ?)', - \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO, - \Magento\SalesRule\Helper\Coupon::COUPON_TYPE_SPECIFIC_AUTOGENERATED + '(main_table.coupon_type = ? AND rule_coupons.type = 1)', + \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO ), $connection->quoteInto( '(main_table.coupon_type = ? AND main_table.use_auto_generation = 1 AND rule_coupons.type = 1)', From 1cf3cb4b6ea24dc7120463a95351a6eccf2dcfd5 Mon Sep 17 00:00:00 2001 From: Sergey Semenov Date: Mon, 30 Jan 2017 18:55:46 +0200 Subject: [PATCH 08/40] MAGETWO-63561: category_ids attribute scope dropdown --- app/code/Magento/Catalog/etc/eav_attributes.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/code/Magento/Catalog/etc/eav_attributes.xml b/app/code/Magento/Catalog/etc/eav_attributes.xml index 133849a28e048..005402937232f 100644 --- a/app/code/Magento/Catalog/etc/eav_attributes.xml +++ b/app/code/Magento/Catalog/etc/eav_attributes.xml @@ -30,6 +30,7 @@ + From a1331cce736188e63224b35af7f025120eb82aea Mon Sep 17 00:00:00 2001 From: Ostap Smolyar Date: Tue, 31 Jan 2017 10:11:48 +0200 Subject: [PATCH 09/40] MTA-3977: Create auto test for Checkout using PayPal Braintree button if Require Customer's Billing Address = Yes --- .../Braintree/Test/Repository/ConfigData.xml | 18 ++++++++ ...heckoutWithBraintreePaypalMinicartTest.xml | 12 +++++ ...illingAndShippingAddressesAreDifferent.php | 46 +++++++++++++++++++ .../tests/app/Magento/Sales/Test/etc/di.xml | 5 ++ 4 files changed, 81 insertions(+) create mode 100644 dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderBillingAndShippingAddressesAreDifferent.php diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml index 191e2763cadfe..08a570c315934 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/Repository/ConfigData.xml @@ -263,6 +263,24 @@ + + + payment + 1 + Yes + 1 + + + + + + payment + 1 + No + 0 + + + payment diff --git a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalMinicartTest.xml b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalMinicartTest.xml index 8b4161fae9a90..adeb4da0ba2da 100644 --- a/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalMinicartTest.xml +++ b/dev/tests/functional/tests/app/Magento/Braintree/Test/TestCase/CheckoutWithBraintreePaypalMinicartTest.xml @@ -48,5 +48,17 @@ + + catalogProductSimple::product_10_dollar + default + guest + Free Shipping + Free + braintree_paypal + braintree, braintree_paypal, freeshipping, braintree_paypal_require_billing_address + test_type:3rd_party_test, severity:S1 + + + 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 new file mode 100644 index 0000000000000..9481af96f2b09 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Constraint/AssertOrderBillingAndShippingAddressesAreDifferent.php @@ -0,0 +1,46 @@ +open(['order_id' => $orderId]); + $orderBillingAddress = $salesOrderView->getAddressesBlock()->getCustomerBillingAddress(); + $orderShippingAddress = $salesOrderView->getAddressesBlock()->getCustomerShippingAddress(); + + \PHPUnit_Framework_Assert::assertFalse( + $orderBillingAddress == $orderShippingAddress, + 'Billing and shipping addresses on order page are the same.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return 'Billing and Shipping addresses are different on order page.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml index d77d737a2e9f9..b6c087e8edba9 100644 --- a/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Sales/Test/etc/di.xml @@ -111,4 +111,9 @@ S0 + + + S1 + + From 22e8f97b1346e6a2d3a6ea26c58c10ffc7a09818 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Tue, 31 Jan 2017 11:57:14 +0200 Subject: [PATCH 10/40] MAGETWO-63403: Auto Generated coupon codes not applying --- .../Model/ResourceModel/Rule/Collection.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php b/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php index e9181504563d7..b1c6fd79d418c 100644 --- a/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php +++ b/app/code/Magento/SalesRule/Model/ResourceModel/Rule/Collection.php @@ -156,11 +156,19 @@ public function setValidationFilter( \Magento\SalesRule\Model\Rule::COUPON_TYPE_NO_COUPON ); - $orWhereConditions = [ + $autoGeneratedCouponCondition = [ $connection->quoteInto( - '(main_table.coupon_type = ? AND rule_coupons.type = 1)', + "main_table.coupon_type = ?", \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO ), + $connection->quoteInto( + "rule_coupons.type = ?", + \Magento\SalesRule\Api\Data\CouponInterface::TYPE_GENERATED + ), + ]; + + $orWhereConditions = [ + "(" . implode($autoGeneratedCouponCondition, " AND ") . ")", $connection->quoteInto( '(main_table.coupon_type = ? AND main_table.use_auto_generation = 1 AND rule_coupons.type = 1)', \Magento\SalesRule\Model\Rule::COUPON_TYPE_SPECIFIC From a631bb6b31479bcb37665699fd2c8a6481c5ffde Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Tue, 31 Jan 2017 16:58:00 +0200 Subject: [PATCH 11/40] MAGETWO-63403: Auto Generated coupon codes not applying --- .../Promo/Quote/Edit/PromoQuoteForm.xml | 5 ++ .../Quote/Edit/Section/ManageCouponCode.php | 50 +++++++++++++++++++ .../AssertCartPriceRuleApplying.php | 14 ++++-- .../SalesRule/Test/Repository/SalesRule.xml | 1 - .../TestCase/CreateSalesRuleEntityTest.php | 21 +++++++- .../TestCase/CreateSalesRuleEntityTest.xml | 27 ++++++++++ 6 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/Section/ManageCouponCode.php diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/PromoQuoteForm.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/PromoQuoteForm.xml index 7e30946214475..28541b56d43f8 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/PromoQuoteForm.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/PromoQuoteForm.xml @@ -80,4 +80,9 @@ [data-index="labels"] css selector + + \Magento\SalesRule\Test\Block\Adminhtml\Promo\Quote\Edit\Section\ManageCouponCode + [data-index="block_promo_sales_rule_edit_tab_coupons"] + css selector + diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/Section/ManageCouponCode.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/Section/ManageCouponCode.php new file mode 100644 index 0000000000000..ebd20616dc891 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Block/Adminhtml/Promo/Quote/Edit/Section/ManageCouponCode.php @@ -0,0 +1,50 @@ +_rootElement->find(self::GENERATE_CODES_BUTTON_CSS_SELECTOR); + $button->click(); + } + + /** + * Retrieve last generated coupon code + * + * @return string + */ + public function getGeneratedCouponCode() + { + $this->waitForSpinner(); + $column = $this->_rootElement->find(self::LAST_GENERATED_COUPON_CODE_SELECTOR, Locator::SELECTOR_XPATH); + return $column->getText(); + } + + private function waitForSpinner() + { + $this->waitForElementNotVisible(self::SPINNER); + sleep(1); + } +} diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleApplying.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleApplying.php index d554ec2ce7991..f27667e91ea64 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleApplying.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleApplying.php @@ -156,6 +156,7 @@ public function processAssert( Customer $customer = null, Address $address = null, $isLoggedIn = null, + $couponCode = null, array $shipping = [], array $cartPrice = [] ) { @@ -179,10 +180,15 @@ public function processAssert( $this->checkoutCart->getShippingBlock()->fillEstimateShippingAndTax($address); $this->checkoutCart->getShippingBlock()->selectShippingMethod($shipping); } - if ($salesRule->getCouponCode() || $salesRuleOrigin->getCouponCode()) { - $this->checkoutCart->getDiscountCodesBlock()->applyCouponCode( - $salesRule->getCouponCode() ? $salesRule->getCouponCode() : $salesRuleOrigin->getCouponCode() - ); + + if ($salesRule->getCouponCode()) { + $couponCode = $salesRule->getCouponCode(); + } elseif($salesRuleOrigin->getCouponCode()) { + $couponCode = $salesRuleOrigin->getCouponCode(); + } + + if ($salesRule->getCouponCode() || $salesRuleOrigin->getCouponCode() || $couponCode) { + $this->checkoutCart->getDiscountCodesBlock()->applyCouponCode($couponCode); } $this->assert(); } diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml index 911ac8e8482bb..9ac8e5abd4fb9 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Repository/SalesRule.xml @@ -95,7 +95,6 @@ 50 Yes - Cart Price Rule with with complex conditions %isolation% Cart Price Rule with with complex conditions diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.php index 68f4470dc275c..1e413bf3ca5ae 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.php @@ -6,6 +6,7 @@ namespace Magento\SalesRule\Test\TestCase; +use Magento\SalesRule\Test\Block\Adminhtml\Promo\Quote\Edit\Section\ManageCouponCode; use Magento\SalesRule\Test\Fixture\SalesRule; use Magento\SalesRule\Test\Page\Adminhtml\PromoQuoteEdit; use Magento\SalesRule\Test\Page\Adminhtml\PromoQuoteIndex; @@ -107,7 +108,8 @@ public function testCreateSalesRule( CatalogProductSimple $productForSalesRule1, CatalogProductSimple $productForSalesRule2 = null, Customer $customer = null, - $conditionEntity = null + $conditionEntity = null, + SalesRule $salesRuleEdit = null ) { $replace = null; $this->salesRuleName = $salesRule->getName(); @@ -127,7 +129,22 @@ public function testCreateSalesRule( // Steps $this->promoQuoteNew->open(); $this->promoQuoteNew->getSalesRuleForm()->fill($salesRule, null, $replace); - $this->promoQuoteNew->getFormPageActions()->save(); + + if ($salesRule->getCouponType() == "Auto") { + $this->promoQuoteNew->getFormPageActions()->saveAndContinue(); + $form = $this->promoQuoteEdit->getSalesRuleForm(); + $form->openSection('manage_coupon_code'); + /** @var ManageCouponCode $section */ + $section = $form->getSection('manage_coupon_code'); + $section->fill($salesRuleEdit); + $section->generateCouponCodes(); + $couponCode = $section->getGeneratedCouponCode(); + $this->promoQuoteEdit->getFormPageActions()->save(); + + return ["couponCode" => $couponCode]; + } else { + $this->promoQuoteNew->getFormPageActions()->save(); + } } /** diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.xml index 05df20e4025b5..7710bd2dc0f0f 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityTest.xml @@ -424,5 +424,32 @@ + + United States + California + 95814 + Flat Rate + Fixed + Cart Price Rule2 %isolation% + Cart Price Rule Description %isolation% + Yes + Main Website + NOT LOGGED IN + Auto + Fixed amount discount + 35 + No + No + Coupon code+fixed amount discount + 1 + simple_for_salesrule_1 + 2 + 200.00 + 140.00 + 70.00 + + + + From f6eb21855f4e615ee6cf1b02a67967da47ada084 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Tue, 31 Jan 2017 17:46:43 +0200 Subject: [PATCH 12/40] MAGETWO-63403: Auto Generated coupon codes not applying --- .../SalesRule/Test/Constraint/AssertCartPriceRuleApplying.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleApplying.php b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleApplying.php index f27667e91ea64..a1893412681cd 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleApplying.php +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/Constraint/AssertCartPriceRuleApplying.php @@ -183,7 +183,7 @@ public function processAssert( if ($salesRule->getCouponCode()) { $couponCode = $salesRule->getCouponCode(); - } elseif($salesRuleOrigin->getCouponCode()) { + } elseif ($salesRuleOrigin->getCouponCode()) { $couponCode = $salesRuleOrigin->getCouponCode(); } From e9338a95a9622dcfb8e0c4c93e27ad031239cf04 Mon Sep 17 00:00:00 2001 From: Ostap Smolyar Date: Wed, 1 Feb 2017 11:15:58 +0200 Subject: [PATCH 13/40] MTA-3977: Create auto test for Checkout using PayPal Braintree button if Require Customer's Billing Address = Yes --- .../AssertOrderBillingAndShippingAddressesAreDifferent.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 9481af96f2b09..fadf9318bfe39 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,9 +28,10 @@ public function processAssert( $orderBillingAddress = $salesOrderView->getAddressesBlock()->getCustomerBillingAddress(); $orderShippingAddress = $salesOrderView->getAddressesBlock()->getCustomerShippingAddress(); - \PHPUnit_Framework_Assert::assertFalse( - $orderBillingAddress == $orderShippingAddress, - 'Billing and shipping addresses on order page are the same.' + \PHPUnit_Framework_Assert::assertNotEquals( + $orderBillingAddress, + $orderShippingAddress, + "Billing and shipping addresses on order page are the same but shouldn't." ); } From d2c036691c497dad60de8037d59a859574563739 Mon Sep 17 00:00:00 2001 From: Oleksandr Osadchyi Date: Thu, 2 Feb 2017 18:32:56 +0200 Subject: [PATCH 14/40] MAGETWO-62616: Products are missed and total count is wrong on category page --- .../Framework/DB/Adapter/Pdo/Mysql.php | 27 +-------------- .../DB/Query/BatchIteratorFactory.php | 2 +- .../Framework/DB/Query/BatchRangeIterator.php | 3 +- .../Unit/DB/Query/BatchRangeIteratorTest.php | 17 +++++----- .../Test/Unit/DB/Query/GeneratorTest.php | 34 +++++++++++++++++++ 5 files changed, 45 insertions(+), 38 deletions(-) diff --git a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php index fa0d081d0a0ea..99f687d172f36 100644 --- a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php +++ b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php @@ -3373,28 +3373,6 @@ public function insertFromSelect(Select $select, $table, array $fields = [], $mo return $query; } - /** - * Get an array of select for insert by range with step parameter - * - * @see selectsByRangeStrategy() - * @param string $rangeField - * @param \Magento\Framework\DB\Select $select - * @param int $stepCount - * @param string $batchStrategy - * @return \Magento\Framework\DB\Select[] - * @throws LocalizedException - * @deprecated - */ - public function selectsByRange( - $rangeField, - \Magento\Framework\DB\Select $select, - $stepCount = 100, - $batchStrategy = \Magento\Framework\DB\Query\BatchIteratorFactory::UNIQUE_FIELD_ITERATOR - ) - { - return $this->selectsByRangeStrategy($rangeField, $select, $stepCount, $batchStrategy); - } - /** * Get an array of select queries using the batching strategy * @@ -3415,11 +3393,8 @@ public function selectsByRange( * @param string $batchStrategy - It determines which strategy is chosen * @return \Magento\Framework\DB\Select[] * @throws LocalizedException Throws if incorrect "FROM" part in \Select exists - * @deprecated This is a temporary solution which is made due to the fact that we - * can't change method selectsByRange() in version 2.1 due to a backwards incompatibility. - * In 2.2 version need to use original method selectsByRange() with additional parameter. */ - public function selectsByRangeStrategy( + public function selectsByRange( $rangeField, \Magento\Framework\DB\Select $select, $batchSize = 100, diff --git a/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php b/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php index 565e441246c20..218bfa413f8c9 100644 --- a/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php +++ b/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php @@ -6,7 +6,7 @@ namespace Magento\Framework\DB\Query; /** - * Factory class for \Magento\Framework\DB\Query\BatchIterator, \Magento\Framework\DB\Query\BatchRangeIterator + * Factory class for \Magento\Framework\DB\Query\BatchIterator | \Magento\Framework\DB\Query\BatchRangeIterator * * @see \Magento\Framework\DB\Query\BatchIterator * @see \Magento\Framework\DB\Query\BatchRangeIterator diff --git a/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php b/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php index 0718d2cb5b7b7..576b545b236b3 100644 --- a/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php +++ b/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php @@ -126,7 +126,7 @@ public function key() } /** - * Move forward to next element + * Move forward to next sub-select * * Retrieve the next sub-select and move cursor to the next element. * Checks that the count of elements more than the sum of limit and offset. @@ -153,7 +153,6 @@ public function next() * Rewind the BatchRangeIterator to the first element. * * Allows to start iteration from the beginning. - * Move cursor to the start. * * @return void */ diff --git a/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php b/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php index d51ceed1f25eb..aeb4ed97b4853 100644 --- a/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/DB/Query/BatchRangeIteratorTest.php @@ -94,10 +94,8 @@ protected function setUp() */ public function testCurrent() { - $filed = $this->correlationName . '.' . $this->rangeField; - $this->selectMock->expects($this->once())->method('limit')->with($this->currentBatch, $this->batchSize); - $this->selectMock->expects($this->once())->method('order')->with($filed . ' ASC'); + $this->selectMock->expects($this->once())->method('order')->with('correlationName.rangeField' . ' ASC'); $this->assertEquals($this->selectMock, $this->model->current()); $this->assertEquals(0, $this->model->key()); } @@ -107,16 +105,17 @@ public function testCurrent() */ public function testIterations() { + $iterations = 0; + $this->connectionMock->expects($this->once()) ->method('fetchRow') ->willReturn(['cnt' => 105]); - $this->model->rewind(); + foreach ($this->model as $key) { + $this->assertEquals($this->selectMock, $key); + $iterations++; + }; - $this->assertEquals($this->selectMock, $this->model->current()); - $this->assertEquals(0, $this->model->key()); - $this->assertEquals($this->selectMock, $this->model->next()); - $this->assertTrue($this->model->valid()); - $this->assertEquals(1, $this->model->key()); + $this->assertEquals(10, $iterations); } } diff --git a/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php b/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php index b20f14a1d9bee..e96429cb42211 100644 --- a/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php @@ -168,4 +168,38 @@ public function testGenerateWithInvalidWithWildcard() )->willReturn($this->iteratorMock); $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100)); } + + /** + * Test success generate with non-unique strategy. + * @return void + */ + public function testGenerateWithNonUniqueStrategy() + { + $map = [ + [ + Select::FROM, + [ + 'cp' => ['joinType' => Select::FROM] + ] + ], + [ + Select::COLUMNS, + [ + ['cp', 'entity_id', 'product_id'] + ] + ] + ]; + $this->selectMock->expects($this->exactly(2))->method('getPart')->willReturnMap($map); + $this->factoryMock->expects($this->once())->method('create')->with( + [ + 'select' => $this->selectMock, + 'batchSize' => 100, + 'correlationName' => 'cp', + 'rangeField' => 'entity_id', + 'rangeFieldAlias' => 'product_id', + 'batchStrategy' => 'non_unique' + ] + )->willReturn($this->iteratorMock); + $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100, 'non_unique')); + } } From 421ad1639be8a3a547398c49d25277b12314f23e Mon Sep 17 00:00:00 2001 From: Oleksandr Osadchyi Date: Fri, 3 Feb 2017 17:39:52 +0200 Subject: [PATCH 15/40] MAGETWO-62616: Products are missed and total count is wrong on category page --- .../Magento/Framework/DB/Query/BatchRangeIterator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php b/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php index 576b545b236b3..baf0a3921c6be 100644 --- a/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php +++ b/lib/internal/Magento/Framework/DB/Query/BatchRangeIterator.php @@ -106,7 +106,7 @@ public function __construct( */ public function current() { - if (null == $this->currentSelect) { + if (null === $this->currentSelect) { $this->isValid = ($this->currentBatch + $this->batchSize) < $this->totalItemCount; $this->currentSelect = $this->initSelectObject(); } @@ -135,7 +135,7 @@ public function key() */ public function next() { - if (null == $this->currentSelect) { + if (null === $this->currentSelect) { $this->current(); } $this->isValid = ($this->batchSize + $this->currentBatch) < $this->totalItemCount; From a3b5a187ea9368b12ee146317284e3515dd2f04f Mon Sep 17 00:00:00 2001 From: as7469 Date: Wed, 8 Feb 2017 14:56:42 +0100 Subject: [PATCH 16/40] Fix for https://github.com/magento/magento2/issues/8392 --- .../Catalog/Model/ProductLink/CollectionProvider.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php index 917a47b637cea..80d625fcb95f5 100644 --- a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php +++ b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php @@ -48,9 +48,14 @@ public function getCollection(\Magento\Catalog\Model\Product $product, $type) $products = $this->providers[$type]->getLinkedProducts($product); $converter = $this->converterPool->getConverter($type); $output = []; + $realoutput = []; foreach ($products as $item) { $output[$item->getId()] = $converter->convert($item); } - return $output; + foreach ($output as $item) { + $realoutput[$item["position"]] = $item; + } + ksort($realoutput); + return $realoutput; } } From 207b160150b020f64b2f9139f973ca2528587bea Mon Sep 17 00:00:00 2001 From: as7469 Date: Wed, 8 Feb 2017 16:42:09 +0100 Subject: [PATCH 17/40] Fix for https://github.com/magento/magento2/issues/8392 --- .../Catalog/Model/ProductLink/CollectionProvider.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php index 80d625fcb95f5..d495da310df00 100644 --- a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php +++ b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php @@ -48,14 +48,14 @@ public function getCollection(\Magento\Catalog\Model\Product $product, $type) $products = $this->providers[$type]->getLinkedProducts($product); $converter = $this->converterPool->getConverter($type); $output = []; - $realoutput = []; + $realoutput = []; foreach ($products as $item) { $output[$item->getId()] = $converter->convert($item); } - foreach ($output as $item) { - $realoutput[$item["position"]] = $item; - } - ksort($realoutput); + foreach ($output as $item) { + $realoutput[$item["position"]] = $item; + } + ksort($realoutput); return $realoutput; } } From 5a53b8ac28d866cd4e7c2c4bd401cfc6e91910a6 Mon Sep 17 00:00:00 2001 From: Oleksandr Osadchyi Date: Thu, 9 Feb 2017 18:11:04 +0200 Subject: [PATCH 18/40] MAGETWO-62616: Products are missed and total count is wrong on category page --- .../Category/Product/AbstractAction.php | 40 +++++--- .../Framework/DB/Adapter/Pdo/Mysql.php | 36 ++----- .../Framework/DB/Query/BatchIterator.php | 2 +- .../DB/Query/BatchIteratorFactory.php | 57 +++-------- .../DB/Query/BatchIteratorInterface.php | 68 +++++++++++++ .../Framework/DB/Query/BatchRangeIterator.php | 2 +- .../Magento/Framework/DB/Query/Generator.php | 95 +++++++++++++++++-- .../Test/Unit/DB/Query/GeneratorTest.php | 21 ++-- 8 files changed, 220 insertions(+), 101 deletions(-) create mode 100644 lib/internal/Magento/Framework/DB/Query/BatchIteratorInterface.php diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php index dbdd164486fab..b031e5bda2944 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php @@ -8,6 +8,8 @@ namespace Magento\Catalog\Model\Indexer\Category\Product; +use Magento\Framework\DB\Query\BatchIteratorInterface as BatchIteratorInterface; +use Magento\Framework\DB\Query\Generator as QueryGenerator; use Magento\Framework\App\ResourceConnection; use Magento\Framework\EntityManager\MetadataPool; @@ -102,6 +104,11 @@ abstract class AbstractAction */ protected $tempTreeIndexTableName; + /** + * @var QueryGenerator + */ + private $queryGenerator; + /** * @param ResourceConnection $resource * @param \Magento\Store\Model\StoreManagerInterface $storeManager @@ -110,12 +117,14 @@ abstract class AbstractAction public function __construct( \Magento\Framework\App\ResourceConnection $resource, \Magento\Store\Model\StoreManagerInterface $storeManager, - \Magento\Catalog\Model\Config $config + \Magento\Catalog\Model\Config $config, + QueryGenerator $queryGenerator ) { $this->resource = $resource; $this->connection = $resource->getConnection(); $this->storeManager = $storeManager; $this->config = $config; + $this->queryGenerator = $queryGenerator; } /** @@ -309,16 +318,25 @@ protected function isRangingNeeded() * @param int $range * @return \Magento\Framework\DB\Select[] */ - protected function prepareSelectsByRange(\Magento\Framework\DB\Select $select, $field, $range = self::RANGE_CATEGORY_STEP) - { - return $this->isRangingNeeded() ? $this->connection->selectsByRange( - $field, - $select, - $range, - \Magento\Framework\DB\Query\BatchIteratorFactory::NON_UNIQUE_FIELD_ITERATOR - ) : [ - $select - ]; + protected function prepareSelectsByRange( + \Magento\Framework\DB\Select $select, + $field, + $range = self::RANGE_CATEGORY_STEP + ) { + if($this->isRangingNeeded()) { + $iterator = $this->queryGenerator->generate( + $field, + $select, + $range + ); + + $queries = []; + foreach ($iterator as $query) { + $queries[] = $query; + } + return $queries; + } + return [$select]; } /** diff --git a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php index 1185ade40ac3a..210ced53e5916 100644 --- a/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php +++ b/lib/internal/Magento/Framework/DB/Adapter/Pdo/Mysql.php @@ -3375,34 +3375,18 @@ public function insertFromSelect(Select $select, $table, array $fields = [], $mo } /** - * Get an array of select queries using the batching strategy - * - * Depending on the $batchStrategy parameter chooses a strategy. This strategy will be used to create - * an array of select queries. By default method use $batchStrategy parameter: - * \Magento\Framework\DB\Query\BatchIteratorFactory::UNIQUE_FIELD_ITERATOR. - * This parameter means that values of $rangeField have relationship - * one-to-one. - * If values of $rangeField is non-unique and have relationship one-to-many, - * than must be used next $batchStrategy parameter: - * \Magento\Framework\DB\Query\BatchIteratorFactory::NON_UNIQUE_FIELD_ITERATOR. - * - * @see BatchIteratorFactory - * @param string $rangeField - Field which is used for the range mechanism in select - * @param Select $select - * @param int $batchSize - Determines on how many parts will be divided - * the number of values in the select. - * @param string $batchStrategy - It determines which strategy is chosen + * Get insert queries in array for insert by range with step parameter + * + * @param string $rangeField + * @param \Magento\Framework\DB\Select $select + * @param int $stepCount * @return \Magento\Framework\DB\Select[] - * @throws LocalizedException Throws if incorrect "FROM" part in \Select exists + * @throws LocalizedException + * @deprecated */ - public function selectsByRange( - $rangeField, - \Magento\Framework\DB\Select $select, - $batchSize = 100, - $batchStrategy = \Magento\Framework\DB\Query\BatchIteratorFactory::UNIQUE_FIELD_ITERATOR - ) { - $iterator = $this->getQueryGenerator()->generate($rangeField, $select, $batchSize, $batchStrategy); - + public function selectsByRange($rangeField, \Magento\Framework\DB\Select $select, $stepCount = 100) + { + $iterator = $this->getQueryGenerator()->generate($rangeField, $select, $stepCount); $queries = []; foreach ($iterator as $query) { $queries[] = $query; diff --git a/lib/internal/Magento/Framework/DB/Query/BatchIterator.php b/lib/internal/Magento/Framework/DB/Query/BatchIterator.php index 4235eeb7a65e9..76e46d72d5c9c 100644 --- a/lib/internal/Magento/Framework/DB/Query/BatchIterator.php +++ b/lib/internal/Magento/Framework/DB/Query/BatchIterator.php @@ -11,7 +11,7 @@ /** * Query batch iterator */ -class BatchIterator implements \Iterator +class BatchIterator implements BatchIteratorInterface { /** * @var int diff --git a/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php b/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php index 218bfa413f8c9..563439bfb13e9 100644 --- a/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php +++ b/lib/internal/Magento/Framework/DB/Query/BatchIteratorFactory.php @@ -6,25 +6,10 @@ namespace Magento\Framework\DB\Query; /** - * Factory class for \Magento\Framework\DB\Query\BatchIterator | \Magento\Framework\DB\Query\BatchRangeIterator - * - * @see \Magento\Framework\DB\Query\BatchIterator - * @see \Magento\Framework\DB\Query\BatchRangeIterator + * Factory class for @see \Magento\Framework\DB\Query\BatchIterator */ class BatchIteratorFactory { - /** - * Constant which determine strategy to create iterator which will to process - * range field eg. entity_id with unique values. - */ - const UNIQUE_FIELD_ITERATOR = "unique"; - - /** - * Constant which determine strategy to create iterator which will to process - * range field with non-unique values. - */ - const NON_UNIQUE_FIELD_ITERATOR = "non_unqiue"; - /** * Object Manager instance * @@ -33,52 +18,34 @@ class BatchIteratorFactory private $objectManager = null; /** + * Instance name to create + * * @var string */ - private $uniqueIteratorInstanceName; - - /** - * @var string - */ - private $nonUniqueIteratorInstanceName; + private $instanceName = null; /** + * Factory constructor + * * @param \Magento\Framework\ObjectManagerInterface $objectManager - * @param \Magento\Framework\DB\Query\BatchIterator $uniqueIteratorInstanceName - * @param \Magento\Framework\DB\Query\BatchRangeIterator $nonUniqueIteratorInstanceName + * @param string $instanceName */ public function __construct( \Magento\Framework\ObjectManagerInterface $objectManager, - $nonUniqueIteratorInstanceName = \Magento\Framework\DB\Query\BatchRangeIterator::class, - $uniqueIteratorInstanceName = \Magento\Framework\DB\Query\BatchIterator::class + $instanceName = \Magento\Framework\DB\Query\BatchIterator::class ) { $this->objectManager = $objectManager; - $this->uniqueIteratorInstanceName = $uniqueIteratorInstanceName; - $this->nonUniqueIteratorInstanceName = $nonUniqueIteratorInstanceName; + $this->instanceName = $instanceName; } /** - * Create iterator instance with specified parameters + * Create class instance with specified parameters * - * Depending on the chosen strategy specified in $data['batchStrategy'] for selects, - * create an instance of iterator. - * By default will be created \Magento\Framework\DB\Query\BatchIterator class. - * This iterator provide interface for accessing sub-selects which was created from main select. - * - * If $data['batchStrategy'] == 'non_unqiue' value then we should to create BatchRangeIterator. This Iterator - * allows to operate with rangeField, which has one-to-many relations with other fields and is not unique. - * The main idea is to separate select to few parts in order to reduce the load of SQL server. - * - * @see \Magento\Framework\DB\Query\Generator * @param array $data - * @return \Iterator + * @return \Magento\Framework\DB\Query\BatchIteratorInterface */ public function create(array $data = []) { - if (isset($data['batchStrategy']) && $data['batchStrategy'] == self::NON_UNIQUE_FIELD_ITERATOR) { - return $this->objectManager->create($this->nonUniqueIteratorInstanceName, $data); - } - - return $this->objectManager->create($this->uniqueIteratorInstanceName, $data); + return $this->objectManager->create($this->instanceName, $data); } } diff --git a/lib/internal/Magento/Framework/DB/Query/BatchIteratorInterface.php b/lib/internal/Magento/Framework/DB/Query/BatchIteratorInterface.php new file mode 100644 index 0000000000000..067b4e76a91c3 --- /dev/null +++ b/lib/internal/Magento/Framework/DB/Query/BatchIteratorInterface.php @@ -0,0 +1,68 @@ +iteratorFactory = $iteratorFactory; + $this->rangeIteratorFactory = $rangeIteratorFactory; } /** * Generate select query list with predefined items count in each select item * - * Generates select parameters - batchSize, correlationName, rangeField, rangeFieldAlias, batchStrategy + * Generates select parameters - batchSize, correlationName, rangeField, rangeFieldAlias * to obtain instance of iterator. The behavior of the iterator will depend on the parameters passed to it. * For example: by default for $batchStrategy parameter used - * \Magento\Framework\DB\Query\BatchIteratorFactory::UNIQUE_FIELD_ITERATOR. This parameter is determine, what + * \Magento\Framework\DB\Query\BatchIteratorInterface::UNIQUE_FIELD_ITERATOR. This parameter is determine, what * instance of Iterator will be returned. * * Other params: @@ -43,21 +51,25 @@ public function __construct(BatchIteratorFactory $iteratorFactory) * rangeField - this is the basic field which used to split select. * rangeFieldAlias - alias of range field. * - * @see BatchIteratorFactory + * @see \Magento\Framework\DB\Query\BatchIteratorInterface * @param string $rangeField - Field which is used for the range mechanism in select * @param \Magento\Framework\DB\Select $select * @param int $batchSize - Determines on how many parts will be divided * the number of values in the select. * @param string $batchStrategy It determines which strategy is chosen - * @return \Iterator + * @return BatchIteratorInterface * @throws LocalizedException Throws if incorrect "FROM" part in \Select exists */ public function generate( $rangeField, \Magento\Framework\DB\Select $select, $batchSize = 100, - $batchStrategy = \Magento\Framework\DB\Query\BatchIteratorFactory::UNIQUE_FIELD_ITERATOR + $batchStrategy = \Magento\Framework\DB\Query\BatchIteratorInterface::UNIQUE_FIELD_ITERATOR ) { + if ($batchStrategy == \Magento\Framework\DB\Query\BatchIteratorInterface::NON_UNIQUE_FIELD_ITERATOR) { + return $this->generateByRange($rangeField, $select, $batchSize); + } + $fromSelect = $select->getPart(\Magento\Framework\DB\Select::FROM); if (empty($fromSelect)) { throw new LocalizedException( @@ -87,13 +99,80 @@ public function generate( } return $this->iteratorFactory->create( + [ + 'select' => $select, + 'batchSize' => $batchSize, + 'correlationName' => $fieldCorrelationName, + 'rangeField' => $rangeField, + 'rangeFieldAlias' => $rangeFieldAlias + ] + ); + } + + /** + * Generate select query list with predefined items count in each select item. + * + * Generates select parameters - batchSize, correlationName, rangeField, rangeFieldAlias + * to obtain instance of BatchRangeIterator. + * + * Other params: + * select - represents the select object, that should be passed into Iterator. + * batchSize - sets the number of items in select. + * correlationName - is the base table involved in the select. + * rangeField - this is the basic field which used to split select. + * rangeFieldAlias - alias of range field. + * + * @see BatchRangeIterator + * @param string $rangeField - Field which is used for the range mechanism in select + * @param \Magento\Framework\DB\Select $select + * @param int $batchSize + * @return BatchIteratorInterface + * @throws LocalizedException Throws if incorrect "FROM" part in \Select exists + * @see \Magento\Framework\DB\Query\Generator + * @deprecated This is a temporary solution which is made due to the fact that we + * can't change method generate() in version 2.1 due to a backwards incompatibility. + * In 2.2 version need to use original method generate() with additional parameter. + */ + public function generateByRange( + $rangeField, + \Magento\Framework\DB\Select $select, + $batchSize = 100 + ) { + $fromSelect = $select->getPart(\Magento\Framework\DB\Select::FROM); + if (empty($fromSelect)) { + throw new LocalizedException( + new \Magento\Framework\Phrase('Select object must have correct "FROM" part') + ); + } + + $fieldCorrelationName = ''; + foreach ($fromSelect as $correlationName => $fromPart) { + if ($fromPart['joinType'] == \Magento\Framework\DB\Select::FROM) { + $fieldCorrelationName = $correlationName; + break; + } + } + + $columns = $select->getPart(\Magento\Framework\DB\Select::COLUMNS); + /** + * Calculate $rangeField alias + */ + $rangeFieldAlias = $rangeField; + foreach ($columns as $column) { + list($table, $columnName, $alias) = $column; + if ($table == $fieldCorrelationName && $columnName == $rangeField) { + $rangeFieldAlias = $alias ?: $rangeField; + break; + } + } + + return $this->rangeIteratorFactory->create( [ 'select' => $select, 'batchSize' => $batchSize, 'correlationName' => $fieldCorrelationName, 'rangeField' => $rangeField, 'rangeFieldAlias' => $rangeFieldAlias, - 'batchStrategy' => $batchStrategy ] ); } diff --git a/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php b/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php index e96429cb42211..1355d62e891d3 100644 --- a/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php @@ -7,6 +7,7 @@ use Magento\Framework\DB\Query\Generator; use Magento\Framework\DB\Query\BatchIteratorFactory; +use Magento\Framework\DB\Query\BatchRangeIteratorFactory; use Magento\Framework\DB\Select; use Magento\Framework\DB\Query\BatchIterator; @@ -32,15 +33,21 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase */ private $iteratorMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $rangeFactoryMock; + /** * Setup test dependencies. */ protected function setUp() { $this->factoryMock = $this->getMock(BatchIteratorFactory::class, [], [], '', false, false); + $this->rangeFactoryMock = $this->getMock(BatchRangeIteratorFactory::class, ['create'], [], '', false, false); $this->selectMock = $this->getMock(Select::class, [], [], '', false, false); $this->iteratorMock = $this->getMock(BatchIterator::class, [], [], '', false, false); - $this->model = new Generator($this->factoryMock); + $this->model = new Generator($this->factoryMock, $this->rangeFactoryMock); } /** @@ -70,8 +77,7 @@ public function testGenerate() 'batchSize' => 100, 'correlationName' => 'cp', 'rangeField' => 'entity_id', - 'rangeFieldAlias' => 'product_id', - 'batchStrategy' => 'unique' + 'rangeFieldAlias' => 'product_id' ] )->willReturn($this->iteratorMock); $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100)); @@ -127,8 +133,7 @@ public function testGenerateWithRangeFieldWithoutAlias() 'batchSize' => 100, 'correlationName' => 'cp', 'rangeField' => 'entity_id', - 'rangeFieldAlias' => 'entity_id', - 'batchStrategy' => 'unique' + 'rangeFieldAlias' => 'entity_id' ] )->willReturn($this->iteratorMock); $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100)); @@ -162,8 +167,7 @@ public function testGenerateWithInvalidWithWildcard() 'batchSize' => 100, 'correlationName' => 'cp', 'rangeField' => 'entity_id', - 'rangeFieldAlias' => 'entity_id', - 'batchStrategy' => 'unique' + 'rangeFieldAlias' => 'entity_id' ] )->willReturn($this->iteratorMock); $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100)); @@ -196,8 +200,7 @@ public function testGenerateWithNonUniqueStrategy() 'batchSize' => 100, 'correlationName' => 'cp', 'rangeField' => 'entity_id', - 'rangeFieldAlias' => 'product_id', - 'batchStrategy' => 'non_unique' + 'rangeFieldAlias' => 'product_id' ] )->willReturn($this->iteratorMock); $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100, 'non_unique')); From fe5525285ac4e05cd3117e00a85903123f95b645 Mon Sep 17 00:00:00 2001 From: Sergey Semenov Date: Thu, 9 Feb 2017 19:12:49 +0200 Subject: [PATCH 19/40] MAGETWO-61830: Modify ConfigurableProduct datasets --- .../Test/Repository/ConfigurableProduct.xml | 34 +++++++++++++++++ .../ConfigurableAttributesData.xml | 38 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml index 07d85bd5b3491..7660a6ea94f44 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct.xml @@ -241,6 +241,40 @@ + + Test configurable product with color and size %isolation% + sku_test_configurable_product_%isolation% + This item has weight + 30 + Yes + Catalog, Search + + taxable_goods + + configurable-product-%isolation% + + color_for_promo_rules + + + In Stock + + + + default + + + + default + + + configurable_default + + + 40 + price_40 + + + Test configurable product %isolation% sku_test_configurable_product_%isolation% diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml index 2c2b02990b45a..9046294258b54 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml @@ -563,6 +563,44 @@ + + + + + + 5.00 + Yes + + + 10.00 + Yes + + + 15.00 + Yes + + + + + + catalogProductAttribute::color_for_promo_rules + + + + 1 + 1 + + + 1 + 1 + + + 1 + 1 + + + + From 5d42cef32e04f516abfefe6f570bff780258def7 Mon Sep 17 00:00:00 2001 From: dmanners Date: Fri, 10 Feb 2017 11:31:29 +0000 Subject: [PATCH 20/40] Update the Adminhtml image tree to use the new Serializer Json rather than Zend_Json --- .../Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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 1b5e4f54f552c..7e52e2bdb4702 100644 --- a/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php +++ b/app/code/Magento/Cms/Block/Adminhtml/Wysiwyg/Images/Tree.php @@ -26,20 +26,30 @@ class Tree extends \Magento\Backend\Block\Template */ protected $_cmsWysiwygImages = null; + /** + * @var \Magento\Framework\Serialize\Serializer\Json + */ + private $serializer; + /** * @param \Magento\Backend\Block\Template\Context $context * @param \Magento\Cms\Helper\Wysiwyg\Images $cmsWysiwygImages * @param \Magento\Framework\Registry $registry * @param array $data + * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer + * @throws \RuntimeException */ public function __construct( \Magento\Backend\Block\Template\Context $context, \Magento\Cms\Helper\Wysiwyg\Images $cmsWysiwygImages, \Magento\Framework\Registry $registry, - array $data = [] + array $data = [], + \Magento\Framework\Serialize\Serializer\Json $serializer = null ) { $this->_coreRegistry = $registry; $this->_cmsWysiwygImages = $cmsWysiwygImages; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); parent::__construct($context, $data); } @@ -65,7 +75,7 @@ public function getTreeJson() 'cls' => 'folder', ]; } - return \Zend_Json::encode($jsonArray); + return $this->serializer->serialize($jsonArray); } /** From f60a56f565741d868c17d9e7341f2d0b63be0ef7 Mon Sep 17 00:00:00 2001 From: Rykh Oleksandr Date: Fri, 10 Feb 2017 18:25:53 +0200 Subject: [PATCH 21/40] MAGETWO-62929: [Jenkins] random fail of CreateProductAttributeEntityFromProductPageTest --- .../Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php index 1681049ee6bf2..78f49f45c8567 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/ProductForm.php @@ -131,6 +131,7 @@ public function openSection($sectionName) $sectionElement = $this->getContainerElement($sectionName); if ($sectionElement->getAttribute('type') == 'button') { $sectionElement->click(); + sleep(1); // according to animation timeout in JS } else { parent::openSection($sectionName); } From adf169c4295bb8db4532d2da27b98c61fac890ef Mon Sep 17 00:00:00 2001 From: Oleksandr Osadchyi Date: Mon, 13 Feb 2017 13:47:10 +0200 Subject: [PATCH 22/40] MAGETWO-62616: Products are missed and total count is wrong on category page --- .../Catalog/Model/Indexer/Category/Product/AbstractAction.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php index b031e5bda2944..c719c2a5fa6f5 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php @@ -327,7 +327,8 @@ protected function prepareSelectsByRange( $iterator = $this->queryGenerator->generate( $field, $select, - $range + $range, + \Magento\Framework\DB\Query\BatchIteratorInterface::NON_UNIQUE_FIELD_ITERATOR ); $queries = []; From 991a54d6d3b40e4151fe4f798044aa94253f121d Mon Sep 17 00:00:00 2001 From: as7469 Date: Mon, 13 Feb 2017 16:07:23 +0100 Subject: [PATCH 23/40] Issue 8392 fix improved --- .../Catalog/Model/ProductLink/CollectionProvider.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php index d495da310df00..47174062488da 100644 --- a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php +++ b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php @@ -53,7 +53,14 @@ public function getCollection(\Magento\Catalog\Model\Product $product, $type) $output[$item->getId()] = $converter->convert($item); } foreach ($output as $item) { - $realoutput[$item["position"]] = $item; + $itemPosition = $item["position"]; + if (!isset($realoutput[$itemposition])) { + $realoutput[$itemPosition] = $item; + } + else { + $newPosition = $itemPosition+1; + $realoutput[$newPosition] = $item; + } } ksort($realoutput); return $realoutput; From acfce4eedf09ba119f5fb4c9f179876a8a3ead02 Mon Sep 17 00:00:00 2001 From: as7469 Date: Mon, 13 Feb 2017 16:09:08 +0100 Subject: [PATCH 24/40] Issue 8392 fix improved --- .../Magento/Catalog/Model/ProductLink/CollectionProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php index 47174062488da..bd27dd473c69c 100644 --- a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php +++ b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php @@ -54,7 +54,7 @@ public function getCollection(\Magento\Catalog\Model\Product $product, $type) } foreach ($output as $item) { $itemPosition = $item["position"]; - if (!isset($realoutput[$itemposition])) { + if (!isset($realoutput[$itemPosition])) { $realoutput[$itemPosition] = $item; } else { From 0002f6d3c4624f660d151d73bcb321f93eb8c032 Mon Sep 17 00:00:00 2001 From: as7469 Date: Mon, 13 Feb 2017 18:16:24 +0100 Subject: [PATCH 25/40] Issue 8392 - formatting wanking --- .../Magento/Catalog/Model/ProductLink/CollectionProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php index bd27dd473c69c..1536c982b40d2 100644 --- a/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php +++ b/app/code/Magento/Catalog/Model/ProductLink/CollectionProvider.php @@ -56,7 +56,7 @@ public function getCollection(\Magento\Catalog\Model\Product $product, $type) $itemPosition = $item["position"]; if (!isset($realoutput[$itemPosition])) { $realoutput[$itemPosition] = $item; - } + } else { $newPosition = $itemPosition+1; $realoutput[$newPosition] = $item; From d3cc57352f0a2017b5779d5a0d121933893abaa7 Mon Sep 17 00:00:00 2001 From: ahurzhii Date: Mon, 13 Feb 2017 20:03:11 +0200 Subject: [PATCH 26/40] MTA-4065: Import Advanced Pricing if Incorrect Data - create test - create file generator by template --- .../Mtf/Util/Filesystem/FileHelper.php | 90 ++++++++++ .../Mtf/Util/Generate/File/Generator.php | 64 ++++++++ .../Util/Generate/File/TemplateInterface.php | 26 +++ ...AssertImportCheckDataErrorMessagesList.php | 61 +++++++ .../Test/TestCase/ImportDataTest.xml | 40 +++++ .../template/pricing/advanced_incorrect.php | 14 ++ .../Test/etc/di.xml | 15 ++ .../Section/AdvancedPricing/OptionTier.php | 11 +- ...AssertAdvancedPriceAbsentOnProductForm.php | 50 ++++++ .../tests/app/Magento/Catalog/Test/etc/di.xml | 5 + .../Mtf/Util/Import/File/CsvTemplate.php | 90 ++++++++++ .../Test/Block/Adminhtml/Import/Edit/Form.php | 14 ++ .../Test/Block/Adminhtml/Import/Edit/Form.xml | 34 ++++ .../Adminhtml/Import/FormPageActions.php | 30 ++++ .../Block/Adminhtml/Import/Frame/Result.php | 62 +++++++ .../AssertImportCheckDataErrorMessage.php | 51 ++++++ .../{ImportExport.xml => ExportData.xml} | 4 +- .../ImportExport/Test/Fixture/Import/File.php | 155 ++++++++++++++++++ .../ImportExport/Test/Fixture/ImportData.xml | 27 +++ .../Test/Page/Adminhtml/AdminImportIndex.xml | 14 ++ .../{ImportExport.xml => ExportData.xml} | 2 +- .../Test/TestCase/ImportDataTest.php | 39 +++++ .../Test/TestCase/ImportDataTest.xml | 10 ++ .../Test/TestStep/ClickCheckDataStep.php | 40 +++++ .../Test/TestStep/FillImportFormStep.php | 58 +++++++ .../Test/TestStep/OpenImportIndexStep.php | 40 +++++ .../Test/Util/Import/File/CsvTemplate.php | 88 ++++++++++ .../app/Magento/ImportExport/Test/etc/di.xml | 28 +++- .../ImportExport/Test/etc/testcase.xml | 15 ++ 29 files changed, 1167 insertions(+), 10 deletions(-) create mode 100644 dev/tests/functional/lib/Magento/Mtf/Util/Filesystem/FileHelper.php create mode 100644 dev/tests/functional/lib/Magento/Mtf/Util/Generate/File/Generator.php create mode 100644 dev/tests/functional/lib/Magento/Mtf/Util/Generate/File/TemplateInterface.php create mode 100644 dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertImportCheckDataErrorMessagesList.php create mode 100644 dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/_files/template/pricing/advanced_incorrect.php create mode 100644 dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/etc/di.xml create mode 100644 dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAdvancedPriceAbsentOnProductForm.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Mtf/Util/Import/File/CsvTemplate.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Edit/Form.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Edit/Form.xml create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Frame/Result.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckDataErrorMessage.php rename dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/{ImportExport.xml => ExportData.xml} (89%) create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/Import/File.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ImportData.xml create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminImportIndex.xml rename dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/{ImportExport.xml => ExportData.xml} (87%) create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.xml create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/ClickCheckDataStep.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/FillImportFormStep.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/OpenImportIndexStep.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/Util/Import/File/CsvTemplate.php create mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/testcase.xml diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Filesystem/FileHelper.php b/dev/tests/functional/lib/Magento/Mtf/Util/Filesystem/FileHelper.php new file mode 100644 index 0000000000000..489e87e893013 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Filesystem/FileHelper.php @@ -0,0 +1,90 @@ +createDirectory($parentDir, $mode, true); + } + + try { + if (!mkdir($path, $mode)) { + return false; + } + } catch (\Exception $e) { + if (!is_dir($path)) { + throw new \Exception("Failed to create directory \"$path\""); + } + } + + try { + return chmod($path, $mode); + } catch (\Exception $e) { + throw new \Exception("Failed to change permissions for directory \"$path\""); + } + } + + /** + * Create a new file with content. + * + * @param string $filename + * @param string $content + * @return bool + */ + public function createFile($filename, $content) + { + return file_put_contents($filename, $content) !== false; + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Generate/File/Generator.php b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/File/Generator.php new file mode 100644 index 0000000000000..aa54300bea67e --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/File/Generator.php @@ -0,0 +1,64 @@ +fileHelper = $fileHelper; + $this->directory = $this->fileHelper->normalizePath(MTF_BP . static::ROOT_DIRECTORY . $directory); + } + + /** + * Method is generate file by template. + * + * @param TemplateInterface $template + * @return string Full path to the generated file. + * @throws \Exception + */ + public function generate(TemplateInterface $template) + { + $filename = $this->fileHelper->normalizePath($this->directory . '/' . $template->getName()); + if (!$this->fileHelper->createDirectory($this->directory) + || !$this->fileHelper->createFile($filename, $template->render()) + ) { + throw new \Exception( + 'Can’t create file with "' . get_class($template) .'" (file "' . $filename . '").' + ); + } + + return $filename; + } +} diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Generate/File/TemplateInterface.php b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/File/TemplateInterface.php new file mode 100644 index 0000000000000..72d4e4286c352 --- /dev/null +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Generate/File/TemplateInterface.php @@ -0,0 +1,26 @@ +getImportResult()->getErrorsList(); + + \PHPUnit_Framework_Assert::assertNotFalse($messages, 'Errors messages block is absent.'); + \PHPUnit_Framework_Assert::assertNotEmpty($messages, 'Errors messages is absent.'); + + foreach ($messages as $message) { + foreach ($errors as $error) { + \PHPUnit_Framework_Assert::assertContains( + sprintf(static::ERROR_ATTRIBUTE_PATTERN, $error['attribute']), + $message, + 'Attribute name is absent in error message.' + ); + \PHPUnit_Framework_Assert::assertContains( + sprintf(static::ERROR_ROWS_PATTERN, $error['rows']), + $message, + 'Count of rows is not contained is the message.' + ); + } + } + } + + /** + * Return string representation of object. + * + * @return string + */ + public function toString() + { + return 'Attribute with error contains in message. ' + . 'Count rows with errors equals count rows in the test variation.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataTest.xml b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataTest.xml new file mode 100644 index 0000000000000..51613ce533d39 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataTest.xml @@ -0,0 +1,40 @@ + + + + + + + + tier_price + 1 + + + + Advanced Pricing + Add/Update + Stop on Error + 10 + , + , + + + catalogProductSimple::default + + + Magento/AdvancedPricingImportExport/Test/_files/template/pricing/advanced_incorrect + 1 + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/_files/template/pricing/advanced_incorrect.php b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/_files/template/pricing/advanced_incorrect.php new file mode 100644 index 0000000000000..9a7a19fd11a84 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/_files/template/pricing/advanced_incorrect.php @@ -0,0 +1,14 @@ + '%sku%', + 'tier_price_website' => 'All Websites [USD]', + 'tier_price_customer_group' => 'ALL GROUPS', + 'tier_price_qty' => '3', + 'tier_price' => 'text', + 'tier_price_value_type' => 'Fixed', +]; diff --git a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/etc/di.xml new file mode 100644 index 0000000000000..cedddcf3c6501 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/etc/di.xml @@ -0,0 +1,15 @@ + + + + + + high + + + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing/OptionTier.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing/OptionTier.php index b3e5fda32ef9a..c18e7f0790522 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing/OptionTier.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/AdvancedPricing/OptionTier.php @@ -3,7 +3,6 @@ * Copyright © 2013-2017 Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\AdvancedPricing; use Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Options\AbstractOptions; @@ -80,4 +79,14 @@ public function isVisibleCustomerGroup(CustomerGroup $customerGroup) $options = $this->_rootElement->find($this->customerGroup, Locator::SELECTOR_XPATH)->getText(); return false !== strpos($options, $customerGroup->getCustomerGroupCode()); } + + /** + * Checking group price options is visible. + * + * @return bool + */ + public function hasGroupPriceOptions() + { + return $this->_rootElement->find('tbody tr')->isPresent(); + } } 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 new file mode 100644 index 0000000000000..3a3d9de7337be --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAdvancedPriceAbsentOnProductForm.php @@ -0,0 +1,50 @@ +open(['id' => $product->getData('id')]); + /** @var AdvancedPricing $advancedPricing */ + $advancedPricing = $productPage->getProductForm() + ->openSection('advanced-pricing') + ->getSection('advanced-pricing'); + + \PHPUnit_Framework_Assert::assertFalse( + $advancedPricing->getTierPriceForm()->hasGroupPriceOptions(), + 'Customer group price options is present in grid.' + ); + } + } + + /** + * Return string representation of object. + * + * @return string + */ + public function toString() + { + return 'Advanced price is absent on product page in form.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml index 5a2704377aebe..73f7d3ed437c2 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml @@ -186,4 +186,9 @@ + + + low + + diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Mtf/Util/Import/File/CsvTemplate.php b/dev/tests/functional/tests/app/Magento/ImportExport/Mtf/Util/Import/File/CsvTemplate.php new file mode 100644 index 0000000000000..2d28ad9583264 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Mtf/Util/Import/File/CsvTemplate.php @@ -0,0 +1,90 @@ +config = $config; + } + + /** + * {@inheritdoc} + */ + public function render() + { + if (!isset($this->config['filename'], $this->config['count'])) { + throw new \InvalidArgumentException( + 'Configuration for file is bad. You must specify "filename" and "count" in configuration.' + ); + } + + $filename = MTF_TESTS_PATH . $this->config['filename'] . '.php'; + + if (!file_exists($filename)) { + throw new \Exception('File "' . $filename . '" does not exists.'); + } + + $data = include $filename; + $count = abs($this->config['count']); + + $placeholders = []; + if (!empty($this->config['placeholders'])) { + $placeholders = $this->config['placeholders']; + } + + $fh = fopen('php://temp', 'rw'); + fputcsv($fh, array_keys($data)); + + for ($i = 0; $i < $count; ++$i) { + $row = array_map( + function ($value) use ($placeholders, $i) { + if (is_string($value) && isset($placeholders[$i])) { + return strtr($value, $placeholders[$i]); + } + + return $value; + }, + $data + ); + fputcsv($fh, $row); + } + + rewind($fh); + $csv = stream_get_contents($fh); + fclose($fh); + + return $csv; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return sprintf( + '%x_%s.csv', + crc32(time()), + basename($this->config['filename']) + ); + } +} diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Edit/Form.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Edit/Form.php new file mode 100644 index 0000000000000..96165e7663db8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Edit/Form.php @@ -0,0 +1,14 @@ + + + + + + select + + + select + + + select + + + + [name='_import_field_separator'] + + + [name='_import_multiple_value_separator'] + + + checkbox + + + upload + + + + diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php new file mode 100644 index 0000000000000..86eadf311a965 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php @@ -0,0 +1,30 @@ +save(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Frame/Result.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Frame/Result.php new file mode 100644 index 0000000000000..7e180e26c69dc --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Frame/Result.php @@ -0,0 +1,62 @@ +_rootElement->find($this->errorMessage); + + if (!$element->isVisible()) { + return false; + } + + return (string) $this->_rootElement->find($this->errorMessage)->getText(); + } + + /** + * Get errors messages list + * + * @return array|false + */ + public function getErrorsList() + { + $element = $this->_rootElement->find($this->validationErrorList); + + if (!$element->isVisible()) { + return false; + } + + $text = $this->_rootElement->find($this->validationErrorList)->getText(); + + return (array) explode("\n", strip_tags($text)); + } +} 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 new file mode 100644 index 0000000000000..dcc50c8de72ee --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Constraint/AssertImportCheckDataErrorMessage.php @@ -0,0 +1,51 @@ +getImportResult()->getErrorMessage(); + + \PHPUnit_Framework_Assert::assertNotFalse($actualMessage, 'Error message is absent.'); + + \PHPUnit_Framework_Assert::assertEquals( + static::ERROR_MESSAGE, + $actualMessage, + 'Wrong error message is displayed.' + . "\nExpected: " . self::ERROR_MESSAGE + . "\nActual: " . $actualMessage + ); + } + + /** + * Return string representation of object. + * + * @return string + */ + public function toString() + { + return 'Data check error message is present.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ImportExport.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ExportData.xml similarity index 89% rename from dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ImportExport.xml rename to dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ExportData.xml index 991349508e407..a7d2195b0a37e 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ImportExport.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ExportData.xml @@ -10,8 +10,8 @@ module="Magento_ImportExport" type="flat" entity_type="importexport_importdata" - repository_class="Magento\ImportExport\Test\Repository\ImportExport" - class="Magento\ImportExport\Test\Fixture\ImportExport"> + repository_class="Magento\ImportExport\Test\Repository\ExportData" + class="Magento\ImportExport\Test\Fixture\ExportData"> diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/Import/File.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/Import/File.php new file mode 100644 index 0000000000000..01d2eb02a4e1d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/Import/File.php @@ -0,0 +1,155 @@ +params = $params; + $this->value = $data; + $this->generator = $generator; + $this->fixtureFactory = $fixtureFactory; + $this->objectManager = $objectManager; + } + + /** + * {@inheritdoc} + */ + public function getData($key = null) + { + if (isset($this->data)) { + return parent::getData($key); + } + + $placeholders = []; + if (!isset($this->products) + && isset($this->value['products']) + && is_array($this->value['products']) + ) { + $this->products = $this->createProducts(); + + foreach ($this->products as $product) { + $placeholders[] = ['%sku%' => $product->getData('sku')]; + } + } + + if (isset($this->value['template']) && is_array($this->value['template'])) { + $this->data = $this->generator->generate( + $this->objectManager->create( + CsvTemplate::class, + [ + 'config' => array_merge( + $this->value['template'], + [ + 'placeholders' => $placeholders + ] + ) + ] + ) + ); + + return parent::getData($key); + } + + $filename = MTF_TESTS_PATH . $this->value; + if (!file_exists($filename)) { + throw new \Exception("CSV file '{$filename}'' not found on the server."); + } + + $this->data = $filename; + + return parent::getData($key); + } + + /** + * Get products fixtures. + * + * @return FixtureInterface[] + */ + public function getProducts() + { + return $this->products ?: []; + } + + /** + * Create products from configuration of variation. + * + * @return FixtureInterface[] + */ + private function createProducts() + { + $products = []; + foreach ($this->value['products'] as $key => $productDataSet) { + list($fixtureCode, $dataset) = explode('::', $productDataSet); + + /** @var FixtureInterface[] $products */ + $products[$key] = $this->fixtureFactory->createByCode(trim($fixtureCode), ['dataset' => trim($dataset)]); + if ($products[$key]->hasData('id') === false) { + $products[$key]->persist(); + } + } + + return $products; + } +} diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ImportData.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ImportData.xml new file mode 100644 index 0000000000000..071137f974644 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ImportData.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminImportIndex.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminImportIndex.xml new file mode 100644 index 0000000000000..d754fbf75a09f --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminImportIndex.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/ImportExport.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/ExportData.xml similarity index 87% rename from dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/ImportExport.xml rename to dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/ExportData.xml index 8661dcf84e397..29ab7c7d95976 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/ImportExport.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Repository/ExportData.xml @@ -6,7 +6,7 @@ */ --> - + Products CSV diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.php new file mode 100644 index 0000000000000..dadfeec4428f9 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.php @@ -0,0 +1,39 @@ +executeScenario(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.xml new file mode 100644 index 0000000000000..ce536ee420b26 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.xml @@ -0,0 +1,10 @@ + + + + + diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/ClickCheckDataStep.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/ClickCheckDataStep.php new file mode 100644 index 0000000000000..614a7c6b7380b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/ClickCheckDataStep.php @@ -0,0 +1,40 @@ +adminImportIndex = $adminImportIndex; + } + + /** + * Click "Check Data" button. + * + * @return void + */ + public function run() + { + $this->adminImportIndex->getFormPageActions()->clickCheckData(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/FillImportFormStep.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/FillImportFormStep.php new file mode 100644 index 0000000000000..0b9475c071a6d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/FillImportFormStep.php @@ -0,0 +1,58 @@ +adminImportIndex = $adminImportIndex; + $this->import = $import; + } + + /** + * Fill import form. + * + * @return array + */ + public function run() + { + $this->adminImportIndex->getImportForm()->fill($this->import); + + /** @var File $file */ + $file = $this->import->getDataFieldConfig('import_file')['source']; + + return [ + 'products' => $file->getProducts() + ]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/OpenImportIndexStep.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/OpenImportIndexStep.php new file mode 100644 index 0000000000000..c6025d0007e14 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestStep/OpenImportIndexStep.php @@ -0,0 +1,40 @@ +adminImportIndex = $adminImportIndex; + } + + /** + * Open import index page. + * + * @return void + */ + public function run() + { + $this->adminImportIndex->open(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Util/Import/File/CsvTemplate.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Util/Import/File/CsvTemplate.php new file mode 100644 index 0000000000000..ac0bde4e6c6de --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Util/Import/File/CsvTemplate.php @@ -0,0 +1,88 @@ +config = $config; + } + + /** + * {@inheritdoc} + */ + public function render() + { + if (!isset($this->config['filename'], $this->config['count'])) { + throw new \InvalidArgumentException('Configuration for file is bad.'); + } + + $filename = MTF_TESTS_PATH . $this->config['filename'] . '.php'; + + if (!file_exists($filename)) { + throw new \Exception('File "' . $filename . '" does not exists.'); + } + + $data = include $filename; + $count = abs($this->config['count']); + + $placeholders = []; + if (!empty($this->config['placeholders'])) { + $placeholders = $this->config['placeholders']; + } + + $fh = fopen('php://temp', 'rw'); + fputcsv($fh, array_keys($data)); + + for ($i = 0; $i < $count; ++$i) { + $row = array_map( + function ($value) use ($placeholders, $i) { + if (is_string($value) && isset($placeholders[$i])) { + return strtr($value, $placeholders[$i]); + } + + return $value; + }, + $data + ); + fputcsv($fh, $row); + } + + rewind($fh); + $csv = stream_get_contents($fh); + fclose($fh); + + return $csv; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return sprintf( + '%x_%s.csv', + crc32(time()), + basename($this->config['filename']) + ); + } +} diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml index 56a89f2abb23f..c55918d063379 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml @@ -5,10 +5,26 @@ * See COPYING.txt for license details. */ --> - - - - high - - + + + + high + + + + + low + + + + + ImportCsvGenerator + + + + + ImportExport/import + + diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/testcase.xml new file mode 100644 index 0000000000000..b1c329822260d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/testcase.xml @@ -0,0 +1,15 @@ + + + + + + + + + From 3e4a7cec63e4f3a52e48c3772590ca81307bf9da Mon Sep 17 00:00:00 2001 From: Oleksandr Osadchyi Date: Tue, 14 Feb 2017 13:52:54 +0200 Subject: [PATCH 27/40] MAGETWO-62616: Products are missed and total count is wrong on category page --- lib/internal/Magento/Framework/DB/Query/Generator.php | 1 + .../Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/DB/Query/Generator.php b/lib/internal/Magento/Framework/DB/Query/Generator.php index 813c7722eba49..793d6c9667c00 100644 --- a/lib/internal/Magento/Framework/DB/Query/Generator.php +++ b/lib/internal/Magento/Framework/DB/Query/Generator.php @@ -26,6 +26,7 @@ class Generator * Initialize dependencies. * * @param BatchIteratorFactory $iteratorFactory + * @param BatchRangeIteratorFactory $rangeIteratorFactory */ public function __construct( BatchIteratorFactory $iteratorFactory, diff --git a/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php b/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php index 1355d62e891d3..28e06506f66ce 100644 --- a/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php +++ b/lib/internal/Magento/Framework/Test/Unit/DB/Query/GeneratorTest.php @@ -203,6 +203,9 @@ public function testGenerateWithNonUniqueStrategy() 'rangeFieldAlias' => 'product_id' ] )->willReturn($this->iteratorMock); - $this->assertEquals($this->iteratorMock, $this->model->generate('entity_id', $this->selectMock, 100, 'non_unique')); + $this->assertEquals( + $this->iteratorMock, + $this->model->generate('entity_id', $this->selectMock, 100, 'non_unique') + ); } } From 0ad069ea72ac9a451985fd2e98e00deb3b3bfe86 Mon Sep 17 00:00:00 2001 From: ahurzhii Date: Wed, 15 Feb 2017 16:04:59 +0200 Subject: [PATCH 28/40] MTA-4065: Import Advanced Pricing if Incorrect Data - CR --- ...AssertImportCheckDataErrorMessagesList.php | 70 ++++++++++----- ...ataTest.xml => ImportDataNegativeTest.xml} | 10 +-- .../Test/etc/di.xml | 2 +- .../Adminhtml/Import/FormPageActions.php | 36 ++++++-- .../Block/Adminhtml/Import/Frame/Result.php | 4 +- ...AssertProductAttributeAbsenceForExport.php | 8 +- .../ImportExport/Test/Fixture/ExportData.xml | 2 +- .../ImportExport/Test/Fixture/Import/File.php | 2 +- .../ImportExport/Test/Fixture/ImportData.xml | 1 - ...ataTest.php => ImportDataNegativeTest.php} | 7 +- .../Test/TestCase/ImportDataTest.xml | 10 --- .../Test/Util/Import/File/CsvTemplate.php | 88 ------------------- .../app/Magento/ImportExport/Test/etc/di.xml | 2 +- .../ImportExport/Test/etc/testcase.xml | 2 +- 14 files changed, 100 insertions(+), 144 deletions(-) rename dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/{ImportDataTest.xml => ImportDataNegativeTest.xml} (85%) rename dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/{ImportDataTest.php => ImportDataNegativeTest.php} (81%) delete mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.xml delete mode 100644 dev/tests/functional/tests/app/Magento/ImportExport/Test/Util/Import/File/CsvTemplate.php diff --git a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertImportCheckDataErrorMessagesList.php b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertImportCheckDataErrorMessagesList.php index 332a25c31dccf..259083278d3b4 100644 --- a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertImportCheckDataErrorMessagesList.php +++ b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/Constraint/AssertImportCheckDataErrorMessagesList.php @@ -13,39 +13,70 @@ */ class AssertImportCheckDataErrorMessagesList extends AbstractConstraint { - /* Errors parts pattern. */ - const ERROR_ATTRIBUTE_PATTERN = 'Value for \'%s\' attribute'; - const ERROR_ROWS_PATTERN = 'in row(s): %d'; - /* end */ - /** * Assert that error message is present. * - * @param array $errors + * @param array $patterns * @param AdminImportIndex $adminImportIndex * @return void */ - public function processAssert(array $errors, AdminImportIndex $adminImportIndex) + public function processAssert(array $patterns, AdminImportIndex $adminImportIndex) { $messages = $adminImportIndex->getImportResult()->getErrorsList(); \PHPUnit_Framework_Assert::assertNotFalse($messages, 'Errors messages block is absent.'); \PHPUnit_Framework_Assert::assertNotEmpty($messages, 'Errors messages is absent.'); + $errors = []; foreach ($messages as $message) { - foreach ($errors as $error) { - \PHPUnit_Framework_Assert::assertContains( - sprintf(static::ERROR_ATTRIBUTE_PATTERN, $error['attribute']), - $message, - 'Attribute name is absent in error message.' - ); - \PHPUnit_Framework_Assert::assertContains( - sprintf(static::ERROR_ROWS_PATTERN, $error['rows']), - $message, - 'Count of rows is not contained is the message.' - ); + if ($this->isNotMatched($patterns, $message)) { + $errors[] = sprintf('This message "%s" mismatch with any pattern', $message); + } + } + + \PHPUnit_Framework_Assert::assertEmpty( + $errors, + 'This assertions contains next errors:' . PHP_EOL . implode(PHP_EOL, $errors) + ); + } + + /** + * Checking message. + * + * @param array $patterns + * @param string $message + * @return bool + */ + private function isNotMatched(array $patterns, $message) + { + $isNotMatch = true; + foreach ($patterns as $parts) { + $parts = (array) $parts; + if ($isNotMatch && $this->match($message, $parts) === count($parts)) { + $isNotMatch = false; } } + + return $isNotMatch; + } + + /** + * Check if patterns are contained in a message. + * + * @param string $message + * @param array $patterns + * @return int + */ + private function match($message, array $patterns) + { + $matchCount = 0; + foreach ($patterns as $pattern) { + if (strpos($message, $pattern) !== false) { + ++$matchCount; + } + } + + return $matchCount; } /** @@ -55,7 +86,6 @@ public function processAssert(array $errors, AdminImportIndex $adminImportIndex) */ public function toString() { - return 'Attribute with error contains in message. ' - . 'Count rows with errors equals count rows in the test variation.'; + return 'All messages for errors match the patterns.'; } } diff --git a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataTest.xml b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataNegativeTest.xml similarity index 85% rename from dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataTest.xml rename to dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataNegativeTest.xml index 51613ce533d39..10c59feb7d7bb 100644 --- a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataTest.xml +++ b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataNegativeTest.xml @@ -6,12 +6,12 @@ */ --> - - - + + + - tier_price - 1 + Value for 'tier_price' attribute + in row(s): 1 diff --git a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/etc/di.xml index cedddcf3c6501..35ddc38d4ff30 100644 --- a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/etc/di.xml @@ -9,7 +9,7 @@ xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> - high + S1 diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php index 86eadf311a965..07ff0c904975b 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php @@ -5,26 +5,52 @@ */ namespace Magento\ImportExport\Test\Block\Adminhtml\Import; -use Magento\Backend\Test\Block\FormPageActions as ParentFormPageActions; +use Magento\Mtf\Client\Locator; /** * Form page actions block. */ -class FormPageActions extends ParentFormPageActions +class FormPageActions extends \Magento\Backend\Test\Block\PageActions { /** - * "Save" button. + * "Check Data" button. * * @var string */ - protected $saveButton = '#upload_button'; + protected $checkDataButton = '#upload_button'; + + /** + * Magento new loader. + * + * @var string + */ + protected $spinner = '[data-role="spinner"]'; + + /** + * Magento loader. + * + * @var string + */ + protected $loader = '//ancestor::body/div[@data-role="loader"]'; + + /** + * Magento varienLoader.js loader. + * + * @var string + */ + protected $loaderOld = '//ancestor::body/div[@id="loading-mask"]'; /** * Click "Check Data" button. + * * @return void */ public function clickCheckData() { - $this->save(); + $this->waitForElementVisible($this->checkDataButton); + $this->_rootElement->find($this->checkDataButton)->click(); + $this->waitForElementNotVisible($this->spinner); + $this->waitForElementNotVisible($this->loader, Locator::SELECTOR_XPATH); + $this->waitForElementNotVisible($this->loaderOld, Locator::SELECTOR_XPATH); } } diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Frame/Result.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Frame/Result.php index 7e180e26c69dc..13540187449c3 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Frame/Result.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/Frame/Result.php @@ -43,7 +43,7 @@ public function getErrorMessage() } /** - * Get errors messages list + * Get errors messages list. * * @return array|false */ @@ -57,6 +57,6 @@ public function getErrorsList() $text = $this->_rootElement->find($this->validationErrorList)->getText(); - return (array) explode("\n", strip_tags($text)); + return (array) explode(PHP_EOL, strip_tags($text)); } } 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 f6bd4fdf76340..cbcc82f2a42e2 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 @@ -7,7 +7,7 @@ namespace Magento\ImportExport\Test\Constraint; use Magento\Catalog\Test\Fixture\CatalogProductAttribute; -use Magento\ImportExport\Test\Fixture\ImportExport; +use Magento\ImportExport\Test\Fixture\ExportData; use Magento\ImportExport\Test\Page\Adminhtml\AdminExportIndex; use Magento\Mtf\Constraint\AbstractConstraint; @@ -22,13 +22,13 @@ class AssertProductAttributeAbsenceForExport extends AbstractConstraint * * @param AdminExportIndex $exportIndex * @param CatalogProductAttribute $attribute - * @param ImportExport $export + * @param ExportData $export * @return void */ public function processAssert( AdminExportIndex $exportIndex, CatalogProductAttribute $attribute, - ImportExport $export + ExportData $export ) { $exportIndex->open(); $exportIndex->getExportForm()->fill($export); @@ -50,6 +50,6 @@ public function processAssert( */ public function toString() { - return 'Product Attribute is absent in Filter export grid'; + return 'Product Attribute is absent in Filter export grid.'; } } diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ExportData.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ExportData.xml index a7d2195b0a37e..afc223fa86b56 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ExportData.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Fixture/ExportData.xml @@ -6,7 +6,7 @@ */ --> - diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataNegativeTest.php similarity index 81% rename from dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.php rename to dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataNegativeTest.php index dadfeec4428f9..11517600cc9cf 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataNegativeTest.php @@ -18,13 +18,12 @@ * 4. Click "Check Data" button. * 5. Perform assertions. * - * @group Advanced_Pricing_Import_Export - * @ZephyrId MAGETWO-46155 + * @group ImportExport */ -class ImportDataTest extends Scenario +class ImportDataNegativeTest extends Scenario { /* tags */ - const MVP = 'no'; + const SEVERITY = 'S1'; /* end tags */ /** diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.xml deleted file mode 100644 index ce536ee420b26..0000000000000 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/TestCase/ImportDataTest.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Util/Import/File/CsvTemplate.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Util/Import/File/CsvTemplate.php deleted file mode 100644 index ac0bde4e6c6de..0000000000000 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Util/Import/File/CsvTemplate.php +++ /dev/null @@ -1,88 +0,0 @@ -config = $config; - } - - /** - * {@inheritdoc} - */ - public function render() - { - if (!isset($this->config['filename'], $this->config['count'])) { - throw new \InvalidArgumentException('Configuration for file is bad.'); - } - - $filename = MTF_TESTS_PATH . $this->config['filename'] . '.php'; - - if (!file_exists($filename)) { - throw new \Exception('File "' . $filename . '" does not exists.'); - } - - $data = include $filename; - $count = abs($this->config['count']); - - $placeholders = []; - if (!empty($this->config['placeholders'])) { - $placeholders = $this->config['placeholders']; - } - - $fh = fopen('php://temp', 'rw'); - fputcsv($fh, array_keys($data)); - - for ($i = 0; $i < $count; ++$i) { - $row = array_map( - function ($value) use ($placeholders, $i) { - if (is_string($value) && isset($placeholders[$i])) { - return strtr($value, $placeholders[$i]); - } - - return $value; - }, - $data - ); - fputcsv($fh, $row); - } - - rewind($fh); - $csv = stream_get_contents($fh); - fclose($fh); - - return $csv; - } - - /** - * {@inheritdoc} - */ - public function getName() - { - return sprintf( - '%x_%s.csv', - crc32(time()), - basename($this->config['filename']) - ); - } -} diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml index c55918d063379..c087e20f23a92 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/di.xml @@ -14,7 +14,7 @@ - low + S1 diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/testcase.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/testcase.xml index b1c329822260d..8c9ff10484fa6 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/testcase.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/etc/testcase.xml @@ -7,7 +7,7 @@ --> - + From 97ca0eff89db8a4f391792e81924203959d1fc49 Mon Sep 17 00:00:00 2001 From: Oleksandr Osadchyi Date: Wed, 15 Feb 2017 17:40:17 +0200 Subject: [PATCH 29/40] MAGETWO-62616: Products are missed and total count is wrong on category page --- .../Model/Indexer/Category/Product/AbstractAction.php | 6 ++++-- lib/internal/Magento/Framework/DB/Query/Generator.php | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php index c719c2a5fa6f5..3a6f833a5a09c 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/AbstractAction.php @@ -113,18 +113,20 @@ abstract class AbstractAction * @param ResourceConnection $resource * @param \Magento\Store\Model\StoreManagerInterface $storeManager * @param \Magento\Catalog\Model\Config $config + * @param QueryGenerator $queryGenerator */ public function __construct( \Magento\Framework\App\ResourceConnection $resource, \Magento\Store\Model\StoreManagerInterface $storeManager, \Magento\Catalog\Model\Config $config, - QueryGenerator $queryGenerator + QueryGenerator $queryGenerator = null ) { $this->resource = $resource; $this->connection = $resource->getConnection(); $this->storeManager = $storeManager; $this->config = $config; - $this->queryGenerator = $queryGenerator; + $this->queryGenerator = $queryGenerator ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(QueryGenerator::class); } /** diff --git a/lib/internal/Magento/Framework/DB/Query/Generator.php b/lib/internal/Magento/Framework/DB/Query/Generator.php index 793d6c9667c00..4e3da17e21908 100644 --- a/lib/internal/Magento/Framework/DB/Query/Generator.php +++ b/lib/internal/Magento/Framework/DB/Query/Generator.php @@ -30,10 +30,11 @@ class Generator */ public function __construct( BatchIteratorFactory $iteratorFactory, - BatchRangeIteratorFactory $rangeIteratorFactory + BatchRangeIteratorFactory $rangeIteratorFactory = null ) { $this->iteratorFactory = $iteratorFactory; - $this->rangeIteratorFactory = $rangeIteratorFactory; + $this->rangeIteratorFactory = $rangeIteratorFactory ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\DB\Query\BatchRangeIteratorFactory::class); } /** From 9c9802a4b6ece767c66fb6d0d6405d55fd4a339f Mon Sep 17 00:00:00 2001 From: ahurzhii Date: Thu, 16 Feb 2017 10:47:35 +0200 Subject: [PATCH 30/40] MTA-4065: Import Advanced Pricing if Incorrect Data - CR --- .../Test/TestCase/ImportDataNegativeTest.xml | 1 + .../tests/app/Magento/Catalog/Test/etc/di.xml | 2 +- .../Mtf/Util/Import/File/CsvTemplate.php | 2 +- .../Adminhtml/Import/FormPageActions.php | 20 ++----------------- .../Test/Page/Adminhtml/AdminImportIndex.xml | 6 +++--- 5 files changed, 8 insertions(+), 23 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataNegativeTest.xml b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataNegativeTest.xml index 10c59feb7d7bb..f103c0cbd3dbd 100644 --- a/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataNegativeTest.xml +++ b/dev/tests/functional/tests/app/Magento/AdvancedPricingImportExport/Test/TestCase/ImportDataNegativeTest.xml @@ -8,6 +8,7 @@ + severity:S1 Value for 'tier_price' attribute diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml index 73f7d3ed437c2..39dce173db16d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/etc/di.xml @@ -188,7 +188,7 @@ - low + S1 diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Mtf/Util/Import/File/CsvTemplate.php b/dev/tests/functional/tests/app/Magento/ImportExport/Mtf/Util/Import/File/CsvTemplate.php index 2d28ad9583264..6c080d4095b86 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Mtf/Util/Import/File/CsvTemplate.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Mtf/Util/Import/File/CsvTemplate.php @@ -41,7 +41,7 @@ public function render() $filename = MTF_TESTS_PATH . $this->config['filename'] . '.php'; if (!file_exists($filename)) { - throw new \Exception('File "' . $filename . '" does not exists.'); + throw new \Exception('File "' . $filename . '" does not exist.'); } $data = include $filename; diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php index 07ff0c904975b..7221c619364f8 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Block/Adminhtml/Import/FormPageActions.php @@ -17,28 +17,14 @@ class FormPageActions extends \Magento\Backend\Test\Block\PageActions * * @var string */ - protected $checkDataButton = '#upload_button'; - - /** - * Magento new loader. - * - * @var string - */ - protected $spinner = '[data-role="spinner"]'; + private $checkDataButton = '#upload_button'; /** * Magento loader. * * @var string */ - protected $loader = '//ancestor::body/div[@data-role="loader"]'; - - /** - * Magento varienLoader.js loader. - * - * @var string - */ - protected $loaderOld = '//ancestor::body/div[@id="loading-mask"]'; + private $loader = '//ancestor::body/div[@data-role="loader"]'; /** * Click "Check Data" button. @@ -49,8 +35,6 @@ public function clickCheckData() { $this->waitForElementVisible($this->checkDataButton); $this->_rootElement->find($this->checkDataButton)->click(); - $this->waitForElementNotVisible($this->spinner); $this->waitForElementNotVisible($this->loader, Locator::SELECTOR_XPATH); - $this->waitForElementNotVisible($this->loaderOld, Locator::SELECTOR_XPATH); } } diff --git a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminImportIndex.xml b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminImportIndex.xml index d754fbf75a09f..f07b7037a5dba 100644 --- a/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminImportIndex.xml +++ b/dev/tests/functional/tests/app/Magento/ImportExport/Test/Page/Adminhtml/AdminImportIndex.xml @@ -7,8 +7,8 @@ --> - - - + + + From a14106125708f3c975bc5d0d3c2b463e8bafeabf Mon Sep 17 00:00:00 2001 From: ahurzhii Date: Thu, 16 Feb 2017 13:32:32 +0200 Subject: [PATCH 31/40] MTA-4065: Import Advanced Pricing if Incorrect Data - simplification the method in the FileHelper class --- .../lib/Magento/Mtf/Util/Filesystem/FileHelper.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Filesystem/FileHelper.php b/dev/tests/functional/lib/Magento/Mtf/Util/Filesystem/FileHelper.php index 489e87e893013..f4eb6e8de8b39 100644 --- a/dev/tests/functional/lib/Magento/Mtf/Util/Filesystem/FileHelper.php +++ b/dev/tests/functional/lib/Magento/Mtf/Util/Filesystem/FileHelper.php @@ -24,6 +24,18 @@ public function normalizePath($path, $ds = DIRECTORY_SEPARATOR) return $path; } + return $this->realpath($ds, $path); + } + + /** + * Returns canonicalized pathname. + * + * @param string $ds + * @param string $path + * @return string + */ + private function realpath($ds, $path) + { $parts = []; foreach (explode($ds, $path) as $part) { if ($part === '..' && !empty($parts) && end($parts) !== '..') { @@ -34,6 +46,7 @@ public function normalizePath($path, $ds = DIRECTORY_SEPARATOR) $parts[] = $part; } } + $path = implode($ds, $parts); return $path === '' ? '.' : $path; From 0f5484465bca0038cdbab2ab66c7339b76e88b0b Mon Sep 17 00:00:00 2001 From: Vlad Veselov Date: Mon, 20 Feb 2017 02:10:22 +0200 Subject: [PATCH 32/40] Fix #8315: test setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/Csv/StdoTest.php crashes in debug mode - it was crashing when running PHPUnit with --debug flag due to STDOUT closing in destructor of object under test --- .../I18n/Dictionary/Writer/Csv/StdoTest.php | 22 +++++-------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/Csv/StdoTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/Csv/StdoTest.php index ddbe9116de13f..6fd93afd27883 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/Csv/StdoTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/Csv/StdoTest.php @@ -5,25 +5,15 @@ */ namespace Magento\Setup\Test\Unit\Module\I18n\Dictionary\Writer\Csv; +use Magento\Setup\Module\I18n\Dictionary\Writer\Csv\Stdo; + class StdoTest extends \PHPUnit_Framework_TestCase { - /** - * @var resource - */ - protected $_handler; - - protected function setUp() - { - $this->_handler = STDOUT; - } - public function testThatHandlerIsRight() { - $this->markTestSkipped('This is skiped as we should not close the STDO!'); - $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); - /** @var \Magento\Setup\Module\I18n\Dictionary\Writer\Csv $writer */ - $writer = $objectManagerHelper->getObject(\Magento\Setup\Module\I18n\Dictionary\Writer\Csv\Stdo::class); - - $this->assertAttributeEquals($this->_handler, '_fileHandler', $writer); + $handler = STDOUT; + // Mocking object's under test destructor here is perfectly valid as there is no way to reopen STDOUT + $writer = $this->getMock(Stdo::class, ['__destruct']); + $this->assertAttributeEquals($handler, '_fileHandler', $writer); } } From 1b5e028551231fc63da00691ce3632382d4f53d7 Mon Sep 17 00:00:00 2001 From: Vlad Veselov Date: Mon, 20 Feb 2017 01:18:24 +0200 Subject: [PATCH 33/40] [PHP 7.1 Compatibility] Void became a reserved word --- .../Creditmemo/{Void.php => VoidAction.php} | 2 +- .../Invoice/{Void.php => VoidAction.php} | 2 +- .../{VoidTest.php => VoidActionTest.php} | 6 +- .../{VoidTest.php => VoidActionTest.php} | 6 +- .../NamingConventions/ReservedWordsSniff.php | 77 +++++++++++-------- .../Framework/App/Router/ActionList.php | 2 +- 6 files changed, 54 insertions(+), 41 deletions(-) rename app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/{Void.php => VoidAction.php} (98%) rename app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/{Void.php => VoidAction.php} (95%) rename app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/{VoidTest.php => VoidActionTest.php} (99%) rename app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/{VoidTest.php => VoidActionTest.php} (99%) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Void.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/VoidAction.php similarity index 98% rename from app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Void.php rename to app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/VoidAction.php index 3f743f596fee6..367151a0405c8 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/Void.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Creditmemo/VoidAction.php @@ -7,7 +7,7 @@ use Magento\Backend\App\Action; -class Void extends \Magento\Backend\App\Action +class VoidAction extends Action { /** * Authorization level of a basic admin session diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Void.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/VoidAction.php similarity index 95% rename from app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Void.php rename to app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/VoidAction.php index 1b790d8b71dc1..235d280b54d9b 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/Void.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Invoice/VoidAction.php @@ -6,7 +6,7 @@ */ namespace Magento\Sales\Controller\Adminhtml\Order\Invoice; -class Void extends \Magento\Sales\Controller\Adminhtml\Invoice\AbstractInvoice\View +class VoidAction extends \Magento\Sales\Controller\Adminhtml\Invoice\AbstractInvoice\View { /** * Void invoice action diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/VoidTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/VoidActionTest.php similarity index 99% rename from app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/VoidTest.php rename to app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/VoidActionTest.php index 5fb4f3e62f4f3..c4686f4a04306 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/VoidTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Creditmemo/VoidActionTest.php @@ -6,11 +6,11 @@ namespace Magento\Sales\Test\Unit\Controller\Adminhtml\Order\Creditmemo; /** - * Class VoidTest + * Class VoidActionTest * @SuppressWarnings(PHPMD.TooManyFields) * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class VoidTest extends \PHPUnit_Framework_TestCase +class VoidActionTest extends \PHPUnit_Framework_TestCase { /** * @var \Magento\Sales\Controller\Adminhtml\Order\Creditmemo\AddComment @@ -179,7 +179,7 @@ protected function setUp() $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->controller = $objectManager->getObject( - \Magento\Sales\Controller\Adminhtml\Order\Creditmemo\Void::class, + \Magento\Sales\Controller\Adminhtml\Order\Creditmemo\VoidAction::class, [ 'context' => $this->contextMock, 'creditmemoLoader' => $this->loaderMock, diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/VoidTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/VoidActionTest.php similarity index 99% rename from app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/VoidTest.php rename to app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/VoidActionTest.php index 96f80c303c08e..597ba5733a43f 100644 --- a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/VoidTest.php +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Invoice/VoidActionTest.php @@ -10,11 +10,11 @@ use Magento\Sales\Api\InvoiceRepositoryInterface; /** - * Class VoidTest + * Class VoidActionTest * @package Magento\Sales\Controller\Adminhtml\Order\Invoice * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ -class VoidTest extends \PHPUnit_Framework_TestCase +class VoidActionTest extends \PHPUnit_Framework_TestCase { /** * @var \PHPUnit_Framework_MockObject_MockObject @@ -166,7 +166,7 @@ protected function setUp() ->getMockForAbstractClass(); $this->controller = $objectManager->getObject( - \Magento\Sales\Controller\Adminhtml\Order\Invoice\Void::class, + \Magento\Sales\Controller\Adminhtml\Order\Invoice\VoidAction::class, [ 'context' => $contextMock, 'resultForwardFactory' => $this->resultForwardFactoryMock diff --git a/dev/tests/static/framework/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php b/dev/tests/static/framework/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php index 87e2d87a427a2..d8b9628c73b38 100644 --- a/dev/tests/static/framework/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php +++ b/dev/tests/static/framework/Magento/Sniffs/NamingConventions/ReservedWordsSniff.php @@ -11,22 +11,27 @@ class ReservedWordsSniff implements PHP_CodeSniffer_Sniff { /** - * source: http://php.net/manual/en/reserved.other-reserved-words.php + * The following words cannot be used to name a class, interface or trait, + * and they are also prohibited from being used in namespaces. * - * @var array PHP 7 reserved words for name spaces + * @link http://php.net/manual/en/reserved.other-reserved-words.php + * + * @var string[] */ protected $reservedWords = [ - 'int', - 'float', - 'bool', - 'string', - 'true', - 'false', - 'null', - 'resource', - 'object', - 'mixed', - 'numeric', + 'int' => '7', + 'float' => '7', + 'bool' => '7', + 'string' => '7', + 'true' => '7', + 'false' => '7', + 'null' => '7', + 'void' => '7.1', + 'iterable' => '7.1', + 'resource' => '7', + 'object' => '7', + 'mixed' => '7', + 'numeric' => '7', ]; /** @@ -34,7 +39,7 @@ class ReservedWordsSniff implements PHP_CodeSniffer_Sniff */ public function register() { - return [T_NAMESPACE, T_CLASS]; + return [T_CLASS, T_INTERFACE, T_TRAIT, T_NAMESPACE]; } /** @@ -44,20 +49,23 @@ public function register() * @param int $stackPtr * @return void */ - protected function validateNameSpace(PHP_CodeSniffer_File $sourceFile, $stackPtr) + protected function validateNamespace(PHP_CodeSniffer_File $sourceFile, $stackPtr) { - $skippedTokens = ['T_NS_SEPARATOR', 'T_WHITESPACE']; - //skip "namespace" and whitespace $stackPtr += 2; $tokens = $sourceFile->getTokens(); - while ('T_SEMICOLON' != $tokens[$stackPtr]['type']) { - if (in_array($tokens[$stackPtr]['type'], $skippedTokens)) { - $stackPtr++; + while ($stackPtr < $sourceFile->numTokens && $tokens[$stackPtr]['code'] !== T_SEMICOLON) { + if ($tokens[$stackPtr]['code'] === T_WHITESPACE || $tokens[$stackPtr]['code'] === T_NS_SEPARATOR) { + $stackPtr++; //skip "namespace" and whitespace continue; } - $nameSpacePart = strtolower($tokens[$stackPtr]['content']); - if (in_array($nameSpacePart, $this->reservedWords)) { - $sourceFile->addError('\'' . $nameSpacePart . '\' is a reserved word in PHP 7.', $stackPtr); + $namespacePart = $tokens[$stackPtr]['content']; + if (isset($this->reservedWords[strtolower($namespacePart)])) { + $sourceFile->addError( + 'Cannot use "%s" in namespace as it is reserved since PHP %s', + $stackPtr, + 'Namespace', + [$namespacePart, $this->reservedWords[$namespacePart]] + ); } $stackPtr++; } @@ -73,12 +81,15 @@ protected function validateNameSpace(PHP_CodeSniffer_File $sourceFile, $stackPtr protected function validateClass(PHP_CodeSniffer_File $sourceFile, $stackPtr) { $tokens = $sourceFile->getTokens(); - //skipped "class" and whitespace - $stackPtr += 2; + $stackPtr += 2; //skip "class" and whitespace $className = strtolower($tokens[$stackPtr]['content']); - - if (in_array($className, $this->reservedWords)) { - $sourceFile->addError('Class name \'' . $className . '\' is a reserved word in PHP 7', $stackPtr); + if (isset($this->reservedWords[$className])) { + $sourceFile->addError( + 'Cannot use "%s" as class name as it is reserved since PHP %s', + $stackPtr, + 'Class', + [$className, $this->reservedWords[$className]] + ); } } @@ -88,12 +99,14 @@ protected function validateClass(PHP_CodeSniffer_File $sourceFile, $stackPtr) public function process(PHP_CodeSniffer_File $sourceFile, $stackPtr) { $tokens = $sourceFile->getTokens(); - switch ($tokens[$stackPtr]['type']) { - case "T_CLASS": + switch ($tokens[$stackPtr]['code']) { + case T_CLASS: + case T_INTERFACE: + case T_TRAIT: $this->validateClass($sourceFile, $stackPtr); break; - case "T_NAMESPACE": - $this->validateNameSpace($sourceFile, $stackPtr); + case T_NAMESPACE: + $this->validateNamespace($sourceFile, $stackPtr); break; } } diff --git a/lib/internal/Magento/Framework/App/Router/ActionList.php b/lib/internal/Magento/Framework/App/Router/ActionList.php index f0fa6fc0adfcd..a6dc2d65ed06b 100644 --- a/lib/internal/Magento/Framework/App/Router/ActionList.php +++ b/lib/internal/Magento/Framework/App/Router/ActionList.php @@ -34,7 +34,7 @@ class ActionList 'for', 'foreach', 'function', 'global', 'goto', 'if', 'implements', 'include', 'instanceof', 'insteadof','interface', 'isset', 'list', 'namespace', 'new', 'or', 'print', 'private', 'protected', 'public', 'require', 'return', 'static', 'switch', 'throw', 'trait', 'try', 'unset', 'use', 'var', - 'while', 'xor', + 'while', 'xor', 'void', ]; /** From ec8ece1a31509c6d60787f5ef3b4eab34af41b88 Mon Sep 17 00:00:00 2001 From: Vlad Veselov Date: Mon, 20 Feb 2017 01:27:00 +0200 Subject: [PATCH 34/40] Fix #8308: test setup/src/Magento/Setup/Test/Unit/Model/Cron/JobSetCacheTest.php crashes in debug mode - it was crashing when running PHPUnit with --debug flag due to object passed via data provider --- .../Setup/Test/Unit/Model/Cron/JobSetCacheTest.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobSetCacheTest.php b/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobSetCacheTest.php index 76b755e4c466d..2d7b2d3649262 100644 --- a/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobSetCacheTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Model/Cron/JobSetCacheTest.php @@ -10,17 +10,21 @@ use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Input\InputArgument; +/** + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + */ class JobSetCacheTest extends \PHPUnit_Framework_TestCase { /** * @dataProvider setCacheDataProvider * @param string $commandClass - * @param string $arrayInput + * @param array $arrayInput * @param string $jobName * @param array $params */ public function testSetCache($commandClass, $arrayInput, $jobName, $params) { + $arrayInput = new ArrayInput($arrayInput); $objectManagerProvider = $this->getMock(\Magento\Setup\Model\ObjectManagerProvider::class, [], [], '', false); $objectManager = $this->getMockForAbstractClass(\Magento\Framework\ObjectManagerInterface::class, [], '', false); @@ -62,18 +66,16 @@ public function testSetCache($commandClass, $arrayInput, $jobName, $params) */ public function setCacheDataProvider() { - $cacheEnable = new ArrayInput(['command' => 'cache:enable', 'types' => ['cache1']]); - $cacheDisable = new ArrayInput(['command' => 'cache:disable']); return [ [ \Magento\Backend\Console\Command\CacheEnableCommand::class, - $cacheEnable, + ['command' => 'cache:enable', 'types' => ['cache1']], 'setup:cache:enable', ['cache1'] ], [ \Magento\Backend\Console\Command\CacheDisableCommand::class, - $cacheDisable, + ['command' => 'cache:disable'], 'setup:cache:disable', [] ], From a60ed27ce41c36120588cfecac15e7d3aa1b75ff Mon Sep 17 00:00:00 2001 From: dmanners Date: Mon, 20 Feb 2017 12:18:04 +0000 Subject: [PATCH 35/40] Remove Zend_Json from Customer module in the auth-pop-up block and add tests for the new test function --- .../Block/Account/AuthenticationPopup.php | 22 ++++++- .../Block/Account/AuthenticationPopupTest.php | 58 ++++++++++++++++++- .../account/authentication-popup.phtml | 2 +- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Customer/Block/Account/AuthenticationPopup.php b/app/code/Magento/Customer/Block/Account/AuthenticationPopup.php index a0f94e1b8f733..efada54438c8c 100644 --- a/app/code/Magento/Customer/Block/Account/AuthenticationPopup.php +++ b/app/code/Magento/Customer/Block/Account/AuthenticationPopup.php @@ -15,16 +15,26 @@ class AuthenticationPopup extends \Magento\Framework\View\Element\Template */ protected $jsLayout; + /** + * @var \Magento\Framework\Serialize\Serializer\Json + */ + private $serializer; + /** * @param \Magento\Framework\View\Element\Template\Context $context * @param array $data + * @param \Magento\Framework\Serialize\Serializer\Json|null $serializer + * @throws \RuntimeException */ public function __construct( \Magento\Framework\View\Element\Template\Context $context, - array $data = [] + array $data = [], + \Magento\Framework\Serialize\Serializer\Json $serializer = null ) { parent::__construct($context, $data); $this->jsLayout = isset($data['jsLayout']) && is_array($data['jsLayout']) ? $data['jsLayout'] : []; + $this->serializer = $serializer ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(\Magento\Framework\Serialize\Serializer\Json::class); } /** @@ -32,7 +42,7 @@ public function __construct( */ public function getJsLayout() { - return \Zend_Json::encode($this->jsLayout); + return $this->serializer->serialize($this->jsLayout); } /** @@ -50,6 +60,14 @@ public function getConfig() ]; } + /** + * @return bool|string + */ + public function getSerializedConfig() + { + return $this->serializer->serialize($this->getConfig()); + } + /** * Is autocomplete enabled for storefront * diff --git a/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php b/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php index 67a3fb8f3a576..476111f8253ea 100644 --- a/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php +++ b/app/code/Magento/Customer/Test/Unit/Block/Account/AuthenticationPopupTest.php @@ -31,6 +31,9 @@ class AuthenticationPopupTest extends \PHPUnit_Framework_TestCase /** @var UrlInterface|\PHPUnit_Framework_MockObject_MockObject */ private $urlBuilderMock; + /** @var \Magento\Framework\Serialize\Serializer\Json|\PHPUnit_Framework_MockObject_MockObject */ + private $serilizerMock; + protected function setUp() { $this->contextMock = $this->getMockBuilder(Context::class) @@ -72,8 +75,13 @@ function ($string) { ->method('getEscaper') ->willReturn($escaperMock); + $this->serilizerMock = $this->getMockBuilder(\Magento\Framework\Serialize\Serializer\Json::class) + ->getMock(); + $this->model = new AuthenticationPopup( - $this->contextMock + $this->contextMock, + [], + $this->serilizerMock ); } @@ -83,6 +91,7 @@ function ($string) { * @param string $registerUrl * @param string $forgotUrl * @param array $result + * @throws \PHPUnit_Framework_Exception * * @dataProvider dataProviderGetConfig */ @@ -172,4 +181,51 @@ public function dataProviderGetConfig() ], ]; } + + /** + * @param mixed $isAutocomplete + * @param string $baseUrl + * @param string $registerUrl + * @param string $forgotUrl + * @param array $result + * @throws \PHPUnit_Framework_Exception + * + * @dataProvider dataProviderGetConfig + */ + public function testGetSerializedConfig($isAutocomplete, $baseUrl, $registerUrl, $forgotUrl, array $result) + { + $this->scopeConfigMock->expects($this->any()) + ->method('getValue') + ->with(Form::XML_PATH_ENABLE_AUTOCOMPLETE, ScopeInterface::SCOPE_STORE, null) + ->willReturn($isAutocomplete); + + /** @var StoreInterface||\PHPUnit_Framework_MockObject_MockObject $storeMock */ + $storeMock = $this->getMockBuilder(StoreInterface::class) + ->setMethods(['getBaseUrl']) + ->getMockForAbstractClass(); + + $this->storeManagerMock->expects($this->any()) + ->method('getStore') + ->with(null) + ->willReturn($storeMock); + + $storeMock->expects($this->any()) + ->method('getBaseUrl') + ->willReturn($baseUrl); + + $this->urlBuilderMock->expects($this->any()) + ->method('getUrl') + ->willReturnMap( + [ + ['customer/account/create', [], $registerUrl], + ['customer/account/forgotpassword', [], $forgotUrl], + ] + ); + $this->serilizerMock->expects($this->any())->method('serialize') + ->willReturn( + json_encode($this->model->getConfig()) + ); + + $this->assertEquals(json_encode($result), $this->model->getSerializedConfig()); + } } diff --git a/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml b/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml index bcf0cc92bc912..20ea488931398 100644 --- a/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml +++ b/app/code/Magento/Customer/view/frontend/templates/account/authentication-popup.phtml @@ -10,7 +10,7 @@ ?>