From 015c75f61aac6e1c93d236481d595cc40d409c41 Mon Sep 17 00:00:00 2001 From: Krissy Hiserote Date: Tue, 8 Aug 2017 12:54:56 -0500 Subject: [PATCH 001/151] MAGETWO-71024: [Tech Debt] Skipped unit/integration tests needs to be re-examined. - refactor tests that were skipped --- .../Test/Unit/Model/ProductRepositoryTest.php | 9 +- .../Model/Import/Product/Type/VirtualTest.php | 5 +- .../AroundProductRepositorySaveTest.php | 351 ------------------ .../Unit/Model/Rule/Condition/ProductTest.php | 6 +- .../Observer/ProcessCronQueueObserverTest.php | 75 ++-- .../Unit/Model/Metadata/Form/FileTest.php | 1 - .../Customer/Test/Unit/Model/SessionTest.php | 3 +- .../Adminhtml/Import/ValidateTest.php | 1 - .../Order/Invoice/Total/ShippingTest.php | 4 +- .../Rule/Action/Discount/CartFixedTest.php | 4 +- .../Sitemap/Test/Unit/Model/SitemapTest.php | 3 +- 11 files changed, 58 insertions(+), 404 deletions(-) delete mode 100644 app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php index 44d38adc5c15c..c98705b4eda63 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php @@ -193,8 +193,8 @@ protected function setUp() 'validate', 'save', 'getMediaGalleryEntries', - 'setData' - ]); + ] + ); $this->initializedProductMock->expects($this->any()) ->method('hasGalleryAttribute') ->willReturn(true); @@ -973,7 +973,6 @@ public function saveExistingWithOptionsDataProvider() */ public function testSaveWithLinks(array $newLinks, array $existingLinks, array $expectedData) { - $this->markTestSkipped('Test needs to be refactored.'); $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $this->resourceModelMock->expects($this->any())->method('getIdBySku')->will($this->returnValue(100)); $this->productFactoryMock->expects($this->any()) @@ -1021,7 +1020,7 @@ public function testSaveWithLinks(array $newLinks, array $existingLinks, array $ $this->productData['product_links'] = []; - $this->initializedProductMock->setData("ignore_links_flag", true); + $this->initializedProductMock->setData('ignore_links_flag', true); $this->initializedProductMock->expects($this->never()) ->method('getProductLinks') ->willReturn([]); @@ -1156,7 +1155,6 @@ protected function setupProductMocksForSave() public function testSaveExistingWithNewMediaGalleryEntries() { - $this->markTestSkipped('Test needs to be refactored.'); $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); $newEntriesData = [ 'images' => [ @@ -1286,7 +1284,6 @@ public function testSaveWithDifferentWebsites() public function testSaveExistingWithMediaGalleryEntries() { - $this->markTestSkipped('Test needs to be refactored.'); $this->storeManagerMock->expects($this->any())->method('getWebsites')->willReturn([1 => 'default']); //update one entry, delete one entry $newEntries = [ diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php index b91d5000ca140..cfc625271acda 100644 --- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php +++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php @@ -13,8 +13,7 @@ class VirtualTest extends \PHPUnit\Framework\TestCase */ public function testPrepareAttributesWithDefaultValueForSave() { - $this->markTestSkipped('Test needs to be refactored.'); - $virtualModelMock = $this->createMock(\Magento\CatalogImportExport\Model\Import\Product\Type\Virtual::class); + $virtualModelMock = $this->createPartialMock(\Magento\CatalogImportExport\Model\Import\Product\Type\Virtual::class, []); $this->setPropertyValue( $virtualModelMock, @@ -64,7 +63,7 @@ public function testPrepareAttributesWithDefaultValueForSave() ]; $result = $virtualModelMock->prepareAttributesWithDefaultValueForSave($rowData); - $this->assertEquals($result, $expectedResult); + $this->assertEquals($expectedResult, $result); } /** diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php deleted file mode 100644 index 049313a9a3108..0000000000000 --- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php +++ /dev/null @@ -1,351 +0,0 @@ -markTestSkipped('Test needs to be refactored.'); - $this->stockRegistry = $this->getMockBuilder(StockRegistryInterface::class) - ->setMethods(['getStockItem', 'updateStockItemBySku']) - ->getMockForAbstractClass(); - $this->storeManager = $this->getMockBuilder(StoreManagerInterface::class) - ->getMockForAbstractClass(); - $this->stockConfiguration = $this->getMockBuilder(StockConfigurationInterface::class) - ->setMethods(['getDefaultScopeId']) - ->getMockForAbstractClass(); - - $this->plugin = new AroundProductRepositorySave( - $this->stockRegistry, - $this->storeManager, - $this->stockConfiguration - ); - - $this->savedProduct = $this->getMockBuilder(ProductInterface::class) - ->setMethods(['getExtensionAttributes', 'getStoreId']) - ->getMockForAbstractClass(); - - $this->productRepository = $this->getMockBuilder(ProductRepositoryInterface::class) - ->setMethods(['get']) - ->getMockForAbstractClass(); - $this->product = $this->getMockBuilder(ProductInterface::class) - ->setMethods(['getExtensionAttributes', 'getStoreId']) - ->getMockForAbstractClass(); - $this->productExtension = $this->getMockForAbstractClass( - ProductExtensionInterface::class, - [], - '', - false, - false, - true, - ['getStockItem'] - ); - $this->stockItem = $this->getMockBuilder(StockItemInterface::class) - ->setMethods(['setWebsiteId', 'getWebsiteId', 'getStockId']) - ->getMockForAbstractClass(); - $this->defaultStock = $this->getMockBuilder(StockInterface::class) - ->setMethods(['getStockId']) - ->getMockForAbstractClass(); - } - - public function testAfterSaveWhenProductHasNoStockItemNeedingToBeUpdated() - { - // pretend we have no extension attributes at all - $this->product->expects($this->once()) - ->method('getExtensionAttributes') - ->willReturn(null); - $this->productExtension->expects($this->never())->method('getStockItem'); - - // pretend that the product already has existing stock item information - $this->stockRegistry->expects($this->once())->method('getStockItem')->willReturn($this->stockItem); - $this->stockItem->expects($this->once())->method('getItemId')->willReturn(1); - $this->stockItem->expects($this->never())->method('setProductId'); - $this->stockItem->expects($this->never())->method('setWebsiteId'); - - // expect that there are no changes to the existing stock item information - $result = $this->plugin->afterSave($this->productRepository, $this->savedProduct, $this->product); - $this->assertEquals( - $this->savedProduct, - $result - ); - } - - public function testAfterSaveWhenProductHasNoPersistentStockItemInfo() - { - // pretend we do have extension attributes, but none for 'stock_item' - $this->product->expects($this->once()) - ->method('getExtensionAttributes') - ->willReturn($this->productExtension); - $this->productExtension->expects($this->once()) - ->method('getStockItem') - ->willReturn(null); - - $this->stockConfiguration->expects($this->once())->method('getDefaultScopeId')->willReturn(1); - $this->stockRegistry->expects($this->once())->method('getStockItem')->willReturn($this->stockItem); - $this->stockRegistry->expects($this->once())->method('updateStockItemBySku'); - - $this->stockItem->expects($this->once())->method('getItemId')->willReturn(null); - $this->stockItem->expects($this->once())->method('setProductId'); - $this->stockItem->expects($this->once())->method('setWebsiteId'); - $this->product->expects(($this->atLeastOnce()))->method('getStoreId')->willReturn(20); - - $newProductMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) - ->disableOriginalConstructor()->getMock(); - $this->productRepository->expects($this->once())->method('get')->willReturn($newProductMock); - - $this->assertEquals( - $newProductMock, - $this->plugin->afterSave($this->productRepository, $this->savedProduct, $this->product) - ); - } - - public function testAfterSave() - { - $productId = 5494; - $storeId = 2; - $sku = 'my product that needs saving'; - $defaultScopeId = 100; - $this->stockConfiguration->expects($this->exactly(2)) - ->method('getDefaultScopeId') - ->willReturn($defaultScopeId); - $this->stockRegistry->expects($this->once()) - ->method('getStock') - ->with($defaultScopeId) - ->willReturn($this->defaultStock); - - $this->product->expects($this->once()) - ->method('getExtensionAttributes') - ->willReturn($this->productExtension); - $this->productExtension->expects($this->once()) - ->method('getStockItem') - ->willReturn($this->stockItem); - - $storedStockItem = $this->getMockBuilder(StockItemInterface::class) - ->setMethods(['getItemId']) - ->getMockForAbstractClass(); - $storedStockItem->expects($this->once()) - ->method('getItemId') - ->willReturn(500); - $this->stockRegistry->expects($this->once()) - ->method('getStockItem') - ->willReturn($storedStockItem); - - $this->product->expects(($this->exactly(2)))->method('getId')->willReturn($productId); - $this->product->expects(($this->atLeastOnce()))->method('getStoreId')->willReturn($storeId); - $this->product->expects($this->atLeastOnce())->method('getSku')->willReturn($sku); - - $this->stockItem->expects($this->once())->method('setProductId')->with($productId); - $this->stockItem->expects($this->once())->method('setWebsiteId')->with($defaultScopeId); - - $this->stockRegistry->expects($this->once()) - ->method('updateStockItemBySku') - ->with($sku, $this->stockItem); - - $newProductMock = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) - ->disableOriginalConstructor()->getMock(); - $this->productRepository->expects($this->once()) - ->method('get') - ->with($sku, false, $storeId, true) - ->willReturn($newProductMock); - - $this->assertEquals( - $newProductMock, - $this->plugin->afterSave($this->productRepository, $this->savedProduct, $this->product) - ); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - * @expectedExceptionMessage Invalid stock id: 100500. Only default stock with id 50 allowed - */ - public function testAfterSaveWithInvalidStockId() - { - $stockId = 100500; - $defaultScopeId = 100; - $defaultStockId = 50; - - $this->stockItem->expects($this->once()) - ->method('getStockId') - ->willReturn($stockId); - $this->stockRegistry->expects($this->once()) - ->method('getStock') - ->with($defaultScopeId) - ->willReturn($this->defaultStock); - $this->stockConfiguration->expects($this->once()) - ->method('getDefaultScopeId') - ->willReturn($defaultScopeId); - $this->defaultStock->expects($this->once()) - ->method('getStockId') - ->willReturn($defaultStockId); - - $this->product->expects($this->once()) - ->method('getExtensionAttributes') - ->willReturn($this->productExtension); - $this->productExtension->expects($this->once()) - ->method('getStockItem') - ->willReturn($this->stockItem); - - $this->plugin->afterSave($this->productRepository, $this->savedProduct, $this->product); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - * @expectedExceptionMessage Invalid stock item id: 0. Should be null or numeric value greater than 0 - */ - public function testAfterSaveWithInvalidStockItemId() - { - $stockId = 80; - $stockItemId = 0; - $defaultScopeId = 100; - $defaultStockId = 80; - - $this->stockItem->expects($this->once()) - ->method('getStockId') - ->willReturn($stockId); - $this->stockRegistry->expects($this->once()) - ->method('getStock') - ->with($defaultScopeId) - ->willReturn($this->defaultStock); - $this->stockConfiguration->expects($this->once()) - ->method('getDefaultScopeId') - ->willReturn($defaultScopeId); - $this->defaultStock->expects($this->once()) - ->method('getStockId') - ->willReturn($defaultStockId); - - $this->product->expects($this->once()) - ->method('getExtensionAttributes') - ->willReturn($this->productExtension); - $this->productExtension->expects($this->once()) - ->method('getStockItem') - ->willReturn($this->stockItem); - - $this->stockItem->expects($this->once()) - ->method('getItemId') - ->willReturn($stockItemId); - - $this->plugin->afterSave($this->productRepository, $this->savedProduct, $this->product); - } - - /** - * @expectedException \Magento\Framework\Exception\LocalizedException - * @expectedExceptionMessage Invalid stock item id: 35. Assigned stock item id is 40 - */ - public function testAfterSaveWithNotAssignedStockItemId() - { - $stockId = 80; - $stockItemId = 35; - $defaultScopeId = 100; - $defaultStockId = 80; - $storedStockitemId = 40; - - $this->stockItem->expects($this->once()) - ->method('getStockId') - ->willReturn($stockId); - $this->stockRegistry->expects($this->once()) - ->method('getStock') - ->with($defaultScopeId) - ->willReturn($this->defaultStock); - $this->stockConfiguration->expects($this->once()) - ->method('getDefaultScopeId') - ->willReturn($defaultScopeId); - $this->defaultStock->expects($this->once()) - ->method('getStockId') - ->willReturn($defaultStockId); - - $this->product->expects($this->once()) - ->method('getExtensionAttributes') - ->willReturn($this->productExtension); - $this->productExtension->expects($this->once()) - ->method('getStockItem') - ->willReturn($this->stockItem); - - $this->stockItem->expects($this->once()) - ->method('getItemId') - ->willReturn($stockItemId); - - $storedStockItem = $this->getMockBuilder(StockItemInterface::class) - ->setMethods(['getItemId']) - ->getMockForAbstractClass(); - $storedStockItem->expects($this->once()) - ->method('getItemId') - ->willReturn($storedStockitemId); - $this->stockRegistry->expects($this->once()) - ->method('getStockItem') - ->willReturn($storedStockItem); - - $this->plugin->afterSave($this->productRepository, $this->savedProduct, $this->product); - } -} diff --git a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php index b8121c73cf400..09270b6b41fc7 100644 --- a/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php +++ b/app/code/Magento/CatalogWidget/Test/Unit/Model/Rule/Condition/ProductTest.php @@ -3,7 +3,6 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ - namespace Magento\CatalogWidget\Test\Unit\Model\Rule\Condition; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; @@ -29,11 +28,11 @@ protected function setUp() $eavConfig = $this->createMock(\Magento\Eav\Model\Config::class); $this->attributeMock = $this->createMock(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class); - $eavConfig->expects($this->once())->method('getAttribute')->willReturn($this->attributeMock); + $eavConfig->expects($this->any())->method('getAttribute')->willReturn($this->attributeMock); $ruleMock = $this->createMock(\Magento\SalesRule\Model\Rule::class); $storeManager = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); $storeMock = $this->createMock(\Magento\Store\Api\Data\StoreInterface::class); - $storeManager->expects($this->once())->method('getStore')->willReturn($storeMock); + $storeManager->expects($this->any())->method('getStore')->willReturn($storeMock); $productResource = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class); $productResource->expects($this->once())->method('loadAllAttributes')->willReturnSelf(); $productResource->expects($this->once())->method('getAttributesByCode')->willReturn([]); @@ -73,7 +72,6 @@ public function testAddToCollection() public function testGetMappedSqlFieldSku() { - $this->markTestSkipped('Test needs to be refactored.'); $this->model->setAttribute('sku'); $this->assertEquals('e.sku', $this->model->getMappedSqlField()); } diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php index e368685f32488..5f9b43bbee4bd 100644 --- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php +++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php @@ -88,7 +88,6 @@ class ProcessCronQueueObserverTest extends \PHPUnit\Framework\TestCase */ protected function setUp() { - $this->markTestSkipped('Test needs to be refactored.'); $this->_objectManager = $this->getMockBuilder( \Magento\Framework\App\ObjectManager::class )->disableOriginalConstructor()->getMock(); @@ -139,6 +138,16 @@ protected function setUp() ); $phpExecutableFinderFactory->expects($this->any())->method('create')->willReturn($phpExecutableFinder); + $this->scheduleResource = $this->getMockBuilder(\Magento\Cron\Model\ResourceModel\Schedule::class) + ->disableOriginalConstructor() + ->getMock(); + $this->connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->scheduleResource->method('getConnection')->willReturn($this->connection); + $this->connection->method('delete')->willReturn(1); + $this->_observer = new ProcessCronQueueObserver( $this->_objectManager, $this->_scheduleFactory, @@ -184,7 +193,7 @@ public function testDispatchNoJobConfig() $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(0)); $this->_config->expects( - $this->once() + $this->any() )->method( 'getJobs' )->will( @@ -196,13 +205,12 @@ public function testDispatchNoJobConfig() $this->_collection->addItem($schedule); - $this->_config->expects($this->once())->method('getJobs')->will($this->returnValue([])); - $scheduleMock = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class )->disableOriginalConstructor()->getMock(); $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); - $this->_scheduleFactory->expects($this->once())->method('create')->will($this->returnValue($scheduleMock)); + $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource)); + $this->_scheduleFactory->expects($this->any())->method('create')->will($this->returnValue($scheduleMock)); $this->_observer->execute($this->observer); } @@ -229,7 +237,7 @@ public function testDispatchCanNotLock() $this->_collection->addItem($schedule); $this->_config->expects( - $this->once() + $this->exactly(2) )->method( 'getJobs' )->will( @@ -240,7 +248,8 @@ public function testDispatchCanNotLock() \Magento\Cron\Model\Schedule::class )->disableOriginalConstructor()->getMock(); $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); - $this->_scheduleFactory->expects($this->once())->method('create')->will($this->returnValue($scheduleMock)); + $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource)); + $this->_scheduleFactory->expects($this->exactly(2))->method('create')->will($this->returnValue($scheduleMock)); $this->_observer->execute($this->observer); } @@ -298,7 +307,7 @@ public function testDispatchExceptionTooLate() $this->_collection->addItem($schedule); $this->_config->expects( - $this->once() + $this->exactly(2) )->method( 'getJobs' )->willReturn( @@ -308,7 +317,8 @@ public function testDispatchExceptionTooLate() $scheduleMock = $this->getMockBuilder(\Magento\Cron\Model\Schedule::class) ->disableOriginalConstructor()->getMock(); $scheduleMock->expects($this->any())->method('getCollection')->willReturn($this->_collection); - $this->_scheduleFactory->expects($this->once())->method('create')->willReturn($scheduleMock); + $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource)); + $this->_scheduleFactory->expects($this->exactly(2))->method('create')->willReturn($scheduleMock); $this->_observer->execute($this->observer); } @@ -348,7 +358,7 @@ public function testDispatchExceptionNoCallback() $jobConfig = ['test_group' => ['test_job1' => ['instance' => 'Some_Class']]]; - $this->_config->expects($this->once())->method('getJobs')->will($this->returnValue($jobConfig)); + $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig)); $lastRun = time() + 10000000; $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun)); @@ -359,7 +369,8 @@ public function testDispatchExceptionNoCallback() \Magento\Cron\Model\Schedule::class )->disableOriginalConstructor()->getMock(); $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); - $this->_scheduleFactory->expects($this->once())->method('create')->will($this->returnValue($scheduleMock)); + $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource)); + $this->_scheduleFactory->expects($this->exactly(2))->method('create')->will($this->returnValue($scheduleMock)); $this->_observer->execute($this->observer); } @@ -409,7 +420,7 @@ public function testDispatchExceptionInCallback( $this->_collection->addItem($schedule); - $this->_config->expects($this->once())->method('getJobs')->will($this->returnValue($jobConfig)); + $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig)); $lastRun = time() + 10000000; $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun)); @@ -419,7 +430,8 @@ public function testDispatchExceptionInCallback( \Magento\Cron\Model\Schedule::class )->disableOriginalConstructor()->getMock(); $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); - $this->_scheduleFactory->expects($this->once())->method('create')->will($this->returnValue($scheduleMock)); + $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource)); + $this->_scheduleFactory->expects($this->exactly(2))->method('create')->will($this->returnValue($scheduleMock)); $this->_objectManager ->expects($this->once()) ->method('create') @@ -502,7 +514,7 @@ public function testDispatchRunJob() $this->_collection->addItem($schedule); - $this->_config->expects($this->once())->method('getJobs')->will($this->returnValue($jobConfig)); + $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig)); $lastRun = time() + 10000000; $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun)); @@ -512,7 +524,8 @@ public function testDispatchRunJob() \Magento\Cron\Model\Schedule::class )->disableOriginalConstructor()->getMock(); $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); - $this->_scheduleFactory->expects($this->once())->method('create')->will($this->returnValue($scheduleMock)); + $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource)); + $this->_scheduleFactory->expects($this->exactly(2))->method('create')->will($this->returnValue($scheduleMock)); $testCronJob = $this->getMockBuilder('CronJob')->setMethods(['execute'])->getMock(); $testCronJob->expects($this->atLeastOnce())->method('execute')->with($schedule); @@ -553,18 +566,18 @@ public function testDispatchNotGenerate() )->method( 'load' )->with( - $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT . 'test_group') + $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . 'test_group') )->will( - $this->returnValue(time() - 10000000) + $this->returnValue(time() + 10000000) ); $this->_cache->expects( - $this->at(2) + $this->at(1) )->method( 'load' )->with( - $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . 'test_group') + $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT . 'test_group') )->will( - $this->returnValue(time() + 10000000) + $this->returnValue(time() - 10000000) ); $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(0)); @@ -622,15 +635,15 @@ public function testDispatchGenerate() )->method( 'load' )->with( - $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT . 'default') - )->willReturn(time() - 10000000); + $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . 'default') + )->willReturn(time() + 10000000); $this->_cache->expects( - $this->at(2) + $this->at(1) )->method( 'load' )->with( - $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . 'default') - )->willReturn(time() + 10000000); + $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT . 'default') + )->willReturn(time() - 10000000); $this->_scopeConfig->expects($this->any())->method('getValue')->willReturnMap( [ @@ -652,7 +665,7 @@ public function testDispatchGenerate() $schedule = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class )->setMethods( - ['getJobCode', 'save', 'getScheduledAt', 'unsScheduleId', 'trySchedule', 'getCollection'] + ['getJobCode', 'save', 'getScheduledAt', 'unsScheduleId', 'trySchedule', 'getCollection', 'getResource'] )->disableOriginalConstructor()->getMock(); $schedule->expects($this->any())->method('getJobCode')->willReturn('job_code1'); $schedule->expects($this->once())->method('getScheduledAt')->willReturn('* * * * *'); @@ -660,6 +673,7 @@ public function testDispatchGenerate() $schedule->expects($this->any())->method('trySchedule')->willReturnSelf(); $schedule->expects($this->any())->method('getCollection')->willReturn($this->_collection); $schedule->expects($this->atLeastOnce())->method('save')->willReturnSelf(); + $schedule->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource)); $this->_collection->addItem(new \Magento\Framework\DataObject()); $this->_collection->addItem($schedule); @@ -690,7 +704,7 @@ public function testDispatchCleanup() $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group')); $this->_collection->addItem($schedule); - $this->_config->expects($this->once())->method('getJobs')->will($this->returnValue($jobConfig)); + $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig)); $this->_cache->expects($this->at(0))->method('load')->will($this->returnValue(time() + 10000000)); $this->_cache->expects($this->at(1))->method('load')->will($this->returnValue(time() - 10000000)); @@ -714,8 +728,9 @@ public function testDispatchCleanup() $scheduleMock = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class - )->setMethods(['getCollection'])->disableOriginalConstructor()->getMock(); + )->setMethods(['getCollection', 'getResource'])->disableOriginalConstructor()->getMock(); $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($collection)); + $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource)); $this->_scheduleFactory->expects($this->at(1))->method('create')->will($this->returnValue($scheduleMock)); $this->_observer->execute($this->observer); @@ -723,6 +738,7 @@ public function testDispatchCleanup() public function testMissedJobsCleanedInTime() { + $this->markTestSkipped('Test needs to be refactored.'); /* 1. Initialize dependencies of _generate() method which is called first */ $jobConfig = [ 'test_group' => ['test_job1' => ['instance' => 'CronJob', 'method' => 'execute']], @@ -754,7 +770,7 @@ public function testMissedJobsCleanedInTime() $schedule2->expects($this->never())->method('delete'); $this->_collection->addItem($schedule1); - $this->_config->expects($this->once())->method('getJobs')->will($this->returnValue($jobConfig)); + $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig)); //get configuration value CACHE_KEY_LAST_HISTORY_CLEANUP_AT in the "_generate()" $this->_cache->expects($this->at(0))->method('load')->will($this->returnValue(time() + 10000000)); @@ -801,6 +817,7 @@ public function testMissedJobsCleanedInTime() \Magento\Cron\Model\Schedule::class )->disableOriginalConstructor()->getMock(); $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($collection)); + $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource)); $this->_scheduleFactory->expects($this->at(1))->method('create')->will($this->returnValue($scheduleMock)); $this->_observer->execute($this->observer); diff --git a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php index 04a4839a3dee7..97452b995ba0b 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/Metadata/Form/FileTest.php @@ -490,7 +490,6 @@ private function initialize(array $data) public function testExtractValueFileUploaderUIComponent() { - $this->markTestSkipped('Test needs to be refactored.'); $attributeCode = 'img1'; $requestScope = 'customer'; $fileName = 'filename.ext1'; diff --git a/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php b/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php index 2e61ab9aa721d..7a6807562f906 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/SessionTest.php @@ -149,7 +149,6 @@ public function testAuthenticate() public function testLoginById() { - $this->markTestSkipped('Test needs to be refactored.'); $customerId = 1; $customerDataMock = $this->prepareLoginDataMock($customerId); @@ -175,7 +174,7 @@ protected function prepareLoginDataMock($customerId) $customerMock = $this->createPartialMock( \Magento\Customer\Model\Customer::class, - ['getId', 'isConfirmationRequired', 'getConfirmation', 'updateData'] + ['getId', 'isConfirmationRequired', 'getConfirmation', 'updateData', 'getGroupId'] ); $customerMock->expects($this->once()) ->method('getId') diff --git a/app/code/Magento/ImportExport/Test/Unit/Controller/Adminhtml/Import/ValidateTest.php b/app/code/Magento/ImportExport/Test/Unit/Controller/Adminhtml/Import/ValidateTest.php index 9295cd65cd044..55e347d62df9a 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Controller/Adminhtml/Import/ValidateTest.php +++ b/app/code/Magento/ImportExport/Test/Unit/Controller/Adminhtml/Import/ValidateTest.php @@ -157,7 +157,6 @@ public function testNoDataWasPosted() */ public function testFileWasNotUploaded() { - $this->markTestSkipped('Test needs to be refactored.'); $data = false; $this->requestMock->expects($this->once()) diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Total/ShippingTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Total/ShippingTest.php index f0549a85db23d..309bd4d99dc1f 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Total/ShippingTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Total/ShippingTest.php @@ -31,7 +31,6 @@ protected function setUp() */ public function testCollectWithNoOrZeroPrevInvoice(array $prevInvoicesData, $orderShipping, $expectedShipping) { - $this->markTestSkipped('Test needs to be refactored.'); $invoice = $this->createInvoiceStub($prevInvoicesData, $orderShipping); $invoice->expects($this->exactly(2)) ->method('setShippingAmount') @@ -61,7 +60,6 @@ public static function collectWithNoOrZeroPrevInvoiceDataProvider() public function testCollectWithPreviousInvoice() { - $this->markTestSkipped('Test needs to be refactored.'); $orderShipping = 10.00; $prevInvoicesData = [['shipping_amount' => '10.000']]; $invoice = $this->createInvoiceStub($prevInvoicesData, $orderShipping); @@ -136,7 +134,7 @@ private function getInvoiceCollection(array $invoicesData) $arguments['data'] = $oneInvoiceData; $arguments = $objectManagerHelper->getConstructArguments($className, $arguments); /** @var $prevInvoice \Magento\Sales\Model\Order\Invoice */ - $prevInvoice = $this->getMockBuilder($className)->setMethods(['_init'])->setConstructorArgs($arguments); + $prevInvoice = $this->getMockBuilder($className)->setMethods(['_init'])->setConstructorArgs($arguments)->getMock(); $result->addItem($prevInvoice); } return $result; diff --git a/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Action/Discount/CartFixedTest.php b/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Action/Discount/CartFixedTest.php index 51390747b8a80..2f1bee9fc686a 100644 --- a/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Action/Discount/CartFixedTest.php +++ b/app/code/Magento/SalesRule/Test/Unit/Model/Rule/Action/Discount/CartFixedTest.php @@ -51,10 +51,11 @@ protected function setUp() { $this->rule = $this->getMockBuilder(\Magento\Framework\DataObject::class) ->setMockClassName('Rule') + ->setMethods(null) ->disableOriginalConstructor() ->getMock(); $this->item = $this->createMock(\Magento\Quote\Model\Quote\Item\AbstractItem::class); - $this->data = $this->createMock(\Magento\SalesRule\Model\Rule\Action\Discount\Data::class); + $this->data = $this->createPartialMock(\Magento\SalesRule\Model\Rule\Action\Discount\Data::class, []); $this->quote = $this->createMock(\Magento\Quote\Model\Quote::class); $this->address = $this->createPartialMock( @@ -85,7 +86,6 @@ protected function setUp() */ public function testCalculate() { - $this->markTestSkipped('Test needs to be refactored.'); $this->rule->setData(['id' => 1, 'discount_amount' => 10.0]); $this->address->expects($this->any())->method('getCartFixedRules')->will($this->returnValue([])); diff --git a/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php b/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php index cec23393c6f72..bf73578085476 100644 --- a/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php +++ b/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php @@ -351,7 +351,6 @@ public static function robotsDataProvider() */ public function testAddSitemapToRobotsTxt($maxLines, $maxFileSize, $expectedFile, $expectedWrites, $robotsInfo) { - $this->markTestSkipped('Test needs to be refactored.'); $actualData = []; $model = $this->_prepareSitemapModelMock( $actualData, @@ -404,7 +403,7 @@ protected function _prepareSitemapModelMock( ); // Check that all expected file descriptors were created - $this->_directoryMock->expects($this->exactly($expectedWrites))->method('openFile')->will( + $this->_directoryMock->expects($this->exactly(count($expectedFile)))->method('openFile')->will( $this->returnCallback( function ($file) use (&$currentFile) { $currentFile = $file; From ade4377bf4e037d30e121b50e8e38f10452b5b74 Mon Sep 17 00:00:00 2001 From: Daniel Renaud Date: Fri, 18 Aug 2017 15:58:22 -0500 Subject: [PATCH 002/151] MAGETWO-71024: [Tech Debt] Skipped unit/integration tests needs to be re-examined. - Refactor unit tests --- .../Observer/ProcessCronQueueObserverTest.php | 74 +++++++++---------- .../Group/Grid/ServiceCollectionTest.php | 1 - .../Import/Product/Type/DownloadableTest.php | 51 ++++++++----- .../Adminhtml/Rating/Edit/Tab/FormTest.php | 24 +++--- .../Test/Unit/Block/Html/TopmenuTest.php | 8 +- .../ResourceModel/Layout/AbstractTestCase.php | 1 - .../Layout/Link/CollectionTest.php | 2 +- .../Layout/Update/CollectionTest.php | 2 +- .../Unit/Helper/ObjectManager.php | 1 + 9 files changed, 90 insertions(+), 74 deletions(-) diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php index 5f9b43bbee4bd..cca5611056d7b 100644 --- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php +++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php @@ -83,6 +83,16 @@ class ProcessCronQueueObserverTest extends \PHPUnit\Framework\TestCase */ protected $appStateMock; + /** + * @var \Magento\Cron\Model\ResourceModel\Schedule|\PHPUnit_Framework_MockObject_MockObject + */ + protected $scheduleResource; + + /** + * @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject + */ + protected $connection; + /** * Prepare parameters */ @@ -738,11 +748,22 @@ public function testDispatchCleanup() public function testMissedJobsCleanedInTime() { - $this->markTestSkipped('Test needs to be refactored.'); - /* 1. Initialize dependencies of _generate() method which is called first */ + /* 1. Initialize dependencies of _cleanup() method which is called first */ + $scheduleMock = $this->getMockBuilder( + \Magento\Cron\Model\Schedule::class + )->disableOriginalConstructor()->getMock(); + $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); + //get configuration value CACHE_KEY_LAST_HISTORY_CLEANUP_AT in the "_cleanup()" + $this->_cache->expects($this->at(0))->method('load')->will($this->returnValue(time() - 10000000)); + $this->_scheduleFactory->expects($this->at(0))->method('create')->will($this->returnValue($scheduleMock)); + + /* 2. Initialize dependencies of _generate() method which is called second */ $jobConfig = [ 'test_group' => ['test_job1' => ['instance' => 'CronJob', 'method' => 'execute']], ]; + //get configuration value CACHE_KEY_LAST_HISTORY_CLEANUP_AT in the "_generate()" + $this->_cache->expects($this->at(2))->method('load')->will($this->returnValue(time() + 10000000)); + $this->_scheduleFactory->expects($this->at(2))->method('create')->will($this->returnValue($scheduleMock)); // This item was scheduled 2 days ago /** @var \Magento\Cron\Model\Schedule|\PHPUnit_Framework_MockObject_MockObject $schedule1 */ @@ -756,6 +777,7 @@ public function testMissedJobsCleanedInTime() $schedule1->expects($this->any())->method('getStatus')->will($this->returnValue(Schedule::STATUS_MISSED)); //we expect this job be deleted from the list $schedule1->expects($this->once())->method('delete')->will($this->returnValue(true)); + $this->_collection->addItem($schedule1); // This item was scheduled 1 day ago $schedule2 = $this->getMockBuilder( @@ -768,55 +790,33 @@ public function testMissedJobsCleanedInTime() $schedule2->expects($this->any())->method('getStatus')->will($this->returnValue(Schedule::STATUS_MISSED)); //we don't expect this job be deleted from the list $schedule2->expects($this->never())->method('delete'); + $this->_collection->addItem($schedule2); - $this->_collection->addItem($schedule1); $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig)); - //get configuration value CACHE_KEY_LAST_HISTORY_CLEANUP_AT in the "_generate()" - $this->_cache->expects($this->at(0))->method('load')->will($this->returnValue(time() + 10000000)); - //get configuration value CACHE_KEY_LAST_HISTORY_CLEANUP_AT in the "_cleanup()" - $this->_cache->expects($this->at(1))->method('load')->will($this->returnValue(time() - 10000000)); - $this->_scopeConfig->expects($this->at(0))->method('getValue') - ->with($this->equalTo('system/cron/test_group/use_separate_process')) - ->will($this->returnValue(0)); + ->with($this->equalTo('system/cron/test_group/history_cleanup_every')) + ->will($this->returnValue(10)); $this->_scopeConfig->expects($this->at(1))->method('getValue') - ->with($this->equalTo('system/cron/test_group/schedule_generate_every')) - ->will($this->returnValue(0)); + ->with($this->equalTo('system/cron/test_group/schedule_lifetime')) + ->will($this->returnValue(2*24*60)); $this->_scopeConfig->expects($this->at(2))->method('getValue') - ->with($this->equalTo('system/cron/test_group/history_cleanup_every')) + ->with($this->equalTo('system/cron/test_group/history_success_lifetime')) ->will($this->returnValue(0)); $this->_scopeConfig->expects($this->at(3))->method('getValue') - ->with($this->equalTo('system/cron/test_group/schedule_lifetime')) - ->will($this->returnValue(2*24*60)); + ->with($this->equalTo('system/cron/test_group/history_failure_lifetime')) + ->will($this->returnValue(0)); $this->_scopeConfig->expects($this->at(4))->method('getValue') - ->with($this->equalTo('system/cron/test_group/history_success_lifetime')) + ->with($this->equalTo('system/cron/test_group/schedule_generate_every')) ->will($this->returnValue(0)); $this->_scopeConfig->expects($this->at(5))->method('getValue') - ->with($this->equalTo('system/cron/test_group/history_failure_lifetime')) + ->with($this->equalTo('system/cron/test_group/use_separate_process')) ->will($this->returnValue(0)); - /* 2. Initialize dependencies of _cleanup() method which is called second */ - $scheduleMock = $this->getMockBuilder( - \Magento\Cron\Model\Schedule::class - )->disableOriginalConstructor()->getMock(); - $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); - $this->_scheduleFactory->expects($this->at(0))->method('create')->will($this->returnValue($scheduleMock)); - - $collection = $this->getMockBuilder( - \Magento\Cron\Model\ResourceModel\Schedule\Collection::class - )->setMethods( - ['addFieldToFilter', 'load', '__wakeup'] - )->disableOriginalConstructor()->getMock(); - $collection->expects($this->any())->method('addFieldToFilter')->will($this->returnSelf()); - $collection->expects($this->any())->method('load')->will($this->returnSelf()); - $collection->addItem($schedule1); - $collection->addItem($schedule2); + $this->_collection->expects($this->any())->method('addFieldToFilter')->will($this->returnSelf()); + $this->_collection->expects($this->any())->method('load')->will($this->returnSelf()); - $scheduleMock = $this->getMockBuilder( - \Magento\Cron\Model\Schedule::class - )->disableOriginalConstructor()->getMock(); - $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($collection)); + $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); $scheduleMock->expects($this->any())->method('getResource')->will($this->returnValue($this->scheduleResource)); $this->_scheduleFactory->expects($this->at(1))->method('create')->will($this->returnValue($scheduleMock)); diff --git a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Group/Grid/ServiceCollectionTest.php b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Group/Grid/ServiceCollectionTest.php index 490480edefa3a..61081e1aaf224 100644 --- a/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Group/Grid/ServiceCollectionTest.php +++ b/app/code/Magento/Customer/Test/Unit/Model/ResourceModel/Group/Grid/ServiceCollectionTest.php @@ -38,7 +38,6 @@ class ServiceCollectionTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $this->markTestSkipped('Test needs to be refactored'); $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->filterBuilder = $this->objectManager->getObject(\Magento\Framework\Api\FilterBuilder::class); $filterGroupBuilder = $this->objectManager diff --git a/app/code/Magento/DownloadableImportExport/Test/Unit/Model/Import/Product/Type/DownloadableTest.php b/app/code/Magento/DownloadableImportExport/Test/Unit/Model/Import/Product/Type/DownloadableTest.php index a23252d101dd6..9cb6b061b14ee 100644 --- a/app/code/Magento/DownloadableImportExport/Test/Unit/Model/Import/Product/Type/DownloadableTest.php +++ b/app/code/Magento/DownloadableImportExport/Test/Unit/Model/Import/Product/Type/DownloadableTest.php @@ -169,7 +169,7 @@ protected function setUp() $this->uploaderHelper->expects($this->any())->method('getUploader')->willReturn($this->uploaderMock); $this->downloadableHelper = $this->createPartialMock( \Magento\DownloadableImportExport\Helper\Data::class, - ['prepareDataForSave'] + ['prepareDataForSave', 'fillExistOptions'] ); $this->downloadableHelper->expects($this->any())->method('prepareDataForSave')->willReturn([]); } @@ -648,28 +648,18 @@ public function isRowValidData() /** * @dataProvider dataForUploaderDir */ - public function testSetUploaderDirFalse($newSku, $bunch, $allowImport) + public function testSetUploaderDirFalse($newSku, $bunch, $allowImport, $parsedOptions) { - $this->markTestSkipped('Test needs to be refactored.'); $this->connectionMock->expects($this->any())->method('fetchAll')->with( $this->select - )->willReturnOnConsecutiveCalls( - [ - [ - 'attribute_set_name' => '1', - 'attribute_id' => '1', - ], - [ - 'attribute_set_name' => '2', - 'attribute_id' => '2', - ], - ] - ); + )->willReturn([]); $metadataPoolMock = $this ->createPartialMock(\Magento\Framework\EntityManager\MetadataPool::class, ['getLinkField', 'getMetadata']); $metadataPoolMock->expects($this->any())->method('getMetadata')->willReturnSelf(); $metadataPoolMock->expects($this->any())->method('getLinkField')->willReturn('entity_id'); + $this->downloadableHelper->expects($this->atLeastOnce()) + ->method('fillExistOptions')->willReturn($parsedOptions['link']); $this->downloadableModelMock = $this->objectManagerHelper->getObject( \Magento\DownloadableImportExport\Model\Import\Product\Type\Downloadable::class, @@ -688,9 +678,8 @@ public function testSetUploaderDirFalse($newSku, $bunch, $allowImport) $this->entityModelMock->expects($this->at(2))->method('getNextBunch')->will($this->returnValue(null)); $this->entityModelMock->expects($this->any())->method('isRowAllowedToImport')->willReturn($allowImport); $exception = new \Magento\Framework\Exception\LocalizedException(new \Magento\Framework\Phrase('Error')); - $this->expectException(\Magento\Framework\Exception\LocalizedException::class); - $this->expectException('\Exception'); $this->uploaderMock->expects($this->any())->method('move')->will($this->throwException($exception)); + $this->entityModelMock->expects($this->exactly(2))->method('addRowError'); $result = $this->downloadableModelMock->saveData(); $this->assertNotNull($result); } @@ -725,6 +714,34 @@ public function dataForUploaderDir() ], ], 'allowImport' => true, + 'parsedOptions' => [ + 'sample' => [ + 'sample_id' => null, + 'product_id' => '25', + 'sample_url' => null, + 'sample_file' => 'media/file.mp4', + 'sample_type' => 'file', + 'sort_order' => '1', + 'group_title' => 'Group Title Samples', + 'title' => 'Title 1', + ], + 'link' => [ + 'link_id' => null, + 'product_id' => '25', + 'sort_order' => '1', + 'number_of_downloads' => 0, + 'is_shareable' => 2, + 'link_url' => null, + 'link_file' => '', + 'link_type' => 'file', + 'sample_url' => null, + 'sample_file' => null, + 'sample_type' => null, + 'group_title' => 'Group Title Links', + 'title' => 'Title 1', + 'price' => '10' + ] + ] ], ]; } diff --git a/app/code/Magento/Review/Test/Unit/Block/Adminhtml/Rating/Edit/Tab/FormTest.php b/app/code/Magento/Review/Test/Unit/Block/Adminhtml/Rating/Edit/Tab/FormTest.php index 37a161be821a7..4c73c66f6d5d5 100644 --- a/app/code/Magento/Review/Test/Unit/Block/Adminhtml/Rating/Edit/Tab/FormTest.php +++ b/app/code/Magento/Review/Test/Unit/Block/Adminhtml/Rating/Edit/Tab/FormTest.php @@ -111,7 +111,7 @@ protected function setUp() $this->store = $this->createMock(\Magento\Store\Model\Store::class); $this->form = $this->createPartialMock( \Magento\Framework\Data\Form::class, - ['setForm', 'addFieldset', 'addField', 'setRenderer', 'getElement'] + ['setForm', 'addFieldset', 'addField', 'setRenderer', 'getElement', 'setValues'] ); $this->directoryReadInterface = $this->createMock(\Magento\Framework\Filesystem\Directory\ReadInterface::class); $this->registry = $this->createMock(\Magento\Framework\Registry::class); @@ -136,6 +136,7 @@ protected function setUp() $this->form->expects($this->any())->method('addFieldset')->will($this->returnSelf()); $this->form->expects($this->any())->method('addField')->will($this->returnSelf()); $this->form->expects($this->any())->method('setRenderer')->will($this->returnSelf()); + $this->form->expects($this->any())->method('setValues')->will($this->returnSelf()); $this->optionFactory->expects($this->any())->method('create')->will($this->returnValue($this->optionRating)); $this->systemStore->expects($this->any())->method('getStoreCollection') ->will($this->returnValue(['0' => $this->store])); @@ -162,12 +163,11 @@ protected function setUp() public function testToHtmlSessionRatingData() { - $this->markTestSkipped('Test needs to be refactored.'); $this->registry->expects($this->any())->method('registry')->will($this->returnValue($this->rating)); - $this->form->expects($this->at(7))->method('getElement')->will($this->returnValue($this->element)); - $this->form->expects($this->at(13))->method('getElement')->will($this->returnValue($this->element)); - $this->form->expects($this->at(16))->method('getElement')->will($this->returnValue($this->element)); - $this->form->expects($this->at(17))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(5))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(11))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(14))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(15))->method('getElement')->will($this->returnValue($this->element)); $this->form->expects($this->any())->method('getElement')->will($this->returnValue(false)); $ratingCodes = ['rating_codes' => ['0' => 'rating_code']]; $this->session->expects($this->any())->method('getRatingData')->will($this->returnValue($ratingCodes)); @@ -177,12 +177,11 @@ public function testToHtmlSessionRatingData() public function testToHtmlCoreRegistryRatingData() { - $this->markTestSkipped('Test needs to be refactored.'); $this->registry->expects($this->any())->method('registry')->will($this->returnValue($this->rating)); - $this->form->expects($this->at(7))->method('getElement')->will($this->returnValue($this->element)); - $this->form->expects($this->at(13))->method('getElement')->will($this->returnValue($this->element)); - $this->form->expects($this->at(16))->method('getElement')->will($this->returnValue($this->element)); - $this->form->expects($this->at(17))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(5))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(11))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(14))->method('getElement')->will($this->returnValue($this->element)); + $this->form->expects($this->at(15))->method('getElement')->will($this->returnValue($this->element)); $this->form->expects($this->any())->method('getElement')->will($this->returnValue(false)); $this->session->expects($this->any())->method('getRatingData')->will($this->returnValue(false)); $ratingCodes = ['rating_codes' => ['0' => 'rating_code']]; @@ -192,9 +191,8 @@ public function testToHtmlCoreRegistryRatingData() public function testToHtmlWithoutRatingData() { - $this->markTestSkipped('Test needs to be refactored.'); $this->registry->expects($this->any())->method('registry')->will($this->returnValue(false)); - $this->systemStore->expects($this->any())->method('getStoreCollection') + $this->systemStore->expects($this->atLeastOnce())->method('getStoreCollection') ->will($this->returnValue(['0' => $this->store])); $this->formFactory->expects($this->any())->method('create')->will($this->returnValue($this->form)); $this->viewFileSystem->expects($this->any())->method('getTemplateFileName') diff --git a/app/code/Magento/Theme/Test/Unit/Block/Html/TopmenuTest.php b/app/code/Magento/Theme/Test/Unit/Block/Html/TopmenuTest.php index 3893ab1adcaa8..49066e79cb798 100644 --- a/app/code/Magento/Theme/Test/Unit/Block/Html/TopmenuTest.php +++ b/app/code/Magento/Theme/Test/Unit/Block/Html/TopmenuTest.php @@ -116,7 +116,6 @@ protected function getTopmenu() public function testGetHtmlWithoutSelectedCategory() { - $this->markTestSkipped('Test needs to be refactored.'); $topmenuBlock = $this->getTopmenu(); $treeNode = $this->buildTree(false); @@ -150,7 +149,6 @@ public function testGetHtmlWithoutSelectedCategory() public function testGetHtmlWithSelectedCategory() { - $this->markTestSkipped('Test needs to be refactored.'); $topmenuBlock = $this->getTopmenu(); $treeNode = $this->buildTree(true); @@ -254,7 +252,11 @@ private function buildTree($isCurrentItem) $nodeMock->expects($this->once()) ->method('getChildren') ->willReturn($children); - $nodeMock->expects($this->any()) + $nodeMock->expects($this->at(0)) + ->method('__call') + ->with('setOutermostClass') + ->willReturn(null); + $nodeMock->expects($this->at(3)) ->method('__call') ->with('getLevel', []) ->willReturn(null); diff --git a/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/AbstractTestCase.php b/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/AbstractTestCase.php index 8ec136e1537d0..32c4d72c8bccd 100644 --- a/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/AbstractTestCase.php +++ b/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/AbstractTestCase.php @@ -83,7 +83,6 @@ abstract protected function _getCollection(\Magento\Framework\DB\Select $select) public function testAddUpdatedDaysBeforeFilter() { - $this->markTestSkipped('Test needs to be refactored.'); $select = $this->createMock(\Magento\Framework\DB\Select::class); $select->expects($this->any())->method('where')->with(self::TEST_WHERE_CONDITION); diff --git a/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/Link/CollectionTest.php b/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/Link/CollectionTest.php index 2efa8d162d802..825d2ca50feda 100644 --- a/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/Link/CollectionTest.php +++ b/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/Link/CollectionTest.php @@ -32,7 +32,7 @@ protected function _getCollection(\Magento\Framework\DB\Select $select) $this->createMock(\Psr\Log\LoggerInterface::class), $this->getMockForAbstractClass(\Magento\Framework\Data\Collection\Db\FetchStrategyInterface::class), $eventManager, - $this->createMock(\Magento\Framework\Stdlib\DateTime::class), + $this->createPartialMock(\Magento\Framework\Stdlib\DateTime::class, []), null, $this->_getResource($select) ); diff --git a/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/Update/CollectionTest.php b/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/Update/CollectionTest.php index 8b8fe130dd6df..3467378eaeb9c 100644 --- a/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/Update/CollectionTest.php +++ b/app/code/Magento/Widget/Test/Unit/Model/ResourceModel/Layout/Update/CollectionTest.php @@ -22,7 +22,7 @@ protected function _getCollection(\Magento\Framework\DB\Select $select) $this->createMock(\Psr\Log\LoggerInterface::class), $this->getMockForAbstractClass(\Magento\Framework\Data\Collection\Db\FetchStrategyInterface::class), $eventManager, - $this->createMock(\Magento\Framework\Stdlib\DateTime::class), + $this->createPartialMock(\Magento\Framework\Stdlib\DateTime::class, []), null, $this->_getResource($select) ); diff --git a/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ObjectManager.php b/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ObjectManager.php index 62966b4a5636e..26457f23c6c78 100644 --- a/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ObjectManager.php +++ b/lib/internal/Magento/Framework/TestFramework/Unit/Helper/ObjectManager.php @@ -191,6 +191,7 @@ protected function getBuilder($className, array $arguments) ->disableOriginalClone() ->disableArgumentCloning() ->disallowMockingUnknownTypes() + ->setMethods(['populateWithArray', 'populate', 'create']) ->getMock(); $objectFactory->expects($this->_testObject->any()) From d00a950ea7431b643baa05e3d1365767d0371018 Mon Sep 17 00:00:00 2001 From: serhii balko Date: Thu, 17 Aug 2017 14:55:53 +0300 Subject: [PATCH 003/151] MAGETWO-56349: [GITHUB] Newsletter Queue doesn't set to local time #5943 #2937 #7560 --- .../Block/Adminhtml/Queue/Edit/QueueForm.php | 28 ++++++ .../Test/Block/Adminhtml/Queue/Grid.php | 51 ++++++++++ .../AssertNewsletterQueueDateStart.php | 50 ++++++++++ .../Page/Adminhtml/TemplateQueueIndex.xml | 14 +++ .../TestCase/UpdateQueueStartDateTest.php | 97 +++++++++++++++++++ .../TestCase/UpdateQueueStartDateTest.xml | 16 +++ 6 files changed, 256 insertions(+) create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueueIndex.xml create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php index 8de406c896591..40ce9c5085e1b 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php @@ -13,6 +13,13 @@ */ class QueueForm extends \Magento\Mtf\Block\Form { + /** + * "Queue Date Start" field selector. + * + * @var string + */ + private $dateStartSelector = 'input[name=start_at]'; + /** * Get data of specified form data. * @@ -25,4 +32,25 @@ protected function _getData(array $fields, SimpleElement $element = null) unset($fields['code']); return parent::_getData($fields, $element); } + + /** + * Get Queue Date Start value. + * + * @return string + */ + public function getDateStart() + { + return $this->_rootElement->find($this->dateStartSelector)->getValue(); + } + + /** + * Set Queue Date Start value. + * + * @param string $val + * @return void + */ + public function setDateStart($val) + { + $this->_rootElement->find($this->dateStartSelector)->setValue($val); + } } diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php new file mode 100644 index 0000000000000..682c91aab425d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php @@ -0,0 +1,51 @@ + [ + 'selector' => 'input[name="newsletter_subject"]', + ], + ]; + + /** + * Locator value for link in action column. + * + * @var string + */ + protected $editLink = 'td.col-subject'; + + /** + * Locator for "Action". + * + * @var string + */ + protected $action = '.col-actions [class*="control-select"]'; + + /** + * Action for newsletter queue template. + * + * @param string $action + * @return void + */ + public function performAction($action) + { + $this->_rootElement->find($this->action, Locator::SELECTOR_CSS, 'select')->setValue($action); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php new file mode 100644 index 0000000000000..10f3fb216bf3a --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php @@ -0,0 +1,50 @@ +open(); + $indexQueue->getQueueTemplateGrid()->searchAndOpen(['newsletter_subject' => $newsletter->getSubject()]); + \PHPUnit_Framework_Assert::assertEquals( + $date, + $templateQueue->getEditForm()->getDateStart(), + 'Field "Queue Date Start" did\'t save correctly' + ); + } + + /** + * {@inheritdoc} + */ + public function toString() + { + return 'Field "Queue Date Start" saved correctly'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueueIndex.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueueIndex.xml new file mode 100644 index 0000000000000..8504673af09b8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueueIndex.xml @@ -0,0 +1,14 @@ + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php new file mode 100644 index 0000000000000..64a57a78764bd --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php @@ -0,0 +1,97 @@ + Newsletter Template + * 3. Find created template in grid + * 4. Execute "Queue Newsletter" action + * 5. Fill Date Start + * 6. Save Newsletter Queue + * + * @group Newsletters + * @ZephyrId MAGETWO-71653 + */ +class UpdateQueueStartDateTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + const STABLE = 'no'; + /* end tags */ + + /** + * Page with newsletter template grid. + * + * @var TemplateIndex + */ + protected $templateIndex; + + /** + * Page with newsletter queue grid. + * + * @var TemplateQueueIndex + */ + protected $indexQueue; + + /** + * Page for edit newsletter queue. + * + * @var TemplateQueue + */ + protected $templateQueue; + + /** + * Inject newsletter page. + * + * @param TemplateIndex $templateIndex + * @param TemplateQueueIndex $indexQueue + * @param TemplateQueue $templateQueue + * @return void + */ + public function __inject( + TemplateIndex $templateIndex, + TemplateQueueIndex $indexQueue, + TemplateQueue $templateQueue + ) { + $this->templateIndex = $templateIndex; + $this->indexQueue = $indexQueue; + $this->templateQueue = $templateQueue; + } + + /** + * @param Template $newsletter + * @param string $date + * @return void + */ + public function test(Template $newsletter, $date) + { + // Preconditions + $newsletter->persist(); + + // Steps + $this->templateIndex->open(); + $this->templateIndex->getNewsletterTemplateGrid()->search(['code' => $newsletter->getCode()]); + $this->templateIndex->getNewsletterTemplateGrid()->performAction('Queue Newsletter'); + $this->templateQueue->getEditForm()->setDateStart($date); + $this->templateQueue->getFormPageActions()->save(); + $this->indexQueue->getMessagesBlock()->assertSuccessMessage(); + } +} diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.xml new file mode 100644 index 0000000000000..f9d4f7b26c3bb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.xml @@ -0,0 +1,16 @@ + + + + + + default + Aug 17, 2017 2:50:30 PM + + + + From f746b834d44ea263e175d7d77ea26330d3d5907f Mon Sep 17 00:00:00 2001 From: serhii balko Date: Mon, 21 Aug 2017 11:30:18 +0300 Subject: [PATCH 004/151] MAGETWO-56349: [GITHUB] Newsletter Queue doesn't set to local time #5943 #2937 #7560 --- app/code/Magento/Newsletter/Model/Queue.php | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Newsletter/Model/Queue.php b/app/code/Magento/Newsletter/Model/Queue.php index 2d1360d33e532..e58a4117e2052 100644 --- a/app/code/Magento/Newsletter/Model/Queue.php +++ b/app/code/Magento/Newsletter/Model/Queue.php @@ -109,6 +109,13 @@ class Queue extends \Magento\Framework\Model\AbstractModel implements TemplateTy */ protected $_transportBuilder; + /** + * Timezone library. + * + * @var \Magento\Framework\Stdlib\DateTime\Timezone + */ + private $timezone; + /** * @param \Magento\Framework\Model\Context $context * @param \Magento\Framework\Registry $registry @@ -120,6 +127,7 @@ class Queue extends \Magento\Framework\Model\AbstractModel implements TemplateTy * @param \Magento\Newsletter\Model\Queue\TransportBuilder $transportBuilder * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection + * @param \Magento\Framework\Stdlib\DateTime\Timezone $timezone * @param array $data * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -134,6 +142,7 @@ public function __construct( \Magento\Newsletter\Model\Queue\TransportBuilder $transportBuilder, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, + \Magento\Framework\Stdlib\DateTime\Timezone $timezone = null, array $data = [] ) { parent::__construct( @@ -149,6 +158,9 @@ public function __construct( $this->_problemFactory = $problemFactory; $this->_subscribersCollection = $subscriberCollectionFactory->create(); $this->_transportBuilder = $transportBuilder; + $this->timezone = $timezone ?: \Magento\Framework\App\ObjectManager::getInstance()->get( + \Magento\Framework\Stdlib\DateTime\Timezone::class + ); } /** @@ -183,8 +195,7 @@ public function setQueueStartAtByString($startAt) if ($startAt === null || $startAt == '') { $this->setQueueStartAt(null); } else { - $time = (new \DateTime($startAt))->getTimestamp(); - $this->setQueueStartAt($this->_date->gmtDate(null, $time)); + $this->setQueueStartAt($this->timezone->convertConfigTimeToUtc($startAt)); } return $this; } From a49b71c9a5b0959fb12726d7a2a67678cb7a1a1f Mon Sep 17 00:00:00 2001 From: serhii balko Date: Mon, 21 Aug 2017 11:44:36 +0300 Subject: [PATCH 005/151] MAGETWO-56349: [GITHUB] Newsletter Queue doesn't set to local time #5943 #2937 #7560 --- .../Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php | 2 +- .../Test/Constraint/AssertNewsletterQueueDateStart.php | 5 +++++ .../Newsletter/Test/Page/Adminhtml/TemplateQueueIndex.xml | 1 - .../Newsletter/Test/TestCase/UpdateQueueStartDateTest.php | 4 +--- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php index 682c91aab425d..bf9004f6caa45 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php @@ -36,7 +36,7 @@ class Grid extends \Magento\Backend\Test\Block\Widget\Grid * * @var string */ - protected $action = '.col-actions [class*="control-select"]'; + private $action = '.col-actions [class*="control-select"]'; /** * Action for newsletter queue template. diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php index 10f3fb216bf3a..b80c732f136f2 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php @@ -32,6 +32,11 @@ public function processAssert( string $date ) { $indexQueue->open(); + $indexQueue->getQueueTemplateGrid()->searchAndOpen(['newsletter_subject' => $newsletter->getSubject()]); + $templateQueue->getEditForm()->setDateStart($date); + $templateQueue->getFormPageActions()->save(); + $indexQueue->getMessagesBlock()->assertSuccessMessage(); + $indexQueue->getQueueTemplateGrid()->searchAndOpen(['newsletter_subject' => $newsletter->getSubject()]); \PHPUnit_Framework_Assert::assertEquals( $date, diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueueIndex.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueueIndex.xml index 8504673af09b8..65f7b91d1a9f8 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueueIndex.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Page/Adminhtml/TemplateQueueIndex.xml @@ -8,7 +8,6 @@ - diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php index 64a57a78764bd..e85216539a10e 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php @@ -81,7 +81,7 @@ public function __inject( * @param string $date * @return void */ - public function test(Template $newsletter, $date) + public function test(Template $newsletter) { // Preconditions $newsletter->persist(); @@ -90,8 +90,6 @@ public function test(Template $newsletter, $date) $this->templateIndex->open(); $this->templateIndex->getNewsletterTemplateGrid()->search(['code' => $newsletter->getCode()]); $this->templateIndex->getNewsletterTemplateGrid()->performAction('Queue Newsletter'); - $this->templateQueue->getEditForm()->setDateStart($date); $this->templateQueue->getFormPageActions()->save(); - $this->indexQueue->getMessagesBlock()->assertSuccessMessage(); } } From f6ca40109bf9aae7aa64ad13e1cb01e2c57238e2 Mon Sep 17 00:00:00 2001 From: serhii balko Date: Mon, 21 Aug 2017 12:50:25 +0300 Subject: [PATCH 006/151] MAGETWO-56349: [GITHUB] Newsletter Queue doesn't set to local time #5943 #2937 #7560 --- app/code/Magento/Newsletter/Model/Queue.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Newsletter/Model/Queue.php b/app/code/Magento/Newsletter/Model/Queue.php index e58a4117e2052..100863fae8ddf 100644 --- a/app/code/Magento/Newsletter/Model/Queue.php +++ b/app/code/Magento/Newsletter/Model/Queue.php @@ -111,7 +111,7 @@ class Queue extends \Magento\Framework\Model\AbstractModel implements TemplateTy /** * Timezone library. - * + * * @var \Magento\Framework\Stdlib\DateTime\Timezone */ private $timezone; From 80811fcfeab152106788b9029ed2de18051c9898 Mon Sep 17 00:00:00 2001 From: Nadiya Syvokonenko Date: Mon, 21 Aug 2017 13:35:35 +0300 Subject: [PATCH 007/151] MAGETWO-49796: Catalog top nav, CSS class not set to active when using Varnish --- lib/web/mage/menu.js | 45 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index fdb796addbcf0..01708c092f1ab 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -59,6 +59,8 @@ define([ } this._assignControls()._listen(); + + this._setActiveMenu(); }, /** @@ -108,6 +110,49 @@ define([ } }, + /** + * Sets 'active' CSS class to menu item for active category if it was not set before. + * If menu item has parent categories, sets 'has-active' class to all af them + * + * @private + * + * @return void + */ + _setActiveMenu: function () { + var currentUrl = window.location.href.split('?')[0], + activeCategoryLink = this.element.find('a[href="' + currentUrl + '"]'); + + if (activeCategoryLink && activeCategoryLink.parent().hasClass('active') !== true + && activeCategoryLink.hasClass('ui-corner-all') + ) { + activeCategoryLink.parent().addClass('active'); + var classes = activeCategoryLink.parent().attr('class'), + classStartPosition = classes.indexOf('nav-'), + classNav = classes.substring(classStartPosition, classes.indexOf(' ', classStartPosition)); + + this._setActiveParent(classNav); + } + }, + + /** + * Sets 'has-active' CSS class to all parent categories in menu has active category + * + * @private + * + * @param {String} childClassName - Class name of active category
  • element + * @return void + */ + _setActiveParent: function (childClassName) { + var parentClass = childClassName.substr(0, childClassName.lastIndexOf('-')); + if (parentClass.lastIndexOf('-') !== -1) { + var parent = this.element.find('.' + parentClass); + if (parent) { + parent.addClass('has-active'); + } + this._setActiveParent(parentClass); + } + }, + /** * Add class for expanded option. */ From 4d9be10cefe65bd3181dc182b3fbffc88e513c7c Mon Sep 17 00:00:00 2001 From: Nadiya Syvokonenko Date: Mon, 21 Aug 2017 18:29:50 +0300 Subject: [PATCH 008/151] MAGETWO-49796: Catalog top nav, CSS class not set to active when using Varnish - cover case for product view page --- lib/web/mage/menu.js | 98 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 77 insertions(+), 21 deletions(-) diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index 01708c092f1ab..b9fefb8f706f1 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -59,7 +59,6 @@ define([ } this._assignControls()._listen(); - this._setActiveMenu(); }, @@ -111,48 +110,105 @@ define([ }, /** - * Sets 'active' CSS class to menu item for active category if it was not set before. - * If menu item has parent categories, sets 'has-active' class to all af them + * Tries to figure out the active category for current page and add appropriate classes: + * - 'active' class for active category + * - 'has-active' class for all parents of active category * - * @private + * First, checks whether current URL is URL of category page, + * otherwise tries to retrieve category URL in case of current URL is product view page URL + * which has category tree path in it. * * @return void + * @private */ _setActiveMenu: function () { - var currentUrl = window.location.href.split('?')[0], - activeCategoryLink = this.element.find('a[href="' + currentUrl + '"]'); - - if (activeCategoryLink && activeCategoryLink.parent().hasClass('active') !== true - && activeCategoryLink.hasClass('ui-corner-all') - ) { - activeCategoryLink.parent().addClass('active'); - var classes = activeCategoryLink.parent().attr('class'), - classStartPosition = classes.indexOf('nav-'), - classNav = classes.substring(classStartPosition, classes.indexOf(' ', classStartPosition)); - - this._setActiveParent(classNav); + var currentUrl = window.location.href.split('?')[0]; + + if (!this._setActiveMenuForCategory(currentUrl)) { + this._setActiveMenuForProduct(currentUrl); } }, /** - * Sets 'has-active' CSS class to all parent categories in menu has active category + * Looks for category with provided URL and adds 'active' CSS class to it if it was not set before. + * If menu item has parent categories, sets 'has-active' class to all af them. * + * @param {String} url - possible category URL + * @returns {boolean} - true if active category was founded by provided URL, otherwise return false * @private + */ + _setActiveMenuForCategory: function (url) { + var activeCategoryLink = this.element.find('a[href="' + url + '"]'), + classes, + classNav; + + if (activeCategoryLink && activeCategoryLink.hasClass('ui-corner-all')) { + + if (!activeCategoryLink.parent().hasClass('active')) { + activeCategoryLink.parent().addClass('active'); + classes = activeCategoryLink.parent().attr('class'); + classNav = classes.match(/(nav\-)[0-9]+(\-[0-9]+)+/gi); + + if (classNav) { + this._setActiveParent(classNav[0]); + } + } + return true; + } + return false; + }, + + /** + * Sets 'has-active' CSS class to all parent categories which have part of provided class in childClassName + * + * @example: + * childClassName - 'nav-1-2-3' + * CSS class 'has-active' will be added to categories have 'nav-1-2' and 'nav-1' classes * * @param {String} childClassName - Class name of active category
  • element * @return void + * @private */ _setActiveParent: function (childClassName) { - var parentClass = childClassName.substr(0, childClassName.lastIndexOf('-')); + var parentElement, + parentClass = childClassName.substr(0, childClassName.lastIndexOf('-')); + if (parentClass.lastIndexOf('-') !== -1) { - var parent = this.element.find('.' + parentClass); - if (parent) { - parent.addClass('has-active'); + parentElement = this.element.find('.' + parentClass); + + if (parentElement) { + parentElement.addClass('has-active'); } this._setActiveParent(parentClass); } }, + /** + * Tries to retrieve category URL from current URL and mark this category as active + * @see _setActiveMenuForCategory(url) + * + * @example: + * currentUrl - http://magento.com/category1/category12/product.html, + * category URLs has extensions .phtml - http://magento.com/category1.phtml + * method sets active category which has URL http://magento.com/category1/category12.phtml + * + * @param {String} currentUrl - current page URL without parameters + * @return void + * @private + */ + _setActiveMenuForProduct: function (currentUrl) { + var categoryUrlExtension, + possibleCategoryUrl, + //retrieve first category URL to know what extension is used for category URLs + firstCategoryUrl = this.element.find('> li a').attr('href'); + + if (firstCategoryUrl) { + categoryUrlExtension = firstCategoryUrl.substr(firstCategoryUrl.lastIndexOf('.')); + possibleCategoryUrl = currentUrl.substr(0, currentUrl.lastIndexOf('/')) + categoryUrlExtension; + this._setActiveMenuForCategory(possibleCategoryUrl); + } + }, + /** * Add class for expanded option. */ From d10e52f14c729aa4d9276bcf0aa408acfbd7b4b7 Mon Sep 17 00:00:00 2001 From: Daniel Renaud Date: Fri, 18 Aug 2017 17:44:54 -0500 Subject: [PATCH 009/151] MAGETWO-71024: [Tech Debt] Skipped unit/integration tests needs to be re-examined. - Fix unit tests in framework - Fix failing code style checks --- .../Model/Import/Product/Type/VirtualTest.php | 5 ++++- .../Observer/ProcessCronQueueObserverTest.php | 11 +++------- .../Test/Unit/Model/ImportTest.php | 1 - .../Order/Invoice/Total/ShippingTest.php | 5 ++++- .../Sitemap/Test/Unit/Model/SitemapTest.php | 18 ++++++++-------- .../Test/Unit/ObjectManagerFactoryTest.php | 1 - .../Data/Test/Unit/Collection/DbTest.php | 13 ++---------- .../Unit/Element/Text/TextList/ItemTest.php | 18 +++++----------- .../Unit/Element/Text/TextList/LinkTest.php | 21 +++++-------------- 9 files changed, 32 insertions(+), 61 deletions(-) diff --git a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php index cfc625271acda..7f5a856dde758 100644 --- a/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php +++ b/app/code/Magento/CatalogImportExport/Test/Unit/Model/Import/Product/Type/VirtualTest.php @@ -13,7 +13,10 @@ class VirtualTest extends \PHPUnit\Framework\TestCase */ public function testPrepareAttributesWithDefaultValueForSave() { - $virtualModelMock = $this->createPartialMock(\Magento\CatalogImportExport\Model\Import\Product\Type\Virtual::class, []); + $virtualModelMock = $this->createPartialMock( + \Magento\CatalogImportExport\Model\Import\Product\Type\Virtual::class, + [] + ); $this->setPropertyValue( $virtualModelMock, diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php index cca5611056d7b..0a7178ad7d126 100644 --- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php +++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php @@ -88,11 +88,6 @@ class ProcessCronQueueObserverTest extends \PHPUnit\Framework\TestCase */ protected $scheduleResource; - /** - * @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject - */ - protected $connection; - /** * Prepare parameters */ @@ -151,12 +146,12 @@ protected function setUp() $this->scheduleResource = $this->getMockBuilder(\Magento\Cron\Model\ResourceModel\Schedule::class) ->disableOriginalConstructor() ->getMock(); - $this->connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) ->disableOriginalConstructor() ->getMock(); - $this->scheduleResource->method('getConnection')->willReturn($this->connection); - $this->connection->method('delete')->willReturn(1); + $this->scheduleResource->method('getConnection')->willReturn($connection); + $connection->method('delete')->willReturn(1); $this->_observer = new ProcessCronQueueObserver( $this->_objectManager, diff --git a/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php b/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php index ed0eed4e4414b..823ec29d41760 100644 --- a/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php +++ b/app/code/Magento/ImportExport/Test/Unit/Model/ImportTest.php @@ -429,7 +429,6 @@ public function testUploadSource() */ public function testValidateSource() { - $this->markTestSkipped('Test needs to be refacotred,'); $validationStrategy = ProcessingErrorAggregatorInterface::VALIDATION_STRATEGY_STOP_ON_ERROR; $allowedErrorCount = 1; diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Total/ShippingTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Total/ShippingTest.php index 309bd4d99dc1f..8c8b459a6306c 100644 --- a/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Total/ShippingTest.php +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Invoice/Total/ShippingTest.php @@ -134,7 +134,10 @@ private function getInvoiceCollection(array $invoicesData) $arguments['data'] = $oneInvoiceData; $arguments = $objectManagerHelper->getConstructArguments($className, $arguments); /** @var $prevInvoice \Magento\Sales\Model\Order\Invoice */ - $prevInvoice = $this->getMockBuilder($className)->setMethods(['_init'])->setConstructorArgs($arguments)->getMock(); + $prevInvoice = $this->getMockBuilder($className) + ->setMethods(['_init']) + ->setConstructorArgs($arguments) + ->getMock(); $result->addItem($prevInvoice); } return $result; diff --git a/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php b/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php index bf73578085476..40b72cbd53c00 100644 --- a/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php +++ b/app/code/Magento/Sitemap/Test/Unit/Model/SitemapTest.php @@ -227,9 +227,9 @@ public static function sitemapDataProvider() ]; return [ - [50000, 10485760, $expectedSingleFile, 1], - [1, 10485760, $expectedMultiFile, 5], - [50000, 264, $expectedMultiFile, 5] + [50000, 10485760, $expectedSingleFile, 6], + [1, 10485760, $expectedMultiFile, 18], + [50000, 264, $expectedMultiFile, 18] ]; } @@ -289,7 +289,7 @@ public static function robotsDataProvider() 50000, 10485760, $expectedSingleFile, - 2, + 6, [ 'robotsStart' => '', 'robotsFinish' => 'Sitemap: http://store.com/sitemap.xml', @@ -300,7 +300,7 @@ public static function robotsDataProvider() 50000, 10485760, $expectedSingleFile, - 2, + 6, [ 'robotsStart' => "User-agent: *", 'robotsFinish' => "User-agent: *" . PHP_EOL . 'Sitemap: http://store.com/sitemap.xml', @@ -311,7 +311,7 @@ public static function robotsDataProvider() 1, 10485760, $expectedMultiFile, - 6, + 18, [ 'robotsStart' => "User-agent: *\r\n", 'robotsFinish' => "User-agent: *\r\n\r\nSitemap: http://store.com/sitemap.xml", @@ -322,7 +322,7 @@ public static function robotsDataProvider() 50000, 264, $expectedMultiFile, - 6, + 18, [ 'robotsStart' => "User-agent: *\n", 'robotsFinish' => "User-agent: *\n\nSitemap: http://store.com/sitemap.xml", @@ -333,7 +333,7 @@ public static function robotsDataProvider() 50000, 10485760, $expectedSingleFile, - 1, + 6, ['robotsStart' => '', 'robotsFinish' => '', 'pushToRobots' => 0] ] // empty robots file ]; @@ -395,7 +395,7 @@ protected function _prepareSitemapModelMock( // Check that all expected lines were written $this->_fileMock->expects( - $this->any() + $this->exactly($expectedWrites) )->method( 'write' )->will( diff --git a/lib/internal/Magento/Framework/App/Test/Unit/ObjectManagerFactoryTest.php b/lib/internal/Magento/Framework/App/Test/Unit/ObjectManagerFactoryTest.php index 065993db51686..cceb31d01a99e 100644 --- a/lib/internal/Magento/Framework/App/Test/Unit/ObjectManagerFactoryTest.php +++ b/lib/internal/Magento/Framework/App/Test/Unit/ObjectManagerFactoryTest.php @@ -45,7 +45,6 @@ public static function tearDownAfterClass() */ public function testCreateObjectManagerFactoryCouldBeOverridden() { - $this->markTestSkipped('Test needs to be refactored.'); $rootPath = __DIR__ . '/_files/'; $factory = Bootstrap::createObjectManagerFactory($rootPath, []); $factory->create([], false); diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Collection/DbTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/Collection/DbTest.php index aefe1e4fc45da..5eea3f8790711 100644 --- a/lib/internal/Magento/Framework/Data/Test/Unit/Collection/DbTest.php +++ b/lib/internal/Magento/Framework/Data/Test/Unit/Collection/DbTest.php @@ -58,9 +58,6 @@ protected function tearDown() unset($this->collection); } - /** - * @return \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\DB\Adapter\Pdo\Mysql - */ public function testSetAddOrder() { $adapter = $this->createPartialMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, ['fetchAll', 'select']); @@ -87,17 +84,11 @@ public function testSetAddOrder() $this->assertEquals('some_field ASC', (string)array_shift($selectOrders)); $this->assertEquals('other_field DESC', (string)array_shift($selectOrders)); $this->assertEmpty(array_shift($selectOrders)); - - return $adapter; } - /** - * @param \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\DB\Adapter\Pdo\Mysql $adapter - * @depends testSetAddOrder - */ - public function testUnshiftOrder($adapter) + public function testUnshiftOrder() { - $this->markTestSkipped('Test needs to be refacotred.'); + $adapter = $this->createPartialMock(\Magento\Framework\DB\Adapter\Pdo\Mysql::class, ['fetchAll', 'select']); $renderer = $this->getSelectRenderer($this->objectManager); $select = new \Magento\Framework\DB\Select($adapter, $renderer); $adapter diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Text/TextList/ItemTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Text/TextList/ItemTest.php index 6c0a83cbb2718..b2b1db44d6a0b 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Text/TextList/ItemTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Text/TextList/ItemTest.php @@ -42,19 +42,13 @@ public function testSetLink() * @dataProvider toHtmlDataProvider * * @param array $liParams - * @param string $attrName - * @param string $attrValue * @param string $innerText */ - public function testToHtml($liParams, $attrName, $attrValue, $innerText) + public function testToHtml($liParams, $innerText, $expectedHtml) { - $this->markTestSkipped('Test needs to be refactored.'); $this->item->setLink($liParams, $innerText); - $this->assertTag([ - 'tag' => 'li', - 'attributes' => [$attrName => $attrValue], - 'content' => $innerText, - ], $this->item->toHtml()); + + $this->assertEquals($expectedHtml, $this->item->toHtml()); } public function toHtmlDataProvider() @@ -62,15 +56,13 @@ public function toHtmlDataProvider() return [ [ 'liParams' => ['class' => 'some-css-class'], - 'attrName' => 'class', - 'attrValue' => 'some-css-class', 'innerText' => 'text', + 'expectedHtml' => '
  • text
  • ' . "\r\n" ], [ 'liParams' => 'class="some-css-class"', - 'attrName' => 'class', - 'attrValue' => 'some-css-class', 'innerText' => 'text', + 'expectedHtml' => '
  • text
  • ' . "\r\n" ] ]; } diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/Text/TextList/LinkTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/Text/TextList/LinkTest.php index 80b5024cba5e1..785c41c1d6e2f 100644 --- a/lib/internal/Magento/Framework/View/Test/Unit/Element/Text/TextList/LinkTest.php +++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/Text/TextList/LinkTest.php @@ -47,20 +47,11 @@ public function testSetLink() /** * @dataProvider toHtmlDataProvider */ - public function testToHtml($liParams, $liAttr, $aParams, $aAttr, $innerText, $afterText) + public function testToHtml($liParams, $aParams, $innerText, $afterText, $expectedHtml) { - $this->markTestSkipped('Test needs to be refactored.'); $this->link->setLink($liParams, $aParams, $innerText, $afterText); - $this->assertTag([ - 'tag' => 'li', - 'attributes' => [$liAttr['name'] => $liAttr['value']], - 'child' => [ - 'tag' => 'a', - 'attributes' => [$aAttr['name'] => $aAttr['value']], - 'content' => $innerText, - ], - 'content' => $afterText, - ], $this->link->toHtml()); + + $this->assertEquals($expectedHtml, $this->link->toHtml()); } public function toHtmlDataProvider() @@ -68,19 +59,17 @@ public function toHtmlDataProvider() return [ [ 'liParams' => ['class' => 'some-css-class'], - 'liAttr' => ['name' => 'class', 'value' => 'some-css-class'], 'aParams' => ['href' => 'url'], - 'aAttr' => ['name' => 'href', 'value' => 'url'], 'innerText' => 'text', 'afterText' => 'afterText', + 'expectedHtml' => '
  • textafterText
  • ' . "\r\n" ], [ 'liParams' => 'class="some-css-class"', - 'liAttr' => ['name' => 'class', 'value' => 'some-css-class'], 'aParams' => 'href="url"', - 'aAttr' => ['name' => 'href', 'value' => 'url'], 'innerText' => 'text', 'afterText' => 'afterText', + 'expectedHtml' => '
  • textafterText
  • ' . "\r\n" ] ]; } From 384fe05d21c43b10197ad9122d8a659cefd60dfb Mon Sep 17 00:00:00 2001 From: Robert He Date: Mon, 21 Aug 2017 14:50:31 -0500 Subject: [PATCH 010/151] MAGETWO-71666: Unable to save product after failed attempt - add better check for the configurable-matrix-serialized variable --- .../Helper/Plugin/Configurable.php | 14 +++++------ .../Helper/Plugin/UpdateConfigurations.php | 24 +++++++++---------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php index 0341811caec02..d4d68b570a21f 100644 --- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php @@ -154,16 +154,16 @@ protected function getVariationMatrix() { $result = []; $configurableMatrix = $this->request->getParam('configurable-matrix-serialized', '[]'); - if ($configurableMatrix != null && !empty($configurableMatrix)) { + if (isset($configurableMatrix) && $configurableMatrix != "") { $configurableMatrix = json_decode($configurableMatrix, true); - } - foreach ($configurableMatrix as $item) { - if ($item['newProduct']) { - $result[$item['variationKey']] = $this->mapData($item); + foreach ($configurableMatrix as $item) { + if ($item['newProduct']) { + $result[$item['variationKey']] = $this->mapData($item); - if (isset($item['qty'])) { - $result[$item['variationKey']]['quantity_and_stock_status']['qty'] = $item['qty']; + if (isset($item['qty'])) { + $result[$item['variationKey']]['quantity_and_stock_status']['qty'] = $item['qty']; + } } } } diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php index aa9470867fd28..44b36859837de 100644 --- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php +++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php @@ -94,22 +94,22 @@ protected function getConfigurations() { $result = []; $configurableMatrix = $this->request->getParam('configurable-matrix-serialized', '[]'); - if ($configurableMatrix != null && !empty($configurableMatrix)) { + if (isset($configurableMatrix) && $configurableMatrix != "") { $configurableMatrix = json_decode($configurableMatrix, true); - } - foreach ($configurableMatrix as $item) { - if (empty($item['was_changed'])) { - continue; - } else { - unset($item['was_changed']); - } + foreach ($configurableMatrix as $item) { + if (empty($item['was_changed'])) { + continue; + } else { + unset($item['was_changed']); + } - if (!$item['newProduct']) { - $result[$item['id']] = $this->mapData($item); + if (!$item['newProduct']) { + $result[$item['id']] = $this->mapData($item); - if (isset($item['qty'])) { - $result[$item['id']]['quantity_and_stock_status']['qty'] = $item['qty']; + if (isset($item['qty'])) { + $result[$item['id']]['quantity_and_stock_status']['qty'] = $item['qty']; + } } } } From 6190aa72236e1eaaca2d0ca6582329def9e53ba7 Mon Sep 17 00:00:00 2001 From: Joan He Date: Mon, 21 Aug 2017 23:04:17 -0500 Subject: [PATCH 011/151] MAGETWO-70837: Pricing discrepancy in shopping cart --- .../Backend/GroupPrice/AbstractGroupPrice.php | 2 +- .../Product/Attribute/Backend/Tierprice.php | 2 +- .../Magento/Checkout/CustomerData/Cart.php | 4 +- .../Test/Unit/CustomerData/CartTest.php | 6 +- .../view/frontend/web/js/model/cart/cache.js | 12 +++ .../js/model/cart/totals-processor/default.js | 4 +- .../view/frontend/web/js/model/totals.js | 14 ++- .../Model/Product/Plugin/UpdateQuoteItems.php | 3 +- app/code/Magento/Quote/Model/Quote.php | 3 +- .../Product/Plugin/UpdateQuoteItemsTest.php | 9 +- .../Attribute/Backend/TierpriceTest.php | 97 +++++++++++-------- 11 files changed, 100 insertions(+), 56 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php index 0bd090b823266..f7ab3f5a8b665 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/GroupPrice/AbstractGroupPrice.php @@ -479,7 +479,7 @@ public function afterSave($object) } if (!empty($update)) { - $isChanged = $this->updateValues($update, $old); + $isChanged |= $this->updateValues($update, $old); } if ($isChanged) { diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php index afc688e39b942..92b9a2e4239b2 100644 --- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php +++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php @@ -180,7 +180,7 @@ protected function updateValues(array $valuesToUpdate, array $oldValues) { $isChanged = false; foreach ($valuesToUpdate as $key => $value) { - if ($oldValues[$key]['price'] != $value['value'] + if ((!empty($value['value']) && $oldValues[$key]['price'] != $value['value']) || $this->getPercentage($oldValues[$key]) != $this->getPercentage($value) ) { $price = new \Magento\Framework\DataObject( diff --git a/app/code/Magento/Checkout/CustomerData/Cart.php b/app/code/Magento/Checkout/CustomerData/Cart.php index 96ea0e366a276..ddb077462ef10 100644 --- a/app/code/Magento/Checkout/CustomerData/Cart.php +++ b/app/code/Magento/Checkout/CustomerData/Cart.php @@ -87,10 +87,12 @@ public function __construct( public function getSectionData() { $totals = $this->getQuote()->getTotals(); + $subtotalAmount = $totals['subtotal']->getValue(); return [ 'summary_count' => $this->getSummaryCount(), + 'subtotalAmount' => $subtotalAmount, 'subtotal' => isset($totals['subtotal']) - ? $this->checkoutHelper->formatPrice($totals['subtotal']->getValue()) + ? $this->checkoutHelper->formatPrice($subtotalAmount) : 0, 'possible_onepage_checkout' => $this->isPossibleOnepageCheckout(), 'items' => $this->getRecentItems(), diff --git a/app/code/Magento/Checkout/Test/Unit/CustomerData/CartTest.php b/app/code/Magento/Checkout/Test/Unit/CustomerData/CartTest.php index 80c5838b2b78b..75e181cbabd08 100644 --- a/app/code/Magento/Checkout/Test/Unit/CustomerData/CartTest.php +++ b/app/code/Magento/Checkout/Test/Unit/CustomerData/CartTest.php @@ -160,7 +160,8 @@ public function testGetSectionData() ], 'extra_actions' => 'Buttons', 'isGuestCheckoutAllowed' => 1, - 'website_id' => $websiteId + 'website_id' => $websiteId, + 'subtotalAmount' => 200, ]; $this->assertEquals($expectedResult, $this->model->getSectionData()); } @@ -262,7 +263,8 @@ public function testGetSectionDataWithCompositeProduct() ], 'extra_actions' => 'Buttons', 'isGuestCheckoutAllowed' => 1, - 'website_id' => $websiteId + 'website_id' => $websiteId, + 'subtotalAmount' => 200, ]; $this->assertEquals($expectedResult, $this->model->getSectionData()); } diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/cache.js b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/cache.js index a7c3089b26790..9b13a579447ed 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/cache.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/cache.js @@ -188,6 +188,18 @@ define([ _isAddressChanged: function (address) { return JSON.stringify(_.pick(this.get('address'), this.requiredFields)) !== JSON.stringify(_.pick(address, this.requiredFields)); + }, + + /** + * Compare cached subtotal with provided. + * Custom method for check object equality. + * + * @param {float} subtotal + * @returns {Boolean} + */ + _isSubtotalChanged: function (subtotal) { + var cached = this.get('totals').subtotal; + return subtotal != cached; } }; }); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js index 55be66f8b0a08..f96924398e520 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js @@ -87,11 +87,13 @@ define([ data.shippingCarrierCode = quote.shippingMethod()['carrier_code']; } + var quoteSubtotal = quote.totals().subtotal; if (!cartCache.isChanged('cartVersion', customerData.get('cart')()['data_id']) && !cartCache.isChanged('shippingMethodCode', data.shippingMethodCode) && !cartCache.isChanged('shippingCarrierCode', data.shippingCarrierCode) && !cartCache.isChanged('address', address) && - cartCache.get('totals') + cartCache.get('totals') && + !cartCache.isChanged('subtotal', quoteSubtotal) ) { quote.setTotals(cartCache.get('totals')); } else { diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js b/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js index 5bf40df24f0d9..01d0786d81038 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js @@ -8,16 +8,24 @@ */ define([ 'ko', - 'Magento_Checkout/js/model/quote' -], function (ko, quote) { + 'Magento_Checkout/js/model/quote', + 'Magento_Customer/js/customer-data' +], function (ko, quote, customerData) { 'use strict'; - var quoteItems = ko.observable(quote.totals().items); + var quoteItems = ko.observable(quote.totals().items), + cartData = customerData.get('cart'); quote.totals.subscribe(function (newValue) { quoteItems(newValue.items); }); + var quoteSubtotal = quote.totals().subtotal, + subtotalAmount = cartData()['subtotalAmount']; + if (quoteSubtotal != subtotalAmount) { + customerData.reload(['cart'], false); + } + return { totals: quote.totals, isLoading: ko.observable(false), diff --git a/app/code/Magento/Quote/Model/Product/Plugin/UpdateQuoteItems.php b/app/code/Magento/Quote/Model/Product/Plugin/UpdateQuoteItems.php index c8dcc5e6ccbc3..310af49773f04 100644 --- a/app/code/Magento/Quote/Model/Product/Plugin/UpdateQuoteItems.php +++ b/app/code/Magento/Quote/Model/Product/Plugin/UpdateQuoteItems.php @@ -34,7 +34,8 @@ public function afterSave( \Magento\Framework\Model\AbstractModel $product ) { $originalPrice = $product->getOrigData('price'); - if (!empty($originalPrice) && ($originalPrice != $product->getPrice())) { + $tierPriceChanged = $product->getData('tier_price_changed'); + if ((!empty($originalPrice) && ($originalPrice != $product->getPrice())) || $tierPriceChanged) { $this->resource->markQuotesRecollect($product->getId()); } return $result; diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index 0cc6ece969f74..ae7701ede9da3 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -2374,7 +2374,8 @@ public function merge(Quote $quote) protected function _afterLoad() { // collect totals and save me, if required - if (1 == $this->getData('trigger_recollect')) { + if (1 == $this->getTriggerRecollect()) { + $this->setTriggerRecollect(0); $this->collectTotals()->save(); } return parent::_afterLoad(); diff --git a/app/code/Magento/Quote/Test/Unit/Model/Product/Plugin/UpdateQuoteItemsTest.php b/app/code/Magento/Quote/Test/Unit/Model/Product/Plugin/UpdateQuoteItemsTest.php index 15b767e0d2f43..38f303dd23582 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/Product/Plugin/UpdateQuoteItemsTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/Product/Plugin/UpdateQuoteItemsTest.php @@ -30,18 +30,20 @@ protected function setUp() * @param int $originalPrice * @param int $newPrice * @param bool $callMethod + * @param bool $tierPriceChanged */ - public function testAfterUpdate($originalPrice, $newPrice, $callMethod) + public function testAfterUpdate($originalPrice, $newPrice, $callMethod, $tierPriceChanged = false) { $productResourceMock = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class); $productMock = $this->getMockBuilder(\Magento\Framework\Model\AbstractModel::class) ->disableOriginalConstructor() - ->setMethods(['getOrigData', 'getPrice', 'getId']) + ->setMethods(['getOrigData', 'getPrice', 'getId', 'getData']) ->getMockForAbstractClass(); $productId = 1; $productMock->expects($this->any())->method('getOrigData')->with('price')->willReturn($originalPrice); $productMock->expects($this->any())->method('getPrice')->willReturn($newPrice); $productMock->expects($this->any())->method('getId')->willReturn($productId); + $productMock->expects($this->any())->method('getData')->willReturn($tierPriceChanged); $this->quoteResource->expects($this->$callMethod())->method('markQuotesRecollect')->with($productId); $result = $this->model->afterSave($productResourceMock, $productResourceMock, $productMock); $this->assertEquals($result, $productResourceMock); @@ -52,7 +54,8 @@ public function aroundUpdateDataProvider() return [ [10, 20, 'once'], [null, 10, 'never'], - [10, 10, 'never'] + [10, 10, 'never'], + [10, 10, 'once', true], ]; } } diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php index 8205ac29527be..1a0439fccacbf 100644 --- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php +++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php @@ -142,8 +142,12 @@ public function testAfterLoad() /** * @magentoAppArea adminhtml + * @param array $tierPrice + * @param bool $isChanged + * @param int $tierPriceCtr + * @dataProvider afterSaveDataProvider */ - public function testAfterSave() + public function testAfterSave($tierPrice, $isChanged, $tierPriceCtr) { /** @var $product \Magento\Catalog\Model\Product */ $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( @@ -151,17 +155,11 @@ public function testAfterSave() ); $product->load($this->productRepository->get('simple')->getId()); $product->unlockAttributes(); - $product->setOrigData(); - $product->setTierPrice( - [ - ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 2, 'price' => 7, 'delete' => true], - ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 5, 'price' => 4], - ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 10, 'price' => 3], - ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 20, 'price' => 2], - ] - ); + // Added tier price + $product->setTierPrice($tierPrice); $this->_model->afterSave($product); + $this->assertEquals($isChanged, $product->getData('tier_price_changed')); $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( \Magento\Catalog\Model\Product::class @@ -171,40 +169,55 @@ public function testAfterSave() $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); $product->setData($linkField, $fixtureProduct->getData($linkField)); $this->_model->afterLoad($product); - $this->assertEquals(3, count($product->getTierPrice())); + $this->assertEquals($tierPriceCtr, count($product->getTierPrice())); + $this->assertEquals(0, $product->getData('tier_price_changed')); } - /** - * @depends testAfterSave - */ - public function testAfterSaveEmpty() + public function afterSaveDataProvider() { - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Store\Model\StoreManagerInterface::class - )->setCurrentStore( - \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Store\Model\StoreManagerInterface::class - )->getStore( - \Magento\Store\Model\Store::DEFAULT_STORE_ID - ) - ); - /** @var $product \Magento\Catalog\Model\Product */ - $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\Product::class - ); - $product->load($this->productRepository->get('simple')->getId()); - $product->setOrigData(); - $product->setTierPrice([]); - $this->_model->afterSave($product); - - $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create( - \Magento\Catalog\Model\Product::class - ); - $fixtureProduct = $this->productRepository->get('simple'); - $product->setId($fixtureProduct->getId()); - $linkField = $this->metadataPool->getMetadata(ProductInterface::class)->getLinkField(); - $product->setData($linkField, $fixtureProduct->getData($linkField)); - $this->_model->afterLoad($product); - $this->assertEmpty($product->getTierPrice()); + return [ + 'same' => [ + [ + ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 2, 'price' => 8], + ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 5, 'price' => 5], + ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 3, 'price' => 5], + ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 10, 'percentage_value' => 50], + ], + 0, + 4, + ], + 'update one' => [ + [ + ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 2, 'price' => 8], + ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 5, 'price' => 5], + ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 3, 'price' => 5], + ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 10, 'percentage_value' => 10], + ], + 1, + 4, + ], + 'delete one' => [ + [ + ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 2, 'price' => 8, 'delete' => true], + ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 5, 'price' => 5], + ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 3, 'price' => 5], + ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 10, 'percentage_value' => 50], + ], + 1, + 3, + ], + 'add one' => [ + [ + ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 2, 'price' => 8], + ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 5, 'price' => 5], + ['website_id' => 0, 'cust_group' => 32000, 'price_qty' => 20, 'percentage_value' => 90], + ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 3, 'price' => 5], + ['website_id' => 0, 'cust_group' => 0, 'price_qty' => 10, 'percentage_value' => 50], + ], + 1, + 5, + ], + 'delete all' => [[], 1, 0,], + ]; } } From 29eb4762ffef2a5f8c40177f0b4ec4225bad7fa5 Mon Sep 17 00:00:00 2001 From: serhii balko Date: Tue, 22 Aug 2017 11:32:25 +0300 Subject: [PATCH 012/151] MAGETWO-56349: [GITHUB] Newsletter Queue doesn't set to local time #5943 #2937 #7560 --- app/code/Magento/Newsletter/Model/Queue.php | 11 ++-- .../Block/Adminhtml/Queue/Edit/QueueForm.php | 28 ---------- .../Block/Adminhtml/Queue/Edit/QueueForm.xml | 29 ++++++++++ .../AssertNewsletterQueueDateStart.php | 55 ------------------- .../Constraint/AssertNewsletterQueueSave.php | 47 ++++++++++++++++ .../Magento/Newsletter/Test/Fixture/Queue.xml | 30 ++++++++++ .../Newsletter/Test/Repository/Queue.xml | 18 ++++++ ...eStartDateTest.php => UpdateQueueTest.php} | 26 +++------ ...eStartDateTest.xml => UpdateQueueTest.xml} | 6 +- 9 files changed, 142 insertions(+), 108 deletions(-) create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.xml delete mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSave.php create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue.xml create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Queue.xml rename dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/{UpdateQueueStartDateTest.php => UpdateQueueTest.php} (78%) rename dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/{UpdateQueueStartDateTest.xml => UpdateQueueTest.xml} (76%) diff --git a/app/code/Magento/Newsletter/Model/Queue.php b/app/code/Magento/Newsletter/Model/Queue.php index 100863fae8ddf..efb68fd4243d1 100644 --- a/app/code/Magento/Newsletter/Model/Queue.php +++ b/app/code/Magento/Newsletter/Model/Queue.php @@ -6,6 +6,7 @@ namespace Magento\Newsletter\Model; use Magento\Framework\App\TemplateTypesInterface; +use Magento\Framework\Stdlib\DateTime\TimezoneInterface; /** * Newsletter queue model. @@ -112,7 +113,7 @@ class Queue extends \Magento\Framework\Model\AbstractModel implements TemplateTy /** * Timezone library. * - * @var \Magento\Framework\Stdlib\DateTime\Timezone + * @var TimezoneInterface */ private $timezone; @@ -127,8 +128,8 @@ class Queue extends \Magento\Framework\Model\AbstractModel implements TemplateTy * @param \Magento\Newsletter\Model\Queue\TransportBuilder $transportBuilder * @param \Magento\Framework\Model\ResourceModel\AbstractResource $resource * @param \Magento\Framework\Data\Collection\AbstractDb $resourceCollection - * @param \Magento\Framework\Stdlib\DateTime\Timezone $timezone * @param array $data + * @param TimezoneInterface $timezone * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -142,8 +143,8 @@ public function __construct( \Magento\Newsletter\Model\Queue\TransportBuilder $transportBuilder, \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null, \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null, - \Magento\Framework\Stdlib\DateTime\Timezone $timezone = null, - array $data = [] + array $data = [], + TimezoneInterface $timezone = null ) { parent::__construct( $context, @@ -159,7 +160,7 @@ public function __construct( $this->_subscribersCollection = $subscriberCollectionFactory->create(); $this->_transportBuilder = $transportBuilder; $this->timezone = $timezone ?: \Magento\Framework\App\ObjectManager::getInstance()->get( - \Magento\Framework\Stdlib\DateTime\Timezone::class + TimezoneInterface::class ); } diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php index 40ce9c5085e1b..8de406c896591 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.php @@ -13,13 +13,6 @@ */ class QueueForm extends \Magento\Mtf\Block\Form { - /** - * "Queue Date Start" field selector. - * - * @var string - */ - private $dateStartSelector = 'input[name=start_at]'; - /** * Get data of specified form data. * @@ -32,25 +25,4 @@ protected function _getData(array $fields, SimpleElement $element = null) unset($fields['code']); return parent::_getData($fields, $element); } - - /** - * Get Queue Date Start value. - * - * @return string - */ - public function getDateStart() - { - return $this->_rootElement->find($this->dateStartSelector)->getValue(); - } - - /** - * Set Queue Date Start value. - * - * @param string $val - * @return void - */ - public function setDateStart($val) - { - $this->_rootElement->find($this->dateStartSelector)->setValue($val); - } } diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.xml new file mode 100644 index 0000000000000..f18c53cb112e2 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.xml @@ -0,0 +1,29 @@ + + + + + + input[name='start_at'] + + + input[name='subject'] + + + input[name='sender_name'] + + + input[name='sender_email'] + + + textarea[name='text'] + + + textarea[name='styles'] + + + \ No newline at end of file diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php deleted file mode 100644 index b80c732f136f2..0000000000000 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueDateStart.php +++ /dev/null @@ -1,55 +0,0 @@ -open(); - $indexQueue->getQueueTemplateGrid()->searchAndOpen(['newsletter_subject' => $newsletter->getSubject()]); - $templateQueue->getEditForm()->setDateStart($date); - $templateQueue->getFormPageActions()->save(); - $indexQueue->getMessagesBlock()->assertSuccessMessage(); - - $indexQueue->getQueueTemplateGrid()->searchAndOpen(['newsletter_subject' => $newsletter->getSubject()]); - \PHPUnit_Framework_Assert::assertEquals( - $date, - $templateQueue->getEditForm()->getDateStart(), - 'Field "Queue Date Start" did\'t save correctly' - ); - } - - /** - * {@inheritdoc} - */ - public function toString() - { - return 'Field "Queue Date Start" saved correctly'; - } -} diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSave.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSave.php new file mode 100644 index 0000000000000..ccc273d0f4ebf --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSave.php @@ -0,0 +1,47 @@ +getMessagesBlock()->assertSuccessMessage(); + $indexQueue->getQueueTemplateGrid()->searchAndOpen(['newsletter_subject' => $queue->getNewsletterSubject()]); + + $dataDiff = $this->verifyData($queue->getData(), $templateQueue->getEditForm()->getData($queue)); + \PHPUnit_Framework_Assert::assertEmpty($dataDiff, $dataDiff); + } + + /** + * {@inheritdoc} + */ + public function toString() + { + return '"Newsletter Queue" saved correctly'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue.xml new file mode 100644 index 0000000000000..1cd11177df0cd --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Queue.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Queue.xml new file mode 100644 index 0000000000000..2cbcc2de63269 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Queue.xml @@ -0,0 +1,18 @@ + + + + + + Aug 17, 2017 2:50:30 PM + Newsletter Subject %isolation% + Sender Name %isolation% + support%isolation%@example.com + Template Content %isolation% + + + diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.php similarity index 78% rename from dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php rename to dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.php index e85216539a10e..2a4aae4bcf0da 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.php @@ -6,6 +6,7 @@ namespace Magento\Newsletter\Test\TestCase; +use Magento\Newsletter\Test\Fixture\Queue; use Magento\Newsletter\Test\Fixture\Template; use Magento\Newsletter\Test\Page\Adminhtml\TemplateIndex; use Magento\Mtf\TestCase\Injectable; @@ -13,7 +14,7 @@ use Magento\Newsletter\Test\Page\Adminhtml\TemplateQueueIndex; /** - * Test to update Start Date in Newsletter Queue. + * Test to update fields in Newsletter Queue. * * Test Flow: * Preconditions: @@ -24,13 +25,13 @@ * 2. Go to Marketing > Newsletter Template * 3. Find created template in grid * 4. Execute "Queue Newsletter" action - * 5. Fill Date Start + * 5. Fill data from fixtures * 6. Save Newsletter Queue * * @group Newsletters * @ZephyrId MAGETWO-71653 */ -class UpdateQueueStartDateTest extends Injectable +class UpdateQueueTest extends Injectable { /* tags */ const MVP = 'yes'; @@ -42,46 +43,36 @@ class UpdateQueueStartDateTest extends Injectable * * @var TemplateIndex */ - protected $templateIndex; - - /** - * Page with newsletter queue grid. - * - * @var TemplateQueueIndex - */ - protected $indexQueue; + private $templateIndex; /** * Page for edit newsletter queue. * * @var TemplateQueue */ - protected $templateQueue; + private $templateQueue; /** * Inject newsletter page. * * @param TemplateIndex $templateIndex - * @param TemplateQueueIndex $indexQueue * @param TemplateQueue $templateQueue * @return void */ public function __inject( TemplateIndex $templateIndex, - TemplateQueueIndex $indexQueue, TemplateQueue $templateQueue ) { $this->templateIndex = $templateIndex; - $this->indexQueue = $indexQueue; $this->templateQueue = $templateQueue; } /** * @param Template $newsletter - * @param string $date + * @param Queue $queue * @return void */ - public function test(Template $newsletter) + public function test(Template $newsletter, Queue $queue) { // Preconditions $newsletter->persist(); @@ -90,6 +81,7 @@ public function test(Template $newsletter) $this->templateIndex->open(); $this->templateIndex->getNewsletterTemplateGrid()->search(['code' => $newsletter->getCode()]); $this->templateIndex->getNewsletterTemplateGrid()->performAction('Queue Newsletter'); + $this->templateQueue->getEditForm()->fill($queue); $this->templateQueue->getFormPageActions()->save(); } } diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.xml similarity index 76% rename from dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.xml rename to dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.xml index f9d4f7b26c3bb..938078551c1cf 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueStartDateTest.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.xml @@ -6,11 +6,11 @@ */ --> - + default - Aug 17, 2017 2:50:30 PM - + default + From 15c586a06bf9b0fea4baa07a76335b7d3126c5d9 Mon Sep 17 00:00:00 2001 From: Nadiya Syvokonenko Date: Tue, 22 Aug 2017 11:57:11 +0300 Subject: [PATCH 013/151] MAGETWO-49796: Catalog top nav, CSS class not set to active when using Varnish - fix code style errors --- lib/web/mage/menu.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index b9fefb8f706f1..667c86cec6454 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -134,7 +134,7 @@ define([ * If menu item has parent categories, sets 'has-active' class to all af them. * * @param {String} url - possible category URL - * @returns {boolean} - true if active category was founded by provided URL, otherwise return false + * @returns {Boolean} - true if active category was founded by provided URL, otherwise return false * @private */ _setActiveMenuForCategory: function (url) { @@ -142,26 +142,27 @@ define([ classes, classNav; - if (activeCategoryLink && activeCategoryLink.hasClass('ui-corner-all')) { + if (!activeCategoryLink || !activeCategoryLink.hasClass('ui-corner-all')) { - if (!activeCategoryLink.parent().hasClass('active')) { - activeCategoryLink.parent().addClass('active'); - classes = activeCategoryLink.parent().attr('class'); - classNav = classes.match(/(nav\-)[0-9]+(\-[0-9]+)+/gi); + //category was not found by provided URL + return false; + } else if (!activeCategoryLink.parent().hasClass('active')) { + activeCategoryLink.parent().addClass('active'); + classes = activeCategoryLink.parent().attr('class'); + classNav = classes.match(/(nav\-)[0-9]+(\-[0-9]+)+/gi); - if (classNav) { - this._setActiveParent(classNav[0]); - } + if (classNav) { + this._setActiveParent(classNav[0]); } - return true; } - return false; + + return true; }, /** * Sets 'has-active' CSS class to all parent categories which have part of provided class in childClassName * - * @example: + * @example * childClassName - 'nav-1-2-3' * CSS class 'has-active' will be added to categories have 'nav-1-2' and 'nav-1' classes * @@ -187,7 +188,7 @@ define([ * Tries to retrieve category URL from current URL and mark this category as active * @see _setActiveMenuForCategory(url) * - * @example: + * @example * currentUrl - http://magento.com/category1/category12/product.html, * category URLs has extensions .phtml - http://magento.com/category1.phtml * method sets active category which has URL http://magento.com/category1/category12.phtml From ee3009485f4633bb4c267e70812a08911cea3e94 Mon Sep 17 00:00:00 2001 From: RomanKis Date: Wed, 9 Aug 2017 13:57:29 +0300 Subject: [PATCH 014/151] MAGETWO-67198: [GitHub] Able to save attributes with null for attribute_code #8064 --- .../Magento/Eav/Model/Entity/Attribute.php | 5 + app/code/Magento/Eav/Setup/EavSetup.php | 25 ++-- app/code/Magento/Eav/Setup/UpgradeSchema.php | 23 ++++ app/code/Magento/Eav/etc/module.xml | 2 +- .../Magento/Eav/Setup/EavSetupTest.php | 121 ++++++++++++++++++ 5 files changed, 165 insertions(+), 11 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Eav/Setup/EavSetupTest.php diff --git a/app/code/Magento/Eav/Model/Entity/Attribute.php b/app/code/Magento/Eav/Model/Entity/Attribute.php index 7143fccbed594..c9865098602c0 100644 --- a/app/code/Magento/Eav/Model/Entity/Attribute.php +++ b/app/code/Magento/Eav/Model/Entity/Attribute.php @@ -26,6 +26,11 @@ class Attribute extends \Magento\Eav\Model\Entity\Attribute\AbstractAttribute im */ const ATTRIBUTE_CODE_MAX_LENGTH = 30; + /** + * Attribute code min length. + */ + const ATTRIBUTE_CODE_MIN_LENGTH = 1; + /** * Cache tag */ diff --git a/app/code/Magento/Eav/Setup/EavSetup.php b/app/code/Magento/Eav/Setup/EavSetup.php index 7de0706eee5ba..13f55308e6fa6 100644 --- a/app/code/Magento/Eav/Setup/EavSetup.php +++ b/app/code/Magento/Eav/Setup/EavSetup.php @@ -771,19 +771,24 @@ private function _getValue($array, $key, $default = null) */ private function _validateAttributeData($data) { - $attributeCodeMaxLength = \Magento\Eav\Model\Entity\Attribute::ATTRIBUTE_CODE_MAX_LENGTH; + $minLength = \Magento\Eav\Model\Entity\Attribute::ATTRIBUTE_CODE_MIN_LENGTH; + $maxLength = \Magento\Eav\Model\Entity\Attribute::ATTRIBUTE_CODE_MAX_LENGTH; + $attributeCode = isset($data['attribute_code']) ? $data['attribute_code'] : ''; - if (isset( - $data['attribute_code'] - ) && !\Zend_Validate::is( - $data['attribute_code'], + $isAllowedLength = \Zend_Validate::is( + trim($attributeCode), 'StringLength', - ['max' => $attributeCodeMaxLength] - ) - ) { - throw new LocalizedException( - __('An attribute code must not be more than %1 characters.', $attributeCodeMaxLength) + ['min' => $minLength, 'max' => $maxLength] + ); + + if (!$isAllowedLength) { + $errorMessage = __( + 'An attribute code must not be less than %1 and more than %2 characters.', + $minLength, + $maxLength ); + + throw new LocalizedException($errorMessage); } return true; diff --git a/app/code/Magento/Eav/Setup/UpgradeSchema.php b/app/code/Magento/Eav/Setup/UpgradeSchema.php index 8f82efe329f17..616514b3aa156 100644 --- a/app/code/Magento/Eav/Setup/UpgradeSchema.php +++ b/app/code/Magento/Eav/Setup/UpgradeSchema.php @@ -25,6 +25,10 @@ public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $con if (version_compare($context->getVersion(), '2.1.0', '<')) { $this->addUniqueKeyToEavAttributeGroupTable($setup); } + + if (version_compare($context->getVersion(), '2.1.1', '<')) { + $this->modifyAttributeCodeColumnForNotNullable($setup); + } $setup->endSetup(); } @@ -45,4 +49,23 @@ private function addUniqueKeyToEavAttributeGroupTable(SchemaSetupInterface $setu \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_UNIQUE ); } + + /** + * Column attribute_code from eav_attribute should not be nullable. + * + * @param SchemaSetupInterface $setup + */ + private function modifyAttributeCodeColumnForNotNullable(SchemaSetupInterface $setup) + { + $setup->getConnection()->modifyColumn( + $setup->getTable('eav_attribute'), + 'attribute_code', + [ + 'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, + 'length' => 255, + 'nullable' => false, + 'comment' => 'Attribute Code', + ] + ); + } } diff --git a/app/code/Magento/Eav/etc/module.xml b/app/code/Magento/Eav/etc/module.xml index 3169cb4e89a49..acd5807a29f90 100644 --- a/app/code/Magento/Eav/etc/module.xml +++ b/app/code/Magento/Eav/etc/module.xml @@ -6,7 +6,7 @@ */ --> - + diff --git a/dev/tests/integration/testsuite/Magento/Eav/Setup/EavSetupTest.php b/dev/tests/integration/testsuite/Magento/Eav/Setup/EavSetupTest.php new file mode 100644 index 0000000000000..5fe836ab189b9 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Eav/Setup/EavSetupTest.php @@ -0,0 +1,121 @@ +eavSetup = $objectManager->create(\Magento\Eav\Setup\EavSetup::class); + } + + /** + * Verify that add attribute work correct attribute_code. + * + * @param string $attributeCode + * + * @dataProvider addAttributeDataProvider + */ + public function testAddAttribute($attributeCode) + { + $attributeData = $this->getAttributeData(); + + $this->eavSetup->addAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode, $attributeData); + + $attribute = $this->eavSetup->getAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode); + + $this->assertEmpty(array_diff($attributeData, $attribute)); + } + + /** + * Data provider for testAddAttributeThrowException(). + * + * @return array + */ + public function addAttributeDataProvider() + { + return [ + ['eav_setup_test'], + ['_29_characters_29_characters_'], + ]; + } + + /** + * Verify that add attribute throw exception if attribute_code is not valid. + * + * @param string|null $attributeCode + * + * @dataProvider addAttributeThrowExceptionDataProvider + * @expectedException \Magento\Framework\Exception\LocalizedException + * @expectedExceptionMessage An attribute code must not be less than 1 and more than 30 characters. + */ + public function testAddAttributeThrowException($attributeCode) + { + $attributeData = $this->getAttributeData(); + + $this->eavSetup->addAttribute(\Magento\Catalog\Model\Product::ENTITY, $attributeCode, $attributeData); + } + + /** + * Data provider for testAddAttributeThrowException(). + * + * @return array + */ + public function addAttributeThrowExceptionDataProvider() + { + return [ + [null], + [''], + [' '], + ['more_than_30_characters_more_than'], + ]; + } + + /** + * Get simple attribute data. + */ + private function getAttributeData() + { + $attributeData = [ + 'type' => 'varchar', + 'backend' => '', + 'frontend' => '', + 'label' => 'Eav Setup Test', + 'input' => 'text', + 'class' => '', + 'source' => '', + 'global' => \Magento\Catalog\Model\ResourceModel\Eav\Attribute::SCOPE_STORE, + 'visible' => 0, + 'required' => 0, + 'user_defined' => 1, + 'default' => 'none', + 'searchable' => 0, + 'filterable' => 0, + 'comparable' => 0, + 'visible_on_front' => 0, + 'unique' => 0, + 'apply_to' => 'category', + ]; + + return $attributeData; + } +} From e676f9fe1e438f8cd6ebcc0f757fcc7f20af26be Mon Sep 17 00:00:00 2001 From: serhii balko Date: Tue, 22 Aug 2017 14:53:26 +0300 Subject: [PATCH 015/151] MAGETWO-58987: Copy paste detector fails in Tax module --- app/code/Magento/Tax/Helper/Data.php | 104 ++++++++++++- .../Tax/Observer/AfterAddressSaveObserver.php | 37 +---- .../Tax/Observer/CustomerLoggedInObserver.php | 35 +---- .../Magento/Tax/Test/Unit/Helper/DataTest.php | 141 +++++++++++++++++- .../Observer/AfterAddressSaveObserverTest.php | 109 ++++++++------ .../Observer/CustomerLoggedInObserverTest.php | 36 +++-- .../Weee/Observer/AfterAddressSave.php | 76 +++------- .../Weee/Observer/CustomerLoggedIn.php | 50 ++----- .../Unit/Observer/AfterAddressSaveTest.php | 114 ++++++++------ .../Unit/Observer/CustomerLoggedInTest.php | 61 ++++---- .../Php/_files/phpcpd/blacklist/common.txt | 2 - 11 files changed, 456 insertions(+), 309 deletions(-) diff --git a/app/code/Magento/Tax/Helper/Data.php b/app/code/Magento/Tax/Helper/Data.php index f77ecc956f26d..240fe5b88a961 100644 --- a/app/code/Magento/Tax/Helper/Data.php +++ b/app/code/Magento/Tax/Helper/Data.php @@ -8,6 +8,7 @@ use Magento\Framework\Pricing\PriceCurrencyInterface; use Magento\Store\Model\Store; use Magento\Customer\Model\Address; +use Magento\Customer\Model\Session; use Magento\Tax\Model\Config; use Magento\Customer\Model\Session as CustomerSession; use Magento\Tax\Api\OrderTaxManagementInterface; @@ -100,6 +101,13 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper */ private $serializer; + /** + * Customer session model. + * + * @var Session + */ + protected $customerSession; + /** * Constructor * @@ -114,6 +122,7 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper * @param OrderTaxManagementInterface $orderTaxManagement * @param PriceCurrencyInterface $priceCurrency * @param Json $serializer + * @param Session|null $customerSession * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -127,7 +136,8 @@ public function __construct( \Magento\Catalog\Helper\Data $catalogHelper, OrderTaxManagementInterface $orderTaxManagement, PriceCurrencyInterface $priceCurrency, - Json $serializer = null + Json $serializer = null, + Session $customerSession = null ) { parent::__construct($context); $this->priceCurrency = $priceCurrency; @@ -140,6 +150,7 @@ public function __construct( $this->catalogHelper = $catalogHelper; $this->orderTaxManagement = $orderTaxManagement; $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); + $this->customerSession = $customerSession ?: ObjectManager::getInstance()->get(Session::class); } /** @@ -797,4 +808,95 @@ public function isCatalogPriceDisplayAffectedByTax($store = null) return $this->displayPriceIncludingTax(); } } + + /** + * Set default Tax Billing and Shipping address into customer session after address save. + * + * @param Address $address + * @return void + */ + public function setAddressCustomerSessionAddressSave(Address $address) + { + if ($this->isDefaultBilling($address)) { + $this->customerSession->setDefaultTaxBillingAddress( + [ + 'country_id' => $address->getCountryId(), + 'region_id' => $address->getRegion() ? $address->getRegionId() : null, + 'postcode' => $address->getPostcode(), + ] + ); + } + if ($this->isDefaultShipping($address)) { + $this->customerSession->setDefaultTaxShippingAddress( + [ + 'country_id' => $address->getCountryId(), + 'region_id' => $address->getRegion() ? $address->getRegionId() : null, + 'postcode' => $address->getPostcode(), + ] + ); + } + } + + /** + * Set default Tax Shipping and Billing addresses into customer session after login. + * + * @param \Magento\Customer\Api\Data\AddressInterface[] $addresses + * @return void + */ + public function setAddressCustomerSessionLogIn(array $addresses) + { + $defaultShippingFound = false; + $defaultBillingFound = false; + foreach ($addresses as $address) { + if ($address->isDefaultBilling()) { + $defaultBillingFound = true; + $this->customerSession->setDefaultTaxBillingAddress( + [ + 'country_id' => $address->getCountryId(), + 'region_id' => $address->getRegion() ? $address->getRegionId() : null, + 'postcode' => $address->getPostcode(), + ] + ); + } + if ($address->isDefaultShipping()) { + $defaultShippingFound = true; + $this->customerSession->setDefaultTaxShippingAddress( + [ + 'country_id' => $address->getCountryId(), + 'region_id' => $address->getRegion() ? $address->getRegionId() : null, + 'postcode' => $address->getPostcode(), + ] + ); + } + if ($defaultShippingFound && $defaultBillingFound) { + break; + } + } + } + + /** + * Check whether specified billing address is default for customer from address. + * + * @param Address $address + * @return bool + */ + private function isDefaultBilling(Address $address) + { + return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultBilling() + || $address->getIsPrimaryBilling() + || $address->getIsDefaultBilling(); + } + + /** + * Check whether specified shipping address is default for customer from address. + * + * @param Address $address + * @return bool + */ + private function isDefaultShipping(Address $address) + { + return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultShipping() + || $address->getIsPrimaryShipping() + || $address->getIsDefaultShipping(); + } } diff --git a/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php b/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php index 27c9d402015d0..8eb841ca25c5a 100644 --- a/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php +++ b/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php @@ -6,7 +6,6 @@ namespace Magento\Tax\Observer; use Magento\Customer\Model\Address; -use Magento\Customer\Model\Session; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Module\Manager; @@ -15,11 +14,6 @@ class AfterAddressSaveObserver implements ObserverInterface { - /** - * @var Session - */ - protected $customerSession; - /** * @var Data */ @@ -40,18 +34,15 @@ class AfterAddressSaveObserver implements ObserverInterface private $cacheConfig; /** - * @param Session $customerSession * @param Data $taxHelper * @param Manager $moduleManager * @param Config $cacheConfig */ public function __construct( - Session $customerSession, Data $taxHelper, Manager $moduleManager, Config $cacheConfig ) { - $this->customerSession = $customerSession; $this->taxHelper = $taxHelper; $this->moduleManager = $moduleManager; $this->cacheConfig = $cacheConfig; @@ -64,31 +55,13 @@ public function __construct( */ public function execute(Observer $observer) { - if ($this->moduleManager->isEnabled('Magento_PageCache') && $this->cacheConfig->isEnabled() && - $this->taxHelper->isCatalogPriceDisplayAffectedByTax()) { + if ($this->moduleManager->isEnabled('Magento_PageCache') + && $this->cacheConfig->isEnabled() + && $this->taxHelper->isCatalogPriceDisplayAffectedByTax() + ) { /** @var $customerAddress Address */ $address = $observer->getCustomerAddress(); - - // Check if the address is either the default billing, shipping, or both - if ($this->isDefaultBilling($address)) { - $this->customerSession->setDefaultTaxBillingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } - - if ($this->isDefaultShipping($address)) { - $this->customerSession->setDefaultTaxShippingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } + $this->taxHelper->setAddressCustomerSessionAddressSave($address); } } diff --git a/app/code/Magento/Tax/Observer/CustomerLoggedInObserver.php b/app/code/Magento/Tax/Observer/CustomerLoggedInObserver.php index 30125c715ca6a..fd244032be5be 100644 --- a/app/code/Magento/Tax/Observer/CustomerLoggedInObserver.php +++ b/app/code/Magento/Tax/Observer/CustomerLoggedInObserver.php @@ -72,8 +72,10 @@ public function __construct( */ public function execute(Observer $observer) { - if ($this->moduleManager->isEnabled('Magento_PageCache') && $this->cacheConfig->isEnabled() && - $this->taxHelper->isCatalogPriceDisplayAffectedByTax()) { + if ($this->moduleManager->isEnabled('Magento_PageCache') + && $this->cacheConfig->isEnabled() + && $this->taxHelper->isCatalogPriceDisplayAffectedByTax() + ) { /** @var \Magento\Customer\Model\Data\Customer $customer */ $customer = $observer->getData('customer'); $customerGroupId = $customer->getGroupId(); @@ -81,36 +83,9 @@ public function execute(Observer $observer) $customerTaxClassId = $customerGroup->getTaxClassId(); $this->customerSession->setCustomerTaxClassId($customerTaxClassId); - /** @var \Magento\Customer\Api\Data\AddressInterface[] $addresses */ $addresses = $customer->getAddresses(); if (isset($addresses)) { - $defaultShippingFound = false; - $defaultBillingFound = false; - foreach ($addresses as $address) { - if ($address->isDefaultBilling()) { - $defaultBillingFound = true; - $this->customerSession->setDefaultTaxBillingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegion()->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } - if ($address->isDefaultShipping()) { - $defaultShippingFound = true; - $this->customerSession->setDefaultTaxShippingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegion()->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } - if ($defaultShippingFound && $defaultBillingFound) { - break; - } - } + $this->taxHelper->setAddressCustomerSessionLogIn($addresses); } } } diff --git a/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php b/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php index 51b1118af415c..70831b9f82177 100644 --- a/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php +++ b/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php @@ -9,6 +9,7 @@ namespace Magento\Tax\Test\Unit\Helper; use Magento\Framework\DataObject as MagentoObject; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** * Class DataTest @@ -17,6 +18,11 @@ */ class DataTest extends \PHPUnit\Framework\TestCase { + /** + * @var ObjectManager + */ + private $objectManager; + /** * @var \Magento\Tax\Helper\Data */ @@ -34,9 +40,14 @@ class DataTest extends \PHPUnit\Framework\TestCase /** @var \PHPUnit_Framework_MockObject_MockObject */ protected $serializer; + /** + * @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject + */ + private $customerSessionMock; + protected function setUp() { - $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->objectManager = new ObjectManager($this); $this->orderTaxManagementMock = $this->getMockBuilder(\Magento\Tax\Api\OrderTaxManagementInterface::class) ->disableOriginalConstructor() @@ -65,13 +76,19 @@ function ($value) { return json_decode($value, true); } ); - $this->helper = $objectManager->getObject( + $this->customerSessionMock = $this->getMockBuilder(\Magento\Customer\Model\Session::class) + ->disableOriginalConstructor() + ->setMethods(['setDefaultTaxBillingAddress', 'setDefaultTaxShippingAddress']) + ->getMock(); + + $this->helper = $this->objectManager->getObject( \Magento\Tax\Helper\Data::class, [ 'orderTaxManagement' => $this->orderTaxManagementMock, 'priceCurrency' => $this->priceCurrencyMock, 'taxConfig' => $this->taxConfigMock, - 'serializer' => $this->serializer + 'serializer' => $this->serializer, + 'customerSession' => $this->customerSessionMock, ] ); } @@ -529,4 +546,122 @@ public function dataProviderIsCatalogPriceDisplayAffectedByTax() [false , false, false, true, false] ]; } + + /** + * @test + * @dataProvider setAddressCustomerSessionAddressSaveDataProvider + * + * @param array $addressId + * @param array $billingInfo + * @param array $shippingInfo + * @param bool $needSetShipping + * @param bool $needSetBilling + */ + public function testSetAddressCustomerSessionAddressSave( + $addressId, + $billingInfo, + $shippingInfo, + $needSetShipping, + $needSetBilling + ) { + list($customerDefBillAddId, $isPrimaryBilling, $isDefaultBilling) = $billingInfo; + list($customerDefShipAddId, $isPrimaryShipping, $isDefaultShipping) = $shippingInfo; + + /* @var \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject $address */ + $address = $this->getMockBuilder(\Magento\Customer\Model\Address::class) + ->setMethods([ + 'getId', + 'getCustomer', + 'getIsPrimaryBilling', + 'getIsDefaultBilling', + 'getIsPrimaryShipping', + 'getIsDefaultShipping', + 'getCountryId', + 'getRegion', + 'getPostcode', + ]) + ->disableOriginalConstructor() + ->getMock(); + + $address->expects($this->any())->method('getCountryId')->willReturn(1); + $address->expects($this->any())->method('getRegion')->willReturn(null); + $address->expects($this->any())->method('getPostcode')->willReturn('11111'); + + $address->expects($this->any())->method('getId')->willReturn($addressId); + $address->expects($this->any())->method('getIsPrimaryBilling')->willReturn($isPrimaryBilling); + $address->expects($this->any())->method('getIsDefaultBilling')->willReturn($isDefaultBilling); + $address->expects($this->any())->method('getIsPrimaryShipping')->willReturn($isPrimaryShipping); + $address->expects($this->any())->method('getIsDefaultShipping')->willReturn($isDefaultShipping); + + /* @var \Magento\Customer\Model\Customer|\PHPUnit_Framework_MockObject_MockObject $customer */ + $customer = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) + ->setMethods(['getDefaultBilling', 'getDefaultShipping']) + ->disableOriginalConstructor() + ->getMock(); + $customer->expects($this->any())->method('getDefaultBilling')->willReturn($customerDefBillAddId); + $customer->expects($this->any())->method('getDefaultShipping')->willReturn($customerDefShipAddId); + + $address->expects($this->any())->method('getCustomer')->willReturn($customer); + + $this->customerSessionMock->expects($needSetShipping ? $this->once() : $this->never()) + ->method('setDefaultTaxShippingAddress') + ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); + $this->customerSessionMock->expects($needSetBilling ? $this->once() : $this->never()) + ->method('setDefaultTaxBillingAddress') + ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); + + $this->helper->setAddressCustomerSessionAddressSave($address); + } + + public function setAddressCustomerSessionAddressSaveDataProvider() + { + return [ + [1, [1, false, false], [1, false, false], true, true], + [1, [2, false, false], [2, false, false], false, false], + [1, [2, false, true], [2, false, true], true, true], + [1, [2, true, false], [2, true, false], true, true], + ]; + } + + /** + * @test + * @dataProvider setAddressCustomerSessionLogInDataProvider + * + * @param bool $isAddressDefaultBilling + * @param bool $isAddressDefaultShipping + */ + public function testSetAddressCustomerSessionLogIn( + $isAddressDefaultBilling, + $isAddressDefaultShipping + ) { + /* @var \Magento\Customer\Api\Data\AddressInterface|\PHPUnit_Framework_MockObject_MockObject $address */ + $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $address->expects($this->any())->method('getCountryId')->willReturn(1); + $address->expects($this->any())->method('getRegion')->willReturn(null); + $address->expects($this->any())->method('getPostcode')->willReturn('11111'); + $address->expects($this->any())->method('isDefaultShipping')->willReturn($isAddressDefaultShipping); + $address->expects($this->any())->method('isDefaultBilling')->willReturn($isAddressDefaultBilling); + + $this->customerSessionMock->expects($isAddressDefaultShipping ? $this->once() : $this->never()) + ->method('setDefaultTaxShippingAddress') + ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); + $this->customerSessionMock->expects($isAddressDefaultBilling ? $this->once() : $this->never()) + ->method('setDefaultTaxBillingAddress') + ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); + + $this->helper->setAddressCustomerSessionLogIn([$address]); + } + + public function setAddressCustomerSessionLogInDataProvider() + { + return [ + [false, false], + [false, true], + [true, false], + [true, true], + ]; + } } diff --git a/app/code/Magento/Tax/Test/Unit/Observer/AfterAddressSaveObserverTest.php b/app/code/Magento/Tax/Test/Unit/Observer/AfterAddressSaveObserverTest.php index 73313161c4d0f..a76dc0088f895 100644 --- a/app/code/Magento/Tax/Test/Unit/Observer/AfterAddressSaveObserverTest.php +++ b/app/code/Magento/Tax/Test/Unit/Observer/AfterAddressSaveObserverTest.php @@ -5,7 +5,6 @@ */ namespace Magento\Tax\Test\Unit\Observer; -use Magento\Customer\Model\Session; use Magento\Framework\Event\Observer; use Magento\Framework\Module\Manager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; @@ -18,57 +17,45 @@ class AfterAddressSaveObserverTest extends \PHPUnit\Framework\TestCase { /** - * @var Observer + * @var Observer|\PHPUnit_Framework_MockObject_MockObject */ protected $observerMock; /** - * @var Session + * @var ObjectManager */ - protected $customerSessionMock; - - /** @var ObjectManager */ - protected $objectManager; + private $objectManager; /** * Module manager * - * @var Manager + * @var Manager|\PHPUnit_Framework_MockObject_MockObject */ private $moduleManagerMock; /** * Cache config * - * @var Config + * @var Config|\PHPUnit_Framework_MockObject_MockObject */ private $cacheConfigMock; /** - * @var Data + * @var Data|\PHPUnit_Framework_MockObject_MockObject */ - protected $taxHelperMock; + private $taxHelperMock; /** - * @var AfterAddressSave + * @var \Magento\Tax\Observer\AfterAddressSaveObserver */ - protected $session; + private $session; protected function setUp() { $this->objectManager = new ObjectManager($this); $this->observerMock = $this->getMockBuilder(\Magento\Framework\Event\Observer::class) ->disableOriginalConstructor() - ->setMethods([ - 'getCustomerAddress', 'getData' - ]) - ->getMock(); - - $this->customerSessionMock = $this->getMockBuilder(\Magento\Customer\Model\Session::class) - ->disableOriginalConstructor() - ->setMethods([ - 'setDefaultTaxBillingAddress', 'setDefaultTaxShippingAddress', 'setWebsiteId' - ]) + ->setMethods(['getCustomerAddress']) ->getMock(); $this->moduleManagerMock = $this->getMockBuilder(\Magento\Framework\Module\Manager::class) @@ -80,54 +67,78 @@ protected function setUp() ->getMock(); $this->taxHelperMock = $this->getMockBuilder(\Magento\Tax\Helper\Data::class) + ->setMethods([ + 'isCatalogPriceDisplayAffectedByTax', + 'setAddressCustomerSessionAddressSave', + ]) ->disableOriginalConstructor() ->getMock(); $this->session = $this->objectManager->getObject( \Magento\Tax\Observer\AfterAddressSaveObserver::class, [ - 'customerSession' => $this->customerSessionMock, 'taxHelper' => $this->taxHelperMock, 'moduleManager' => $this->moduleManagerMock, - 'cacheConfig' => $this->cacheConfigMock + 'cacheConfig' => $this->cacheConfigMock, ] ); } - public function testExecute() - { - $this->moduleManagerMock->expects($this->once()) + /** + * @test + * @dataProvider getExecuteDataProvider + * + * @param bool $isEnabledPageCache + * @param bool $isEnabledConfigCache + * @param bool $isCatalogPriceDisplayAffectedByTax + * @param bool $isNeedSetAddress + */ + public function testExecute( + $isEnabledPageCache, + $isEnabledConfigCache, + $isCatalogPriceDisplayAffectedByTax, + $isNeedSetAddress + ) { + $this->moduleManagerMock->expects($this->any()) ->method('isEnabled') ->with('Magento_PageCache') - ->willReturn(true); + ->willReturn($isEnabledPageCache); - $this->cacheConfigMock->expects($this->once()) + $this->cacheConfigMock->expects($this->any()) ->method('isEnabled') - ->willReturn(true); + ->willReturn($isEnabledConfigCache); $this->taxHelperMock->expects($this->any()) ->method('isCatalogPriceDisplayAffectedByTax') - ->willReturn(true); - - $address = $this->objectManager->getObject(\Magento\Customer\Model\Address::class); - $address->setIsDefaultShipping(true); - $address->setIsDefaultBilling(true); - $address->setIsPrimaryBilling(true); - $address->setIsPrimaryShipping(true); - $address->setCountryId(1); - $address->setData('postcode', 11111); - - $this->customerSessionMock->expects($this->once()) - ->method('setDefaultTaxBillingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); - $this->customerSessionMock->expects($this->once()) - ->method('setDefaultTaxShippingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); - - $this->observerMock->expects($this->once()) + ->willReturn($isCatalogPriceDisplayAffectedByTax); + + /* @var \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject $address */ + $address = $this->getMockBuilder(\Magento\Customer\Model\Address::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->observerMock->expects($this->any()) ->method('getCustomerAddress') ->willReturn($address); + $this->taxHelperMock->expects($isNeedSetAddress ? $this->once() : $this->never()) + ->method('setAddressCustomerSessionAddressSave') + ->with($address); + $this->session->execute($this->observerMock); } + + public function getExecuteDataProvider() + { + return [ + [false, false, false, false], + [false, false, true, false], + [false, true, false, false], + [false, true, true, false], + [true, false, false, false], + [true, false, true, false], + [true, true, false, false], + [true, true, true, true], + ]; + } } diff --git a/app/code/Magento/Tax/Test/Unit/Observer/CustomerLoggedInObserverTest.php b/app/code/Magento/Tax/Test/Unit/Observer/CustomerLoggedInObserverTest.php index 70a5c87518bef..20e269dd85d3a 100644 --- a/app/code/Magento/Tax/Test/Unit/Observer/CustomerLoggedInObserverTest.php +++ b/app/code/Magento/Tax/Test/Unit/Observer/CustomerLoggedInObserverTest.php @@ -48,7 +48,7 @@ class CustomerLoggedInObserverTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->observerMock = $this->getMockBuilder(\Magento\Framework\Event\Observer::class) ->disableOriginalConstructor() ->setMethods([ @@ -79,7 +79,7 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->session = $this->objectManager->getObject( + $this->session = $objectManager->getObject( \Magento\Tax\Observer\CustomerLoggedInObserver::class, [ 'groupRepository' => $this->groupRepositoryMock, @@ -91,6 +91,9 @@ protected function setUp() ); } + /** + * @test + */ public function testExecute() { $this->moduleManagerMock->expects($this->once()) @@ -119,6 +122,15 @@ public function testExecute() ->method('getGroupId') ->willReturn(1); + /* @var \Magento\Customer\Api\Data\AddressInterface|\PHPUnit_Framework_MockObject_MockObject $address */ + $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $customerMock->expects($this->once()) + ->method('getAddresses') + ->willReturn([$address]); + $customerGroupMock = $this->getMockBuilder(\Magento\Customer\Model\Data\Group::class) ->disableOriginalConstructor() ->getMock(); @@ -136,23 +148,9 @@ public function testExecute() ->method('setCustomerTaxClassId') ->with(1); - $address = $this->objectManager->getObject(\Magento\Customer\Model\Data\Address::class); - $address->setIsDefaultShipping(true); - $address->setIsDefaultBilling(true); - $address->setCountryId(1); - $address->setPostCode(11111); - - $addresses = [$address]; - $customerMock->expects($this->once()) - ->method('getAddresses') - ->willReturn($addresses); - - $this->customerSessionMock->expects($this->once()) - ->method('setDefaultTaxBillingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); - $this->customerSessionMock->expects($this->once()) - ->method('setDefaultTaxShippingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); + $this->taxHelperMock->expects($this->once()) + ->method('setAddressCustomerSessionLogIn') + ->with([$address]); $this->session->execute($this->observerMock); } diff --git a/app/code/Magento/Weee/Observer/AfterAddressSave.php b/app/code/Magento/Weee/Observer/AfterAddressSave.php index a27f60de1ad58..1db48de518548 100644 --- a/app/code/Magento/Weee/Observer/AfterAddressSave.php +++ b/app/code/Magento/Weee/Observer/AfterAddressSave.php @@ -6,20 +6,15 @@ namespace Magento\Weee\Observer; use Magento\Customer\Model\Address; -use Magento\Customer\Model\Session; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Module\Manager; use Magento\PageCache\Model\Config; use Magento\Weee\Helper\Data; +use Magento\Tax\Helper\Data as TaxHelper; class AfterAddressSave implements ObserverInterface { - /** - * @var Session - */ - protected $customerSession; - /** * @var Data */ @@ -40,21 +35,28 @@ class AfterAddressSave implements ObserverInterface private $cacheConfig; /** - * @param Session $customerSession + * Tax helper + * + * @var TaxHelper + */ + private $taxHelper; + + /** * @param Data $weeeHelper * @param Manager $moduleManager * @param Config $cacheConfig + * @param TaxHelper $taxHelper */ public function __construct( - Session $customerSession, Data $weeeHelper, Manager $moduleManager, - Config $cacheConfig + Config $cacheConfig, + TaxHelper $taxHelper ) { - $this->customerSession = $customerSession; $this->weeeHelper = $weeeHelper; $this->moduleManager = $moduleManager; $this->cacheConfig = $cacheConfig; + $this->taxHelper = $taxHelper; } /** @@ -64,57 +66,13 @@ public function __construct( */ public function execute(Observer $observer) { - if ($this->moduleManager->isEnabled('Magento_PageCache') && $this->cacheConfig->isEnabled() && - $this->weeeHelper->isEnabled()) { + if ($this->moduleManager->isEnabled('Magento_PageCache') + && $this->cacheConfig->isEnabled() + && $this->weeeHelper->isEnabled() + ) { /** @var $customerAddress Address */ $address = $observer->getCustomerAddress(); - - // Check if the address is either the default billing, shipping, or both - if ($this->isDefaultBilling($address)) { - $this->customerSession->setDefaultTaxBillingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } - - if ($this->isDefaultShipping($address)) { - $this->customerSession->setDefaultTaxShippingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } + $this->taxHelper->setAddressCustomerSessionAddressSave($address); } } - - /** - * Check whether specified billing address is default for its customer - * - * @param Address $address - * @return bool - */ - protected function isDefaultBilling($address) - { - return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultBilling() - || $address->getIsPrimaryBilling() - || $address->getIsDefaultBilling(); - } - - /** - * Check whether specified shipping address is default for its customer - * - * @param Address $address - * @return bool - */ - protected function isDefaultShipping($address) - { - return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultShipping() - || $address->getIsPrimaryShipping() - || $address->getIsDefaultShipping(); - } } diff --git a/app/code/Magento/Weee/Observer/CustomerLoggedIn.php b/app/code/Magento/Weee/Observer/CustomerLoggedIn.php index f415f3b20bbd2..258bcba582ac3 100644 --- a/app/code/Magento/Weee/Observer/CustomerLoggedIn.php +++ b/app/code/Magento/Weee/Observer/CustomerLoggedIn.php @@ -11,6 +11,7 @@ use Magento\Framework\Module\Manager; use Magento\PageCache\Model\Config; use Magento\Weee\Helper\Data; +use Magento\Tax\Helper\Data as TaxHelper; class CustomerLoggedIn implements ObserverInterface { @@ -23,6 +24,11 @@ class CustomerLoggedIn implements ObserverInterface * @var Data */ protected $weeeHelper; + + /** + * @var TaxHelper + */ + private $taxHelper; /** * Module manager @@ -39,21 +45,21 @@ class CustomerLoggedIn implements ObserverInterface private $cacheConfig; /** - * @param Session $customerSession * @param Data $weeeHelper * @param Manager $moduleManager * @param Config $cacheConfig + * @param TaxHelper $taxHelper */ public function __construct( - Session $customerSession, Data $weeeHelper, Manager $moduleManager, - Config $cacheConfig + Config $cacheConfig, + TaxHelper $taxHelper ) { - $this->customerSession = $customerSession; $this->weeeHelper = $weeeHelper; $this->moduleManager = $moduleManager; $this->cacheConfig = $cacheConfig; + $this->taxHelper = $taxHelper; } /** @@ -63,41 +69,15 @@ public function __construct( */ public function execute(Observer $observer) { - if ($this->moduleManager->isEnabled('Magento_PageCache') && $this->cacheConfig->isEnabled() && - $this->weeeHelper->isEnabled()) { + if ($this->moduleManager->isEnabled('Magento_PageCache') + && $this->cacheConfig->isEnabled() + && $this->weeeHelper->isEnabled() + ) { /** @var \Magento\Customer\Model\Data\Customer $customer */ $customer = $observer->getData('customer'); - - /** @var \Magento\Customer\Api\Data\AddressInterface[] $addresses */ $addresses = $customer->getAddresses(); if (isset($addresses)) { - $defaultShippingFound = false; - $defaultBillingFound = false; - foreach ($addresses as $address) { - if ($address->isDefaultBilling()) { - $defaultBillingFound = true; - $this->customerSession->setDefaultTaxBillingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegion()->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } - if ($address->isDefaultShipping()) { - $defaultShippingFound = true; - $this->customerSession->setDefaultTaxShippingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegion()->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } - if ($defaultShippingFound && $defaultBillingFound) { - break; - } - } + $this->taxHelper->setAddressCustomerSessionLogIn($addresses); } } } diff --git a/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php b/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php index 373927ce3ab25..a21131a17f897 100644 --- a/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php +++ b/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php @@ -4,37 +4,43 @@ * See COPYING.txt for license details. */ namespace Magento\Weee\Test\Unit\Observer; +use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class AfterAddressSaveTest extends \PHPUnit\Framework\TestCase { /** - * @var \Magento\Framework\Event\Observer + * @var ObjectManager */ - protected $observerMock; - + private $objectManager; + /** - * @var \Magento\Customer\Model\Session + * @var \Magento\Framework\Event\Observer|\PHPUnit_Framework_MockObject_MockObject */ - protected $customerSessionMock; + private $observerMock; /** * Module manager * - * @var \Magento\Framework\Module\Manager + * @var \Magento\Framework\Module\Manager|\PHPUnit_Framework_MockObject_MockObject */ private $moduleManagerMock; /** * Cache config * - * @var \Magento\PageCache\Model\Config + * @var \Magento\PageCache\Model\Config|\PHPUnit_Framework_MockObject_MockObject */ private $cacheConfigMock; /** - * @var \Magento\Weee\Helper\Data + * @var \Magento\Weee\Helper\Data|\PHPUnit_Framework_MockObject_MockObject */ - protected $weeeHelperMock; + private $weeeHelperMock; + + /** + * @var \Magento\Tax\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + */ + protected $taxHelperMock; /** * @var \Magento\Weee\Observer\AfterAddressSave @@ -43,19 +49,10 @@ class AfterAddressSaveTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->objectManager = new ObjectManager($this); $this->observerMock = $this->getMockBuilder(\Magento\Framework\Event\Observer::class) ->disableOriginalConstructor() - ->setMethods([ - 'getCustomerAddress', 'getData' - ]) - ->getMock(); - - $this->customerSessionMock = $this->getMockBuilder(\Magento\Customer\Model\Session::class) - ->disableOriginalConstructor() - ->setMethods([ - 'setDefaultTaxBillingAddress', 'setDefaultTaxShippingAddress', 'setWebsiteId' - ]) + ->setMethods(['getCustomerAddress']) ->getMock(); $this->moduleManagerMock = $this->getMockBuilder(\Magento\Framework\Module\Manager::class) @@ -69,52 +66,77 @@ protected function setUp() $this->weeeHelperMock = $this->getMockBuilder(\Magento\Weee\Helper\Data::class) ->disableOriginalConstructor() ->getMock(); + + $this->taxHelperMock = $this->getMockBuilder(\Magento\Tax\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); $this->session = $this->objectManager->getObject( \Magento\Weee\Observer\AfterAddressSave::class, [ - 'customerSession' => $this->customerSessionMock, 'weeeHelper' => $this->weeeHelperMock, 'moduleManager' => $this->moduleManagerMock, - 'cacheConfig' => $this->cacheConfigMock + 'cacheConfig' => $this->cacheConfigMock, + 'taxHelper' => $this->taxHelperMock, ] ); } - public function testExecute() - { - $this->moduleManagerMock->expects($this->once()) + /** + * @test + * @dataProvider getExecuteDataProvider + * + * @param $isEnabledPageCache + * @param $isEnabledConfigCache + * @param $isEnabledWeee + * @param $isNeedSetAddress + */ + public function testExecute( + $isEnabledPageCache, + $isEnabledConfigCache, + $isEnabledWeee, + $isNeedSetAddress + ) { + $this->moduleManagerMock->expects($this->any()) ->method('isEnabled') ->with('Magento_PageCache') - ->willReturn(true); + ->willReturn($isEnabledPageCache); - $this->cacheConfigMock->expects($this->once()) + $this->cacheConfigMock->expects($this->any()) ->method('isEnabled') - ->willReturn(true); + ->willReturn($isEnabledConfigCache); $this->weeeHelperMock->expects($this->any()) ->method('isEnabled') - ->willReturn(true); - - $address = $this->objectManager->getObject(\Magento\Customer\Model\Address::class); - $address->setIsDefaultShipping(true); - $address->setIsDefaultBilling(true); - $address->setIsPrimaryBilling(true); - $address->setIsPrimaryShipping(true); - $address->setCountryId(1); - $address->setData('postcode', 11111); - - $this->customerSessionMock->expects($this->once()) - ->method('setDefaultTaxBillingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); - $this->customerSessionMock->expects($this->once()) - ->method('setDefaultTaxShippingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); - - $this->observerMock->expects($this->once()) + ->willReturn($isEnabledWeee); + + /* @var \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject $address */ + $address = $this->getMockBuilder(\Magento\Customer\Model\Address::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->observerMock->expects($this->any()) ->method('getCustomerAddress') ->willReturn($address); + $this->taxHelperMock->expects($isNeedSetAddress ? $this->once() : $this->never()) + ->method('setAddressCustomerSessionAddressSave') + ->with($address); + $this->session->execute($this->observerMock); } + + public function getExecuteDataProvider() + { + return [ + [false, false, false, false], + [false, false, true, false], + [false, true, false, false], + [false, true, true, false], + [true, false, false, false], + [true, false, true, false], + [true, true, false, false], + [true, true, true, true], + ]; + } } diff --git a/app/code/Magento/Weee/Test/Unit/Observer/CustomerLoggedInTest.php b/app/code/Magento/Weee/Test/Unit/Observer/CustomerLoggedInTest.php index 7cbb7ab13fae4..844db7d7f541c 100644 --- a/app/code/Magento/Weee/Test/Unit/Observer/CustomerLoggedInTest.php +++ b/app/code/Magento/Weee/Test/Unit/Observer/CustomerLoggedInTest.php @@ -12,11 +12,6 @@ class CustomerLoggedInTest extends \PHPUnit\Framework\TestCase */ protected $observerMock; - /** - * @var \Magento\Customer\Model\Session - */ - protected $customerSessionMock; - /** * Module manager * @@ -36,6 +31,11 @@ class CustomerLoggedInTest extends \PHPUnit\Framework\TestCase */ protected $weeeHelperMock; + /** + * @var \Magento\Tax\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + */ + private $taxHelperMock; + /** * @var \Magento\Weee\Observer\CustomerLoggedIn */ @@ -43,7 +43,7 @@ class CustomerLoggedInTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->observerMock = $this->getMockBuilder(\Magento\Framework\Event\Observer::class) ->disableOriginalConstructor() ->setMethods([ @@ -51,13 +51,6 @@ protected function setUp() ]) ->getMock(); - $this->customerSessionMock = $this->getMockBuilder(\Magento\Customer\Model\Session::class) - ->disableOriginalConstructor() - ->setMethods([ - 'setDefaultTaxBillingAddress', 'setDefaultTaxShippingAddress', 'setWebsiteId' - ]) - ->getMock(); - $this->moduleManagerMock = $this->getMockBuilder(\Magento\Framework\Module\Manager::class) ->disableOriginalConstructor() ->getMock(); @@ -70,17 +63,24 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->session = $this->objectManager->getObject( + $this->taxHelperMock = $this->getMockBuilder(\Magento\Tax\Helper\Data::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->session = $objectManager->getObject( \Magento\Weee\Observer\CustomerLoggedIn::class, [ - 'customerSession' => $this->customerSessionMock, 'weeeHelper' => $this->weeeHelperMock, 'moduleManager' => $this->moduleManagerMock, - 'cacheConfig' => $this->cacheConfigMock + 'cacheConfig' => $this->cacheConfigMock, + 'taxHelper' => $this->taxHelperMock, ] ); } + /** + * @test + */ public function testExecute() { $this->moduleManagerMock->expects($this->once()) @@ -100,28 +100,23 @@ public function testExecute() ->disableOriginalConstructor() ->getMock(); + /* @var \Magento\Customer\Api\Data\AddressInterface|\PHPUnit_Framework_MockObject_MockObject $address */ + $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $customerMock->expects($this->once()) + ->method('getAddresses') + ->willReturn([$address]); + $this->observerMock->expects($this->once()) ->method('getData') ->with('customer') ->willReturn($customerMock); - $address = $this->objectManager->getObject(\Magento\Customer\Model\Data\Address::class); - $address->setIsDefaultShipping(true); - $address->setIsDefaultBilling(true); - $address->setCountryId(1); - $address->setPostCode(11111); - - $addresses = [$address]; - $customerMock->expects($this->once()) - ->method('getAddresses') - ->willReturn($addresses); - - $this->customerSessionMock->expects($this->once()) - ->method('setDefaultTaxBillingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); - $this->customerSessionMock->expects($this->once()) - ->method('setDefaultTaxShippingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); + $this->taxHelperMock->expects($this->once()) + ->method('setAddressCustomerSessionLogIn') + ->with([$address]); $this->session->execute($this->observerMock); } diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt index ebe8501337eff..d81c0eb240398 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt @@ -173,8 +173,6 @@ Magento/Reports/Model/ResourceModel/Customer/Orders Magento/Sales/Model/ResourceModel/Report Magento/SalesRule/Model Magento/Search/Ui/Component/Listing/Column/Scope -Magento/Tax/Model/Calculation -Magento/Tax/Observer Magento/Vault/Model/Ui Magento/GroupedProduct/Model/ResourceModel/Product/Indexer/Price Magento/AdvancedSalesRule/Model/Rule/Condition/Product From bc6b4af3ecb8321933c0cceebbe517900b30a943 Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Tue, 22 Aug 2017 16:01:34 +0300 Subject: [PATCH 016/151] MAGETWO-65688: Unable to configure products from products and wish list accordion when managing shopping cart --- .../Magento/Backend/view/adminhtml/templates/widget/grid.phtml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml index 3c44f629cd8af..4f845b1a2daa2 100644 --- a/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml +++ b/app/code/Magento/Backend/view/adminhtml/templates/widget/grid.phtml @@ -149,7 +149,8 @@ $numColumns = sizeof($block->getColumns()); getRowClickCallback(), 'order.') !== false): ?> - deps.push('Magento_Sales/order/create/form') + deps.push('Magento_Sales/order/create/form'); + deps.push('jQuery'); deps.push('mage/adminhtml/grid'); From 299d9d76a29de3167cfbe9bdc08190bd0a4476a7 Mon Sep 17 00:00:00 2001 From: serhii balko Date: Tue, 22 Aug 2017 16:07:56 +0300 Subject: [PATCH 017/151] MAGETWO-58987: Copy paste detector fails in Tax module --- .../Model/Calculation/UnitBaseCalculator.php | 50 +++++++++++-------- .../Unit/Observer/AfterAddressSaveTest.php | 1 + 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php b/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php index ed469e822d937..a3364dd57a7d9 100644 --- a/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php +++ b/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php @@ -9,27 +9,6 @@ class UnitBaseCalculator extends AbstractCalculator { - /** - * {@inheritdoc} - */ - protected function roundAmount( - $amount, - $rate = null, - $direction = null, - $type = self::KEY_REGULAR_DELTA_ROUNDING, - $round = true, - $item = null - ) { - if ($item->getAssociatedItemCode()) { - // Use delta rounding of the product's instead of the weee's - $type = $type . $item->getAssociatedItemCode(); - } else { - $type = $type . $item->getCode(); - } - - return $this->deltaRound($amount, $rate, $direction, $type, $round); - } - /** * {@inheritdoc} */ @@ -103,6 +82,35 @@ protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $qua ->setAppliedTaxes($appliedTaxes); } + /** + * Round amount. + * + * @param float $amount + * @param null|string $rate + * @param null|bool $direction + * @param string $type + * @param bool $round + * @param QuoteDetailsItemInterface $item + * @return float + */ + protected function roundAmount( + float $amount, + string $rate = null, + bool $direction = null, + string $type = self::KEY_REGULAR_DELTA_ROUNDING, + bool $round = true, + QuoteDetailsItemInterface $item = null + ) { + if ($item->getAssociatedItemCode()) { + // Use delta rounding of the product's instead of the weee's + $type = $type . $item->getAssociatedItemCode(); + } else { + $type = $type . $item->getCode(); + } + + return $this->deltaRound($amount, $rate, $direction, $type, $round); + } + /** * {@inheritdoc} */ diff --git a/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php b/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php index a21131a17f897..413c7baaa5e65 100644 --- a/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php +++ b/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php @@ -4,6 +4,7 @@ * See COPYING.txt for license details. */ namespace Magento\Weee\Test\Unit\Observer; + use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class AfterAddressSaveTest extends \PHPUnit\Framework\TestCase From d1851abd505edc023f3bf79eb877144f300c1bda Mon Sep 17 00:00:00 2001 From: Joan He Date: Tue, 22 Aug 2017 09:21:21 -0500 Subject: [PATCH 018/151] MAGETWO-70837: Pricing discrepancy in shopping cart - fix JSUNIT test failure --- .../frontend/web/js/model/cart/totals-processor/default.js | 3 +-- .../frontend/js/model/cart/totals-processor/default.test.js | 3 +++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js index f96924398e520..276fed5a294f9 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js @@ -87,13 +87,12 @@ define([ data.shippingCarrierCode = quote.shippingMethod()['carrier_code']; } - var quoteSubtotal = quote.totals().subtotal; if (!cartCache.isChanged('cartVersion', customerData.get('cart')()['data_id']) && !cartCache.isChanged('shippingMethodCode', data.shippingMethodCode) && !cartCache.isChanged('shippingCarrierCode', data.shippingCarrierCode) && !cartCache.isChanged('address', address) && cartCache.get('totals') && - !cartCache.isChanged('subtotal', quoteSubtotal) + !cartCache.isChanged('subtotal', quote.totals()['subtotal']) ) { quote.setTotals(cartCache.get('totals')); } else { diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/totals-processor/default.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/totals-processor/default.test.js index 6476432c027a2..44f06279dcbef 100644 --- a/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/totals-processor/default.test.js +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Checkout/frontend/js/model/cart/totals-processor/default.test.js @@ -50,6 +50,9 @@ define([ 'method_code': 'flatrate', 'carrier_code': 'flatrate' }), + totals: ko.observable({ + 'subtotal': 4 + }), setTotals: jasmine.createSpy() }, 'mage/storage': { From 917c37b482e193a3ca038e13dedd28bfc2b448ac Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Wed, 23 Aug 2017 15:38:08 -0500 Subject: [PATCH 019/151] MAGETWO-71765 Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Fix capture amount float rounding --- app/code/Magento/Paypal/Model/Payflowpro.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Paypal/Model/Payflowpro.php b/app/code/Magento/Paypal/Model/Payflowpro.php index f3db5a2baa880..a7987b9c14dd1 100644 --- a/app/code/Magento/Paypal/Model/Payflowpro.php +++ b/app/code/Magento/Paypal/Model/Payflowpro.php @@ -396,8 +396,8 @@ public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount protected function _getCaptureAmount($amount) { $infoInstance = $this->getInfoInstance(); - $amountToPay = round($amount, 2); - $authorizedAmount = round($infoInstance->getAmountAuthorized(), 2); + $amountToPay = number_format($amount, 2); + $authorizedAmount = number_format($infoInstance->getAmountAuthorized(), 2); return $amountToPay != $authorizedAmount ? $amountToPay : 0; } From 7d96846f6f150ac8e3fd3c4e93f9bc429a575d19 Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Thu, 24 Aug 2017 19:53:07 -0500 Subject: [PATCH 020/151] MAGETWO-71765 Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Fix capture amount float rounding - Swapped out rounding for sprintf --- app/code/Magento/Paypal/Model/Payflowpro.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Paypal/Model/Payflowpro.php b/app/code/Magento/Paypal/Model/Payflowpro.php index a7987b9c14dd1..0a988ffd8abc5 100644 --- a/app/code/Magento/Paypal/Model/Payflowpro.php +++ b/app/code/Magento/Paypal/Model/Payflowpro.php @@ -396,8 +396,8 @@ public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount protected function _getCaptureAmount($amount) { $infoInstance = $this->getInfoInstance(); - $amountToPay = number_format($amount, 2); - $authorizedAmount = number_format($infoInstance->getAmountAuthorized(), 2); + $amountToPay = sprintf('%.2F', $amount); + $authorizedAmount = sprintf('%.2F', $infoInstance->getAmountAuthorized()); return $amountToPay != $authorizedAmount ? $amountToPay : 0; } From 106513f6d6bbc66c02c8b1d856bd0884c0651263 Mon Sep 17 00:00:00 2001 From: serhii balko Date: Fri, 25 Aug 2017 11:24:08 +0300 Subject: [PATCH 021/151] MAGETWO-56349: [GITHUB] Newsletter Queue doesn't set to local time #5943 #2937 #7560 --- .../Block/Adminhtml/Queue/Edit/QueueForm.xml | 4 ++ ...Save.php => AssertNewsletterQueueForm.php} | 11 ++-- .../AssertNewsletterQueueInGrid.php | 47 ++++++++++++++ .../AssertNewsletterQueueSaveMessage.php | 48 +++++++++++++++ .../Magento/Newsletter/Test/Fixture/Queue.xml | 5 +- .../Newsletter/Test/Fixture/Queue/Stores.php | 61 +++++++++++++++++++ .../Newsletter/Test/Repository/Queue.xml | 12 +++- .../Test/TestCase/UpdateQueueTest.xml | 6 +- 8 files changed, 182 insertions(+), 12 deletions(-) rename dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/{AssertNewsletterQueueSave.php => AssertNewsletterQueueForm.php} (76%) create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSaveMessage.php create mode 100644 dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue/Stores.php diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.xml index f18c53cb112e2..c1970955013e8 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Edit/QueueForm.xml @@ -10,6 +10,10 @@ input[name='start_at'] + + select[name="stores[]"] + multiselectgrouplist + input[name='subject'] diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSave.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueForm.php similarity index 76% rename from dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSave.php rename to dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueForm.php index ccc273d0f4ebf..89df51175b069 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSave.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueForm.php @@ -8,17 +8,16 @@ use Magento\Mtf\Constraint\AbstractAssertForm; use Magento\Newsletter\Test\Fixture\Queue; -use Magento\Newsletter\Test\Fixture\Template; use Magento\Newsletter\Test\Page\Adminhtml\TemplateQueue; use Magento\Newsletter\Test\Page\Adminhtml\TemplateQueueIndex; /** - * Assert that "Newsletter Queue" saved correctly. + * Assert that Newsletter Queue form data equal the fixture data. */ -class AssertNewsletterQueueSave extends AbstractAssertForm +class AssertNewsletterQueueForm extends AbstractAssertForm { /** - * Assert that "Newsletter Queue" saved correctly. + * Assert that Newsletter Queue form data equal the fixture data. * * @param TemplateQueueIndex $indexQueue * @param TemplateQueue $templateQueue @@ -30,7 +29,7 @@ public function processAssert( TemplateQueue $templateQueue, Queue $queue ) { - $indexQueue->getMessagesBlock()->assertSuccessMessage(); + $indexQueue->open(); $indexQueue->getQueueTemplateGrid()->searchAndOpen(['newsletter_subject' => $queue->getNewsletterSubject()]); $dataDiff = $this->verifyData($queue->getData(), $templateQueue->getEditForm()->getData($queue)); @@ -42,6 +41,6 @@ public function processAssert( */ public function toString() { - return '"Newsletter Queue" saved correctly'; + return 'Newsletter Queue form data equal the fixture data.'; } } diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php new file mode 100644 index 0000000000000..35606db3e5202 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php @@ -0,0 +1,47 @@ +open(); + $filter = [ + 'newsletter_subject' => $queue->getNewsletterSubject(), + ]; + + \PHPUnit_Framework_Assert::assertTrue( + $indexQueue->getQueueTemplateGrid()->isRowVisible($filter), + 'Newsletter Queue \'' . $queue->getNewsletterSubject() . '\' is absent in grid.' + ); + } + + /** + * {@inheritdoc} + */ + public function toString() + { + return 'Newsletter Queue is present in grid.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSaveMessage.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSaveMessage.php new file mode 100644 index 0000000000000..4e240d6edd0c1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueSaveMessage.php @@ -0,0 +1,48 @@ +getMessagesBlock()->getSuccessMessages(); + \PHPUnit_Framework_Assert::assertContains( + self::SUCCESS_MESSAGE, + $actualMessages, + 'Wrong success message is displayed.' + . "\nExpected: " . self::SUCCESS_MESSAGE + . "\nActual:\n" . implode("\n - ", $actualMessages) + ); + } + + /** + * {@inheritdoc} + */ + public function toString() + { + return 'Newsletter Queue success save message is present.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue.xml index 1cd11177df0cd..7e723e678e1ae 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue.xml @@ -24,7 +24,8 @@ - - + + + diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue/Stores.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue/Stores.php new file mode 100644 index 0000000000000..c0d9e6f1e7e73 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue/Stores.php @@ -0,0 +1,61 @@ +params = $params; + if (isset($data['dataset'])) { + $datasets = is_array($data['dataset']) ? $data['dataset'] : [$data['dataset']]; + foreach ($datasets as $dataset) { + /** @var \Magento\Store\Test\Fixture\Store $store */ + $store = $fixtureFactory->createByCode('store', ['dataset' => $dataset]); + if (!$store->hasData('store_id')) { + $store->persist(); + } + $this->stores[] = $store; + $this->data[] = $store->getGroupId() . '/' . $store->getName(); + } + } + } + + /** + * Return stores. + * + * @return array + */ + public function getStores() + { + return $this->stores; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Queue.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Queue.xml index 2cbcc2de63269..eac5caac897ff 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Queue.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Repository/Queue.xml @@ -7,8 +7,16 @@ --> - - Aug 17, 2017 2:50:30 PM + + + M j, Y g:i:s A + + + + default + custom + + Newsletter Subject %isolation% Sender Name %isolation% support%isolation%@example.com diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.xml index 938078551c1cf..02bc8aa7c1c04 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.xml @@ -9,8 +9,10 @@ default - default - + default_with_stores + + + From 7e25b81a29c7cabe034108fff5948bd6a9b0f0b5 Mon Sep 17 00:00:00 2001 From: serhii balko Date: Fri, 25 Aug 2017 18:56:02 +0300 Subject: [PATCH 022/151] MAGETWO-58987: Copy paste detector fails in Tax module --- .../Tax/Api/TaxAddressManagerInterface.php | 32 ++++ app/code/Magento/Tax/Helper/Data.php | 104 +---------- .../Model/Calculation/UnitBaseCalculator.php | 50 +++--- .../Magento/Tax/Model/TaxAddressManager.php | 122 +++++++++++++ .../Tax/Observer/AfterAddressSaveObserver.php | 41 ++--- .../Tax/Observer/CustomerLoggedInObserver.php | 15 +- .../Magento/Tax/Test/Unit/Helper/DataTest.php | 141 +-------------- .../Test/Unit/Model/TaxAddressManagerTest.php | 163 ++++++++++++++++++ .../Observer/AfterAddressSaveObserverTest.php | 22 ++- .../Observer/CustomerLoggedInObserverTest.php | 20 ++- app/code/Magento/Tax/etc/di.xml | 1 + .../Weee/Observer/AfterAddressSave.php | 16 +- .../Weee/Observer/CustomerLoggedIn.php | 17 +- .../Unit/Observer/AfterAddressSaveTest.php | 19 +- .../Unit/Observer/CustomerLoggedInTest.php | 16 +- .../Php/_files/phpcpd/blacklist/common.txt | 1 + 16 files changed, 442 insertions(+), 338 deletions(-) create mode 100644 app/code/Magento/Tax/Api/TaxAddressManagerInterface.php create mode 100644 app/code/Magento/Tax/Model/TaxAddressManager.php create mode 100644 app/code/Magento/Tax/Test/Unit/Model/TaxAddressManagerTest.php diff --git a/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php b/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php new file mode 100644 index 0000000000000..0be05a06cda39 --- /dev/null +++ b/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php @@ -0,0 +1,32 @@ +priceCurrency = $priceCurrency; @@ -150,7 +140,6 @@ public function __construct( $this->catalogHelper = $catalogHelper; $this->orderTaxManagement = $orderTaxManagement; $this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class); - $this->customerSession = $customerSession ?: ObjectManager::getInstance()->get(Session::class); } /** @@ -808,95 +797,4 @@ public function isCatalogPriceDisplayAffectedByTax($store = null) return $this->displayPriceIncludingTax(); } } - - /** - * Set default Tax Billing and Shipping address into customer session after address save. - * - * @param Address $address - * @return void - */ - public function setAddressCustomerSessionAddressSave(Address $address) - { - if ($this->isDefaultBilling($address)) { - $this->customerSession->setDefaultTaxBillingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } - if ($this->isDefaultShipping($address)) { - $this->customerSession->setDefaultTaxShippingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } - } - - /** - * Set default Tax Shipping and Billing addresses into customer session after login. - * - * @param \Magento\Customer\Api\Data\AddressInterface[] $addresses - * @return void - */ - public function setAddressCustomerSessionLogIn(array $addresses) - { - $defaultShippingFound = false; - $defaultBillingFound = false; - foreach ($addresses as $address) { - if ($address->isDefaultBilling()) { - $defaultBillingFound = true; - $this->customerSession->setDefaultTaxBillingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } - if ($address->isDefaultShipping()) { - $defaultShippingFound = true; - $this->customerSession->setDefaultTaxShippingAddress( - [ - 'country_id' => $address->getCountryId(), - 'region_id' => $address->getRegion() ? $address->getRegionId() : null, - 'postcode' => $address->getPostcode(), - ] - ); - } - if ($defaultShippingFound && $defaultBillingFound) { - break; - } - } - } - - /** - * Check whether specified billing address is default for customer from address. - * - * @param Address $address - * @return bool - */ - private function isDefaultBilling(Address $address) - { - return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultBilling() - || $address->getIsPrimaryBilling() - || $address->getIsDefaultBilling(); - } - - /** - * Check whether specified shipping address is default for customer from address. - * - * @param Address $address - * @return bool - */ - private function isDefaultShipping(Address $address) - { - return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultShipping() - || $address->getIsPrimaryShipping() - || $address->getIsDefaultShipping(); - } } diff --git a/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php b/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php index a3364dd57a7d9..ed469e822d937 100644 --- a/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php +++ b/app/code/Magento/Tax/Model/Calculation/UnitBaseCalculator.php @@ -9,6 +9,27 @@ class UnitBaseCalculator extends AbstractCalculator { + /** + * {@inheritdoc} + */ + protected function roundAmount( + $amount, + $rate = null, + $direction = null, + $type = self::KEY_REGULAR_DELTA_ROUNDING, + $round = true, + $item = null + ) { + if ($item->getAssociatedItemCode()) { + // Use delta rounding of the product's instead of the weee's + $type = $type . $item->getAssociatedItemCode(); + } else { + $type = $type . $item->getCode(); + } + + return $this->deltaRound($amount, $rate, $direction, $type, $round); + } + /** * {@inheritdoc} */ @@ -82,35 +103,6 @@ protected function calculateWithTaxInPrice(QuoteDetailsItemInterface $item, $qua ->setAppliedTaxes($appliedTaxes); } - /** - * Round amount. - * - * @param float $amount - * @param null|string $rate - * @param null|bool $direction - * @param string $type - * @param bool $round - * @param QuoteDetailsItemInterface $item - * @return float - */ - protected function roundAmount( - float $amount, - string $rate = null, - bool $direction = null, - string $type = self::KEY_REGULAR_DELTA_ROUNDING, - bool $round = true, - QuoteDetailsItemInterface $item = null - ) { - if ($item->getAssociatedItemCode()) { - // Use delta rounding of the product's instead of the weee's - $type = $type . $item->getAssociatedItemCode(); - } else { - $type = $type . $item->getCode(); - } - - return $this->deltaRound($amount, $rate, $direction, $type, $round); - } - /** * {@inheritdoc} */ diff --git a/app/code/Magento/Tax/Model/TaxAddressManager.php b/app/code/Magento/Tax/Model/TaxAddressManager.php new file mode 100644 index 0000000000000..ea44a740205d6 --- /dev/null +++ b/app/code/Magento/Tax/Model/TaxAddressManager.php @@ -0,0 +1,122 @@ +customerSession = $customerSession; + } + + /** + * Set default Tax Billing and Shipping address into customer session after address save. + * + * @param Address $address + * @return void + */ + public function setDefaultAddressAfterSave(Address $address) + { + if ($this->isDefaultBilling($address)) { + $this->customerSession->setDefaultTaxBillingAddress( + [ + 'country_id' => $address->getCountryId(), + 'region_id' => $address->getRegion() ? $address->getRegionId() : null, + 'postcode' => $address->getPostcode(), + ] + ); + } + if ($this->isDefaultShipping($address)) { + $this->customerSession->setDefaultTaxShippingAddress( + [ + 'country_id' => $address->getCountryId(), + 'region_id' => $address->getRegion() ? $address->getRegionId() : null, + 'postcode' => $address->getPostcode(), + ] + ); + } + } + + /** + * Set default Tax Shipping and Billing addresses into customer session after login. + * + * @param \Magento\Customer\Api\Data\AddressInterface[] $addresses + * @return void + */ + public function setDefaultAddressAfterLogIn(array $addresses) + { + $defaultShippingFound = false; + $defaultBillingFound = false; + foreach ($addresses as $address) { + if ($address->isDefaultBilling()) { + $defaultBillingFound = true; + $this->customerSession->setDefaultTaxBillingAddress( + [ + 'country_id' => $address->getCountryId(), + 'region_id' => $address->getRegion() ? $address->getRegionId() : null, + 'postcode' => $address->getPostcode(), + ] + ); + } + if ($address->isDefaultShipping()) { + $defaultShippingFound = true; + $this->customerSession->setDefaultTaxShippingAddress( + [ + 'country_id' => $address->getCountryId(), + 'region_id' => $address->getRegion() ? $address->getRegionId() : null, + 'postcode' => $address->getPostcode(), + ] + ); + } + if ($defaultShippingFound && $defaultBillingFound) { + break; + } + } + } + + /** + * Check whether specified billing address is default for customer from address. + * + * @param Address $address + * @return bool + */ + private function isDefaultBilling(Address $address) + { + return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultBilling() + || $address->getIsPrimaryBilling() + || $address->getIsDefaultBilling(); + } + + /** + * Check whether specified shipping address is default for customer from address. + * + * @param Address $address + * @return bool + */ + private function isDefaultShipping(Address $address) + { + return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultShipping() + || $address->getIsPrimaryShipping() + || $address->getIsDefaultShipping(); + } +} diff --git a/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php b/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php index 8eb841ca25c5a..bd4f2fbfa4bfa 100644 --- a/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php +++ b/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php @@ -10,6 +10,7 @@ use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Module\Manager; use Magento\PageCache\Model\Config; +use Magento\Tax\Api\TaxAddressManagerInterface; use Magento\Tax\Helper\Data; class AfterAddressSaveObserver implements ObserverInterface @@ -33,19 +34,29 @@ class AfterAddressSaveObserver implements ObserverInterface */ private $cacheConfig; + /** + * Manager to save data in customer session. + * + * @var TaxAddressManagerInterface + */ + private $addressManager; + /** * @param Data $taxHelper * @param Manager $moduleManager * @param Config $cacheConfig + * @param TaxAddressManagerInterface $addressManager */ public function __construct( Data $taxHelper, Manager $moduleManager, - Config $cacheConfig + Config $cacheConfig, + TaxAddressManagerInterface $addressManager ) { $this->taxHelper = $taxHelper; $this->moduleManager = $moduleManager; $this->cacheConfig = $cacheConfig; + $this->addressManager = $addressManager; } /** @@ -61,33 +72,7 @@ public function execute(Observer $observer) ) { /** @var $customerAddress Address */ $address = $observer->getCustomerAddress(); - $this->taxHelper->setAddressCustomerSessionAddressSave($address); + $this->addressManager->setDefaultAddressAfterSave($address); } } - - /** - * Check whether specified billing address is default for its customer - * - * @param Address $address - * @return bool - */ - protected function isDefaultBilling($address) - { - return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultBilling() - || $address->getIsPrimaryBilling() - || $address->getIsDefaultBilling(); - } - - /** - * Check whether specified shipping address is default for its customer - * - * @param Address $address - * @return bool - */ - protected function isDefaultShipping($address) - { - return $address->getId() && $address->getId() == $address->getCustomer()->getDefaultShipping() - || $address->getIsPrimaryShipping() - || $address->getIsDefaultShipping(); - } } diff --git a/app/code/Magento/Tax/Observer/CustomerLoggedInObserver.php b/app/code/Magento/Tax/Observer/CustomerLoggedInObserver.php index fd244032be5be..eda7898e9a1b2 100644 --- a/app/code/Magento/Tax/Observer/CustomerLoggedInObserver.php +++ b/app/code/Magento/Tax/Observer/CustomerLoggedInObserver.php @@ -11,6 +11,7 @@ use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Module\Manager; use Magento\PageCache\Model\Config; +use Magento\Tax\Api\TaxAddressManagerInterface; use Magento\Tax\Helper\Data; class CustomerLoggedInObserver implements ObserverInterface @@ -44,25 +45,35 @@ class CustomerLoggedInObserver implements ObserverInterface */ private $groupRepository; + /** + * Manager to save data in customer session. + * + * @var TaxAddressManagerInterface + */ + private $addressManager; + /** * @param GroupRepositoryInterface $groupRepository * @param Session $customerSession * @param Data $taxHelper * @param Manager $moduleManager * @param Config $cacheConfig + * @param TaxAddressManagerInterface $addressManager */ public function __construct( GroupRepositoryInterface $groupRepository, Session $customerSession, Data $taxHelper, Manager $moduleManager, - Config $cacheConfig + Config $cacheConfig, + TaxAddressManagerInterface $addressManager ) { $this->groupRepository = $groupRepository; $this->customerSession = $customerSession; $this->taxHelper = $taxHelper; $this->moduleManager = $moduleManager; $this->cacheConfig = $cacheConfig; + $this->addressManager = $addressManager; } /** @@ -85,7 +96,7 @@ public function execute(Observer $observer) $addresses = $customer->getAddresses(); if (isset($addresses)) { - $this->taxHelper->setAddressCustomerSessionLogIn($addresses); + $this->addressManager->setDefaultAddressAfterLogIn($addresses); } } } diff --git a/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php b/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php index 70831b9f82177..51b1118af415c 100644 --- a/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php +++ b/app/code/Magento/Tax/Test/Unit/Helper/DataTest.php @@ -9,7 +9,6 @@ namespace Magento\Tax\Test\Unit\Helper; use Magento\Framework\DataObject as MagentoObject; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; /** * Class DataTest @@ -18,11 +17,6 @@ */ class DataTest extends \PHPUnit\Framework\TestCase { - /** - * @var ObjectManager - */ - private $objectManager; - /** * @var \Magento\Tax\Helper\Data */ @@ -40,14 +34,9 @@ class DataTest extends \PHPUnit\Framework\TestCase /** @var \PHPUnit_Framework_MockObject_MockObject */ protected $serializer; - /** - * @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject - */ - private $customerSessionMock; - protected function setUp() { - $this->objectManager = new ObjectManager($this); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->orderTaxManagementMock = $this->getMockBuilder(\Magento\Tax\Api\OrderTaxManagementInterface::class) ->disableOriginalConstructor() @@ -76,19 +65,13 @@ function ($value) { return json_decode($value, true); } ); - $this->customerSessionMock = $this->getMockBuilder(\Magento\Customer\Model\Session::class) - ->disableOriginalConstructor() - ->setMethods(['setDefaultTaxBillingAddress', 'setDefaultTaxShippingAddress']) - ->getMock(); - - $this->helper = $this->objectManager->getObject( + $this->helper = $objectManager->getObject( \Magento\Tax\Helper\Data::class, [ 'orderTaxManagement' => $this->orderTaxManagementMock, 'priceCurrency' => $this->priceCurrencyMock, 'taxConfig' => $this->taxConfigMock, - 'serializer' => $this->serializer, - 'customerSession' => $this->customerSessionMock, + 'serializer' => $this->serializer ] ); } @@ -546,122 +529,4 @@ public function dataProviderIsCatalogPriceDisplayAffectedByTax() [false , false, false, true, false] ]; } - - /** - * @test - * @dataProvider setAddressCustomerSessionAddressSaveDataProvider - * - * @param array $addressId - * @param array $billingInfo - * @param array $shippingInfo - * @param bool $needSetShipping - * @param bool $needSetBilling - */ - public function testSetAddressCustomerSessionAddressSave( - $addressId, - $billingInfo, - $shippingInfo, - $needSetShipping, - $needSetBilling - ) { - list($customerDefBillAddId, $isPrimaryBilling, $isDefaultBilling) = $billingInfo; - list($customerDefShipAddId, $isPrimaryShipping, $isDefaultShipping) = $shippingInfo; - - /* @var \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject $address */ - $address = $this->getMockBuilder(\Magento\Customer\Model\Address::class) - ->setMethods([ - 'getId', - 'getCustomer', - 'getIsPrimaryBilling', - 'getIsDefaultBilling', - 'getIsPrimaryShipping', - 'getIsDefaultShipping', - 'getCountryId', - 'getRegion', - 'getPostcode', - ]) - ->disableOriginalConstructor() - ->getMock(); - - $address->expects($this->any())->method('getCountryId')->willReturn(1); - $address->expects($this->any())->method('getRegion')->willReturn(null); - $address->expects($this->any())->method('getPostcode')->willReturn('11111'); - - $address->expects($this->any())->method('getId')->willReturn($addressId); - $address->expects($this->any())->method('getIsPrimaryBilling')->willReturn($isPrimaryBilling); - $address->expects($this->any())->method('getIsDefaultBilling')->willReturn($isDefaultBilling); - $address->expects($this->any())->method('getIsPrimaryShipping')->willReturn($isPrimaryShipping); - $address->expects($this->any())->method('getIsDefaultShipping')->willReturn($isDefaultShipping); - - /* @var \Magento\Customer\Model\Customer|\PHPUnit_Framework_MockObject_MockObject $customer */ - $customer = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) - ->setMethods(['getDefaultBilling', 'getDefaultShipping']) - ->disableOriginalConstructor() - ->getMock(); - $customer->expects($this->any())->method('getDefaultBilling')->willReturn($customerDefBillAddId); - $customer->expects($this->any())->method('getDefaultShipping')->willReturn($customerDefShipAddId); - - $address->expects($this->any())->method('getCustomer')->willReturn($customer); - - $this->customerSessionMock->expects($needSetShipping ? $this->once() : $this->never()) - ->method('setDefaultTaxShippingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); - $this->customerSessionMock->expects($needSetBilling ? $this->once() : $this->never()) - ->method('setDefaultTaxBillingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); - - $this->helper->setAddressCustomerSessionAddressSave($address); - } - - public function setAddressCustomerSessionAddressSaveDataProvider() - { - return [ - [1, [1, false, false], [1, false, false], true, true], - [1, [2, false, false], [2, false, false], false, false], - [1, [2, false, true], [2, false, true], true, true], - [1, [2, true, false], [2, true, false], true, true], - ]; - } - - /** - * @test - * @dataProvider setAddressCustomerSessionLogInDataProvider - * - * @param bool $isAddressDefaultBilling - * @param bool $isAddressDefaultShipping - */ - public function testSetAddressCustomerSessionLogIn( - $isAddressDefaultBilling, - $isAddressDefaultShipping - ) { - /* @var \Magento\Customer\Api\Data\AddressInterface|\PHPUnit_Framework_MockObject_MockObject $address */ - $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) - ->disableOriginalConstructor() - ->getMock(); - - $address->expects($this->any())->method('getCountryId')->willReturn(1); - $address->expects($this->any())->method('getRegion')->willReturn(null); - $address->expects($this->any())->method('getPostcode')->willReturn('11111'); - $address->expects($this->any())->method('isDefaultShipping')->willReturn($isAddressDefaultShipping); - $address->expects($this->any())->method('isDefaultBilling')->willReturn($isAddressDefaultBilling); - - $this->customerSessionMock->expects($isAddressDefaultShipping ? $this->once() : $this->never()) - ->method('setDefaultTaxShippingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); - $this->customerSessionMock->expects($isAddressDefaultBilling ? $this->once() : $this->never()) - ->method('setDefaultTaxBillingAddress') - ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); - - $this->helper->setAddressCustomerSessionLogIn([$address]); - } - - public function setAddressCustomerSessionLogInDataProvider() - { - return [ - [false, false], - [false, true], - [true, false], - [true, true], - ]; - } } diff --git a/app/code/Magento/Tax/Test/Unit/Model/TaxAddressManagerTest.php b/app/code/Magento/Tax/Test/Unit/Model/TaxAddressManagerTest.php new file mode 100644 index 0000000000000..b0698824f040c --- /dev/null +++ b/app/code/Magento/Tax/Test/Unit/Model/TaxAddressManagerTest.php @@ -0,0 +1,163 @@ +objectManager = new ObjectManager($this); + + $this->customerSessionMock = $this->getMockBuilder(\Magento\Customer\Model\Session::class) + ->disableOriginalConstructor() + ->setMethods(['setDefaultTaxBillingAddress', 'setDefaultTaxShippingAddress']) + ->getMock(); + + $this->manager = $this->objectManager->getObject( + TaxAddressManagerInterface::class, + [ + 'customerSession' => $this->customerSessionMock, + ] + ); + } + + /** + * @test + * @dataProvider setAddressCustomerSessionAddressSaveDataProvider + * + * @param array $addressId + * @param array $billingInfo + * @param array $shippingInfo + * @param bool $needSetShipping + * @param bool $needSetBilling + */ + public function testSetDefaultAddressAfterSave( + $addressId, + $billingInfo, + $shippingInfo, + $needSetShipping, + $needSetBilling + ) { + list($customerDefBillAddId, $isPrimaryBilling, $isDefaultBilling) = $billingInfo; + list($customerDefShipAddId, $isPrimaryShipping, $isDefaultShipping) = $shippingInfo; + + /* @var \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject $address */ + $address = $this->getMockBuilder(\Magento\Customer\Model\Address::class) + ->setMethods([ + 'getId', + 'getCustomer', + 'getIsPrimaryBilling', + 'getIsDefaultBilling', + 'getIsPrimaryShipping', + 'getIsDefaultShipping', + 'getCountryId', + 'getRegion', + 'getPostcode', + ]) + ->disableOriginalConstructor() + ->getMock(); + + $address->expects($this->any())->method('getCountryId')->willReturn(1); + $address->expects($this->any())->method('getRegion')->willReturn(null); + $address->expects($this->any())->method('getPostcode')->willReturn('11111'); + + $address->expects($this->any())->method('getId')->willReturn($addressId); + $address->expects($this->any())->method('getIsPrimaryBilling')->willReturn($isPrimaryBilling); + $address->expects($this->any())->method('getIsDefaultBilling')->willReturn($isDefaultBilling); + $address->expects($this->any())->method('getIsPrimaryShipping')->willReturn($isPrimaryShipping); + $address->expects($this->any())->method('getIsDefaultShipping')->willReturn($isDefaultShipping); + + /* @var \Magento\Customer\Model\Customer|\PHPUnit_Framework_MockObject_MockObject $customer */ + $customer = $this->getMockBuilder(\Magento\Customer\Model\Customer::class) + ->setMethods(['getDefaultBilling', 'getDefaultShipping']) + ->disableOriginalConstructor() + ->getMock(); + $customer->expects($this->any())->method('getDefaultBilling')->willReturn($customerDefBillAddId); + $customer->expects($this->any())->method('getDefaultShipping')->willReturn($customerDefShipAddId); + + $address->expects($this->any())->method('getCustomer')->willReturn($customer); + + $this->customerSessionMock->expects($needSetShipping ? $this->once() : $this->never()) + ->method('setDefaultTaxShippingAddress') + ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); + $this->customerSessionMock->expects($needSetBilling ? $this->once() : $this->never()) + ->method('setDefaultTaxBillingAddress') + ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); + + $this->manager->setDefaultAddressAfterSave($address); + } + + public function setAddressCustomerSessionAddressSaveDataProvider() + { + return [ + [1, [1, false, false], [1, false, false], true, true], + [1, [2, false, false], [2, false, false], false, false], + [1, [2, false, true], [2, false, true], true, true], + [1, [2, true, false], [2, true, false], true, true], + ]; + } + + /** + * @test + * @dataProvider setAddressCustomerSessionLogInDataProvider + * + * @param bool $isAddressDefaultBilling + * @param bool $isAddressDefaultShipping + */ + public function testSetDefaultAddressAfterLogIn( + $isAddressDefaultBilling, + $isAddressDefaultShipping + ) { + /* @var \Magento\Customer\Api\Data\AddressInterface|\PHPUnit_Framework_MockObject_MockObject $address */ + $address = $this->getMockBuilder(\Magento\Customer\Api\Data\AddressInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $address->expects($this->any())->method('getCountryId')->willReturn(1); + $address->expects($this->any())->method('getRegion')->willReturn(null); + $address->expects($this->any())->method('getPostcode')->willReturn('11111'); + $address->expects($this->any())->method('isDefaultShipping')->willReturn($isAddressDefaultShipping); + $address->expects($this->any())->method('isDefaultBilling')->willReturn($isAddressDefaultBilling); + + $this->customerSessionMock->expects($isAddressDefaultShipping ? $this->once() : $this->never()) + ->method('setDefaultTaxShippingAddress') + ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); + $this->customerSessionMock->expects($isAddressDefaultBilling ? $this->once() : $this->never()) + ->method('setDefaultTaxBillingAddress') + ->with(['country_id' => 1, 'region_id' => null, 'postcode' => 11111]); + + $this->manager->setDefaultAddressAfterLogIn([$address]); + } + + public function setAddressCustomerSessionLogInDataProvider() + { + return [ + [false, false], + [false, true], + [true, false], + [true, true], + ]; + } +} diff --git a/app/code/Magento/Tax/Test/Unit/Observer/AfterAddressSaveObserverTest.php b/app/code/Magento/Tax/Test/Unit/Observer/AfterAddressSaveObserverTest.php index a76dc0088f895..14d678d02366b 100644 --- a/app/code/Magento/Tax/Test/Unit/Observer/AfterAddressSaveObserverTest.php +++ b/app/code/Magento/Tax/Test/Unit/Observer/AfterAddressSaveObserverTest.php @@ -9,7 +9,9 @@ use Magento\Framework\Module\Manager; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; use Magento\PageCache\Model\Config; +use Magento\Tax\Api\TaxAddressManagerInterface; use Magento\Tax\Helper\Data; +use PHPUnit_Framework_MockObject_MockObject as MockObject; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -45,6 +47,11 @@ class AfterAddressSaveObserverTest extends \PHPUnit\Framework\TestCase */ private $taxHelperMock; + /** + * @var TaxAddressManagerInterface|MockObject + */ + private $addressManagerMock; + /** * @var \Magento\Tax\Observer\AfterAddressSaveObserver */ @@ -67,10 +74,12 @@ protected function setUp() ->getMock(); $this->taxHelperMock = $this->getMockBuilder(\Magento\Tax\Helper\Data::class) - ->setMethods([ - 'isCatalogPriceDisplayAffectedByTax', - 'setAddressCustomerSessionAddressSave', - ]) + ->setMethods(['isCatalogPriceDisplayAffectedByTax']) + ->disableOriginalConstructor() + ->getMock(); + + $this->addressManagerMock = $this->getMockBuilder(TaxAddressManagerInterface::class) + ->setMethods(['setDefaultAddressAfterSave', 'setDefaultAddressAfterLogIn']) ->disableOriginalConstructor() ->getMock(); @@ -80,6 +89,7 @@ protected function setUp() 'taxHelper' => $this->taxHelperMock, 'moduleManager' => $this->moduleManagerMock, 'cacheConfig' => $this->cacheConfigMock, + 'addressManager' => $this->addressManagerMock, ] ); } @@ -121,8 +131,8 @@ public function testExecute( ->method('getCustomerAddress') ->willReturn($address); - $this->taxHelperMock->expects($isNeedSetAddress ? $this->once() : $this->never()) - ->method('setAddressCustomerSessionAddressSave') + $this->addressManagerMock->expects($isNeedSetAddress ? $this->once() : $this->never()) + ->method('setDefaultAddressAfterSave') ->with($address); $this->session->execute($this->observerMock); diff --git a/app/code/Magento/Tax/Test/Unit/Observer/CustomerLoggedInObserverTest.php b/app/code/Magento/Tax/Test/Unit/Observer/CustomerLoggedInObserverTest.php index 20e269dd85d3a..9e15e529288eb 100644 --- a/app/code/Magento/Tax/Test/Unit/Observer/CustomerLoggedInObserverTest.php +++ b/app/code/Magento/Tax/Test/Unit/Observer/CustomerLoggedInObserverTest.php @@ -5,6 +5,9 @@ */ namespace Magento\Tax\Test\Unit\Observer; +use Magento\Tax\Api\TaxAddressManagerInterface; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + class CustomerLoggedInObserverTest extends \PHPUnit\Framework\TestCase { /** @@ -41,6 +44,11 @@ class CustomerLoggedInObserverTest extends \PHPUnit\Framework\TestCase */ protected $taxHelperMock; + /** + * @var TaxAddressManagerInterface|MockObject + */ + private $addressManagerMock; + /** * @var \Magento\Tax\Observer\CustomerLoggedInObserver */ @@ -79,6 +87,11 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); + $this->addressManagerMock = $this->getMockBuilder(TaxAddressManagerInterface::class) + ->setMethods(['setDefaultAddressAfterSave', 'setDefaultAddressAfterLogIn']) + ->disableOriginalConstructor() + ->getMock(); + $this->session = $objectManager->getObject( \Magento\Tax\Observer\CustomerLoggedInObserver::class, [ @@ -86,7 +99,8 @@ protected function setUp() 'customerSession' => $this->customerSessionMock, 'taxHelper' => $this->taxHelperMock, 'moduleManager' => $this->moduleManagerMock, - 'cacheConfig' => $this->cacheConfigMock + 'cacheConfig' => $this->cacheConfigMock, + 'addressManager' => $this->addressManagerMock, ] ); } @@ -148,8 +162,8 @@ public function testExecute() ->method('setCustomerTaxClassId') ->with(1); - $this->taxHelperMock->expects($this->once()) - ->method('setAddressCustomerSessionLogIn') + $this->addressManagerMock->expects($this->once()) + ->method('setDefaultAddressAfterLogIn') ->with([$address]); $this->session->execute($this->observerMock); diff --git a/app/code/Magento/Tax/etc/di.xml b/app/code/Magento/Tax/etc/di.xml index f7b30db6e7bcb..66b23f24e1095 100644 --- a/app/code/Magento/Tax/etc/di.xml +++ b/app/code/Magento/Tax/etc/di.xml @@ -61,6 +61,7 @@ + diff --git a/app/code/Magento/Weee/Observer/AfterAddressSave.php b/app/code/Magento/Weee/Observer/AfterAddressSave.php index 1db48de518548..1644ce43f86f0 100644 --- a/app/code/Magento/Weee/Observer/AfterAddressSave.php +++ b/app/code/Magento/Weee/Observer/AfterAddressSave.php @@ -10,8 +10,8 @@ use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Module\Manager; use Magento\PageCache\Model\Config; +use Magento\Tax\Api\TaxAddressManagerInterface; use Magento\Weee\Helper\Data; -use Magento\Tax\Helper\Data as TaxHelper; class AfterAddressSave implements ObserverInterface { @@ -35,28 +35,28 @@ class AfterAddressSave implements ObserverInterface private $cacheConfig; /** - * Tax helper + * Manager to save data in customer session. * - * @var TaxHelper + * @var TaxAddressManagerInterface */ - private $taxHelper; + private $addressManager; /** * @param Data $weeeHelper * @param Manager $moduleManager * @param Config $cacheConfig - * @param TaxHelper $taxHelper + * @param TaxAddressManagerInterface $addressManager */ public function __construct( Data $weeeHelper, Manager $moduleManager, Config $cacheConfig, - TaxHelper $taxHelper + TaxAddressManagerInterface $addressManager ) { $this->weeeHelper = $weeeHelper; $this->moduleManager = $moduleManager; $this->cacheConfig = $cacheConfig; - $this->taxHelper = $taxHelper; + $this->addressManager = $addressManager; } /** @@ -72,7 +72,7 @@ public function execute(Observer $observer) ) { /** @var $customerAddress Address */ $address = $observer->getCustomerAddress(); - $this->taxHelper->setAddressCustomerSessionAddressSave($address); + $this->addressManager->setDefaultAddressAfterSave($address); } } } diff --git a/app/code/Magento/Weee/Observer/CustomerLoggedIn.php b/app/code/Magento/Weee/Observer/CustomerLoggedIn.php index 258bcba582ac3..8a498d628dabd 100644 --- a/app/code/Magento/Weee/Observer/CustomerLoggedIn.php +++ b/app/code/Magento/Weee/Observer/CustomerLoggedIn.php @@ -10,6 +10,7 @@ use Magento\Framework\Event\ObserverInterface; use Magento\Framework\Module\Manager; use Magento\PageCache\Model\Config; +use Magento\Tax\Api\TaxAddressManagerInterface; use Magento\Weee\Helper\Data; use Magento\Tax\Helper\Data as TaxHelper; @@ -24,11 +25,13 @@ class CustomerLoggedIn implements ObserverInterface * @var Data */ protected $weeeHelper; - + /** - * @var TaxHelper + * Manager to save data in customer session. + * + * @var TaxAddressManagerInterface */ - private $taxHelper; + private $addressManager; /** * Module manager @@ -48,18 +51,18 @@ class CustomerLoggedIn implements ObserverInterface * @param Data $weeeHelper * @param Manager $moduleManager * @param Config $cacheConfig - * @param TaxHelper $taxHelper + * @param TaxAddressManagerInterface $addressManager */ public function __construct( Data $weeeHelper, Manager $moduleManager, Config $cacheConfig, - TaxHelper $taxHelper + TaxAddressManagerInterface $addressManager ) { $this->weeeHelper = $weeeHelper; $this->moduleManager = $moduleManager; $this->cacheConfig = $cacheConfig; - $this->taxHelper = $taxHelper; + $this->addressManager = $addressManager; } /** @@ -77,7 +80,7 @@ public function execute(Observer $observer) $customer = $observer->getData('customer'); $addresses = $customer->getAddresses(); if (isset($addresses)) { - $this->taxHelper->setAddressCustomerSessionLogIn($addresses); + $this->addressManager->setDefaultAddressAfterLogIn($addresses); } } } diff --git a/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php b/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php index 413c7baaa5e65..19f55550bac65 100644 --- a/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php +++ b/app/code/Magento/Weee/Test/Unit/Observer/AfterAddressSaveTest.php @@ -6,6 +6,8 @@ namespace Magento\Weee\Test\Unit\Observer; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; +use Magento\Tax\Api\TaxAddressManagerInterface; +use PHPUnit_Framework_MockObject_MockObject as MockObject; class AfterAddressSaveTest extends \PHPUnit\Framework\TestCase { @@ -37,11 +39,11 @@ class AfterAddressSaveTest extends \PHPUnit\Framework\TestCase * @var \Magento\Weee\Helper\Data|\PHPUnit_Framework_MockObject_MockObject */ private $weeeHelperMock; - + /** - * @var \Magento\Tax\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + * @var TaxAddressManagerInterface|MockObject */ - protected $taxHelperMock; + private $addressManagerMock; /** * @var \Magento\Weee\Observer\AfterAddressSave @@ -67,8 +69,9 @@ protected function setUp() $this->weeeHelperMock = $this->getMockBuilder(\Magento\Weee\Helper\Data::class) ->disableOriginalConstructor() ->getMock(); - - $this->taxHelperMock = $this->getMockBuilder(\Magento\Tax\Helper\Data::class) + + $this->addressManagerMock = $this->getMockBuilder(TaxAddressManagerInterface::class) + ->setMethods(['setDefaultAddressAfterSave', 'setDefaultAddressAfterLogIn']) ->disableOriginalConstructor() ->getMock(); @@ -78,7 +81,7 @@ protected function setUp() 'weeeHelper' => $this->weeeHelperMock, 'moduleManager' => $this->moduleManagerMock, 'cacheConfig' => $this->cacheConfigMock, - 'taxHelper' => $this->taxHelperMock, + 'addressManager' => $this->addressManagerMock, ] ); } @@ -120,8 +123,8 @@ public function testExecute( ->method('getCustomerAddress') ->willReturn($address); - $this->taxHelperMock->expects($isNeedSetAddress ? $this->once() : $this->never()) - ->method('setAddressCustomerSessionAddressSave') + $this->addressManagerMock->expects($isNeedSetAddress ? $this->once() : $this->never()) + ->method('setDefaultAddressAfterSave') ->with($address); $this->session->execute($this->observerMock); diff --git a/app/code/Magento/Weee/Test/Unit/Observer/CustomerLoggedInTest.php b/app/code/Magento/Weee/Test/Unit/Observer/CustomerLoggedInTest.php index 844db7d7f541c..aaca1c237aad1 100644 --- a/app/code/Magento/Weee/Test/Unit/Observer/CustomerLoggedInTest.php +++ b/app/code/Magento/Weee/Test/Unit/Observer/CustomerLoggedInTest.php @@ -5,6 +5,9 @@ */ namespace Magento\Weee\Test\Unit\Observer; +use Magento\Tax\Api\TaxAddressManagerInterface; +use PHPUnit_Framework_MockObject_MockObject as MockObject; + class CustomerLoggedInTest extends \PHPUnit\Framework\TestCase { /** @@ -32,9 +35,9 @@ class CustomerLoggedInTest extends \PHPUnit\Framework\TestCase protected $weeeHelperMock; /** - * @var \Magento\Tax\Helper\Data|\PHPUnit_Framework_MockObject_MockObject + * @var TaxAddressManagerInterface|MockObject */ - private $taxHelperMock; + private $addressManagerMock; /** * @var \Magento\Weee\Observer\CustomerLoggedIn @@ -63,7 +66,8 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); - $this->taxHelperMock = $this->getMockBuilder(\Magento\Tax\Helper\Data::class) + $this->addressManagerMock = $this->getMockBuilder(TaxAddressManagerInterface::class) + ->setMethods(['setDefaultAddressAfterSave', 'setDefaultAddressAfterLogIn']) ->disableOriginalConstructor() ->getMock(); @@ -73,7 +77,7 @@ protected function setUp() 'weeeHelper' => $this->weeeHelperMock, 'moduleManager' => $this->moduleManagerMock, 'cacheConfig' => $this->cacheConfigMock, - 'taxHelper' => $this->taxHelperMock, + 'addressManager' => $this->addressManagerMock, ] ); } @@ -114,8 +118,8 @@ public function testExecute() ->with('customer') ->willReturn($customerMock); - $this->taxHelperMock->expects($this->once()) - ->method('setAddressCustomerSessionLogIn') + $this->addressManagerMock->expects($this->once()) + ->method('setDefaultAddressAfterLogIn') ->with([$address]); $this->session->execute($this->observerMock); diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt index d81c0eb240398..9a2363c16dfc9 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt @@ -173,6 +173,7 @@ Magento/Reports/Model/ResourceModel/Customer/Orders Magento/Sales/Model/ResourceModel/Report Magento/SalesRule/Model Magento/Search/Ui/Component/Listing/Column/Scope +Magento/Tax/Model/Calculation Magento/Vault/Model/Ui Magento/GroupedProduct/Model/ResourceModel/Product/Indexer/Price Magento/AdvancedSalesRule/Model/Rule/Condition/Product From 92a8ea9ab6035bbaa0a5b0804ed39e4c86965140 Mon Sep 17 00:00:00 2001 From: serhii balko Date: Mon, 28 Aug 2017 13:57:30 +0300 Subject: [PATCH 023/151] MAGETWO-56349: [GITHUB] Newsletter Queue doesn't set to local time #5943 #2937 #7560 --- .../app/Magento/Newsletter/Test/Fixture/Queue/Stores.php | 4 +--- .../{UpdateQueueTest.php => CreateNewsletterQueueTest.php} | 4 ++-- .../{UpdateQueueTest.xml => CreateNewsletterQueueTest.xml} | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) rename dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/{UpdateQueueTest.php => CreateNewsletterQueueTest.php} (95%) rename dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/{UpdateQueueTest.xml => CreateNewsletterQueueTest.xml} (79%) diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue/Stores.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue/Stores.php index c0d9e6f1e7e73..17585cd2860b2 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue/Stores.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Fixture/Queue/Stores.php @@ -22,11 +22,9 @@ class Stores extends DataSource * * @var array */ - protected $stores; + private $stores; /** - * Create custom Store if we have block with custom store view. - * * @constructor * @param FixtureFactory $fixtureFactory * @param array $params diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/CreateNewsletterQueueTest.php similarity index 95% rename from dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.php rename to dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/CreateNewsletterQueueTest.php index 2a4aae4bcf0da..7fef2f6545b49 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/CreateNewsletterQueueTest.php @@ -14,7 +14,7 @@ use Magento\Newsletter\Test\Page\Adminhtml\TemplateQueueIndex; /** - * Test to update fields in Newsletter Queue. + * Test to create Newsletter Queue. * * Test Flow: * Preconditions: @@ -31,7 +31,7 @@ * @group Newsletters * @ZephyrId MAGETWO-71653 */ -class UpdateQueueTest extends Injectable +class CreateNewsletterQueueTest extends Injectable { /* tags */ const MVP = 'yes'; diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.xml b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/CreateNewsletterQueueTest.xml similarity index 79% rename from dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.xml rename to dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/CreateNewsletterQueueTest.xml index 02bc8aa7c1c04..7d5b55a14d99d 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/UpdateQueueTest.xml +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/TestCase/CreateNewsletterQueueTest.xml @@ -6,8 +6,8 @@ */ --> - - + + default default_with_stores From 47d69c0e5b1570b70c873c90106c4d28a429cb6e Mon Sep 17 00:00:00 2001 From: serhii balko Date: Mon, 28 Aug 2017 14:00:01 +0300 Subject: [PATCH 024/151] MAGETWO-58987: Copy paste detector fails in Tax module --- app/code/Magento/Tax/Api/TaxAddressManagerInterface.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php b/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php index 0be05a06cda39..6b0d3c2a5009e 100644 --- a/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php +++ b/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php @@ -1,9 +1,7 @@ Date: Mon, 28 Aug 2017 17:10:43 +0300 Subject: [PATCH 025/151] MAGETWO-56349: [GITHUB] Newsletter Queue doesn't set to local time #5943 #2937 #7560 --- .../Newsletter/Test/Block/Adminhtml/Queue/Grid.php | 6 ++++++ .../Test/Constraint/AssertNewsletterQueueInGrid.php | 9 +++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php index bf9004f6caa45..642f3792bd3d9 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Block/Adminhtml/Queue/Grid.php @@ -22,6 +22,12 @@ class Grid extends \Magento\Backend\Test\Block\Widget\Grid 'newsletter_subject' => [ 'selector' => 'input[name="newsletter_subject"]', ], + 'start_at_from' => [ + 'selector' => 'input[name="start_at[from]"]', + ], + 'start_at_to' => [ + 'selector' => 'input[name="start_at[to]"]', + ], ]; /** diff --git a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php index 35606db3e5202..e29c585f0f011 100644 --- a/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php +++ b/dev/tests/functional/tests/app/Magento/Newsletter/Test/Constraint/AssertNewsletterQueueInGrid.php @@ -26,13 +26,18 @@ public function processAssert( TemplateQueueIndex $indexQueue, Queue $queue ) { - $indexQueue->open(); + $startAt = strftime("%b %e, %Y", strtotime($queue->getQueueStartAt())); $filter = [ 'newsletter_subject' => $queue->getNewsletterSubject(), + 'start_at_from' => $startAt, + 'start_at_to' => $startAt, ]; + $indexQueue->open(); + $indexQueue->getQueueTemplateGrid()->search(['newsletter_subject' => $queue->getNewsletterSubject()]); + \PHPUnit_Framework_Assert::assertTrue( - $indexQueue->getQueueTemplateGrid()->isRowVisible($filter), + $indexQueue->getQueueTemplateGrid()->isRowVisible($filter, false, false), 'Newsletter Queue \'' . $queue->getNewsletterSubject() . '\' is absent in grid.' ); } From 6567adedc52471e2900c2930fdd2d1e5d2c5ef36 Mon Sep 17 00:00:00 2001 From: Deepty Thampy Date: Mon, 28 Aug 2017 13:24:42 -0500 Subject: [PATCH 026/151] MAGETWO-71666: Unable to save product after failed attempt - Added functional test --- .../AssertDateInvalidErrorMessage.php | 49 +++++++++ .../ReSavingProductAfterInitialSaveTest.php | 104 ++++++++++++++++++ .../ReSavingProductAfterInitialSaveTest.xml | 26 +++++ 3 files changed, 179 insertions(+) create mode 100644 dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertDateInvalidErrorMessage.php create mode 100644 dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertDateInvalidErrorMessage.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertDateInvalidErrorMessage.php new file mode 100644 index 0000000000000..9ee0175484af8 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertDateInvalidErrorMessage.php @@ -0,0 +1,49 @@ +getMessagesBlock()->getErrorMessage(); + \PHPUnit_Framework_Assert::assertContains( + self::INVALID_DATE_ERROR_MESSAGE, + $actualMessages, + 'Wrong error message is displayed.' + . "\nExpected: " . self::INVALID_DATE_ERROR_MESSAGE + . "\nActual:\n" . $actualMessages + ); + } + + /** + * Returns a string representation of the object + * + * @return string + */ + public function toString() + { + return 'Invalid date range error message is displayed.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php new file mode 100644 index 0000000000000..7bf4afc139619 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php @@ -0,0 +1,104 @@ +productGrid = $productGrid; + $this->newProductPage = $newProductPage; + $this->catalogProductEdit = $catalogProductEdit; + $this->fixtureFactory = $fixtureFactory; + $this->assertDateErrorMessage = $assertDateErrorMessage; + + } + + /** + * Verify the product can be saved successfully after its initial save is failed. + * @param CatalogProductSimple $originalProduct + * @param CatalogProductSimple $productWithValidFromDate + * @param CatalogProductSimple $productWithValidToDate + */ + + public function test(CatalogProductSimple $originalProduct, CatalogProductSimple $productWithValidFromDate, CatalogProductSimple $productWithValidToDate ) + { + $this->productGrid->open(); + $this->productGrid->getGridPageActionBlock()->addProduct('simple'); + $this->newProductPage->getProductForm()->fill($originalProduct); + $this->catalogProductEdit->getProductForm()->fill($productWithValidFromDate); + $this->catalogProductEdit->getFormPageActions()->save(); + $this->assertDateErrorMessage->processAssert($this->catalogProductEdit); + $this->catalogProductEdit->getProductForm()->fill($productWithValidToDate); + $this->catalogProductEdit->getFormPageActions()->save(); + } +} \ No newline at end of file diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.xml new file mode 100644 index 0000000000000..7511792c50341 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.xml @@ -0,0 +1,26 @@ + + + + + + Verify if product is saved successfully after initial save fails + simple-originalProduct-%isolation% + Simple originalProduct %isolation% + simple_originalProduct_%isolation% + Yes + 100 + m/d/y -1 day + 500 + In Stock + 7 + m/d/y +1 day + m/d/y +3 days + + + + From 420300ccc9b01f04f59f88160f43279908f2e5ed Mon Sep 17 00:00:00 2001 From: Deepty Thampy Date: Mon, 28 Aug 2017 14:06:36 -0500 Subject: [PATCH 027/151] MAGETWO-71666: Unable to save product after failed attempt - Added comments to the test --- .../TestCase/Product/ReSavingProductAfterInitialSaveTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php index 7bf4afc139619..fa49f61867cd0 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php @@ -19,9 +19,9 @@ * Steps: * * 1. Login to backend. - * 2. Create a product with special price with invalid from and To dates + * 2. Create a product with invalid from and To dates * 3. Save the product which generates an error messsage - * 4. Modify the special price dates to valid values + * 4. Modify the dates to valid values * 5. Save the product again * 6. Product is saved successfully */ From 8c64127de7f4bd6aa7386b7b12e95655d39386a4 Mon Sep 17 00:00:00 2001 From: pdohogne-magento Date: Thu, 24 Aug 2017 16:58:09 -0500 Subject: [PATCH 028/151] MAGETWO-71648: Disabling temp table removal on non-persistent connections for performance --- .../Search/Adapter/Mysql/TemporaryStorage.php | 19 ++++++-- .../Adapter/Mysql/TemporaryStorageTest.php | 43 ++++++++++++++++--- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/lib/internal/Magento/Framework/Search/Adapter/Mysql/TemporaryStorage.php b/lib/internal/Magento/Framework/Search/Adapter/Mysql/TemporaryStorage.php index 021b9cdf9556b..dcb977bfa2ae8 100644 --- a/lib/internal/Magento/Framework/Search/Adapter/Mysql/TemporaryStorage.php +++ b/lib/internal/Magento/Framework/Search/Adapter/Mysql/TemporaryStorage.php @@ -6,6 +6,8 @@ namespace Magento\Framework\Search\Adapter\Mysql; +use Magento\Framework\App\DeploymentConfig; +use Magento\Framework\App\ObjectManager; use Magento\Framework\DB\Adapter\AdapterInterface; use Magento\Framework\DB\Ddl\Table; use Magento\Framework\DB\Select; @@ -25,12 +27,21 @@ class TemporaryStorage */ private $resource; + /** + * @var DeploymentConfig + */ + private $config; + /** * @param \Magento\Framework\App\ResourceConnection $resource + * @param DeploymentConfig|null $config */ - public function __construct(\Magento\Framework\App\ResourceConnection $resource) - { + public function __construct( + \Magento\Framework\App\ResourceConnection $resource, + DeploymentConfig $config = null + ) { $this->resource = $resource; + $this->config = $config !== null ? $config : ObjectManager::getInstance()->get(DeploymentConfig::class); } /** @@ -117,7 +128,9 @@ private function createTemporaryTable() $connection = $this->getConnection(); $tableName = $this->resource->getTableName(str_replace('.', '_', uniqid(self::TEMPORARY_TABLE_PREFIX, true))); $table = $connection->newTable($tableName); - $connection->dropTemporaryTable($table->getName()); + if ($this->config->get('db/connection/indexer/persistent')) { + $connection->dropTemporaryTable($table->getName()); + } $table->addColumn( self::FIELD_ENTITY_ID, Table::TYPE_INTEGER, diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/TemporaryStorageTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/TemporaryStorageTest.php index 3b274e12e84b3..d71bd447cc578 100644 --- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/TemporaryStorageTest.php +++ b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/TemporaryStorageTest.php @@ -26,6 +26,11 @@ class TemporaryStorageTest extends \PHPUnit\Framework\TestCase */ private $model; + /** + * @var \Magento\Framework\App\DeploymentConfig|\PHPUnit_Framework_MockObject_MockObject + */ + private $config; + protected function setUp() { $this->tableName = 'some_table_name'; @@ -44,9 +49,13 @@ protected function setUp() ->method('getTableName') ->willReturn($this->tableName); + $this->config = $this->getMockBuilder(\Magento\Framework\App\DeploymentConfig::class) + ->disableOriginalConstructor() + ->getMock(); + $this->model = (new ObjectManager($this))->getObject( \Magento\Framework\Search\Adapter\Mysql\TemporaryStorage::class, - ['resource' => $resource] + ['resource' => $resource, 'config' => $this->config] ); } @@ -138,15 +147,38 @@ public function testStoreApiDocuments() $this->assertEquals($result, $table); } + public function testNoDropIfNotPersistent() + { + $this->createTemporaryTable(false); + + $this->adapter->expects($this->never()) + ->method('dropTemporaryTable'); + + // model->createTemporaryTable() is a private method; this will call it + $this->model->storeApiDocuments([]); + } + /** * @return \Magento\Framework\DB\Ddl\Table|\PHPUnit_Framework_MockObject_MockObject */ - private function createTemporaryTable() + private function createTemporaryTable($persistentConnection = true) { + $this->config->expects($this->any()) + ->method('get') + ->with('db/connection/indexer/persistent') + ->willReturn($persistentConnection); + $table = $this->getMockBuilder(\Magento\Framework\DB\Ddl\Table::class) ->disableOriginalConstructor() ->getMock(); - $table->expects($this->at(1)) + + $tableInteractionCount = 0; + if ($persistentConnection) { + $this->adapter->expects($this->once()) + ->method('dropTemporaryTable'); + $tableInteractionCount += 1; + } + $table->expects($this->at($tableInteractionCount)) ->method('addColumn') ->with( TemporaryStorage::FIELD_ENTITY_ID, @@ -155,7 +187,8 @@ private function createTemporaryTable() ['unsigned' => true, 'nullable' => false, 'primary' => true], 'Entity ID' ); - $table->expects($this->at(2)) + $tableInteractionCount += 1; + $table->expects($this->at($tableInteractionCount)) ->method('addColumn') ->with( 'score', @@ -172,8 +205,6 @@ private function createTemporaryTable() ->method('newTable') ->with($this->tableName) ->willReturn($table); - $this->adapter->expects($this->once()) - ->method('dropTemporaryTable'); $this->adapter->expects($this->once()) ->method('createTemporaryTable') ->with($table); From 61176a342127499b428da6f7945a3d1336f7cbbf Mon Sep 17 00:00:00 2001 From: Daniel Renaud Date: Mon, 28 Aug 2017 15:50:39 -0500 Subject: [PATCH 029/151] MAGETWO-71024: [Tech Debt] Skipped unit/integration tests needs to be re-examined. - Avoid relying on current time in unit test --- .../Observer/ProcessCronQueueObserverTest.php | 79 ++++++++++++------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php index 0a7178ad7d126..0db6a598fb56f 100644 --- a/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php +++ b/app/code/Magento/Cron/Test/Unit/Observer/ProcessCronQueueObserverTest.php @@ -12,6 +12,7 @@ /** * Class \Magento\Cron\Test\Unit\Model\ObserverTest * @SuppressWarnings(PHPMD.CouplingBetweenObjects) + * @SuppressWarnings(PHPMD.TooManyFields) */ class ProcessCronQueueObserverTest extends \PHPUnit\Framework\TestCase { @@ -88,6 +89,11 @@ class ProcessCronQueueObserverTest extends \PHPUnit\Framework\TestCase */ protected $scheduleResource; + /** + * @var int + */ + protected $time = 1501538400; + /** * Prepare parameters */ @@ -134,7 +140,7 @@ protected function setUp() $this->dateTimeMock = $this->getMockBuilder(\Magento\Framework\Stdlib\DateTime\DateTime::class) ->disableOriginalConstructor() ->getMock(); - $this->dateTimeMock->expects($this->any())->method('gmtTimestamp')->will($this->returnValue(time())); + $this->dateTimeMock->expects($this->any())->method('gmtTimestamp')->will($this->returnValue($this->time)); $phpExecutableFinder = $this->createMock(\Symfony\Component\Process\PhpExecutableFinder::class); $phpExecutableFinder->expects($this->any())->method('find')->willReturn('php'); @@ -173,7 +179,7 @@ protected function setUp() */ public function testDispatchNoPendingJobs() { - $lastRun = time() + 10000000; + $lastRun = $this->time + 10000000; $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun)); $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(0)); @@ -193,7 +199,7 @@ public function testDispatchNoPendingJobs() */ public function testDispatchNoJobConfig() { - $lastRun = time() + 10000000; + $lastRun = $this->time + 10000000; $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun)); $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(0)); @@ -225,17 +231,19 @@ public function testDispatchNoJobConfig() */ public function testDispatchCanNotLock() { - $lastRun = time() + 10000000; + $lastRun = $this->time + 10000000; $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun)); $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(0)); $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group')); + + $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400); $schedule = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class )->setMethods( ['getJobCode', 'tryLockJob', 'getScheduledAt', '__wakeup', 'save'] )->disableOriginalConstructor()->getMock(); $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('test_job1')); - $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue('-1 day')); + $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue($dateScheduledAt)); $schedule->expects($this->once())->method('tryLockJob')->will($this->returnValue(false)); $abstractModel = $this->createMock(\Magento\Framework\Model\AbstractModel::class); $schedule->expects($this->any())->method('save')->will($this->returnValue($abstractModel)); @@ -269,10 +277,12 @@ public function testDispatchExceptionTooLate() $jobCode = 'test_job1'; $exception = $exceptionMessage . ' Schedule Id: ' . $scheduleId . ' Job Code: ' . $jobCode; - $lastRun = time() + 10000000; + $lastRun = $this->time + 10000000; $this->_cache->expects($this->any())->method('load')->willReturn($lastRun); $this->_scopeConfig->expects($this->any())->method('getValue')->willReturn(0); $this->_request->expects($this->any())->method('getParam')->willReturn('test_group'); + + $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400); $schedule = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class )->setMethods( @@ -290,7 +300,7 @@ public function testDispatchExceptionTooLate() ] )->disableOriginalConstructor()->getMock(); $schedule->expects($this->any())->method('getJobCode')->willReturn($jobCode); - $schedule->expects($this->once())->method('getScheduledAt')->willReturn('-1 day'); + $schedule->expects($this->once())->method('getScheduledAt')->willReturn($dateScheduledAt); $schedule->expects($this->once())->method('tryLockJob')->willReturn(true); $schedule->expects( $this->once() @@ -336,13 +346,14 @@ public function testDispatchExceptionNoCallback() $exceptionMessage = 'No callbacks found'; $exception = new \Exception(__($exceptionMessage)); + $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400); $schedule = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class )->setMethods( ['getJobCode', 'tryLockJob', 'getScheduledAt', 'save', 'setStatus', 'setMessages', '__wakeup', 'getStatus'] )->disableOriginalConstructor()->getMock(); $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('test_job1')); - $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue('-1 day')); + $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue($dateScheduledAt)); $schedule->expects($this->once())->method('tryLockJob')->will($this->returnValue(true)); $schedule->expects( $this->once() @@ -365,10 +376,12 @@ public function testDispatchExceptionNoCallback() $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig)); - $lastRun = time() + 10000000; + $lastRun = $this->time + 10000000; $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun)); - $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(strtotime('+1 day'))); + $this->_scopeConfig->expects($this->any()) + ->method('getValue') + ->will($this->returnValue($this->time + 86400)); $scheduleMock = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class @@ -405,13 +418,15 @@ public function testDispatchExceptionInCallback( ]; $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group')); + + $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400); $schedule = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class )->setMethods( ['getJobCode', 'tryLockJob', 'getScheduledAt', 'save', 'setStatus', 'setMessages', '__wakeup', 'getStatus'] )->disableOriginalConstructor()->getMock(); $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('test_job1')); - $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue('-1 day')); + $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue($dateScheduledAt)); $schedule->expects($this->once())->method('tryLockJob')->will($this->returnValue(true)); $schedule->expects($this->once()) ->method('setStatus') @@ -427,9 +442,11 @@ public function testDispatchExceptionInCallback( $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig)); - $lastRun = time() + 10000000; + $lastRun = $this->time + 10000000; $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun)); - $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(strtotime('+1 day'))); + $this->_scopeConfig->expects($this->any()) + ->method('getValue') + ->will($this->returnValue($this->time + 86400)); $scheduleMock = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class @@ -479,6 +496,7 @@ public function testDispatchRunJob() ]; $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group')); + $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400); $scheduleMethods = [ 'getJobCode', 'tryLockJob', @@ -497,7 +515,7 @@ public function testDispatchRunJob() $scheduleMethods )->disableOriginalConstructor()->getMock(); $schedule->expects($this->any())->method('getJobCode')->will($this->returnValue('test_job1')); - $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue('-1 day')); + $schedule->expects($this->once())->method('getScheduledAt')->will($this->returnValue($dateScheduledAt)); $schedule->expects($this->once())->method('tryLockJob')->will($this->returnValue(true)); // cron start to execute some job @@ -521,9 +539,11 @@ public function testDispatchRunJob() $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig)); - $lastRun = time() + 10000000; + $lastRun = $this->time + 10000000; $this->_cache->expects($this->any())->method('load')->will($this->returnValue($lastRun)); - $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(strtotime('+1 day'))); + $this->_scopeConfig->expects($this->any()) + ->method('getValue') + ->will($this->returnValue($this->time + 86400)); $scheduleMock = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class @@ -573,7 +593,7 @@ public function testDispatchNotGenerate() )->with( $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . 'test_group') )->will( - $this->returnValue(time() + 10000000) + $this->returnValue($this->time + 10000000) ); $this->_cache->expects( $this->at(1) @@ -582,7 +602,7 @@ public function testDispatchNotGenerate() )->with( $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT . 'test_group') )->will( - $this->returnValue(time() - 10000000) + $this->returnValue($this->time - 10000000) ); $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(0)); @@ -641,14 +661,14 @@ public function testDispatchGenerate() 'load' )->with( $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_HISTORY_CLEANUP_AT . 'default') - )->willReturn(time() + 10000000); + )->willReturn($this->time + 10000000); $this->_cache->expects( $this->at(1) )->method( 'load' )->with( $this->equalTo(ProcessCronQueueObserver::CACHE_KEY_LAST_SCHEDULE_GENERATE_AT . 'default') - )->willReturn(time() - 10000000); + )->willReturn($this->time - 10000000); $this->_scopeConfig->expects($this->any())->method('getValue')->willReturnMap( [ @@ -699,20 +719,21 @@ public function testDispatchCleanup() 'test_group' => ['test_job1' => ['instance' => 'CronJob', 'method' => 'execute']], ]; + $dateExecutedAt = date('Y-m-d H:i:s', $this->time - 86400); $schedule = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class )->disableOriginalConstructor()->setMethods( ['getExecutedAt', 'getStatus', 'delete', '__wakeup'] )->getMock(); - $schedule->expects($this->any())->method('getExecutedAt')->will($this->returnValue('-1 day')); + $schedule->expects($this->any())->method('getExecutedAt')->will($this->returnValue($dateExecutedAt)); $schedule->expects($this->any())->method('getStatus')->will($this->returnValue('success')); $this->_request->expects($this->any())->method('getParam')->will($this->returnValue('test_group')); $this->_collection->addItem($schedule); $this->_config->expects($this->exactly(2))->method('getJobs')->will($this->returnValue($jobConfig)); - $this->_cache->expects($this->at(0))->method('load')->will($this->returnValue(time() + 10000000)); - $this->_cache->expects($this->at(1))->method('load')->will($this->returnValue(time() - 10000000)); + $this->_cache->expects($this->at(0))->method('load')->will($this->returnValue($this->time + 10000000)); + $this->_cache->expects($this->at(1))->method('load')->will($this->returnValue($this->time - 10000000)); $this->_scopeConfig->expects($this->any())->method('getValue')->will($this->returnValue(0)); @@ -749,7 +770,7 @@ public function testMissedJobsCleanedInTime() )->disableOriginalConstructor()->getMock(); $scheduleMock->expects($this->any())->method('getCollection')->will($this->returnValue($this->_collection)); //get configuration value CACHE_KEY_LAST_HISTORY_CLEANUP_AT in the "_cleanup()" - $this->_cache->expects($this->at(0))->method('load')->will($this->returnValue(time() - 10000000)); + $this->_cache->expects($this->at(0))->method('load')->will($this->returnValue($this->time - 10000000)); $this->_scheduleFactory->expects($this->at(0))->method('create')->will($this->returnValue($scheduleMock)); /* 2. Initialize dependencies of _generate() method which is called second */ @@ -757,10 +778,11 @@ public function testMissedJobsCleanedInTime() 'test_group' => ['test_job1' => ['instance' => 'CronJob', 'method' => 'execute']], ]; //get configuration value CACHE_KEY_LAST_HISTORY_CLEANUP_AT in the "_generate()" - $this->_cache->expects($this->at(2))->method('load')->will($this->returnValue(time() + 10000000)); + $this->_cache->expects($this->at(2))->method('load')->will($this->returnValue($this->time + 10000000)); $this->_scheduleFactory->expects($this->at(2))->method('create')->will($this->returnValue($scheduleMock)); - // This item was scheduled 2 days ago + // This item was scheduled 2 days and 2 hours ago + $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 180000); /** @var \Magento\Cron\Model\Schedule|\PHPUnit_Framework_MockObject_MockObject $schedule1 */ $schedule1 = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class @@ -768,20 +790,21 @@ public function testMissedJobsCleanedInTime() ['getExecutedAt', 'getScheduledAt', 'getStatus', 'delete', '__wakeup'] )->getMock(); $schedule1->expects($this->any())->method('getExecutedAt')->will($this->returnValue(null)); - $schedule1->expects($this->any())->method('getScheduledAt')->will($this->returnValue('-2 day -2 hour')); + $schedule1->expects($this->any())->method('getScheduledAt')->will($this->returnValue($dateScheduledAt)); $schedule1->expects($this->any())->method('getStatus')->will($this->returnValue(Schedule::STATUS_MISSED)); //we expect this job be deleted from the list $schedule1->expects($this->once())->method('delete')->will($this->returnValue(true)); $this->_collection->addItem($schedule1); // This item was scheduled 1 day ago + $dateScheduledAt = date('Y-m-d H:i:s', $this->time - 86400); $schedule2 = $this->getMockBuilder( \Magento\Cron\Model\Schedule::class )->disableOriginalConstructor()->setMethods( ['getExecutedAt', 'getScheduledAt', 'getStatus', 'delete', '__wakeup'] )->getMock(); $schedule2->expects($this->any())->method('getExecutedAt')->will($this->returnValue(null)); - $schedule2->expects($this->any())->method('getScheduledAt')->will($this->returnValue('-1 day')); + $schedule2->expects($this->any())->method('getScheduledAt')->will($this->returnValue($dateScheduledAt)); $schedule2->expects($this->any())->method('getStatus')->will($this->returnValue(Schedule::STATUS_MISSED)); //we don't expect this job be deleted from the list $schedule2->expects($this->never())->method('delete'); From d7f73f830d7f67633d355fb46339c74cbff98c35 Mon Sep 17 00:00:00 2001 From: serhii balko Date: Tue, 29 Aug 2017 10:25:36 +0300 Subject: [PATCH 030/151] MAGETWO-58987: Copy paste detector fails in Tax module --- app/code/Magento/Tax/Api/TaxAddressManagerInterface.php | 3 ++- app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php | 2 +- .../Magento/Tax/Test/Unit/Model/TaxAddressManagerTest.php | 6 +++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php b/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php index 6b0d3c2a5009e..8eaa57e078d53 100644 --- a/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php +++ b/app/code/Magento/Tax/Api/TaxAddressManagerInterface.php @@ -3,6 +3,7 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + namespace Magento\Tax\Api; use Magento\Customer\Model\Address; @@ -27,4 +28,4 @@ public function setDefaultAddressAfterSave(Address $address); * @return void */ public function setDefaultAddressAfterLogIn(array $addresses); -} \ No newline at end of file +} diff --git a/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php b/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php index bd4f2fbfa4bfa..025a16a1aea55 100644 --- a/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php +++ b/app/code/Magento/Tax/Observer/AfterAddressSaveObserver.php @@ -36,7 +36,7 @@ class AfterAddressSaveObserver implements ObserverInterface /** * Manager to save data in customer session. - * + * * @var TaxAddressManagerInterface */ private $addressManager; diff --git a/app/code/Magento/Tax/Test/Unit/Model/TaxAddressManagerTest.php b/app/code/Magento/Tax/Test/Unit/Model/TaxAddressManagerTest.php index b0698824f040c..ec640b74f8985 100644 --- a/app/code/Magento/Tax/Test/Unit/Model/TaxAddressManagerTest.php +++ b/app/code/Magento/Tax/Test/Unit/Model/TaxAddressManagerTest.php @@ -6,7 +6,7 @@ namespace Magento\Tax\Test\Unit\Model; use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; -use Magento\Tax\Api\TaxAddressManagerInterface; +use Magento\Tax\Model\TaxAddressManager; use \PHPUnit_Framework_MockObject_MockObject as MockObject; class TaxAddressManagerTest extends \PHPUnit\Framework\TestCase @@ -17,7 +17,7 @@ class TaxAddressManagerTest extends \PHPUnit\Framework\TestCase private $objectManager; /** - * @var TaxAddressManagerInterface + * @var TaxAddressManager */ private $manager; @@ -36,7 +36,7 @@ protected function setUp() ->getMock(); $this->manager = $this->objectManager->getObject( - TaxAddressManagerInterface::class, + TaxAddressManager::class, [ 'customerSession' => $this->customerSessionMock, ] From 56d05dafa13ac87b12a1a3725c60c92da83e049e Mon Sep 17 00:00:00 2001 From: Andrei Malets Date: Tue, 29 Aug 2017 15:12:29 +0300 Subject: [PATCH 031/151] MAGETWO-72076: Update benchmark.jmx and README files in Performance Toolkit, add performance analytics script --- setup/performance-toolkit/README.md | 311 + setup/performance-toolkit/README.txt | 91 - .../aggregate-report/b2c_mappings.php | 779 + .../aggregate-report/generate.php | 299 + setup/performance-toolkit/benchmark.jmx | 29871 ++++++++++++---- .../files/downloadable_original.txt | 1 + .../files/downloadable_sample.txt | 1 + .../files/search_terms.csv | 10 + .../files/search_terms_filter.csv | 10 + 9 files changed, 24852 insertions(+), 6521 deletions(-) create mode 100644 setup/performance-toolkit/README.md delete mode 100644 setup/performance-toolkit/README.txt create mode 100644 setup/performance-toolkit/aggregate-report/b2c_mappings.php create mode 100644 setup/performance-toolkit/aggregate-report/generate.php create mode 100644 setup/performance-toolkit/files/downloadable_original.txt create mode 100644 setup/performance-toolkit/files/downloadable_sample.txt create mode 100644 setup/performance-toolkit/files/search_terms.csv create mode 100644 setup/performance-toolkit/files/search_terms_filter.csv diff --git a/setup/performance-toolkit/README.md b/setup/performance-toolkit/README.md new file mode 100644 index 0000000000000..d29e752a34985 --- /dev/null +++ b/setup/performance-toolkit/README.md @@ -0,0 +1,311 @@ +## Performance Toolkit + +## Overview + +The Performance Toolkit enables you to test the performance of your Magento installations and the impact of your customizations. It allows you to generate sample data for testing performance and torun Apache JMeter scenarios, which imitate users activity. As a result, you get a set of metrics, that you can use to judge how changes affect performance, and the overall load capacity of your server(s). + +## Installation + +### Apache JMeter + +- Go tothe [Download Apache JMeter](http://jmeter.apache.org/download_jmeter.cgi) page and download JMeter in the *Binaries* section. Note that Java 8 or later is required. +- Unzip the archive. + +### JSON Plugins +- Go to the [JMeter Installing Plugins](https://jmeter-plugins.org/install/Install/) page. +- Download `plugins-manager.jar` and put it into the `{JMeter path}/lib/ext` directory. Then restart JMeter. +- Follow the instructions provided on the [JMeter Plugins Manager](https://jmeter-plugins.org/wiki/PluginsManager/) page to open Plugins Manager. +- Select *Json Plugins* from the plugins listed on the *Available Plugins* tab, then click the *Apply changes and restart JMeter* button. + +## Quick Start + +Before running the JMeter tests for the first time, you will need to first use the `php bin/magento setup:performance:generate-fixtures {profile path}` command to generate the test data. You can find the configuration files of available profiles in the folders `setup/performance-toolkit/profiles/ce` and `setup/performance-toolkit/profiles/ee`. + +It can take a significant amount of time to generate a profile. For example, generating the medium profile takes up to 6 hours, while generating the large profile can take up to 22 hours. So we recommend using the `-s` option to skip indexation. Then you can start indexation manually. + +Splitting generation and indexation processes doesn't reduce total processing time, but it requires fewer resources. For example, to generate a small profile, use commands: + + php bin/magento setup:performance:generate-fixtures -s setup/performance-toolkit/profiles/ce/small.xml + php bin/magento indexer:reindex + +For more information about the available profiles and generating fixtures generation, read [Generate data for performance testing](http://devdocs.magento.com/guides/v2.2/config-guide/cli/config-cli-subcommands-perf-data.html). + +**Note:** Before generating medium or large profiles, it may be necessary to increase the value of `tmp_table_size` and `max_heap_table_size` parameters for MySQL to 512Mb or more. The value of `memory_limit` for PHP should be 1Gb or more. + +There are two JMeter scenarios located in `setup/performance-toolkit` folder: `benchmark.jmx` and `benchmark_2015.jmx` (legacy version). + +**Note:** To be sure that all quotes are empty, run the following MySQL query before each run of a scenario: + + UPDATE quote SET is_active = 0 WHERE is_active = 1; + +### Run JMeter scenario via console + +The following parameters can be passed to the `benchmark.jmx` scenario: + +| Parameter Name | Default Value | Description | +| --------------------------------- | ------------------- | ---------------------------------------------------------------------------------------- | +| host | | URL component 'host' of application being tested (URL or IP). | +| base_path | | Base path for tested site. | +| admin_path | backend | Admin backend path. | +| admin_user | admin | Admin backend user. | +| admin_password | 123123q | Admin backend password. | +| customer_password | 123123q | Storefront customer password. | +| customers_page_size | 20 | Page size for customers grid in Magento Admin. | +| files_folder | ./files/ | Path to various files that are used in scenario (`setup/performance-toolkit/files`). | +| loops | 1 | Number of loops to run. | +| orders_page_size | 500 | Page size for orders grid. | +| test_duration | 900 | Total duration (s) of scenario execution. | +| numberOfThreads | 48 | Total number of all threads. | +| frontEndPoolPercentage | 90 | Percentage of Frontend Pool. | +| adminPoolPercentage | 10 | Percentage of Admin Pool. | +| browseCatalogPercentage | 30 | Percentage of threads in Frontend Pool that emulate catalog browsing activities. | +| siteSearchPercentage | 30 | Percentage of threads in Frontend Pool that emulate catalog search activities. | +| checkoutByGuestPercentage | 4 | Percentage of threads in Frontend Pool that emulate checkout by guest. | +| checkoutByCustomerPercentage | 4 | Percentage of threads in Frontend Pool that emulate checkout by customer. | +| addToCartPercentage | 28 | Percentage of threads in Frontend Pool that emulate abandoned cart activities. | +| addToWishlistPercentage | 2 | Percentage of threads in Frontend Pool that emulate adding products to Wishlist. | +| compareProductsPercentage | 2 | Percentage of threads in Frontend Pool that emulate products comparison. | +| productCompareDelay | 0 | Delay (s) between iterations of product comparison. | +| promotionRulesPercentage | 10 | Percentage of threads in Admin Pool that emulate creation of promotion rules. | +| adminPromotionsManagementDelay | 0 | Delay (s) between creation of promotion rules. | +| merchandizingPercentage | 50 | Percentage of threads in Admin Pool that emulate merchandizing activities. | +| adminProductManagementPercentage | 90 | Percentage of threads in Merchandizing Pool that emulate product management activities. | +| adminCategoryManagementPercentage | 10 | Percentage of threads in Merchandizing Pool that emulate category management activities. | +| adminProductEditingPercentage | 60 | Percentage of threads in Product Management Pool that emulate product editing. | +| adminProductCreationPercentage | 40 | Percentage of threads in Product Management Pool that emulate creation of products. | +| adminCategoryManagementDelay | 0 | Delay (s) between iterations of category management activities. | +| apiProcessOrdersPercentage | 30 | Percentage of threads in Admin Pool that emulate orders processing activities. | +| adminProcessReturnsPercentage | 10 | Percentage of threads in Admin Pool that emulate creation/processing of returns. | +| csrPoolPercentage | 0 | Percentage of CSR Pool. | +| csrBrowseCustomersPercentage | 10 | Percentage of threads in CSR Pool that emulate customers browsing activities. | +| csrCreateOrderPercentage | 70 | Percentage of threads in CSR Pool that emulate creation of orders. | +| csrCreateProcessReturnsPercentage | 20 | Percentage of threads in CSR Pool that emulate creation/processing of returns. | +| csrCreateProcessReturnsDelay | 0 | Delay (s) between creation of returns. | +| wishlistDelay | 0 | Delay (s) between adding products to Wishlist. | +| categories_count | 200 | Total number of categories that are be used in scenario. | +| simple_products_count | 30 | Total number of simple products that are be used in scenario. | +| nested_categories_count | 50 | Total number of last-level categories that can be used in scenario. | + +Parameters must be passed to command line with the `J` prefix: + +`-J{parameter_name}={parameter_value}` + +The required parameters are `{host}` and `{base_path}`. All other parameters are optional. If you do not pass any custom value, a default value will be used. + +There are some options that you should pass to JMeter in the console mode: + +`-n` Run scenario in Non-GUI mode +`-t` Path to the JMX file to be run +`-l` Path to the JTL file to log sample results to +`-j` Path to JMeter run log file + +To get more details about available JMeter options, read [Non-GUI Mode](http://jmeter.apache.org/usermanual/get-started.html#non_gui). + +For example, you can run a scenario via console with 100 threads for 5 minutes as follows: + + cd {JMeter path}/bin/ + jmeter -n -t {path to peformance toolkit}/benchmark.jmx -j ./jmeter.log -l ./jmeter-results.jtl -Jhost=magento2.dev -Jbase_path=/ -Jadmin_path=admin -Jtest_duration=300 -JnumberOfThreads=100 + +As a result, you will get `jmeter.log` and `jmeter-results.jtl`. The`jmeter.log` contains information about the test run and can be helpful in determining the cause of an error. The JTL file is a text file containing the results of a test run. It can be opened in GUI mode to perform analysis of the results (see the *Output* section below). + + +The following parameters can be passed to the `benchmark_2015.jmx` scenario: + +| Parameter Name | Default Value | Description | +| -------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | +| host | localhost | URL component 'host' of application being tested (URL or IP). | +| base_path | / | Base path for tested site. | +| report_save_path | ./ | Path where reports will be saved. Reports will be saved in current working directory by default. | +| ramp_period | 300 | Ramp period (seconds). Period the request will be distributed within. | +| orders | 0 | Number of orders in the period specified in the current allocation. If `orders` is specified, the `users` parameter will be recalculated. | +| users | 100 | Number of concurrent users. Recommended amount is 100. Minimal amount is 10. | +| view_product_add_to_cart_percent | 62 | Percentage of users that will only reach the add to cart stage. | +| view_catalog_percent | 30 | Percentage of users that will only reach the view catalog stage. | +| guest_checkout_percent | 4 | Percentage of users that will reach the guest checkout stage. | +| customer_checkout_percent | 4 | Percentage of users that will reach the (logged-in) customer checkout stage. | +| loops | 1 | Number of loops to run. | +| admin_path | admin | Admin backend path. | +| admin_user | admin | Admin backend user. | +| admin_password | 123123q | Admin backend password. | +| think_time_deviation | 1000 | Deviation (ms) for "think time" emulation. | +| think_time_delay_offset | 2000 | Constant delay offset (ms) for "think time" emulation. | + +### Run JMeter scenario via GUI + +**Note:** Use the GUI mode only for scenario debugging and viewing reports. Use the console mode for real-life load testing, because it requires significantly fewer resources. + +- Change directories to `{JMeter path}/bin/` and run `jmeter.bat`. +- Click *File -> Open (Ctrl+O)* and select `benchmark.jmx` file or drag and drop the `benchmark.jmx` file in the opened GUI. + +In the root node (*Performance Test Plan*) in the left panel, you can change *User Defined Variables* listed in the previous section. +To run a script, click the *Start* button (green arrow in the top menu). + +## Output + +The results of running a JMeter scenario are available in the *View Results Tree* and *Aggregate Report* nodes in the left panel of the JMeter GUI. + +When the script is run via GUI, the results are available in the left panel. Choose the corresponding report. When the script is run via console, a JTL report is generated. You can run JMeter GUI later and open it in the corresponding report node. + +The legacy scenario (Benchmark_2015) contains *View Results Tree*, *Detailed URLs Report* and *Summary Report* nodes. + +### View Results Tree + +This report shows the tree of all requests and responses made during the scenario run. It provides information about the response time, headers and response codes. This report is useful for scenario debugging, but should be disabled during load testing because it consumes a lot of resources. + +You can open a JTL file in this report to debug a scenario and view the requests that cause errors. By default, a JTL file doesn't contain bodies of requests/responses, so it is better to debug scenarios in the GUI mode. + +For more details, read [View Results Tree](http://jmeter.apache.org/usermanual/component_reference.html#View_Results_Tree). + +### Aggregate Report + +This report contains aggregated information about all requests. It provides request count, min, max, average, error rate, approximate throughput, etc. You can open a JTL file in this report to analyze the results of a scenario run. + +For more details, read [Aggregate Report](http://jmeter.apache.org/usermanual/component_reference.html#Aggregate_Report). + +### Detailed URLs Report (Legacy) + +This report contains information about URLs. Note that the URL is displayed only in a generated report file (URL is not displayed in the GUI). The report file name is `{report_save_path}/detailed-urls-report.log`. It can be opened as a CSV file. + +For more details, read [View Results in Table](http://jmeter.apache.org/usermanual/component_reference.html#View_Results_in_Table). + +### Summary Report (Legacy) + +The report contains aggregated information about threads. The report file name is `{report_save_path}/summary-report.log`. + +For more details, read [Summary Report](http://jmeter.apache.org/usermanual/component_reference.html#Summary_Report). + +## Additional Information + +### Threads + +`benchmark.jmx` scenario has the following thread groups and default percentage breakdown: + +- **Frontend Pool** (90%) + +| Thread Group Name | Label Suffix | % of Pool | +| ------------------------- | ------------------------------------------------------ | --------- | +| Catalog Browsing By Guest | Catalog Browsing By Guest | 30 | +| Site Search | SearchQuick, SearchQuickWithFilter and SearchAdvanced | 30 | +| Add To Cart (Guest) | Add To Cart By Guest | 28 | +| Add to Wishlist | WishList | 2 | +| Compare Products | Product Compare By Guest | 2 | +| Checkout By Guest | Checkout By Guest | 4 | +| Checkout By Customer | Checkout By Customer | 4 | + +Site Search thread group contains 3 variations: +- Quick Search (65%) +- Quick Search With Filtering (35%) +- Advanced Search (5%) + +- **Admin Pool** (10%) + +| Thread Group Name | Label Suffix | % of Pool | +| ----------------------------------------- | ------------ | --------- | +| *Merchandizing Pool* (see below) | - | 50 | +| Admin Promotion Rules | - | 10 | +| Admin API - Process Orders | - | 30 | +| Admin Create/Process Returns | - | 10 | + +*Merchandizing Pool* (50% of Admin Pool) + +| Thread Group Name | Label Suffix | % of Pool | +| ----------------------------------------- | ------------ | --------- | +| *Product Management Pool* (see below) | - | 90 | +| Admin Category Management (Merchandizing) | - | 10 | + +*Product Management Pool* (90% of Merchandizing Pool) + +| Thread Group Name | Label Suffix | % of Pool | +| ----------------------------------------- | ------------ | --------- | +| Admin Edit Product (Merchandizing) | - | 60 | +| Admin Create Product (Merchandizing) | - | 40 | + +- **CSR Pool** (0%) + +| Thread Group Name | Label Suffix | % of Pool | +| -------------------------- | ------------ | --------- | +| CSR Browse Customers | - | 10 | +| CSR Create Order | - | 70 | +| CSR Create/Process Returns | - | 20 | + +The number of threads in each group can be calculated by formula: + + N = {numberOfThreads} * {poolPercentage} * {threadGroupPercentage} / 10000 + +For example, the value of {numberOfThreads} parameter is 100 and we want to get the number of threads in the *Checkout By Guest* group: + + N = 100 * 90 * 4 / 10000 = 4 + +The *Merchandizing Pool* and the *Product Management Pool* should be taken into account when the number of product or category management threads needs to be calculated. For example, the number of threads in *Admin Create Product (Merchandizing)* group is calculated as follows: + + N = {numberOfThreads} * {adminPoolPercentage} * {merchandizingPercentage} * {adminProductManagementPercentage} * {adminProductCreationPercentage} / 100 / 100 / 100 / 100 + +If {numberOfThreads} equals to 100: + + N = 100 * 10 * 50 * 90 * 40 / 100000000 = 2 + +To change the percentage breakdown, pass custom values for each pool or thread group to the script. For example, to run the scenario with *Frontend Pool* only enabled, run the script with the following parameters + + -JfrontEndPoolPercentage=100 -JadminPoolPercentage=0 -JcsrPoolPercentage=0. + +**Legacy Threads** + +The `benchmark_2015.jmx` script consists of five thread groups: the setup thread and four user threads. +By default, the percentage ratio between thread groups is as follows: +- Browsing, adding items to the cart and abandon cart (BrowsAddToCart suffix in reports) - 62% +- Just browsing (CatProdBrows suffix in reports) - 30% +- Browsing, adding items to cart and checkout as guest (GuestChkt suffix in reports) - 4% +- Browsing, adding items to cart and checkout as registered customer (CustomerChkt suffix in reports) - 4% + +### Results Interpretation + +In order to build an aggregate report from the results of the `benchmark.kmx` scenario run, use the script `generate.php` in the folder `setup/performance-toolkit/aggregate-report`. + +The script parses the JTL file and generates an aggregate report in CSV format. The report consists of the 4 sections separated by two empty lines: + +1. Summary information: Checkouts Per Hour, Page Views Per Hour and Test Duration (in seconds) +2. Aggregated information about all requests within each thread group (median time, average time, min/max, amount of hits per hour, etc.) +3. Aggregated information about common requests (open home page, category page, product page, login, etc.) accross the entire scenario +4. List of the requests that weren't executed during the scenario run + +Also, the aggregate report can include information about the memory usage for each request type. This requires additional configuration. You should add the following code at the end of `pub/index.php`: + + if (strpos($_SERVER['REQUEST_URI'], '/banner/ajax/load/') === false) { + if (!file_exists('../var/log/memory_usage.log')) { + file_put_contents('../var/log/memory_usage.log', str_pad('Usage', 12, ' ', STR_PAD_LEFT) . ' ' . str_pad('Real Usage', 12, ' ', STR_PAD_LEFT) . ' URI' . "\n", FILE_APPEND | LOCK_EX); + } + $result = str_pad(memory_get_peak_usage(), 12, ' ', STR_PAD_LEFT) . ' ' . str_pad(memory_get_peak_usage(true), 12, ' ', STR_PAD_LEFT) . ' ' . $_SERVER['REQUEST_URI']; + file_put_contents('../var/log/memory_usage.log', $result . "\n", FILE_APPEND | LOCK_EX); + } +After that, the information about memory usage for each request will be logged in the file `var/log/memory_usage.log`. + +To generate the aggregate report, run the following command from the Magento root directory: + + php setup/performance-toolkit/aggregate-report/generate.php -j {path to folder with JTL file}/jmeter_report.jtl -m var/log/memory_usage.log -o aggregate_report.csv + +**Legacy Scenario** + +It is convenient to use *Summary Report* for the results analysis. To evaluate the number of each request per hour, use the value in the *Throughput* column. + +To get the summary value of throughput for some action: +1. Find all rows that relate to the desired action +2. Convert values from *Throughput* column to a common denominator +3. Sum up the obtained values + +For example, to get summary throughput for the *Simple Product View* action when the following rows are present in the *Summary Report*: + +| Label | # Samples | ... | Throughput | +| ------------------------------------- | --------------- | --- | ---------- | +| ... | ... | ... | ... | +| Open Home Page(CatProdBrows) | 64 | ... | 2.2/sec | +| Simple Product 1 View(GuestChkt) | 4 | ... | 1.1/sec | +| Simple Product 2 View(BrowsAddToCart) | 30 | ... | 55.6/min | +| ... | ... | ... | ... | + +Find all rows with the label *Simple Product # View* and calculate the summary throughput: + + 1.1/sec + 55.6/min = 66/min + 55.6/min = 121.6/min = 2.02/sec + +If you need information about the summary throughput of the *Checkout* actions, find the rows with labels *Checkout success* and make the same calculation. + +For the total number of page views, sum up all actions, minus the setup thread. diff --git a/setup/performance-toolkit/README.txt b/setup/performance-toolkit/README.txt deleted file mode 100644 index 09c9b57965e5f..0000000000000 --- a/setup/performance-toolkit/README.txt +++ /dev/null @@ -1,91 +0,0 @@ -Performance Toolkit -============= - -Installation ------------ -jMeter: --- go to http://jmeter.apache.org/download_jmeter.cgi and download jMeter in Binary section (pay you attention that Java 6 or later is required) --- unzip archive - -Json Plugins: --- go to https://jmeter-plugins.org/install/Install/ --- download plugins-manager.jar and put it into /lib/ext directory, then restart JMeter --- follow instructions from https://jmeter-plugins.org/wiki/PluginsManager/ to open Plugins Manager --- select Json Plugins in plugins listing from "Available Plugins" tab, then click "Apply changes and restart JMeter" button - - -Usage ------------ -Before running the jMeter tests for the first time, you will need to first use bin/magento setup:performance:generate-fixtures command to generate the test data. - -1. Run via console -Scenario can accept parameters that are described bellow in format : - - URL component 'host' of application being tested (URL or IP). Default is 'localhost'. - Base path for tested site. Default is '/'. - Path where reports will be saved. Reports will be saved in current working directory by default. Default is './'. - Ramp period (seconds). Period the request will be distributed within. Default is '300'. - Number of orders in the period specified in the current allocation. If is specified, the parameter will be recalculated. Default is '0'. - Number of concurrent users. Recommended amount is 100. Minimal amount is 10. Default is '100'. - Percentage of users that will only reach the add to cart stage. Default is '62'. - Percentage of users that will only reach the view catalog stage. Default is '30'. - Percentage of users that will reach the guest checkout stage. Default is '4'. - Percentage of users that will reach the (logged-in) customer checkout stage. Default is '4'. - Number of loops to run. Default is '1'. - Admin backend path. Default is 'admin'. - Admin backend user. Default is 'admin'. - Admin backend password. Default is '123123q'. - Deviation (ms) for "think time" emulation. Default is '1000'. - Constant delay offset (ms) for "think time" emulation. Default is '2000'. - -Necessary parameters must be passed to command line with "J" prefix: "-J=" - -Example: -> cd /directory_of_jMeter/bin/ -> jmeter -n -t /path_to_benchmark_file/benchmark.jmx -Jhost=magento2.dev -Jbase_path=/ -Jusers=100 -Jramp_period=300 -Jreport_save_path=./ - -2. Run via GUI --- Open jMeter/bin directory and run jmeter.bat --- Click in menu File -> Open (Ctrl+O) and select file; or drag and drop benchmark.jmx file in opened GUI. - -On the first tab 'Test Toolkit' you can change 'User Defined variables' like as , , , , . -For running script click "Start" (green arrow in the top menu). - - -Results of running (Report types) ------------ - -After running via GUI you can see result of working in left panel. Choose the corresponding report. -After running script via console report will be generated in the path that has been specified in . - - -Threads ------------ - -jMeter script consists of five threads. Setup thread and four user threads. -Percentage ratio between threads is as follows: -Browsing, adding items to the cart and abandon cart (BrowsAddToCart suffix in reports) - 62% -Just browsing (BrowsAddToCart suffix in reports) - 30% -Browsing, adding items to cart and checkout it as guest (GuestChkt suffix in reports) - 4% -Browsing, adding items to cart and checkout as registered customer (CustomerChkt suffix in reports) - 4% - - -About reports: ------------ - -Summary Report. -Report contains aggregated information about threads. -Report file name is {report_save_path}/summary-report.log -Details http://jmeter.apache.org/usermanual/component_reference.html#Summary_Report - -Detailed URLs report. -Report contains information about URLs. -Pay your attention that URL is displayed only in generated report file (in GUI, URL is not displayed). -Report file name is {report_save_path}/detailed-urls-report.log (can be open as csv format). -Details http://jmeter.apache.org/usermanual/component_reference.html#View_Results_in_Table - -About other types read on -http://jmeter.apache.org/usermanual/component_reference.html - -About fixtures generation -http://devdocs.magento.com/guides/v2.2/config-guide/cli/config-cli-subcommands-perf-data.html diff --git a/setup/performance-toolkit/aggregate-report/b2c_mappings.php b/setup/performance-toolkit/aggregate-report/b2c_mappings.php new file mode 100644 index 0000000000000..3bc1620ffec7a --- /dev/null +++ b/setup/performance-toolkit/aggregate-report/b2c_mappings.php @@ -0,0 +1,779 @@ + 'Open Home Page', + 'uri' => '^\/$', + 'title' => 'Home Page', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Open Home Page', + 'uri' => '^\/$', + 'title' => 'Home Page\(Catalog Browsing', + 'scenario' => 'Catalog Browsing', + ], + [ + 'label' => 'Open Home Page', + 'uri' => '^\/$', + 'title' => 'Home Page\(Search', + 'scenario' => 'Search', + ], + [ + 'label' => 'Open Home Page', + 'uri' => '^\/$', + 'title' => 'Home Page\(Add To Cart', + 'scenario' => 'Add to Cart', + ], + [ + 'label' => 'Open Home Page', + 'uri' => '^\/$', + 'title' => 'Home Page\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + ], + [ + 'label' => 'Open Home Page', + 'uri' => '^\/$', + 'title' => 'Home Page\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + ], + [ + 'label' => 'Open Category Page', + 'uri' => '\/category-\d+\.html', + 'title' => 'Open Category', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Open Category Page', + 'uri' => '\/category-\d+\.html', + 'title' => 'Open Category\(Catalog Browsing', + 'scenario' => 'Catalog Browsing', + ], + [ + 'label' => 'Open Category Page', + 'uri' => '\/category-\d+\.html', + 'title' => 'Open Category\(Add To Cart', + 'scenario' => 'Add To Cart', + ], + [ + 'label' => 'Open Category Page', + 'uri' => '\/category-\d+\.html', + 'title' => 'Open Category\(Product Compare', + 'scenario' => 'Compare Products', + ], + [ + 'label' => 'Open Category Page', + 'uri' => '\/category-\d+\.html', + 'title' => 'Open Category\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + ], + [ + 'label' => 'Open Category Page', + 'uri' => '\/category-\d+\.html', + 'title' => 'Open Category\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + ], + [ + 'label' => 'Open Simple Product Page (Guest)', + 'uri' => '\/simple-product-\d+\.html', + 'title' => '^(?:Simple )?Product \d+ View', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Open Simple Product Page (Customer)', + 'uri' => '\/simple-product-\d+\.html', + 'title' => 'Simple Product View', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Open Simple Product Page', + 'uri' => '\/simple-product-\d+\.html', + 'title' => '^Simple Product \d+ View\(Catalog Browsing', + 'scenario' => 'Catalog Browsing', + ], + [ + 'label' => 'Open Product Page', + 'uri' => '\/(?:simple|configurable)-product-\d+\.html', + 'title' => '^Product \d+ View(\s\d)?\(Search', + 'scenario' => 'Search', + ], + [ + 'label' => 'Open Simple Product Page', + 'uri' => '\/simple-product-\d+\.html', + 'title' => '^Simple Product \d+ View\(Add To Cart', + 'scenario' => 'Add To Cart', + ], + [ + 'label' => 'Open Simple Product Page', + 'uri' => '\/simple-product-\d+\.html', + 'title' => '^Simple Product \d+ View\(Add To Cart', + 'scenario' => 'Add To Cart', + ], + [ + 'label' => 'Open Simple Product Page', + 'uri' => '\/simple-product-\d+\.html', + 'title' => '^Simple Product View\(WishList', + 'scenario' => 'WishList', + ], + [ + 'label' => 'Open Simple Product Page', + 'uri' => '\/simple-product-\d+\.html', + 'title' => '^Simple Product \d+ View\(Product Compare', + 'scenario' => 'Compare Products', + ], + [ + 'label' => 'Open Simple Product Page', + 'uri' => '\/simple-product-\d+\.html', + 'title' => '^Simple Product \d+ View\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + ], + [ + 'label' => 'Open Simple Product Page', + 'uri' => '\/simple-product-\d+\.html', + 'title' => '^Simple Product \d+ View\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + ], + [ + 'label' => 'Open Configurable Product Page', + 'uri' => '\/configurable-product-\d+\.html', + 'title' => 'Configurable Product \d+ View', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Open Configurable Product Page', + 'uri' => '\/configurable-product-\d+\.html', + 'title' => 'Configurable Product \d+ View\(Catalog Browsing', + 'scenario' => 'Catalog Browsing', + ], + [ + 'label' => 'Open Configurable Product Page', + 'uri' => '\/configurable-product-\d+\.html', + 'title' => 'Configurable Product \d+ View\(Add To Cart', + 'scenario' => 'Add To Cart', + ], + [ + 'label' => 'Open Configurable Product Page', + 'uri' => '\/configurable-product-\d+\.html', + 'title' => 'Configurable Product \d+ View\(Product Compare', + 'scenario' => 'Compare Products', + ], + [ + 'label' => 'Open Configurable Product Page', + 'uri' => '\/configurable-product-\d+\.html', + 'title' => 'Configurable Product \d+ View\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + ], + [ + 'label' => 'Open Configurable Product Page', + 'uri' => '\/configurable-product-\d+\.html', + 'title' => 'Configurable Product \d+ View\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + ], + [ + 'label' => 'Quick Search', + 'uri' => '\/catalogsearch\/result', + 'title' => 'Search\(SearchQuick\)', + 'scenario' => 'Search', + 'is_storefront' => true, + ], + [ + 'label' => 'Ajax Product Review', + 'uri' => '\/review\/product\/listAjax\/id\/\d+', + 'title' => 'Ajax Review.*\(Search', + 'scenario' => 'Search', + 'is_storefront' => true, + ], + [ + 'label' => 'Quick Search With Filter', + 'uri' => '\/catalogsearch\/result', + 'title' => 'Search(?:\s\d)?\(SearchQuickWithFilter\)', + 'scenario' => 'Search', + 'is_storefront' => true, + ], + [ + 'label' => 'Filter By Attribute', + 'uri' => '\/catalogsearch\/result', + 'title' => 'Filter by Attribute', + 'scenario' => 'Search', + 'is_storefront' => true, + ], + [ + 'label' => 'Open Advanced Search Page', + 'uri' => '\/catalogsearch\/advanced', + 'title' => 'Open Advanced Search', + 'scenario' => 'Search', + 'is_storefront' => true, + ], + [ + 'label' => 'Perform Advanced Search', + 'uri' => '\/catalogsearch\/advanced\/result', + 'title' => '^Search\(SearchAdvanced\)', + 'scenario' => 'Search', + 'is_storefront' => true, + ], + [ + 'label' => 'Add Simple Product To Cart', + 'uri' => '\/checkout\/cart\/add\/uenc', + 'title' => 'Simple.*Add To Cart', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Add Simple Product To Cart', + 'uri' => '\/checkout\/cart\/add\/uenc', + 'title' => 'Simple.*Add To Cart\(Add To Cart', + 'scenario' => 'Add To Cart', + ], + [ + 'label' => 'Add Simple Product To Cart', + 'uri' => '\/checkout\/cart\/add\/uenc', + 'title' => 'Simple.*Add To Cart\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + ], + [ + 'label' => 'Add Simple Product To Cart', + 'uri' => '\/checkout\/cart\/add\/uenc', + 'title' => 'Simple.*Add To Cart\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + ], + [ + 'label' => 'Add Configurable Product To Cart', + 'uri' => '\/checkout\/cart\/add\/uenc', + 'title' => 'Configurable.*Add To Cart', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Add Configurable Product To Cart', + 'uri' => '\/checkout\/cart\/add\/uenc', + 'title' => 'Configurable.*Add To Cart\(Add To Cart', + 'scenario' => 'Add To Cart', + ], + [ + 'label' => 'Add Configurable Product To Cart', + 'uri' => '\/checkout\/cart\/add\/uenc', + 'title' => 'Configurable.*Add To Cart\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + ], + [ + 'label' => 'Add Configurable Product To Cart', + 'uri' => '\/checkout\/cart\/add\/uenc', + 'title' => 'Configurable.*Add To Cart\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + ], + [ + 'label' => 'Load Customer Cart Section', + 'uri' => '\/customer\/section\/load.*sections=cart', + 'title' => '(Customer Section )?Load\s*(?:Guest|Customer)+', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Load Customer Cart Section', + 'uri' => '\/customer\/section\/load.*sections=cart', + 'title' => 'Load Guest\d?\(Add To Cart', + 'scenario' => 'Add To Cart', + ], + [ + 'label' => 'Load Customer Cart Section', + 'uri' => '\/customer\/section\/load.*sections=cart', + 'title' => 'Load Guest\d?\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + ], + [ + 'label' => 'Load Customer Cart Section', + 'uri' => '\/customer\/section\/load.*sections=cart', + 'title' => 'Load Customer\d?\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + ], + [ + 'label' => 'Delete Item From Shopping Cart', + 'uri' => '\/checkout\/cart\/delete', + 'title' => 'Delete From Cart', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Open Login Page', + 'uri' => '\/customer\/account\/login', + 'title' => 'Open Login Page', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Open Login Page', + 'uri' => '\/customer\/account\/login', + 'title' => 'Open Login Page\(WishList', + 'scenario' => 'WishList', + ], + [ + 'label' => 'Open Login Page', + 'uri' => '\/customer\/account\/login', + 'title' => 'Open Login Page\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + ], + [ + 'label' => 'Ajax Load Login Form', + 'uri' => '\/page_cache\/block\/render', + 'title' => 'Ajax Load Login Form', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Ajax Load Login Form', + 'uri' => '\/page_cache\/block\/render', + 'title' => 'Ajax Load Login Form\(WishList', + 'scenario' => 'WishList', + ], + [ + 'label' => 'Ajax Load Login Form', + 'uri' => '\/page_cache\/block\/render', + 'title' => 'Ajax Load Login Form\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + ], + [ + 'label' => 'Login Action', + 'uri' => '\/customer\/account\/loginPost', + 'title' => '^Login\s*\(', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Login Action', + 'uri' => '\/customer\/account\/loginPost', + 'title' => 'Login\s*\(WishList', + 'scenario' => 'WishList', + ], + [ + 'label' => 'Login Action', + 'uri' => '\/customer\/account\/loginPost', + 'title' => 'Login\s*\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + ], + [ + 'label' => 'Add Product To Wishlist', + 'uri' => '\/wishlist\/index\/add', + 'title' => 'Add To Wishlist', + 'scenario' => 'Wishlist', + 'is_storefront' => true, + ], + [ + 'label' => 'Load Wishlist Section', + 'uri' => '\/customer\/section\/load.*sections=wishlist', + 'title' => 'Load Wishlist', + 'scenario' => 'Wishlist', + 'is_storefront' => true, + ], + [ + 'label' => 'Delete Item From Wishlist', + 'uri' => 'wishlist\/index\/remove', + 'title' => 'Clear Wishlist', + 'scenario' => 'Wishlist', + 'is_storefront' => true, + ], + [ + 'label' => 'Logout Action', + 'uri' => '\/customer\/account\/logout', + 'title' => 'Logout', + 'is_service_url' => true, + 'is_storefront' => true, + ], + [ + 'label' => 'Add Simple Product To Compare List', + 'uri' => '\/catalog\/product_compare\/add', + 'title' => '^(Simple )?Product .* Comparison Add', + 'scenario' => 'Compare Products', + 'is_storefront' => true, + ], + [ + 'label' => 'Add Configurable Product To Compare List', + 'uri' => '\/catalog\/product_compare\/add', + 'title' => 'Configurable Product .* Comparison Add', + 'scenario' => 'Compare Products', + 'is_storefront' => true, + ], + [ + 'label' => 'Compare Products', + 'uri' => '\/catalog\/product_compare\/index\/items\/', + 'title' => 'Compare Products\(.*', + 'scenario' => 'Compare Products', + 'is_storefront' => true, + ], + [ + 'label' => 'Remove Products From Comparison', + 'uri' => '\/catalog\/product_compare\/clear', + 'title' => 'Compare Products Clear', + 'scenario' => 'Compare Products', + 'is_storefront' => true, + ], + [ + 'label' => 'Start Checkout (Guest)', + 'uri' => '\/checkout\/$', + 'title' => 'Checkout Start\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + 'is_storefront' => true, + ], + [ + 'label' => 'Check If Email Is Available', + 'uri' => '\/rest\/default\/V1\/customers\/isEmailAvailable', + 'title' => 'Checkout Email Available', + 'scenario' => 'Checkout By Guest', + 'is_storefront' => true, + ], + [ + 'label' => 'Checkout Estimate Shipping Methods (Guest)', + 'uri' => '\/rest\/default\/V1\/guest-carts\/[a-f0-9]+\/estimate-shipping-methods', + 'title' => 'Checkout Estimate Shipping Methods\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + 'is_storefront' => true, + ], + [ + 'label' => 'Checkout Billing/Shipping Information (Guest)', + 'uri' => '\/rest\/default\/V1\/guest-carts\/[a-f0-9]+\/shipping-information', + 'title' => 'Checkout Billing\/Shipping Information\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + 'is_storefront' => true, + ], + [ + 'label' => 'Checkout Payment/Info Place Order (Guest)', + 'uri' => '\/rest\/default\/V1\/guest-carts\/[a-f0-9]+\/payment-information', + 'title' => 'Checkout Payment Info\/Place Order\(Checkout By Guest', + 'scenario' => 'Checkout By Guest', + 'is_storefront' => true, + ], + [ + 'label' => 'Checkout Success Page By Guest', + 'uri' => '\/checkout\/onepage\/success', + 'title' => 'Checkout success\(Checkout By Guest\)', + 'scenario' => 'Checkout By Guest', + 'is_storefront' => true, + ], + [ + 'label' => 'Start Checkout (Customer)', + 'uri' => '\/checkout\/$', + 'title' => 'Checkout Start\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + 'is_storefront' => true, + ], + [ + 'label' => 'Checkout Estimate Shipping Methods (Customer)', + 'uri' => '\/rest\/default\/V1\/carts\/mine\/estimate-shipping-methods-by-address-id', + 'title' => 'Checkout Estimate Shipping Methods\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + 'is_storefront' => true, + ], + [ + 'label' => 'Checkout Billing/Shipping Information (Customer)', + 'uri' => '\/rest\/default\/V1\/carts\/mine\/shipping-information', + 'title' => 'Checkout Billing\/Shipping Information\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + 'is_storefront' => true, + ], + [ + 'label' => 'Checkout Payment/Info Place Order (Customer)', + 'uri' => '\/rest\/default\/V1\/carts\/mine\/payment-information', + 'title' => 'Checkout Payment Info\/Place Order\(Checkout By Customer', + 'scenario' => 'Checkout By Customer', + 'is_storefront' => true, + ], + [ + 'label' => 'Checkout Success Page By Customer', + 'uri' => '\/checkout\/onepage\/success', + 'title' => 'Checkout success\(Checkout By Customer\)', + 'scenario' => 'Checkout By Customer', + 'is_storefront' => true, + ], + [ + 'label' => 'Login To Admin Panel', + 'uri' => '\/admin', + 'title' => '- Login$', + 'is_service_url' => true + ], + [ + 'label' => 'Login To Admin Panel - Submit Form', + 'uri' => '\/admin\/admin\/dashboard', + 'title' => '- Login Submit Form', + 'is_service_url' => true, + ], + [ + 'label' => 'Admin - Edit Simple Product', + 'uri' => '\/admin\/catalog\/product\/edit\/id', + 'title' => 'Admin Edit Product - Edit Simple Product$', + 'scenario' => 'Admin - Edit Product', + ], + [ + 'label' => 'Admin - Validate Simple Product', + 'uri' => '\/admin\/catalog\/product\/validate\/id', + 'title' => 'Admin Edit Product - Edit Simple Product Validate', + 'scenario' => 'Admin - Edit Product', + ], + [ + 'label' => 'Admin - Save Simple Product', + 'uri' => '\/admin\/catalog\/product\/save\/id', + 'title' => 'Admin Edit Product - Edit Simple Product Save', + 'scenario' => 'Admin - Edit Product', + ], + [ + 'label' => 'Admin - Edit Configurable Product', + 'uri' => '\/admin\/catalog\/product\/edit\/id', + 'title' => 'Admin Edit Product - Edit Configurable Product$', + 'scenario' => 'Admin - Edit Product', + ], + [ + 'label' => 'Admin - Validate Configurable Product', + 'uri' => '\/admin\/catalog\/product\/validate\/id', + 'title' => 'Admin Edit Product - Edit Configurable Product Validate', + 'scenario' => 'Admin - Edit Product', + ], + [ + 'label' => 'Admin - Save Configurable Product', + 'uri' => '\/admin\/catalog\/product\/save\/id', + 'title' => 'Admin Edit Product - Edit Configurable Product Save', + 'scenario' => 'Admin - Edit Product', + ], + [ + 'label' => 'Admin - Open Product Page', + 'uri' => '\/admin\/catalog\/product\/', + 'title' => 'Admin Create Product - Catalog Product', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Create New Bundle Product', + 'uri' => '\/admin\/catalog\/product\/new\/set\/4\/type\/bundle\/', + 'title' => 'Admin Create Product - New Bundle Product$', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Validate New Bundle Product', + 'uri' => '\/admin\/catalog\/product\/validate\/set\/4\/', + 'title' => 'Admin Create Product - New Bundle Product Validate', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Save New Bundle Product', + 'uri' => '\/admin\/catalog\/product\/save\/set\/4\/type\/bundle\/back\/edit\/active_tab\/product-details\/', + 'title' => 'Admin Create Product - New Bundle Product Save', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Create New Configurable Product', + 'uri' => '\/admin\/catalog\/product\/new\/set\/4\/type\/configurable\/', + 'title' => 'Admin Create Product - New Configurable Product$', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Create Product Options', + 'uri' => '\/admin\/catalog\/product_attribute\/createOptions\/\?isAjax=true', + 'title' => 'Admin Create Product - Create Options', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Validate New Configurable Product', + 'uri' => '\/admin\/catalog\/product\/validate\/set\/4\/', + 'title' => 'Admin Create Product - New Configurable Product Validate', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Save New Configurable Product', + 'uri' => '\/admin\/catalog\/product\/save\/set\/4\/type\/configurable\/back\/edit\/active_tab\/product-details\/', + 'title' => 'Admin Create Product - New Configurable Product Save', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Create New Downloadable Product', + 'uri' => '\/admin\/catalog\/product\/new\/set\/4\/type\/downloadable\/', + 'title' => 'Admin Create Product - New Downloadable Product$', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Add Original File To Downloadable Product', + 'uri' => '\/admin\/downloadable_file\/upload\/type\/links\/\?isAjax=true', + 'title' => 'Admin Create Product - New Downloadable Upload Original File', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Add Sample File To Downloadable Product', + 'uri' => '\/admin\/downloadable_file\/upload\/type\/samples\/\?isAjax=true', + 'title' => 'Admin Create Product - New Downloadable Upload Sample File', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Validate New Downloadable Product', + 'uri' => '\/admin\/catalog\/product\/validate\/set\/4\/type\/downloadable\/', + 'title' => 'Admin Create Product - New Downloadable Product Validate', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Save New Downloadable Product', + 'uri' => '\/admin\/catalog\/product\/save\/set\/4\/type\/downloadable\/back\/edit\/active_tab\/product-details\/', + 'title' => 'Admin Create Product - New Downloadable Product Save', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Create New Simple Product', + 'uri' => '\/admin\/catalog\/product\/new\/set\/4\/type\/simple\/', + 'title' => 'Admin Create Product - New Simple Product$', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Validate New Simple Product', + 'uri' => '\/admin\/catalog\/product\/validate\/set\/4\/', + 'title' => 'Admin Create Product - New Simple Product Validate', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Save New Simple Product', + 'uri' => '\/admin\/catalog\/product\/save\/set\/4\/type\/simple\/back\/edit\/active_tab\/product-details\/', + 'title' => 'Admin Create Product - New Simple Product Save', + 'scenario' => 'Admin - Create Product', + ], + [ + 'label' => 'Admin - Open Category', + 'uri' => '\/admin\/catalog\/category\/', + 'title' => 'Admin Category Management - Landing Page', + 'scenario' => 'Admin - Category Management', + ], + [ + 'label' => 'Admin - Edit Category', + 'uri' => '\/admin\/catalog\/category\/edit\/id\/', + 'title' => 'Admin Category Management - Select parent category', + 'scenario' => 'Admin - Category Management', + ], + [ + 'label' => 'Admin - Open New Category Page', + 'uri' => '\/admin\/catalog\/category\/add\/store\/0\/parent\/', + 'title' => 'Admin Category Management - Open new category page', + 'scenario' => 'Admin - Category Management', + ], + [ + 'label' => 'Admin - Create Empty Category', + 'uri' => '\/admin\/catalog\/category\/save\/', + 'title' => 'Admin Category Management - Create empty category', + 'scenario' => 'Admin - Category Management', + ], + [ + 'label' => 'Admin - Add Products To Category', + 'uri' => '\/admin\/merchandiser\/position\/save\/', + 'title' => 'Admin Category Management - Add products', + 'scenario' => 'Admin - Category Management', + ], + [ + 'label' => 'Admin - Verify Products Added To Category', + 'uri' => '\/admin\/merchandiser\/category\/grid\/id\/', + 'title' => 'Admin Category Management - Verify products added', + 'scenario' => 'Admin - Category Management', + ], + [ + 'label' => 'Admin - Save Category With Products', + 'uri' => '\/admin\/catalog\/category\/save\/', + 'title' => 'Admin Category Management - Save category', + 'scenario' => 'Admin - Category Management', + ], + [ + 'label' => 'Admin - Move Category', + 'uri' => '\/admin\/catalog\/category\/move\/', + 'title' => 'Admin Category Management - Move category', + 'scenario' => 'Admin - Category Management', + ], + [ + 'label' => 'Admin - Delete Category', + 'uri' => '\/admin\/catalog\/category\/delete\/id\/', + 'title' => 'Admin Category Management - Delete category', + 'scenario' => 'Admin - Category Management', + ], + [ + 'label' => 'Admin - Open Promotions Page', + 'uri' => '\/admin\/sales_rule\/promo_quote\/$', + 'title' => 'Admin Promotions Management - Landing Page', + 'scenario' => 'Admin - Promotion Rules', + ], + [ + 'label' => 'Admin - Create New Promotion Rule', + 'uri' => '\/admin\/sales_rule\/promo_quote\/new$', + 'title' => 'Admin Promotions Management - Create New$', + 'scenario' => 'Admin - Promotion Rules', + ], + [ + 'label' => 'Admin - Create New Condition For Promotion Rule', + 'uri' => '\/admin\/sales_rule\/promo_quote\/newConditionHtml\/form\/sales_rule_formrule_conditions_fieldset_\/form_namespace\/sales_rule_form', + 'title' => 'Admin Promotions Management - Create New Conditional', + 'scenario' => 'Admin - Promotion Rules', + ], + [ + 'label' => 'Admin - Save Promotion Rule', + 'uri' => '\/admin\/sales_rule\/promo_quote\/save\/', + 'title' => 'Admin Promotions Management - Save$', + 'scenario' => 'Admin - Promotion Rules', + ], + [ + 'label' => 'API - Create Invoice', + 'uri' => '\/rest\/default\/V1\/order\/\d+\/invoice', + 'title' => 'API - Create Invoice', + 'scenario' => 'Admin - Process Orders', + ], + [ + 'label' => 'API - Create Shipment', + 'uri' => '\/rest\/default\/V1\/order\/\d+\/ship', + 'title' => 'API - Create Shipment', + 'scenario' => 'Admin - Process Orders', + ], + [ + 'label' => 'Admin - Open Orders Grid', + 'uri' => '\/admin\/mui\/index\/render', + 'title' => 'Admin Edit Order - Open Orders', + 'scenario' => 'Admin - Create/Process Returns', + ], + [ + 'label' => 'Admin - Open Orders Grid With Filter', + 'uri' => '\/admin\/mui\/index\/render', + 'title' => 'Admin Edit Order - Search Pending Orders Limit', + 'scenario' => 'Admin - Create/Process Returns', + ], + [ + 'label' => 'Admin - Open Orders Page', + 'uri' => '\/admin\/sales\/order\/', + 'title' => 'Admin Edit Order - Orders Page', + 'scenario' => 'Admin - Create/Process Returns', + ], + [ + 'label' => 'Admin - Open Order', + 'uri' => '\/admin\/sales\/order\/view\/order_id\/', + 'title' => 'Admin Edit Order - Open Order$', + 'scenario' => 'Admin - Create/Process Returns', + ], + [ + 'label' => 'Admin - Start Invoicing', + 'uri' => '\/admin\/sales\/order_invoice\/start\/order_id\/', + 'title' => 'Admin Edit Order - Invoice Start', + 'scenario' => 'Admin - Create/Process Returns', + ], + [ + 'label' => 'Admin - Submit Invoice', + 'uri' => '\/admin\/sales\/order_invoice\/save\/order_id\/', + 'title' => 'Admin Edit Order - Invoice Submit', + 'scenario' => 'Admin - Create/Process Returns', + ], + [ + 'label' => 'Admin - Start Credit Memo', + 'uri' => '\/admin\/sales\/order_creditmemo\/start\/order_id\/', + 'title' => 'Admin Edit Order - Credit Memo Start', + 'scenario' => 'Admin - Create/Process Returns', + ], + [ + 'label' => 'Admin - Submit Credit Memo', + 'uri' => '\/admin\/sales\/order_creditmemo\/save\/order_id\/', + 'title' => 'Admin Edit Order - Credit Memo Submit', + 'scenario' => 'Admin - Create/Process Returns', + ], + [ + 'label' => 'Admin - Search Order By Increment Id', + 'uri' => '\/admin\/mui\/index\/render', + 'title' => 'Admin Edit Order - Search Orders$', + 'scenario' => 'Admin - Create/Process Returns', + ], +]; \ No newline at end of file diff --git a/setup/performance-toolkit/aggregate-report/generate.php b/setup/performance-toolkit/aggregate-report/generate.php new file mode 100644 index 0000000000000..f4e973e585772 --- /dev/null +++ b/setup/performance-toolkit/aggregate-report/generate.php @@ -0,0 +1,299 @@ + $line[0], + 'uri' => $line[2], + ]; + } + fclose($file); + + return $memoryUsage; +} + +/** + * Parse JTL report and group all http requests by title. + * + * @param string $jmeterReport Path to the JTL report + * @param bool $includeErrors If true failed requests are included in report + * @return array First element - requests grouped by title, second - total execution time of the scenario + */ +function parseJmeterReport($jmeterReport, $includeErrors) +{ + $result = []; + $f = fopen($jmeterReport, 'r'); + $line = fgetcsv($f); + if (is_array($line) && count($line) > 1) { + $delimiter_char = ","; + } elseif (is_array($line = fgetcsv($f, 1000, $delimiter = "|")) && count($line) > 1) { + $delimiter_char = "|"; + } + do { + $responseTime = (int)$line[1]; + if (is_numeric($responseTime)) { + $title = $line[2]; + if (!$includeErrors) { + if ($line[7] == 'false') { + continue; + } + } + if (!isset($result[$title])) { + $result[$title] = ['times' => []]; + } + $result[$title]['times'][] = $responseTime; + + if (strpos($title, 'WarmUp Add To Cart') !== false) { + $startTime = $line[0]; + } + if (strpos($title, 'Clear properties') !== false) { + $endTime = $line[0]; + } + } + } while (!feof($f) && is_array($line = fgetcsv($f, 1000, $delimiter = $delimiter_char))); + + return [$result, $endTime - $startTime]; +} + +/** + * Aggregate data from JTL and memory log using mapping. + * + * @param array $jmeterData + * @param array $memoryUsageData + * @param array $mappings + * @return array + */ +function prepareAggregatedResult(array $jmeterData, array $memoryUsageData, array $mappings) +{ + $aggregatedResult = []; + foreach ($mappings as $key => $mapping) { + $aggregatedResult[$key]['label'] = $mapping['label']; + $aggregatedResult[$key]['scenario'] = $mapping['scenario'] ?? 'Total'; + $aggregatedResult[$key]['is_service_url'] = $mapping['is_service_url'] ?? false; + $aggregatedResult[$key]['is_storefront'] = $mapping['is_storefront'] ?? false; + $aggregatedResult[$key]['time'] = []; + $aggregatedResult[$key]['labels'] = []; + $aggregatedResult[$key]['order'] = 0; + $order = 0; + foreach ($jmeterData as $label => $time) { + $order++; + if (strpos($label, 'SetUp') !== false && !$aggregatedResult[$key]['is_service_url']) { + continue; + } + if (preg_match('/' . $mapping['title'] . '/i', $label)) { + if (empty($aggregatedResult[$key]['order'])) { + $aggregatedResult[$key]['order'] = $order; + } + array_push($aggregatedResult[$key]['time'], ...$time['times']); + if (!in_array($label, $aggregatedResult[$key]['labels']) + && !$aggregatedResult[$key]['is_service_url']) { + array_push($aggregatedResult[$key]['labels'], $label); + } + } + } + $memoryUsage = []; + foreach ($memoryUsageData as $row) { + if (preg_match('/' . $mapping['uri'] . '/i', $row['uri'])) { + $memoryUsage[] = $row['memory']; + } + } + $aggregatedResult[$key]['memory'] = count($memoryUsage) + ? round(calculate_average($memoryUsage) / 1024 / 1024, 2) : '-'; + } + usort( + $aggregatedResult, + function ($a, $b) { + return $a['order'] <=> $b['order']; + } + ); + return $aggregatedResult; +} + +/** + * Write aggregate report to the output file. + * + * @param array $aggregatedResult + * @param int $executionTime + * @param string $outputFile Path to the output report + * @return void + */ +function parseReportAndWriteToCsv(array $aggregatedResult, $executionTime, $outputFile) +{ + $headersArray = [ + 'Scenario', + 'Label', + 'JMeter Label', + 'Median elapsed time, ms', + 'Average elapsed time, ms', + 'Min elapsed time, ms', + 'Max elapsed time, ms', + '95 percentile elapsed time, ms', + '99 percentile elapsed time, ms', + 'Amount of hits per hour', + 'Memory Usage, Mb' + ]; + $fp = fopen($outputFile, 'w'); + + $pageViews = 0; + $checkoutCount = 0; + foreach ($aggregatedResult as $row) { + if ($row['is_storefront']) { + $pageViews += count($row['time']); + } + if (strpos($row['label'], 'Checkout Success Page') !== false) { + $checkoutCount += count($row['time']); + } + } + fputcsv($fp, ['Checkouts Per Hour:', round($checkoutCount / $executionTime * 3600000, 2)]); + fputcsv($fp, ['Page Views Per Hour:', round($pageViews / $executionTime * 3600000, 2)]); + fputcsv($fp, ['Test Duration, s:', round($executionTime / 1000)]); + fputcsv($fp, ['']); + fputcsv($fp, ['']); + fputcsv($fp, $headersArray); + foreach ($aggregatedResult as $row) { + if (count($row['time']) && !$row['is_service_url']) { + sort($row['time']); + $ar = [ + $row['scenario'], + $row['label'], + implode("\n", $row['labels']), + calculate_median($row['time']), + calculate_average($row['time']), + min($row['time']), + max($row['time']), + calculate_percentile($row['time'], 0.95), + calculate_percentile($row['time'], 0.99), + round(count($row['time']) / $executionTime * 3600000, 2), + $row['memory'] + ]; + fputcsv($fp, $ar); + } + } + fputcsv($fp, ['']); + fputcsv($fp, ['']); + foreach ($aggregatedResult as $row) { + if (count($row['time']) && $row['is_service_url']) { + sort($row['time']); + $ar = [ + 'Total', + $row['label'], + implode("\n", $row['labels']), + calculate_median($row['time']), + calculate_average($row['time']), + min($row['time']), + max($row['time']), + calculate_percentile($row['time'], 0.95), + calculate_percentile($row['time'], 0.99), + round(count($row['time']) / $executionTime * 3600000, 2), + $row['memory'] + ]; + fputcsv($fp, $ar); + } + } + fputcsv($fp, ['']); + fputcsv($fp, ['']); + foreach ($aggregatedResult as $row) { + if (count($row['time']) == 0) { + $ar = [$row['scenario'], $row['label'], '-', '-', '-', '-', '-', '-', '-', 0, '-']; + fputcsv($fp, $ar); + } + } + fclose($fp); +} + +/** + * Calculate average value of elements in array. + * + * @param array $arr + * @return int + */ +function calculate_average(array $arr) +{ + return (int)(array_sum($arr)/count($arr)); +} + +/** + * Calculate median value of elements in array. + * + * @param array $arr + * @return int + */ +function calculate_median(array $arr) +{ + $count = count($arr); + $middleval = floor(($count - 1) / 2); + if ($count % 2) { + $median = $arr[$middleval]; + } else { + $low = $arr[$middleval]; + $high = $arr[$middleval+1]; + $median = (($low + $high) / 2); + } + return (int)$median; +} + +/** + * Calculate percentile value of elements in array. + * + * @param array $arr + * @param float $percentile From 0 to 1 + * @return int + */ +function calculate_percentile(array $arr, $percentile) +{ + $count = count($arr); + $allindex = ($count - 1) * $percentile; + $intvalindex = intval($allindex); + $floatval = $allindex - $intvalindex; + if (!is_float($floatval)){ + $result = $arr[$intvalindex]; + }else { + if ($count > $intvalindex + 1) { + $result = $floatval * ($arr[$intvalindex + 1] - $arr[$intvalindex]) + $arr[$intvalindex]; + } else { + $result = $arr[$intvalindex]; + } + } + return (int)$result; +} diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index 844b5d127a014..a7884bbbca194 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -1,49 +1,19 @@ - + - + - + false false - - abandonedCartByGuest - ${__P(abandonedCartByGuest,0)} - = - - - abandonedCartByGuestPercent - ${__P(abandonedCartByGuestPercent,100)} - = - - - abandonedCartByCustomer - ${__P(abandonedCartByCustomer,0)} - = - - - abandonedCartByCustomerPercent - ${__P(abandonedCartByCustomerPercent,100)} - = - - - accountManagement - ${__P(accountManagement,0)} - = - - - accountManagementPercent - ${__P(accountManagementPercent,100)} - = - admin_password ${__P(admin_password,123123q)} @@ -51,7 +21,7 @@ admin_path - ${__P(admin_path,admin)} + ${__P(admin_path,backend)} = @@ -59,371 +29,11 @@ ${__P(admin_user,admin)} = - - adminBrowseCustomersGridPercent - ${__P(adminBrowseCustomersGridPercent,100)} - = - - - adminBrowseCustomersGridScenario1_ViewOddGridPages - ${__P(adminBrowseCustomersGridScenario1_ViewOddGridPages,0)} - = - - - adminBrowseCustomersGridScenario2_ViewEvenGridPages - ${__P(adminBrowseCustomersGridScenario2_ViewEvenGridPages,0)} - = - - - adminBrowseCustomersGridScenario3_Filtering - ${__P(adminBrowseCustomersGridScenario3_Filtering,0)} - = - - - adminBrowseCustomersGridScenario4_Sorting - ${__P(adminBrowseCustomersGridScenario4_Sorting,0)} - = - - - adminBrowseCustomersGridScenario5_FilteringAndSorting - ${__P(adminBrowseCustomersGridScenario5_FilteringAndSorting,0)} - = - - - adminBrowseOrdersGridPercent - ${__P(adminBrowseOrdersGridPercent,100)} - = - - - adminBrowseOrdersGridScenario1_ViewOddGridPages - ${__P(adminBrowseOrdersGridScenario1_ViewOddGridPages,0)} - = - - - adminBrowseOrdersGridScenario2_ViewEvenGridPages - ${__P(adminBrowseOrdersGridScenario2_ViewEvenGridPages,0)} - = - - - adminBrowseOrdersGridScenario3_Filtering - ${__P(adminBrowseOrdersGridScenario3_Filtering,0)} - = - - - adminBrowseOrdersGridScenario4_Sorting - ${__P(adminBrowseOrdersGridScenario4_Sorting,0)} - = - - - adminBrowseOrdersGridScenario5_FilteringAndSorting - ${__P(adminBrowseOrdersGridScenario5_FilteringAndSorting,0)} - = - - - adminBrowseProductsGridPercent - ${__P(adminBrowseProductsGridPercent,100)} - = - - - adminBrowseProductsGridScenario1_ViewOddGridPages - ${__P(adminBrowseProductsGridScenario1_ViewOddGridPages,0)} - = - - - adminBrowseProductsGridScenario2_ViewEvenGridPages - ${__P(adminBrowseProductsGridScenario2_ViewEvenGridPages,0)} - = - - - adminBrowseProductsGridScenario3_Filtering - ${__P(adminBrowseProductsGridScenario3_Filtering,0)} - = - - - adminBrowseProductsGridScenario4_Sorting - ${__P(adminBrowseProductsGridScenario4_Sorting,0)} - = - - - adminBrowseProductsGridScenario5_FilteringAndSorting - ${__P(adminBrowseProductsGridScenario5_FilteringAndSorting,0)} - = - - - adminCategoryCount - ${__P(adminCategoryCount,0)} - = - - - adminCategoryManagement - ${__P(adminCategoryManagement,0)} - = - - - adminCategoryManagementDelay - ${__P(adminCategoryManagementDelay,0)} - = - - - adminCategoryManagementPercent - ${__P(adminCategoryManagementPercent,100)} - = - - - adminCMSManagement - ${__P(adminCMSManagement,0)} - = - - - adminCMSManagementDelay - ${__P(adminCMSManagementDelay,0)} - = - - - adminCMSManagementPercent - ${__P(adminCMSManagementPercent,100)} - = - - - adminCreateOrder - ${__P(adminCreateOrder,0)} - = - - - adminCreateOrderPercent - ${__P(adminCreateOrderPercent,100)} - = - - - adminCreateProduct - ${__P(adminCreateProduct,0)} - = - - - adminCreateProductPercent - ${__P(adminCreateProductPercent,100)} - = - - - adminCustomerManagement - ${__P(adminCustomerManagement,0)} - = - - - adminCustomerManagementDelay - ${__P(adminCustomerManagementDelay,0)} - = - - - adminCustomerManagementPercent - ${__P(adminCustomerManagementPercent,100)} - = - - - adminEditOrder - ${__P(adminEditOrder,0)} - = - - - adminEditOrderPercent - ${__P(adminEditOrderPercent,100)} - = - - - adminEditProduct - ${__P(adminEditProduct,0)} - = - - - adminEditProductPercent - ${__P(adminEditProductPercent,100)} - = - - - adminExportCustomers - ${__P(adminExportCustomers,0)} - = - - - adminExportProducts - ${__P(adminExportProducts,0)} - = - - - adminImportCustomerBehavior - ${__P(adminImportCustomerBehavior,)} - = - - - adminImportCustomerFilePath - ${__P(adminImportCustomerFilePath,0)} - = - - - adminImportCustomers - ${__P(adminImportCustomers,0)} - = - - - adminImportProductBehavior - ${__P(adminImportProductBehavior,)} - = - - - adminImportProductFilePath - ${__P(adminImportProductFilePath,0)} - = - - - adminImportProductFilePath-2 - ${__P(adminImportProductFilePath-2,0)} - = - - - adminImportProducts - ${__P(adminImportProducts,0)} - = - - - adminPromotionsManagement - ${__P(adminPromotionsManagement,0)} - = - - - adminPromotionsManagementDelay - ${__P(adminPromotionsManagementDelay,0)} - = - - - adminPromotionsManagementPercent - ${__P(adminPromotionsManagementPercent,100)} - = - - - apiBrowseAndBuyFlow - ${__P(apiBrowseAndBuyFlow,0)} - = - - - apiBrowseAndBuyFlowPercent - ${__P(apiBrowseAndBuyFlowPercent,100)} - = - - - apiCustomerSync - ${__P(apiCustomerSync,0)} - = - - - apiCustomerSyncPercent - ${__P(apiCustomerSyncPercent,100)} - = - - - apiOrderInvoiceShipmentSync - ${__P(apiOrderInvoiceShipmentSync,0)} - = - - - apiOrderInvoiceShipmentSyncPercent - ${__P(apiOrderInvoiceShipmentSyncPercent,100)} - = - - - apiProcessOrders - ${__P(apiProcessOrders,0)} - = - - - apiProcessOrdersPercent - ${__P(apiProcessOrdersPercent,100)} - = - - - apiProductSync - ${__P(apiProductSync,0)} - = - - - apiProductSyncPercent - ${__P(apiProductSyncPercent,100)} - = - - - apiSnapshot - ${__P(apiSnapshot,0)} - = - - - bamboo_build_number - ${__P(bamboo_build_number,)} - = - base_path ${__P(base_path,)} = - - cache_indicator - ${__P(cache_indicator,0)} - = - - - catalogBrowsingByGuest - ${__P(catalogBrowsingByGuest,0)} - = - - - catalogBrowsingByGuestPercent - ${__P(catalogBrowsingByGuestPercent,100)} - = - - - catalogBrowsingByCustomer - ${__P(catalogBrowsingByCustomer,0)} - = - - - catalogBrowsingByCustomerPercent - ${__P(catalogBrowsingByCustomerPercent,100)} - = - - - categories_count - ${__P(categories_count,100)} - = - - - checkoutByGuest - ${__P(checkoutByGuest,0)} - = - - - checkoutByGuestPercent - ${__P(checkoutByGuestPercent,100)} - = - - - checkoutByCustomer - ${__P(checkoutByCustomer,0)} - = - - - checkoutByCustomerPercent - ${__P(checkoutByCustomerPercent,100)} - = - - - configurable_products_count - ${__P(configurable_products_count,30)} - = - - - customer_checkout_percent - ${__P(customer_checkout_percent,4)} - = - customer_limit ${__P(customer_limit,20)} @@ -446,12 +56,7 @@ files_folder - ${__P(files_folder,/opt/mpaf/tool/fragments/files/)} - = - - - guest_checkout_percent - ${__P(guest_checkout_percent,4)} + ${__P(files_folder,./files/)} = @@ -464,11 +69,6 @@ ${__P(loops,1)} = - - lineItemsAmount - ${__P(lineItemsAmount,10)} - = - orders ${__P(orders,0)} @@ -476,187 +76,187 @@ orders_page_size - ${__P(orders_page_size,20)} + ${__P(orders_page_size,500)} = - - products_page_size - ${__P(products_page_size,20)} + + report_save_path + ${__P(report_save_path,./)} = - - productCompareByGuest - ${__P(productCompareByGuest,0)} + + response_time_file_name + ${__P(response_time_file_name,production.csv)} = - - productCompareByGuestPercent - ${__P(productCompareByGuestPercent,100)} + + start_time + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} = - - productCompareDelay - ${__P(productCompareDelay,0)} + + starting_index + ${__P(starting_index,0)} = - - productsGridMassActions - ${__P(productsGridMassActions,0)} + + test_duration + ${__P(test_duration,900)} = - - productsGridMassActionsPercent - ${__P(productsGridMassActionsPercent,100)} + + url_suffix + .html = - - ramp_period - ${__P(ramp_period,0)} + + users + ${__P(users,100)} = - - redis_host - ${__P(redis_host,)} + + website_id + 1 = - - report_save_path - ${__P(report_save_path,./)} + + setupAndTearDownThread + ${__P(setupAndTearDownThread,1)} = - - response_time_file_name - ${__P(response_time_file_name,production.csv)} + + numberOfThreads + ${__P(numberOfThreads,48)} = - - reviewByCustomer - ${__P(reviewByCustomer,0)} + + frontEndPoolPercentage + ${__P(frontEndPoolPercentage,90)} = - - reviewByCustomerPercent - ${__P(reviewByCustomerPercent,100)} + + adminPoolPercentage + ${__P(adminPoolPercentage,10)} = - - reviewDelay - ${__P(reviewDelay,0)} + + browseCatalogPercentage + ${__P(browseCatalogPercentage,30)} = - - scenario - ${__P(scenario,)} + + processOrdersPercentage + ${__P(processOrdersPercentage,30)} = - - seedForRandom - ${__P(seedForRandom,1)} + + siteSearchPercentage + ${__P(siteSearchPercentage,30)} = - - searchQuick - ${__P(searchQuick,0)} + + checkoutByGuestPercentage + ${__P(checkoutByGuestPercentage,4)} = - - searchQuick_percent - ${__P(searchQuick_percent,100)} + + checkoutByCustomerPercentage + ${__P(checkoutByCustomerPercentage,4)} = - - searchQuickFilter - ${__P(searchQuickFilter,0)} + + addToCartPercentage + ${__P(addToCartPercentage,28)} = - - searchQuickFilter_percent - ${__P(searchQuickFilter_percent,100)} + + addToWishlistPercentage + ${__P(addToWishlistPercentage,2)} = - - searchAdvanced - ${__P(searchAdvanced,0)} + + compareProductsPercentage + ${__P(compareProductsPercentage,2)} = - - searchAdvanced_percent - ${__P(searchAdvanced_percent,100)} + + productCompareDelay + ${__P(productCompareDelay,0)} = - - setupAndTearDownThread - ${__P(setupAndTearDownThread,1)} + + promotionRulesPercentage + ${__P(promotionRulesPercentage,10)} = - - simple_products_count - ${__P(simple_products_count,30)} + + adminPromotionsManagementDelay + ${__P(adminPromotionsManagementDelay,0)} = - - sprint_identifier - ${__P(sprint_identifier,)} + + merchandizingPercentage + ${__P(merchandizingPercentage,50)} = - - start_time - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + + adminProductManagementPercentage + ${__P(adminProductManagementPercentage,90)} = - - starting_index - ${__P(starting_index,0)} + + adminCategoryManagementPercentage + ${__P(adminCategoryManagementPercentage,10)} = - - test_duration - ${__P(test_duration,900)} + + adminProductEditingPercentage + ${__P(adminProductEditingPercentage,60)} = - - think_time_deviation - ${__P(think_time_deviation,1000)} + + adminProductCreationPercentage + ${__P(adminProductCreationPercentage,40)} = - - think_time_delay_offset - ${__P(think_time_delay_offset,2000)} + + adminCategoryManagementDelay + ${__P(adminCategoryManagementDelay,0)} = - - url_suffix - .html + + apiProcessOrdersPercentage + ${__P(apiProcessOrdersPercentage,30)} = - - users - ${__P(users,100)} + + adminProcessReturnsPercentage + ${__P(adminProcessReturnsPercentage,10)} = - - view_catalog_percent - ${__P(view_catalog_percent,62)} + + csrPoolPercentage + ${__P(csrPoolPercentage,0)} = - - view_product_add_to_cart_percent - ${__P(view_product_add_to_cart_percent,30)} + + csrBrowseCustomersPercentage + ${__P(csrBrowseCustomersPercentage,10)} = - - website_id - 1 + + csrCreateOrderPercentage + ${__P(csrCreateOrderPercentage,70)} = - - wishlistByCustomer - ${__P(wishlistByCustomer,0)} + + csrCreateProcessReturnsPercentage + ${__P(csrCreateProcessReturnsPercentage,20)} = - - wishlistByCustomerPercent - ${__P(wishlistByCustomerPercent,100)} + + csrCreateProcessReturnsDelay + ${__P(csrCreateProcessReturnsDelay,0)} = @@ -664,6225 +264,23636 @@ ${__P(wishlistDelay,0)} = + + categories_count + ${__P(categories_count,200)} + = + + + simple_products_count + ${__P(simple_products_count,30)} + = + + + nested_categories_count + ${__P(nested_categories_count,50)} + = + - - - - - ${host} - - - - http - utf-8 - - Java - 4 - - - - - - - Accept-Language - en-US,en;q=0.5 - - - Accept - application/json,text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 - - - User-Agent - Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0 - - - Accept-Encoding - gzip, deflate - - - - - - - - - 30 - ${host} - / - false - 0 - true - true + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + + + + + + + true + true + true + + true + true + true + true + false + true + true + false + false + true + false + false + true + false + false + 0 + true + true + true + true + + + /var/www/magento2-infra/build/core_dev/performance/mpaf/tool/96c96t-jmeter-results.jtl + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + + + /var/www/magento2-infra/build/core_dev/performance/mpaf/tool/96c96t-jmeter-results.jtl + + + + + - - true - - - - - stoptest - - false - 1 - - ${setupAndTearDownThread} - 1 - 1384333221000 - 1384333221000 - false - - - - - - -// Init and save random object for get random values with/without seed -import java.util.Random; -Random random = new Random(); -if (${seedForRandom} > 0) { - random.setSeed(${seedForRandom}); -} -props.put("RandomObject", random); - -props.remove("category_url_key"); -props.remove("category_url_keys_list"); -props.remove("category_name"); -props.remove("category_names_list"); -props.remove("simple_products_list"); -props.remove("configurable_products_list"); -props.remove("users"); -props.remove("customer_emails_list"); - -/* This is only used when admin is enabled. */ -props.put("activeAdminThread", ""); + ${host} + + + + http + utf-8 + + Java + 4 + + + + + + Accept-Language + en-US,en;q=0.5 + + + Accept + application/json,text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + + + User-Agent + Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0 + + + Accept-Encoding + gzip, deflate + + + + + + + + 30 + ${host} + / + false + 0 + true + true + + + true + + + + stoptest + + false + 1 + + ${setupAndTearDownThread} + 0 + 1384333221000 + 1384333221000 + false + + + + + + props.remove("category_url_key"); +props.remove("category_url_keys_list"); +props.remove("category_name"); +props.remove("category_names_list"); +props.remove("simple_products_list"); +props.remove("configurable_products_list"); +props.remove("users"); +props.remove("customer_emails_list"); +props.remove("customer_ids_index"); -/* Set the environment - at this time '01' or '02' */ -String path = "${host}"; +/* Set the environment - at this time '01' or '02' */ +String path = "${host}"; String environment = path.substring(4, 6); -props.put("environment", environment); - - - false - - - - Boolean stopTestOnError (String error) { +props.put("environment", environment); + + + false + + + + Boolean stopTestOnError (String error) { log.error(error); System.out.println(error); SampleResult.setStopTest(true); return false; } -if ("${host}" == "1") { - return stopTestOnError("\"host\" parameter is not defined. Please define host parameter as: \"-Jhost=example.com\""); +if ("${host}" == "1") { + return stopTestOnError("\"host\" parameter is not defined. Please define host parameter as: \"-Jhost=example.com\""); } -String path = "${base_path}"; -String slash = "/"; +String path = "${base_path}"; +String slash = "/"; if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substring(0, 1))) { - return stopTestOnError("\"base_path\" parameter is invalid. It must start and end with \"/\""); + return stopTestOnError("\"base_path\" parameter is invalid. It must start and end with \"/\""); } - - - false - - - - - - - - - - - - - ${base_path}${admin_path} - GET - true - false - true - false - false - - - - - - Welcome - <title>Magento Admin</title> - - Assertion.response_data - false - 2 - - - - false - admin_form_key - <input name="form_key" type="hidden" value="([^'"]+)" /> - $1$ - - 1 - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - admin_form_key - - - - - - - - false - - = - true - dummy - - - false - ${admin_form_key} - = - true - form_key - - - true - ${admin_password} - = - true - login[password] - - - true - ${admin_user} - = - true - login[username] - - - - - - - - - - ${base_path}${admin_path}/admin/dashboard/ - POST - true - false - true - false - Java - false - - Implementation needs to be set to Java as per http://stackoverflow.com/questions/19636282/jmeter-error-in-redirect-url-for-get - - - - - <title>Dashboard / Magento Admin</title> - - Assertion.response_data - false - 2 - - - - - - - - true - ${admin_form_key} - = - true - form_key - - - true - types - = - true - massaction_prepare_key - - - true - config,layout,block_html,collections,reflection,db_ddl,eav,config_integration,full_page,target_rule,translate,config_webservice,config_integration_api - = - true - types - - - - - - - - - - ${base_path}${admin_path}/admin/cache/massEnable - POST - true - false - true - false - false - - Begin by enabling all cache types - - - - - - - true - ${admin_form_key} - = - true - form_key - - - true - types - = - true - massaction_prepare_key - - - true - config,layout,block_html,collections,reflection,db_ddl,eav,config_integration,full_page,target_rule,translate,config_webservice,config_integration_api - = - true - types - - - - - - - - - - ${base_path}${admin_path}/admin/cache/massRefresh - POST - true - false - true - false - false - - Refresh all cache types - - - - - - - - Content-Type - application/json - - - Accept - */* - - - + + + false + - - true - - - - false - {"username":"${admin_user}","password":"${admin_password}"} - = - - - - - - - - - - ${base_path}rest/V1/integration/admin/token - POST + + + + + + + + + + + ${base_path}${admin_path} + GET true false true false false - + - - admin_token - $ - - - BODY - + + + Welcome + <title>Magento Admin</title> + + Assertion.response_data + false + 2 + + + + false + admin_form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + - + - ^[a-z0-9-]+$ + ^.+$ Assertion.response_data false 1 variable - admin_token + admin_form_key - - - - Authorization - Bearer ${admin_token} - - - - - - + + - - true - path - = - true - searchCriteria[filterGroups][0][filters][0][field] - - - true - 1/2/% - = - true - searchCriteria[filterGroups][0][filters][0][value] - - - true - like - = - true - searchCriteria[filterGroups][0][filters][0][conditionType] - - - true - level + + false + ${admin_form_key} = true - searchCriteria[filterGroups][1][filters][0][field] + form_key - + true - 2 + ${admin_password} = true - searchCriteria[filterGroups][1][filters][0][value] + login[password] - + true - ${categories_count} + ${admin_user} = true - searchCriteria[pageSize] + login[username] - - - - - - - ${base_path}rest/V1/categories/list - GET + + + + + + + ${base_path}${admin_path}/admin/dashboard/ + POST true false - false + true false + Java false - + + Implementation needs to be set to Java as per http://stackoverflow.com/questions/19636282/jmeter-error-in-redirect-url-for-get - - false - category_url_keys - url_key\",\"value\":\"(.*?)\" - $1$ - - -1 - - - - false - category_names - name\":\"(.*?)\" - $1$ - - -1 - + + + <title>Dashboard / Magento Admin</title> + + Assertion.response_data + false + 2 + - - - category_url_keys - category_url_key - true - - - - 1 - - 1 - category_url_key_counter - - false - - - - import java.util.ArrayList; - -// If it is first iteration of cycle then recreate category url key list -if (1 == Integer.parseInt(vars.get("category_url_key_counter"))) { - categoryUrlKeysList = new ArrayList(); - props.put("category_url_keys_list", categoryUrlKeysList); - props.put("category_url_key", vars.get("category_url_key")); -} else { - categoryUrlKeysList = props.get("category_url_keys_list"); -} -categoryUrlKeysList.add(vars.get("category_url_key")); - - - false - - - - - category_names - category_name - true - - - - 1 - - 1 - category_name_counter - - false - - - - import java.util.ArrayList; - -// If it is first iteration of cycle then recreate category name list -if (1 == Integer.parseInt(vars.get("category_name_counter"))) { - categoryNamesList = new ArrayList(); - props.put("category_names_list",categoryNamesList); - props.put("category_name", vars.get("category_name")); -} else { - categoryNamesList = props.get("category_names_list"); -} - -categoryNamesList.add(vars.get("category_name")); - - - false - - - - - props.put("category_url_key", vars.get("category_url_key")); -props.put("category_name", vars.get("category_name")); - - - false - - - - - - - - Content-Type - application/json - - - Accept - */* - - - - - - true - + + - - false - {"username":"${admin_user}","password":"${admin_password}"} + + true + ${admin_form_key} + = + true + form_key + + + true + types + = + true + massaction_prepare_key + + + true + config,layout,block_html,collections,reflection,db_ddl,eav,config_integration,full_page,target_rule,translate,config_webservice,config_integration_api = + true + types - - - - - - - ${base_path}rest/V1/integration/admin/token + + + + + + + ${base_path}${admin_path}/admin/cache/massEnable POST true false true false false - + + Begin by enabling all cache types - - - admin_token - $ - - - BODY - - - - - ^[a-z0-9-]+$ - - Assertion.response_data - false - 1 - variable - admin_token - - - - - - - Authorization - Bearer ${admin_token} - - - - - + + - + true - type_id + ${admin_form_key} = true - searchCriteria[filterGroups][0][filters][0][field] + form_key - + true - simple + types = true - searchCriteria[filterGroups][0][filters][0][value] + massaction_prepare_key - + true - ${simple_products_count} + config,layout,block_html,collections,reflection,db_ddl,eav,config_integration,full_page,target_rule,translate,config_webservice,config_integration_api = true - searchCriteria[pageSize] + types - - - - - - - ${base_path}rest/V1/products - GET + + + + + + + ${base_path}${admin_path}/admin/cache/massRefresh + POST true false true false false - + + Refresh all cache types + + - - false - simple_products_url_keys - url_key\",\"value\":\"(.*?)\" - $1$ - - -1 - + + + + Content-Type + application/json + + + Accept + */* + + + - - false - simple_product_ids - \"id\":(\d+), - $1$ - - -1 - + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + - - false - simple_product_names - name\":\"(.*?)\" - $1$ - - -1 - + + + + + true + path + = + true + searchCriteria[filterGroups][0][filters][0][field] + + + true + 1/2/% + = + true + searchCriteria[filterGroups][0][filters][0][value] + + + true + like + = + true + searchCriteria[filterGroups][0][filters][0][conditionType] + + + true + level + = + true + searchCriteria[filterGroups][1][filters][0][field] + + + true + 2 + = + true + searchCriteria[filterGroups][1][filters][0][value] + + + true + ${categories_count} + = + true + searchCriteria[pageSize] + + + + + + + + + + ${base_path}rest/V1/categories/list + GET + true + false + false + false + false + + + + + false + category_url_keys + url_key\",\"value\":\"(.*?)\" + $1$ + + -1 + + + + false + category_names + name\":\"(.*?)\" + $1$ + + -1 + + + + + + category_url_keys + category_url_key + true + + + + 1 + + 1 + category_url_key_counter + + false + + + + import java.util.ArrayList; + +// If it is first iteration of cycle then recreate category url key list +if (1 == Integer.parseInt(vars.get("category_url_key_counter"))) { + categoryUrlKeysList = new ArrayList(); + props.put("category_url_keys_list", categoryUrlKeysList); + props.put("category_url_key", vars.get("category_url_key")); +} else { + categoryUrlKeysList = props.get("category_url_keys_list"); +} +categoryUrlKeysList.add(vars.get("category_url_key")); + + + false + - - - simple_product_ids - simple_product_id - true - - - - 1 - - 1 - simple_products_counter - - false - - - - import java.util.ArrayList; -import java.util.HashMap; -import org.apache.commons.codec.binary.Base64; + + category_names + category_name + true + + + + 1 + + 1 + category_name_counter + + false + + + + import java.util.ArrayList; -// If it is first iteration of cycle then recreate productList -if (1 == Integer.parseInt(vars.get("simple_products_counter"))) { - productList = new ArrayList(); - props.put("simple_products_list", productList); +// If it is first iteration of cycle then recreate category name list +if (1 == Integer.parseInt(vars.get("category_name_counter"))) { + categoryNamesList = new ArrayList(); + props.put("category_names_list",categoryNamesList); + props.put("category_name", vars.get("category_name")); } else { - productList = props.get("simple_products_list"); + categoryNamesList = props.get("category_names_list"); } -String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); -encodedUrl = Base64.encodeBase64(productUrl.getBytes()); -// Create product map -Map productMap = new HashMap(); -productMap.put("id", vars.get("simple_product_id")); -productMap.put("title", vars.get("simple_product_names_" + vars.get("simple_products_counter"))); -productMap.put("url_key", vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))); -productMap.put("uenc", new String(encodedUrl)); -// Collect products map in products list -productList.add(productMap); - - +categoryNamesList.add(vars.get("category_name")); + + + false + + + + + props.put("category_url_key", vars.get("category_url_key")); +props.put("category_name", vars.get("category_name")); + + false - - - - - - - Content-Type - application/json - - - Accept - */* - - - - - - true - - - - false - {"username":"${admin_user}","password":"${admin_password}"} - = + + + + + + Content-Type + application/json + + + Accept + */* - - - - - - - - ${base_path}rest/V1/integration/admin/token - POST + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + true + type_id + = + true + searchCriteria[filterGroups][0][filters][0][field] + + + true + simple + = + true + searchCriteria[filterGroups][0][filters][0][value] + + + true + ${simple_products_count} + = + true + searchCriteria[pageSize] + + + + + + + + + + ${base_path}rest/V1/products + GET + true + false + true + false + false + + + + + false + simple_products_url_keys + url_key\",\"value\":\"(.*?)\" + $1$ + + -1 + + + + false + simple_product_ids + \"id\":(\d+), + $1$ + + -1 + + + + false + simple_product_names + name\":\"(.*?)\" + $1$ + + -1 + + + + + + simple_product_ids + simple_product_id + true + + + + 1 + + 1 + simple_products_counter + + false + + + + import java.util.ArrayList; +import java.util.HashMap; +import org.apache.commons.codec.binary.Base64; + +// If it is first iteration of cycle then recreate productList +if (1 == Integer.parseInt(vars.get("simple_products_counter"))) { + productList = new ArrayList(); + props.put("simple_products_list", productList); +} else { + productList = props.get("simple_products_list"); +} +String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); +encodedUrl = Base64.encodeBase64(productUrl.getBytes()); +// Create product map +Map productMap = new HashMap(); +productMap.put("id", vars.get("simple_product_id")); +productMap.put("title", vars.get("simple_product_names_" + vars.get("simple_products_counter"))); +productMap.put("url_key", vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))); +productMap.put("uenc", new String(encodedUrl)); + +// Collect products map in products list +productList.add(productMap); + + + false + + + + + + + + + Content-Type + application/json + + + Accept + */* + + + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + true + type_id + = + true + searchCriteria[filterGroups][0][filters][0][field] + + + true + configurable + = + true + searchCriteria[filterGroups][0][filters][0][value] + + + true + ${simple_products_count} + = + true + searchCriteria[pageSize] + + + + + + + + + + ${base_path}rest/V1/products + GET + true + false + true + false + false + + + + + false + configurable_products_url_keys + url_key\",\"value\":\"(.*?)\" + $1$ + + -1 + + + + false + configurable_product_ids + \"id\":(\d+), + $1$ + + -1 + + + + false + configurable_product_names + name\":\"(.*?)\" + $1$ + + -1 + + + + false + configurable_product_skus + sku\":\"(.*?)\" + $1$ + + -1 + + + + + + configurable_product_ids + configurable_product_id + true + + + + 1 + + 1 + configurable_products_counter + + false + + + + import java.util.ArrayList; +import java.util.HashMap; +import org.apache.commons.codec.binary.Base64; + +// If it is first iteration of cycle then recreate productList +if (1 == Integer.parseInt(vars.get("configurable_products_counter"))) { + productList = new ArrayList(); + props.put("configurable_products_list", productList); +} else { + productList = props.get("configurable_products_list"); +} + +String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); +encodedUrl = Base64.encodeBase64(productUrl.getBytes()); +// Create product map +Map productMap = new HashMap(); +productMap.put("id", vars.get("configurable_product_id")); +productMap.put("title", vars.get("configurable_product_names_" + vars.get("configurable_products_counter"))); +productMap.put("sku", vars.get("configurable_product_skus_" + vars.get("configurable_products_counter"))); +productMap.put("url_key", vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))); +productMap.put("uenc", new String(encodedUrl)); + +// Collect products map in products list +productList.add(productMap); + + + false + + + + + + + + + + + + + + ${base_path}${admin_path}/customer/index/ + GET true false true false false - + - - admin_token - $ - - - BODY - + + + + true + import org.apache.jmeter.protocol.http.control.CookieManager; +import org.apache.jmeter.protocol.http.control.Cookie; +CookieManager manager = sampler.getCookieManager(); +Cookie cookie = new Cookie("adminhtml",vars.get("COOKIE_adminhtml"),vars.get("host"),"/",false,0); +manager.add(cookie); + - + - ^[a-z0-9-]+$ + Customers + <title>Customers / Customers / Magento Admin</title> Assertion.response_data false - 1 - variable - admin_token + 2 - - - - Authorization - Bearer ${admin_token} - - - - - - + + - + + true + customer_listing + = + true + namespace + + + true + + = + true + search + + + true + customer_since[locale]=en_US&website_id=1 + = + true + filters[placeholder] + + + true + ${customers_page_size} + = + true + paging[pageSize] + + + true + 1 + = + true + paging[current] + + true - type_id + entity_id = true - searchCriteria[filterGroups][0][filters][0][field] + sorting[field] - + true - configurable + asc = true - searchCriteria[filterGroups][0][filters][0][value] + sorting[direction] - + true - ${configurable_products_count} + true = true - searchCriteria[pageSize] + isAjax - - - - - - - ${base_path}rest/V1/products + + + + + + + ${base_path}${admin_path}/mui/index/render/ GET true false true false false - + - - false - configurable_products_url_keys - url_key\",\"value\":\"(.*?)\" - $1$ - - -1 - - - - false - configurable_product_ids - \"id\":(\d+), - $1$ - - -1 - + + $.totalRecords + 0 + true + false + true + true + - - false - configurable_product_names - name\":\"(.*?)\" - $1$ - - -1 - + + customer_emails + $.items[*].email + + + BODY + - - false - configurable_product_skus - sku\":\"(.*?)\" - $1$ - - -1 - + + customer_ids + $.items[*].entity_id + + + BODY + - - - configurable_product_ids - configurable_product_id - true - - - - 1 - - 1 - configurable_products_counter - - false - - - - import java.util.ArrayList; -import java.util.HashMap; -import org.apache.commons.codec.binary.Base64; - -// If it is first iteration of cycle then recreate productList -if (1 == Integer.parseInt(vars.get("configurable_products_counter"))) { - productList = new ArrayList(); - props.put("configurable_products_list", productList); -} else { - productList = props.get("configurable_products_list"); -} - -String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); -encodedUrl = Base64.encodeBase64(productUrl.getBytes()); -// Create product map -Map productMap = new HashMap(); -productMap.put("id", vars.get("configurable_product_id")); -productMap.put("title", vars.get("configurable_product_names_" + vars.get("configurable_products_counter"))); -productMap.put("sku", vars.get("configurable_product_skus_" + vars.get("configurable_products_counter"))); -productMap.put("url_key", vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))); -productMap.put("uenc", new String(encodedUrl)); - -// Collect products map in products list -productList.add(productMap); - - - false - - - - - - - - - - - - - - ${base_path}${admin_path}/customer/index/ - GET - true - false - true - false - false - - - - - - - true - import org.apache.jmeter.protocol.http.control.CookieManager; -import org.apache.jmeter.protocol.http.control.Cookie; -CookieManager manager = sampler.getCookieManager(); -Cookie cookie = new Cookie("adminhtml",vars.get("COOKIE_adminhtml"),vars.get("host"),"/",false,0); -manager.add(cookie); - - - - - Customers - <title>Customers / Customers / Magento Admin</title> - - Assertion.response_data - false - 2 - - - - - - - - - true - customer_listing - = - true - namespace - - - true - - = - true - search - - - true - customer_since[locale]=en_US&website_id=1 - = - true - filters[placeholder] - - - true - ${customers_page_size} - = - true - paging[pageSize] - - - true - 1 - = - true - paging[current] - - - true - entity_id - = - true - sorting[field] - - - true - asc - = - true - sorting[direction] - - - true - true - = - true - isAjax - - - - - - - - - - ${base_path}${admin_path}/mui/index/render/ - GET - true - false - true - false - false - - - - - - \"totalRecords\":0 - - Assertion.response_data - false - 20 - - - - false - customer_emails - \"email\":\"([^"]+) - $1$ - - -1 - - - - false - customer_ids - \"entity_id\":\"([^"]+) - $1$ - - -1 - - - - - customer_emails - customer_email - true - - - - 1 - - 1 - email_counter - - false - - - - import java.util.ArrayList; + + customer_emails + customer_email + true + + + + 1 + + 1 + email_counter + + false + + + + import java.util.ArrayList; // If it is first iteration of cycle then recreate emailsList -if (1 == Integer.parseInt(vars.get("email_counter"))) { +if (1 == Integer.parseInt(vars.get("email_counter"))) { emailsList = new ArrayList(); - props.put("customer_emails_list", emailsList); + props.put("customer_emails_list", emailsList); } else { - emailsList = props.get("customer_emails_list"); + emailsList = props.get("customer_emails_list"); } -emailsList.add(vars.get("customer_email")); - - - false - - - - - customer_ids - customer_id - true - - - - 1 - - 1 - id_counter - - false - - - - import java.util.ArrayList; +emailsList.add(vars.get("customer_email")); + + + false + + + + + customer_ids + customer_id + true + + + + 1 + + 1 + id_counter + + false + + + + import java.util.ArrayList; // If it is first iteration of cycle then recreate idsList -if (1 == Integer.parseInt(vars.get("id_counter"))) { +if (1 == Integer.parseInt(vars.get("id_counter"))) { idsList = new ArrayList(); - props.put("customer_ids_list", idsList); + props.put("customer_ids_list", idsList); } else { - idsList = props.get("customer_ids_list"); + idsList = props.get("customer_ids_list"); } -idsList.add(vars.get("customer_id")); - - - false - - - - - Boolean stopTestOnError (String error) { +idsList.add(vars.get("customer_id")); + + + false + + + + + Boolean stopTestOnError (String error) { log.error(error); System.out.println(error); SampleResult.setStopTest(true); return false; } -if (props.get("simple_products_list") == null) { - return stopTestOnError("Cannot find simple products. Test stopped."); +if (props.get("simple_products_list") == null) { + return stopTestOnError("Cannot find simple products. Test stopped."); } -if (props.get("configurable_products_list") == null) { - return stopTestOnError("Cannot find configurable products. Test stopped."); +if (props.get("configurable_products_list") == null) { + return stopTestOnError("Cannot find configurable products. Test stopped."); } -if (props.get("customer_emails_list") == null) { - return stopTestOnError("Cannot find customer emails. Test stopped."); +if (props.get("customer_emails_list") == null) { + return stopTestOnError("Cannot find customer emails. Test stopped."); } -if (props.get("category_url_keys_list") == null) { - return stopTestOnError("Cannot find category url keys. Test stopped."); +if (props.get("category_url_keys_list") == null) { + return stopTestOnError("Cannot find category url keys. Test stopped."); } -if (props.get("category_names_list") == null) { - return stopTestOnError("Cannot find category names. Test stopped."); +if (props.get("category_names_list") == null) { + return stopTestOnError("Cannot find category names. Test stopped."); } -int orders = Integer.parseInt(vars.get("orders")); +int orders = Integer.parseInt(vars.get("orders")); if (orders > 0) { - int checkout_sum = Integer.parseInt(vars.get("guest_checkout_percent")) + Integer.parseInt(vars.get("customer_checkout_percent")); + int checkout_sum = Integer.parseInt(vars.get("guest_checkout_percent")) + Integer.parseInt(vars.get("customer_checkout_percent")); checkout_sum = checkout_sum > 0 ? checkout_sum : 1; int users = orders * (100 / checkout_sum); - props.put("users", users); + props.put("users", users); } else { - props.put("users", Integer.parseInt(vars.get("users"))); -} - - - - false - - - - "${cache_indicator}" == "1" || "${cache_indicator}" == "2" - false - - - - // Default to disable all cache types -vars.put("cache_types", "config,layout,block_html,collections,reflection,db_ddl,eav,config_integration,full_page,target_rule,translate,config_webservice,config_integration_api"); - -if ("${cache_indicator}" == "1") { - // Only disable Full Page Cache - vars.put("cache_types", "full_page"); + props.put("users", Integer.parseInt(vars.get("users"))); } - - + + false - + + ${adminPoolPercentage} > 0 + false + + + + + + Content-Type + application/json + + + Accept + */* + + + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + + + true + sales_order_grid + = + true + namespace + + + true + + = + true + search + + + true + true + = + true + filters[placeholder] + + + true + Pending + = + true + filters[status] + + + true + ${orders_page_size} + = + true + paging[pageSize] + + + true + 1 + = + true + paging[current] + + + true + entity_id + = + true + sorting[field] + + + true + asc + = + true + sorting[direction] + + + true + true + = + true + isAjax + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + false + order_list_id + view\\\/order_id\\\/(\d+)\\\/ + $1$ + + -1 + + + + + order_list_id + order_id + true + + + + 1 + + 1 + order_counter + + false + + + + import java.util.ArrayList; + +// If it is first iteration of cycle then recreate orders list +if (1 == Integer.parseInt(vars.get("order_counter"))) { + ordersList = new ArrayList(); + props.put("orders_list", ordersList); +} else { + ordersList = props.get("orders_list"); +} + +// Collect orders map in orders list +ordersList.add(vars.get("order_id")); + + + false + + + + + + + + + + + true + children_count + = + true + searchCriteria[filterGroups][0][filters][0][field] + + + true + 0 + = + true + searchCriteria[filterGroups][0][filters][0][value] + + + true + level + = + true + searchCriteria[filterGroups][1][filters][0][field] + + + true + 2 + = + true + searchCriteria[filterGroups][1][filters][0][value] + + + true + gt + = + true + searchCriteria[filterGroups][1][filters][0][conditionType] + + + true + ${nested_categories_count} + = + true + searchCriteria[pageSize] + + + + + + + + + + ${base_path}rest/default/V1/categories/list + GET + true + false + true + false + false + + + + + false + category_list_id + \{\"id\":(\d+), + $1$ + + -1 + + + + + category_list_id + category_id + true + + + + 1 + + 1 + category_counter + + false + + + + import java.util.ArrayList; + +// If it is first iteration of cycle then recreate categories ids list +if (1 == Integer.parseInt(vars.get("category_counter"))) { + categoriesIdsList = new ArrayList(); + props.put("categories_ids_list", categoriesIdsList); +} else { + categoriesIdsList = props.get("categories_ids_list"); +} +categoriesIdsList.add(vars.get("category_id")); + + + false + + + + + + - + true - ${admin_form_key} + ["customer_form_login"] = true - form_key + blocks - + true - types + ["default","customer_account_login"] = true - massaction_prepare_key + handles - + true - ${cache_types} + {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} = true - types + originalRequest - - - - - - - - - ${base_path}${admin_path}/admin/cache/massDisable - POST - true - false - true - false - true - false - - - - - - "${cache_indicator}" == "0" - false - - - - - - - false - ${admin_form_key} + + true + true = true - form_key - true + ajax + + + true + true + = + true + isAjax - - - - - - - ${base_path}${admin_path}/admin/cache/ + + + + + + + ${base_path}page_cache/block/render/ GET true false true false - true false - + - + - TRANSLATE(?s).+?<span>Enabled</span> - CONFIG(?s).+?<span>Enabled</span> - LAYOUT_GENERAL_CACHE_TAG(?s).+?<span>Enabled</span> - BLOCK_HTML(?s).+?<span>Enabled</span> - COLLECTION_DATA(?s).+?<span>Enabled</span> - EAV(?s).+?<span>Enabled</span> - FPC(?s).+?<span>Enabled</span> - DB_DDL(?s).+?<span>Enabled</span> - INTEGRATION(?s).+?<span>Enabled</span> - INTEGRATION_API_CONFIG(?s).+?<span>Enabled</span> - WEBSERVICE(?s).+?<span>Enabled</span> - REFLECTION(?s).+?<span>Enabled</span> - TARGET_RULE(?s).+?<span>Enabled</span> + "customer_form_login" + Registered Customers + form_key Assertion.response_data false 2 + + false + form_key + <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + form_key + + - - - "${cache_indicator}" == "1" - false - - - + + + false + 1 + = + true + product + + + false + + = + true + related_product + + + false + 1 + = + true + qty + false - ${admin_form_key} + ${form_key} = true form_key - true - - - - - - - ${base_path}${admin_path}/admin/cache/ - GET + + + + + + + ${base_path}checkout/cart/add + POST true false true false - true false - + + + + + continue + + false + ${loops} + + ${__javaScript(Math.round(${numberOfThreads}*${frontEndPoolPercentage}*${browseCatalogPercentage}/10000))} + 0 + 1437409133000 + 1437409133000 + false + + + + + + ${test_duration} + - - - TRANSLATE(?s).+?<span>Enabled</span> - CONFIG(?s).+?<span>Enabled</span> - LAYOUT_GENERAL_CACHE_TAG(?s).+?<span>Enabled</span> - BLOCK_HTML(?s).+?<span>Enabled</span> - COLLECTION_DATA(?s).+?<span>Enabled</span> - EAV(?s).+?<span>Enabled</span> - FPC(?s).+?<span>Disabled</span> - DB_DDL(?s).+?<span>Enabled</span> - INTEGRATION(?s).+?<span>Enabled</span> - INTEGRATION_API_CONFIG(?s).+?<span>Enabled</span> - WEBSERVICE(?s).+?<span>Enabled</span> - REFLECTION(?s).+?<span>Enabled</span> - TARGET_RULE(?s).+?<span>Enabled</span - - Assertion.response_data - false - 2 - + + Passing arguments between threads + import org.apache.jmeter.samplers.SampleResult; + +number = (int)(Math.random() * props.get("simple_products_list").size()); +simpleList = props.get("simple_products_list").get(number); +vars.put("simple_product_1_url_key", simpleList.get("url_key")); +vars.put("simple_product_1_name", simpleList.get("title")); +vars.put("simple_product_1_id", simpleList.get("id")); + +do { + number1 = (int)(Math.random() * props.get("simple_products_list").size()); +} while(number == number1); +simpleList = props.get("simple_products_list").get(number1); +vars.put("simple_product_2_url_key", simpleList.get("url_key")); +vars.put("simple_product_2_name", simpleList.get("title")); +vars.put("simple_product_2_id", simpleList.get("id")); + +number = (int)(Math.random() * props.get("configurable_products_list").size()); +configurableList = props.get("configurable_products_list").get(number); +vars.put("configurable_product_1_url_key", configurableList.get("url_key")); +vars.put("configurable_product_1_name", configurableList.get("title")); +vars.put("configurable_product_1_id", configurableList.get("id")); + +number = (int)(Math.random() * props.get("category_url_keys_list").size()); +vars.put("category_url_key", props.get("category_url_keys_list").get(number)); +vars.put("category_name", props.get("category_names_list").get(number)); +vars.put("testLabel", "Catalog Browsing By Guest"); + + + + true + + + + + + + + + + + + ${base_path} + GET + true + false + true + false + false + + + + + + <title>Home page</title> + + Assertion.response_data + false + 2 + + + + + + false + manager = ctx.getCurrentSampler().getCookieManager(); +for (i=0; i < manager.getCookieCount(); i++) { + manager.remove(i); +} + + + + + + + + + + + + + + ${base_path}${category_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <span class="base" data-ui-id="page-title">${category_name}</span> + + Assertion.response_data + false + 6 + + + + false + category_id + <li class="item category([^'"]+)">\s*<strong>${category_name}</strong>\s*</li> + $1$ + + 1 + simple_product_1_url_key + + + + + ^[0-9]+$ + + Assertion.response_data + false + 1 + variable + category_id + + + + + + + + + + + + + + ${base_path}${simple_product_1_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${simple_product_1_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${simple_product_2_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${simple_product_2_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${configurable_product_1_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${configurable_product_1_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + - - "${cache_indicator}" == "2" - false - + + continue + + false + ${loops} + + ${__javaScript(Math.round(${numberOfThreads}*${frontEndPoolPercentage}*${siteSearchPercentage}/10000))} + 1 + 1494597847000 + 1494597847000 + false + + + - - - - - false - ${admin_form_key} - = - true - form_key - true - - - - - - - - - - ${base_path}${admin_path}/admin/cache/ - GET - true - false - true - false - true - false - - + + ${test_duration} + - - - TRANSLATE(?s).+?<span>Disabled</span> - CONFIG(?s).+?<span>Disabled</span> - LAYOUT_GENERAL_CACHE_TAG(?s).+?<span>Disabled</span> - BLOCK_HTML(?s).+?<span>Disabled</span> - COLLECTION_DATA(?s).+?<span>Disabled</span> - EAV(?s).+?<span>Disabled</span> - FPC(?s).+?<span>Disabled</span> - DB_DDL(?s).+?<span>Disabled</span> - INTEGRATION(?s).+?<span>Disabled</span> - INTEGRATION_API_CONFIG(?s).+?<span>Disabled</span> - WEBSERVICE(?s).+?<span>Disabled</span> - REFLECTION(?s).+?<span>Disabled</span> - TARGET_RULE(?s).+?<span>Disabled</span - - Assertion.response_data - false - 2 - + + import java.util.ArrayList; + +values = vars.getObject("random_values"); + +if (values == null) { + values = new ArrayList(); + + //define default sequence of values, value percentage = number of value in list / list size * 100 + for (int i = 0; i < 12; i++) { + values.add(0); + } + for (int i = 0; i < 7; i++) { + values.add(1); + } + values.add(2); + + Collections.shuffle(values); + vars.putObject("random_values", values); +} + +increment = vars.getObject("increment"); +if (increment == null) { + increment = 0; +} else { + //calculate index of the next value from sequence + increment = (Integer.parseInt(increment) + 1) % values.size(); +} +value = Integer.toString(values.get(increment)); +vars.put("switch_value", value); +vars.putObject("increment", String.valueOf(increment)); + +return value; + + + false + + + ${switch_value} + + + + + + Passing arguments between threads + vars.put("testLabel", "SearchQuick"); + + + + true + + + + + + + + + + + + + ${base_path} + GET + true + false + true + false + false + + + + + + <title>Home page</title> + + Assertion.response_data + false + 2 + + + + + ${files_folder}search_terms.csv + + + , + true + true + false + shareMode.thread + + + + + + + true + q + ${searchTerm} + = + true + + + + + + + + + + ${base_path}catalogsearch/result/ + GET + true + false + true + false + false + + + + + + Search results for: + Items <span class="toolbar-number">1 + + Assertion.response_data + false + 2 + + + + false + product_url_keys + <a class="product-item-link"(?s).+?href="http://${host}${base_path}(index.php/)?([^'"]+)${url_suffix}">(?s). + $2$ + + -1 + + + + + product_url_keys + product_url_key + true + 0 + 3 + + + + 1 + 3 + 1 + _counter + + true + true + + + + + + + + + + + + + ${base_path}${product_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + + + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + + + + + + + + Passing arguments between threads + vars.put("testLabel", "SearchQuickWithFilter"); + + + + true + + + + + + + + + + + + + ${base_path} + GET + true + false + true + false + false + + + + + + <title>Home page</title> + + Assertion.response_data + false + 2 + + + + + ${files_folder}search_terms.csv + + + , + true + true + false + shareMode.thread + + + + vars.put("search_url", props.get("base_path") + "catalogsearch/result/?q=" + vars.get("searchTerm")); + + + false + + + + + + + true + q + ${searchTerm} + = + true + + + + + + + + + + ${base_path}catalogsearch/result/ + GET + true + false + true + false + false + + + + + + Search results for: + Items <span class="toolbar-number">1 + + Assertion.response_data + false + 2 + + + + 0 + attribute_1_options_count + count((//div[@class="filter-options-content"])[1]//li[@class="item"]) + false + true + false + + + + 0 + attribute_2_options_count + count((//div[@class="filter-options-content"])[2]//li[@class="item"]) + false + true + false + + + + + attribute_1_filter_url + ((//div[@class="filter-options-content"])[1]//li[@class="item"]//a)[${__javaScript(Math.floor(Math.random()*${attribute_1_options_count})+1)}]/@href + false + true + false + + + + false + product_url_keys + <a class="product-item-link"(?s).+?href="http://${host}${base_path}(index.php/)?([^'"]+)${url_suffix}">(?s). + $2$ + + -1 + + + + + ${attribute_1_options_count} > 0 + false + + + + vars.put("search_url", vars.get("attribute_1_filter_url")); + + + false + + + + + + + + + + + + + ${attribute_1_filter_url} + GET + true + false + true + false + false + + + + + + Search results for: + <span class="toolbar-number">[1-9]+ + + Assertion.response_data + false + 2 + + + + 0 + attribute_2_options_count + count((//div[@class="filter-options-content"])[2]//li[@class="item"]) + false + true + false + + + + + attribute_2_filter_url + ((//div[@class="filter-options-content"])[2]//li[@class="item"]//a)[${__javaScript(Math.floor(Math.random()*${attribute_2_options_count})+1)}]/@href + false + true + false + + + + false + product_url_keys + <a class="product-item-link"(?s).+?href="http://${host}${base_path}(index.php/)?([^'"]+)${url_suffix}">(?s). + $2$ + + -1 + + + + + + ${attribute_2_options_count} > 0 + false + + + + vars.put("search_url", vars.get("attribute_2_filter_url")); + + + false + + + + + + + + + + + + + ${attribute_2_filter_url} + GET + true + false + true + false + false + + + + + + Search results for: + <span class="toolbar-number">[1-9]+ + + Assertion.response_data + false + 2 + + + + false + product_url_keys + <a class="product-item-link"(?s).+?href="http://${host}${base_path}(index.php/)?([^'"]+)${url_suffix}">(?s). + $2$ + + -1 + + + + + + product_url_keys + product_url_key + true + 0 + 3 + + + + 1 + 3 + 1 + _counter + + true + true + + + + + + + + + + + + + ${base_path}${product_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + + + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + + + + + + + + + + + + + + ${search_url}&p=2 + GET + true + false + true + false + false + + + + + + Search results for: + <span class="toolbar-number">[1-9]+ + + Assertion.response_data + false + 2 + + + + false + product_url_keys + <a class="product-item-link"(?s).+?href="http://${host}${base_path}(index.php/)?([^'"]+)${url_suffix}">(?s). + $2$ + + -1 + + + + + product_url_keys + product_url_key + true + 0 + 3 + + + + 1 + 3 + 1 + _counter + + true + true + + + + + + + + + + + + + ${base_path}${product_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + + + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + + + + + + + + Passing arguments between threads + vars.put("testLabel", "SearchAdvanced"); + + + + true + + + + + + + + + + + + + ${base_path} + GET + true + false + true + false + false + + + + + + <title>Home page</title> + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}catalogsearch/advanced/ + GET + true + false + true + false + false + + + + + + <title>Advanced Search</title> + + Assertion.response_data + false + 2 + + + + + attribute_name + (//select[@class="multiselect"])[last()]/@name + false + true + false + + + + 0 + attribute_options_count + count((//select[@class="multiselect"])[last()]/option) + false + true + false + + + + + attribute_value + ((//select[@class="multiselect"])[last()]/option)[${__javaScript(Math.floor(Math.random()*${attribute_options_count})+1)}]/@value + false + true + false + + + + + ${files_folder}search_terms.csv + + + , + true + true + false + shareMode.thread + + + + + + + true + name + + = + true + + + true + sku + + = + true + + + true + description + ${searchTerm} + = + true + + + true + short_description + + = + true + + + true + price%5Bfrom%5D + + = + true + + + true + price%5Bto%5D + ${priceTo} + = + true + + + true + tax_class_id + + = + true + + + true + ${attribute_value} + = + true + ${attribute_name} + + + + + + + + + + ${base_path}catalogsearch/advanced/result/ + GET + true + false + true + false + false + + + + + + items</strong> were found using the following search criteria + + Assertion.response_data + false + 2 + + + + false + product_url_keys + <a class="product-item-link"(?s).+?href="http://${host}${base_path}(index.php/)?([^'"]+)${url_suffix}">(?s). + $2$ + + -1 + + + + + product_url_keys + product_url_key + true + 0 + 3 + + + + 1 + 3 + 1 + _counter + + true + true + + + + + + + + + + + + + ${base_path}${product_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + + + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + + + + + - - - - - true - ["customer_form_login"] - = - true - blocks + + continue + + false + ${loops} + + ${__javaScript(Math.round(${numberOfThreads}*${frontEndPoolPercentage}*${addToCartPercentage}/10000))} + 0 + 1494514672000 + 1494514672000 + false + + + + + + ${test_duration} + + + + Passing arguments between threads + import org.apache.jmeter.samplers.SampleResult; + + number = (int)(Math.random() * props.get("simple_products_list").size()); + simpleList = props.get("simple_products_list").get(number); + vars.put("simple_product_1_url_key", simpleList.get("url_key")); + vars.put("simple_product_1_name", simpleList.get("title")); + vars.put("simple_product_1_id", simpleList.get("id")); + vars.put("simple_product_1_uenc", simpleList.get("uenc")); + + + do { + number1 = (int)(Math.random() * props.get("simple_products_list").size()); + } while(number == number1); + simpleList = props.get("simple_products_list").get(number1); + vars.put("simple_product_2_url_key", simpleList.get("url_key")); + vars.put("simple_product_2_name", simpleList.get("title")); + vars.put("simple_product_2_id", simpleList.get("id")); + vars.put("simple_product_2_uenc", simpleList.get("uenc")); + + + + number = (int)(Math.random() * props.get("configurable_products_list").size()); + configurableList = props.get("configurable_products_list").get(number); + vars.put("configurable_product_1_url_key", configurableList.get("url_key")); + vars.put("configurable_product_1_name", configurableList.get("title")); + vars.put("configurable_product_1_sku", configurableList.get("sku")); + vars.put("configurable_product_1_id", configurableList.get("id")); + vars.put("configurable_product_1_uenc", simpleList.get("uenc")); + + + + number = (int)(Math.random() * props.get("category_url_keys_list").size()); + vars.put("category_url_key", props.get("category_url_keys_list").get(number)); + vars.put("category_name", props.get("category_names_list").get(number)); + vars.put("loadType", "Guest"); + vars.put("testLabel", "Add To Cart By Guest"); + + + true + + + + + - - true - ["default","customer_account_login"] - = - true - handles + + + + + + + ${base_path} + GET + true + false + true + false + false + + + + + + <title>Home page</title> + + Assertion.response_data + false + 2 + + + + + + + + true + ["customer_form_login"] + = + true + blocks + + + true + ["default","customer_account_login"] + = + true + handles + + + true + {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} + = + true + originalRequest + + + true + true + = + true + ajax + + + true + true + = + true + isAjax + + - - true - {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} - = - true - originalRequest + + + + + + + ${base_path}page_cache/block/render/ + GET + true + false + true + false + false + + + + + + "customer_form_login" + Registered Customers + form_key + + Assertion.response_data + false + 2 + + + + false + form_key + <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + form_key + + + + + + - - true - true - = - true - ajax + + + + + + + ${base_path}${category_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <span class="base" data-ui-id="page-title">${category_name}</span> + + Assertion.response_data + false + 6 + + + + false + category_id + <li class="item category([^'"]+)">\s*<strong>${category_name}</strong>\s*</li> + $1$ + + 1 + simple_product_1_url_key + + + + + ^[0-9]+$ + + Assertion.response_data + false + 1 + variable + category_id + + + + + + - - true - true - = - true - isAjax + + + + + + + ${base_path}${simple_product_1_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${simple_product_1_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + false + ${simple_product_1_id} + = + true + product + + + false + + = + true + related_product + + + false + 1 + = + true + qty + + + false + ${form_key} + = + true + form_key + + - + + + + + + + ${base_path}checkout/cart/add/uenc/${simple_product_1_uenc}/product/${simple_product_1_id}/ + POST + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + + + + true + cart,messages + = + true + sections + + + true + true + = + true + update_section_id + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + You added ${simple_product_1_name} to your shopping cart. + + Assertion.response_data + false + 2 + + + + + This product is out of stock. + + Assertion.response_data + false + 6 + + + + + \"summary_count\":1 + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${simple_product_2_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${simple_product_2_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + false + ${simple_product_2_id} + = + true + product + + + false + + = + true + related_product + + + false + 1 + = + true + qty + + + false + ${form_key} + = + true + form_key + + + + + + + + + + ${base_path}checkout/cart/add/uenc/${simple_product_2_uenc}/product/${simple_product_2_id}/ + POST + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + + + + true + cart,messages + = + true + sections + true + + + true + true + = + true + update_section_id + true + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + true + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + You added ${simple_product_2_name} to your shopping cart. + + Assertion.response_data + false + 2 + + + + + This product is out of stock. + + Assertion.response_data + false + 6 + + + + + \"summary_count\":2 + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${configurable_product_1_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${configurable_product_1_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + + Content-Type + application/json + + + Accept + */* + + + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + + + + + + + ${base_path}rest/V1/configurable-products/${configurable_product_1_sku}/options/all + GET + true + false + true + false + false + + + + + attribute_ids + $.[*].attribute_id + NO_VALUE + + BODY + + + + option_values + $.[*].values[0].value_index + NO_VALUE + + BODY + + + + + + + + + false + ${configurable_product_1_id} + = + true + product + + + false + + = + true + related_product + + + false + 1 + = + true + qty + + + false + ${form_key} + = + true + form_key + + + + + + + + + + ${base_path}checkout/cart/add/uenc/${configurable_product_1_uenc}/product/${configurable_product_1_id}/ + POST + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + false + + + try { + attribute_ids = vars.get("attribute_ids"); + option_values = vars.get("option_values"); + attribute_ids = attribute_ids.replace("[","").replace("]","").replace("\"", ""); + option_values = option_values.replace("[","").replace("]","").replace("\"", ""); + attribute_ids_array = attribute_ids.split(","); + option_values_array = option_values.split(","); + args = ctx.getCurrentSampler().getArguments(); + it = args.iterator(); + while (it.hasNext()) { + argument = it.next(); + if (argument.getStringValue().contains("${")) { + args.removeArgument(argument.getName()); + } + } + for (int i = 0; i < attribute_ids_array.length; i++) { + ctx.getCurrentSampler().addArgument("super_attribute[" + attribute_ids_array[i] + "]", option_values_array[i]); + } +} catch (Exception e) { + log.error("error…", e); +} + + + + + + + + true + cart,messages + = + true + sections + true + + + true + true + = + true + update_section_id + true + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + true + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + You added ${configurable_product_1_name} to your shopping cart. + + Assertion.response_data + false + 2 + + + + + We don't have as many &quot;${configurable_product_1_name}&quot; as you requested. + + Assertion.response_data + false + 6 + + + + + \"summary_count\":3 + + Assertion.response_data + false + 2 + + + + false + quote_item_ids + \"item_id\":\"(\d+)\", + $1$ + + -1 + simple_product_1_url_key + + + + + quote_item_ids + item_id + true + + + + + + + false + ${item_id} + = + true + id + + + false + ${form_key} + = + true + form_key + + + + + + + + + + ${base_path}checkout/cart/delete + POST + false + false + true + false + false + + + + + + + + continue + + false + ${loops} - - - - - - - ${base_path}page_cache/block/render/ - GET - true - false - true - false - false - - + ${__javaScript(Math.round(${numberOfThreads}*${frontEndPoolPercentage}*${addToWishlistPercentage}/10000))} + 0 + 1437177203000 + 1437177203000 + false + + + - - - "customer_form_login" - Registered Customers - form_key - - Assertion.response_data - false - 2 - - - - false - form_key - <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> - $1$ - - 1 - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - form_key - + + + true + - - - - - - false - 1 - = - true - product + + ${test_duration} + + + + Passing arguments between threads + import org.apache.jmeter.samplers.SampleResult; +import java.util.ArrayList; +java.util.Random random = new java.util.Random(); + +number = (int)(random.nextDouble() * props.get("simple_products_list").size()); +numbersArray = new ArrayList(); +numbersArray.add(number); +simpleList = props.get("simple_products_list").get(number); +vars.put("simple_product_url_key_1", simpleList.get("url_key")); +vars.put("simple_product_name_1", simpleList.get("title")); +vars.put("simple_product_id_1", simpleList.get("id")); +vars.put("simple_product_uenc_1", simpleList.get("uenc")); + +do { + number1 = (int)(random.nextDouble() * props.get("simple_products_list").size()); +} while(numbersArray.indexOf(number1) != -1); +numbersArray.add(number1); +simpleList = props.get("simple_products_list").get(number1); +vars.put("simple_product_url_key_2", simpleList.get("url_key")); +vars.put("simple_product_name_2", simpleList.get("title")); +vars.put("simple_product_id_2", simpleList.get("id")); +vars.put("simple_product_uenc_2", simpleList.get("uenc")); + +do { + number2 = (int)(random.nextDouble() * props.get("simple_products_list").size()); +} while(numbersArray.indexOf(number2) != -1); +numbersArray.add(number2); +simpleList = props.get("simple_products_list").get(number2); +vars.put("simple_product_url_key_3", simpleList.get("url_key")); +vars.put("simple_product_name_3", simpleList.get("title")); +vars.put("simple_product_id_3", simpleList.get("id")); +vars.put("simple_product_uenc_3", simpleList.get("uenc")); + +do { + number3 = (int)(random.nextDouble() * props.get("simple_products_list").size()); +} while(numbersArray.indexOf(number3) != -1); +numbersArray.add(number3); +simpleList = props.get("simple_products_list").get(number3); +vars.put("simple_product_url_key_4", simpleList.get("url_key")); +vars.put("simple_product_name_4", simpleList.get("title")); +vars.put("simple_product_id_4", simpleList.get("id")); +vars.put("simple_product_uenc_4", simpleList.get("uenc")); + +do { + number4 = (int)(random.nextDouble() * props.get("simple_products_list").size()); +} while(numbersArray.indexOf(number4) != -1); +numbersArray.add(number4); +simpleList = props.get("simple_products_list").get(number4); +vars.put("simple_product_url_key_5", simpleList.get("url_key")); +vars.put("simple_product_name_5", simpleList.get("title")); +vars.put("simple_product_id_5", simpleList.get("id")); +vars.put("simple_product_uenc_5", simpleList.get("uenc")); + +emails_index = 0; +if (!props.containsKey("customer_emails_index")) { + props.put("customer_emails_index", emails_index); +} + +try { + emails_index = props.get("customer_emails_index"); + emails_list = props.get("customer_emails_list"); + if (emails_index == emails_list.size()) { + emails_index=0; + } + vars.put("customer_email", emails_list.get(emails_index)); + props.put("customer_emails_index", ++emails_index); +} +catch (java.lang.Exception e) { + log.error("Caught Exception in 'Add to Wishlist' thread."); + log.info("Using default email address - user_1@example.com"); + vars.put("customer_email", "user_1@example.com"); +} +vars.put("testLabel", "WishList"); +vars.put("loadType", "Customer"); + + + + + true + + + + + - - false - - = - true - related_product + + + + + + + ${base_path}customer/account/login/ + GET + true + false + true + false + false + + + + + + <title>Customer Login</title> + + Assertion.response_data + false + 2 + + + + + + + + true + ["customer_form_login"] + = + true + blocks + + + true + ["default","customer_account_login"] + = + true + handles + + + true + {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} + = + true + originalRequest + + + true + true + = + true + ajax + + + true + true + = + true + isAjax + + - - false - 1 - = - true - qty + + + + + + + ${base_path}page_cache/block/render/ + GET + true + false + true + false + false + + + + + + "customer_form_login" + Registered Customers + form_key + + Assertion.response_data + false + 2 + + + + false + form_key + <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + form_key + + + + + + + + true + ${form_key} + = + true + form_key + + + true + ${customer_email} + = + true + login[username] + + + true + ${customer_password} + = + true + login[password] + + + true + + = + true + send + + - - false - ${form_key} - = - true - form_key + + + + + + + ${base_path}customer/account/loginPost/ + POST + true + false + true + false + false + + + + + + <title>My Account</title> + + Assertion.response_data + false + 2 + + + + false + addressId + customer/address/edit/id/([^'"]+)/ + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + addressId + + + + + simple_product_url_key + url_key + true + 0 + 5 + + + + 1 + 5 + 1 + counter + + true + true + + + + + + + + + + + + + ${base_path}${url_key}${url_suffix} + GET + true + false + true + false + false + + + + + false + + + vars.put("simple_product_name", vars.get("simple_product_name_" + vars.get("counter"))); + + + + + <title>${simple_product_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + false + simple_product_uenc + "uenc":"([^"]+)" + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + simple_product_uenc + + + + + + + + true + ${form_key} + = + true + form_key + false + + + true + ${simple_product_uenc} + = + true + uenc + + + true + ${product_id} + = + true + product + + + + + + + + + + ${base_path}wishlist/index/add/ + POST + true + false + true + false + false + + + + + false + + + vars.put("product_id", vars.get("simple_product_id_" + vars.get("counter"))); + + + + + <title>My Wish List</title> + + Assertion.response_data + false + 16 + + + + false + wishListItems + data-post-remove='\{"action":"(.+)\/wishlist\\/index\\/remove\\/","data":\{"item":"([^"]+)" + $2$ + + -1 + + + + false + + + sampler = ctx.getCurrentSampler(); +manager = sampler.getCookieManager(); +for (int i = 0; i < manager.getCookieCount(); i++){ + cookie = manager.get(i); + if (cookie.getName().equals("mage-messages")){ + sampler.getCookieManager().remove(i); + break; + } +} + + + + + + + + true + wishlist,messages + = + true + sections + + + true + false + = + true + update_section_id + + + true + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + {"wishlist":{"counter":" + + Assertion.response_data + false + 16 + + + + ${wishlistDelay}*1000 + + + + + + wishListItems + wishListItem + true + + + + 1 + 5 + 1 + counter + + true + true + + + + + + + true + ${form_key} + = + true + form_key + true + + + true + ${simple_product_uenc} + = + true + uenc + true + + + true + ${wishListItem} + = + true + item + true + + + + + + + + + + ${base_path}wishlist/index/remove/ + POST + true + false + true + false + false + + + + + false + + + vars.put("simple_product_uenc", vars.get("simple_product_uenc_" + vars.get("counter"))); + + + + + + + - + + + + + + + ${base_path}customer/account/logout/ + GET + true + false + true + false + false + + + + + + You are signed out. + + Assertion.response_data + false + 2 + + + + + + + continue + + false + ${loops} - - - - - - - ${base_path}checkout/cart/add - POST - true - false - true - false - false - - - - - - - continue - - false - ${loops} - - ${__javaScript(Math.round(props.get("users")*${view_catalog_percent}/100>>0))} - ${ramp_period} - 1437409133000 - 1437409133000 - false - - - - - - Passing arguments between threads - -number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); -simpleList = props.get("simple_products_list").get(number); -vars.put("simple_product_1_url_key", simpleList.get("url_key")); -vars.put("simple_product_1_name", simpleList.get("title")); -vars.put("simple_product_1_id", simpleList.get("id")); + ${__javaScript(Math.round(${numberOfThreads}*${frontEndPoolPercentage}*${compareProductsPercentage}/10000))} + 0 + 1437177203000 + 1437177203000 + false + + + + + + + true + + + + ${test_duration} + + + + Passing arguments between threads + import org.apache.jmeter.samplers.SampleResult; -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); -simpleList = props.get("simple_products_list").get(number1); -vars.put("simple_product_2_url_key", simpleList.get("url_key")); -vars.put("simple_product_2_name", simpleList.get("title")); -vars.put("simple_product_2_id", simpleList.get("id")); +number = (int)(Math.random() * props.get("simple_products_list").size()); +simpleList = props.get("simple_products_list").get(number); +vars.put("simple_product_1_url_key", simpleList.get("url_key")); +vars.put("simple_product_1_name", simpleList.get("title")); +vars.put("simple_product_1_id", simpleList.get("id")); +vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); -configurableList = props.get("configurable_products_list").get(number); -vars.put("configurable_product_1_url_key", configurableList.get("url_key")); -vars.put("configurable_product_1_name", configurableList.get("title")); -vars.put("configurable_product_1_id", configurableList.get("id")); +number = (int)(Math.random() * props.get("configurable_products_list").size()); +configurableList = props.get("configurable_products_list").get(number); +vars.put("configurable_product_1_url_key", configurableList.get("url_key")); +vars.put("configurable_product_1_name", configurableList.get("title")); +vars.put("configurable_product_1_id", configurableList.get("id")); +vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); -vars.put("category_url_key", props.get("category_url_keys_list").get(number)); -vars.put("category_name", props.get("category_names_list").get(number)); -vars.put("testLabel", "CatProdBrows"); - - - true - - - - - - +number = (int)(Math.random() * props.get("category_url_keys_list").size()); +vars.put("category_url_key", props.get("category_url_keys_list").get(number)); +vars.put("category_name", props.get("category_names_list").get(number)); +vars.put("category_id", props.get("category_id")); +vars.put("testLabel", "Product Compare By Guest"); + + + true + + + + + + + true + ["customer_form_login"] + = + true + blocks + + + true + ["default","customer_account_login"] + = + true + handles + + + true + {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} + = + true + originalRequest + + + true + true + = + true + ajax + + + true + true + = + true + isAjax + + + + + + + + + + ${base_path}page_cache/block/render/ + GET + true + false + true + false + false + + + + + + "customer_form_login" + Registered Customers + form_key + + Assertion.response_data + false + 2 + + + + false + form_key + <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + form_key + + + + + + + + + + + + + + ${base_path}${simple_product_1_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${simple_product_1_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + true + ${simple_product_1_id} + = + true + product + + + true + ${form_key} + = + true + form_key + + + true + ${simple_product_1_uenc} + = + true + uenc + + + + + + + + + + ${base_path}catalog/product_compare/add/ + POST + true + false + true + false + false + + + + + + + + true + + = + true + sections + + + true + false + = + true + update_section_id + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + + + + + + + + ${base_path}${category_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <span class="base" data-ui-id="page-title">${category_name}</span> + + Assertion.response_data + false + 6 + + + + false + random_product_compare_id + catalog\\/product_compare\\/add\\/\",\"data\":\{\"product\":\"([0-9]+)\" + $1$ + + 0 + + + + + ^[0-9]+$ + + Assertion.response_data + false + 1 + variable + random_product_compare_id + + + + false + product_compare_uenc + catalog\\/product_compare\\/add\\/\",\"data\":\{\"product\":\"([0-9]+)\",\"uenc\":\"([^"]+)\" + $2$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + product_compare_uenc + + + + + + + + true + ${random_product_compare_id} + = + true + product + + + true + ${form_key} + = + true + form_key + + + true + ${product_compare_uenc} + = + true + uenc + + + + + + + + + + ${base_path}catalog/product_compare/add/ + POST + true + false + true + false + false + + + + + + + + true + + = + true + sections + + + true + false + = + true + update_section_id + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + + + + + + + + ${base_path}${configurable_product_1_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${configurable_product_1_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + true + ${configurable_product_1_id} + = + true + product + + + true + ${form_key} + = + true + form_key + + + true + ${configurable_product_1_uenc} + = + true + uenc + + + + + + + + + + ${base_path}catalog/product_compare/add/ + POST + true + false + true + false + false + + + + + + + + true + + = + true + sections + + + true + false + = + true + update_section_id + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + + + + + + + + ${base_path}catalog/product_compare/index/items/${simple_product_1_id},${random_product_compare_id},${configurable_product_1_id}/uenc/${product_compare_uenc}/ + GET + true + false + true + false + false + + + + + + + + true + + = + true + sections + + + true + false + = + true + update_section_id + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + \"messages\": + + Assertion.response_data + false + 2 + + + + + 1 + 0 + ${__javaScript(Math.round(${productCompareDelay}*1000))} + + + + + + + true + ${form_key} + = + true + form_key + + + true + + = + true + uenc + + + + + + + + + + ${base_path}catalog/product_compare/clear + POST + true + false + true + false + false + + + + + false + + + curSampler = ctx.getCurrentSampler(); + +if (curSampler.getName().contains("Compare Products Clear")) { + manager = curSampler.getCookieManager(); + manager.clear(); +} + + + + + + continue + + false + ${loops} - - - - - - - ${base_path} - GET - true - false - true - false - false - - + ${__javaScript(Math.round(${numberOfThreads}*${frontEndPoolPercentage}*${checkoutByGuestPercentage}/10000))} + 0 + 1437409133000 + 1437409133000 + false + + + - - - <title>Home page</title> - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${category_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <span class="base" data-ui-id="page-title">${category_name}</span> - - Assertion.response_data - false - 6 - - - - false - category_id - <li class="item category([^'"]+)">\s*<strong>${category_name}</strong>\s*</li> - $1$ - - 1 - simple_product_1_url_key - - - - - ^[0-9]+$ - - Assertion.response_data - false - 1 - variable - category_id - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${simple_product_1_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${simple_product_1_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - product_id - .//input[@type="hidden" and @name="product"]/@value - false - true - false - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - product_id - - - - - - - - - - - - - - ${base_path}review/product/listAjax/id/${product_id}/ - GET - true - false - true - false - false - - - - - - 200 - - Assertion.response_code - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${simple_product_2_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${simple_product_2_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - product_id - .//input[@type="hidden" and @name="product"]/@value - false - true - false - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - product_id - - - - - - - - - - - - - - ${base_path}review/product/listAjax/id/${product_id}/ - GET - true - false - true - false - false - - - - - - 200 - - Assertion.response_code - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${configurable_product_1_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${configurable_product_1_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - - - continue - - false - ${loops} - - ${__javaScript(Math.round(props.get("users")*${view_product_add_to_cart_percent}/100>>0))} - ${ramp_period} - 1437411475000 - 1437411475000 - false - - - - - - Passing arguments between threads - number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); -simpleList = props.get("simple_products_list").get(number); -vars.put("simple_product_1_url_key", simpleList.get("url_key")); -vars.put("simple_product_1_name", simpleList.get("title")); -vars.put("simple_product_1_id", simpleList.get("id")); -vars.put("simple_product_1_uenc", simpleList.get("uenc")); + + ${test_duration} + + + + Passing arguments between threads + import org.apache.jmeter.samplers.SampleResult; -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); -simpleList = props.get("simple_products_list").get(number1); -vars.put("simple_product_2_url_key", simpleList.get("url_key")); -vars.put("simple_product_2_name", simpleList.get("title")); -vars.put("simple_product_2_id", simpleList.get("id")); -vars.put("simple_product_2_uenc", simpleList.get("uenc")); + number = (int)(Math.random() * props.get("simple_products_list").size()); + simpleList = props.get("simple_products_list").get(number); + vars.put("simple_product_1_url_key", simpleList.get("url_key")); + vars.put("simple_product_1_name", simpleList.get("title")); + vars.put("simple_product_1_id", simpleList.get("id")); + vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); -configurableList = props.get("configurable_products_list").get(number); -vars.put("configurable_product_1_url_key", configurableList.get("url_key")); -vars.put("configurable_product_1_name", configurableList.get("title")); -vars.put("configurable_product_1_id", configurableList.get("id")); -vars.put("configurable_attribute_id", configurableList.get("attribute_id")); -vars.put("configurable_option_id", configurableList.get("attribute_option_id")); -vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); -vars.put("category_url_key", props.get("category_url_keys_list").get(number)); -vars.put("category_name", props.get("category_names_list").get(number)); -vars.put("testLabel", "BrowsAddToCart"); -vars.put("loadType", "Guest"); - - - true - - - - - - + do { + number1 = (int)(Math.random() * props.get("simple_products_list").size()); + } while(number == number1); + simpleList = props.get("simple_products_list").get(number1); + vars.put("simple_product_2_url_key", simpleList.get("url_key")); + vars.put("simple_product_2_name", simpleList.get("title")); + vars.put("simple_product_2_id", simpleList.get("id")); + vars.put("simple_product_2_uenc", simpleList.get("uenc")); + + + + number = (int)(Math.random() * props.get("configurable_products_list").size()); + configurableList = props.get("configurable_products_list").get(number); + vars.put("configurable_product_1_url_key", configurableList.get("url_key")); + vars.put("configurable_product_1_name", configurableList.get("title")); + vars.put("configurable_product_1_sku", configurableList.get("sku")); + vars.put("configurable_product_1_id", configurableList.get("id")); + vars.put("configurable_product_1_uenc", simpleList.get("uenc")); + + + + number = (int)(Math.random() * props.get("category_url_keys_list").size()); + vars.put("category_url_key", props.get("category_url_keys_list").get(number)); + vars.put("category_name", props.get("category_names_list").get(number)); + vars.put("loadType", "Guest"); + vars.put("testLabel", "Checkout By Guest"); + + + true + + + + + + + + + + + + + ${base_path} + GET + true + false + true + false + false + + + + + + <title>Home page</title> + + Assertion.response_data + false + 2 + + + + + + + + true + ["customer_form_login"] + = + true + blocks + + + true + ["default","customer_account_login"] + = + true + handles + + + true + {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} + = + true + originalRequest + + + true + true + = + true + ajax + + + true + true + = + true + isAjax + + + + + + + + + + ${base_path}page_cache/block/render/ + GET + true + false + true + false + false + + + + + + "customer_form_login" + Registered Customers + form_key + + Assertion.response_data + false + 2 + + + + false + form_key + <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + form_key + + + + + + + + + + + + + + ${base_path}${category_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <span class="base" data-ui-id="page-title">${category_name}</span> + + Assertion.response_data + false + 6 + + + + false + category_id + <li class="item category([^'"]+)">\s*<strong>${category_name}</strong>\s*</li> + $1$ + + 1 + simple_product_1_url_key + + + + + ^[0-9]+$ + + Assertion.response_data + false + 1 + variable + category_id + + + + + + + + + + + + + + ${base_path}${simple_product_1_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${simple_product_1_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + false + ${simple_product_1_id} + = + true + product + + + false + + = + true + related_product + + + false + 1 + = + true + qty + + + false + ${form_key} + = + true + form_key + + + + + + + + + + ${base_path}checkout/cart/add/uenc/${simple_product_1_uenc}/product/${simple_product_1_id}/ + POST + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + + + + true + cart,messages + = + true + sections + + + true + true + = + true + update_section_id + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + You added ${simple_product_1_name} to your shopping cart. + + Assertion.response_data + false + 2 + + + + + This product is out of stock. + + Assertion.response_data + false + 6 + + + + + \"summary_count\":1 + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${simple_product_2_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${simple_product_2_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + false + ${simple_product_2_id} + = + true + product + + + false + + = + true + related_product + + + false + 1 + = + true + qty + + + false + ${form_key} + = + true + form_key + + + + + + + + + + ${base_path}checkout/cart/add/uenc/${simple_product_2_uenc}/product/${simple_product_2_id}/ + POST + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + + + + true + cart,messages + = + true + sections + true + + + true + true + = + true + update_section_id + true + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + true + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + You added ${simple_product_2_name} to your shopping cart. + + Assertion.response_data + false + 2 + + + + + This product is out of stock. + + Assertion.response_data + false + 6 + + + + + \"summary_count\":2 + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${configurable_product_1_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${configurable_product_1_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + + Content-Type + application/json + + + Accept + */* + + + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + + + + + + + ${base_path}rest/V1/configurable-products/${configurable_product_1_sku}/options/all + GET + true + false + true + false + false + + + + + attribute_ids + $.[*].attribute_id + NO_VALUE + + BODY + + + + option_values + $.[*].values[0].value_index + NO_VALUE + + BODY + + + + + + + + + false + ${configurable_product_1_id} + = + true + product + + + false + + = + true + related_product + + + false + 1 + = + true + qty + + + false + ${form_key} + = + true + form_key + + + + + + + + + + ${base_path}checkout/cart/add/uenc/${configurable_product_1_uenc}/product/${configurable_product_1_id}/ + POST + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + false + + + try { + attribute_ids = vars.get("attribute_ids"); + option_values = vars.get("option_values"); + attribute_ids = attribute_ids.replace("[","").replace("]","").replace("\"", ""); + option_values = option_values.replace("[","").replace("]","").replace("\"", ""); + attribute_ids_array = attribute_ids.split(","); + option_values_array = option_values.split(","); + args = ctx.getCurrentSampler().getArguments(); + it = args.iterator(); + while (it.hasNext()) { + argument = it.next(); + if (argument.getStringValue().contains("${")) { + args.removeArgument(argument.getName()); + } + } + for (int i = 0; i < attribute_ids_array.length; i++) { + ctx.getCurrentSampler().addArgument("super_attribute[" + attribute_ids_array[i] + "]", option_values_array[i]); + } +} catch (Exception e) { + log.error("error…", e); +} + + + + + + + + true + cart,messages + = + true + sections + true + + + true + true + = + true + update_section_id + true + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + true + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + You added ${configurable_product_1_name} to your shopping cart. + + Assertion.response_data + false + 2 + + + + + We don't have as many &quot;${configurable_product_1_name}&quot; as you requested. + + Assertion.response_data + false + 6 + + + + + \"summary_count\":3 + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}checkout/ + GET + true + false + true + false + false + + + + + + <title>Checkout</title> + + Assertion.response_data + false + 2 + + + + + <title>Shopping Cart</title> + + Assertion.response_data + false + 6 + + + + false + cart_id + "quoteData":{"entity_id":"([^'"]+)", + $1$ + + 1 + + + + false + form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + cart_id + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + form_key + + + + + true + + + + false + {"customerEmail":"test@example.com"} + = + + + + + + + + + + ${base_path}rest/default/V1/customers/isEmailAvailable + POST + true + false + true + false + false + + + + + + + Referer + ${base_path}checkout/onepage/ + + + Content-Type + application/json; charset=UTF-8 + + + X-Requested-With + XMLHttpRequest + + + Accept + application/json + + + + + + + true + + Assertion.response_data + false + 8 + + + + + true + + + + false + {"address":{"country_id":"US","postcode":"95630"}} + = + + + + + + + + + + ${base_path}rest/default/V1/guest-carts/${cart_id}/estimate-shipping-methods + POST + true + false + true + false + false + + + + + + + Referer + ${base_path}checkout/onepage/ + + + Content-Type + application/json; charset=UTF-8 + + + X-Requested-With + XMLHttpRequest + + + Accept + application/json + + + + + + + "available":true + + Assertion.response_data + false + 2 + + + + + true + + + + false + {"addressInformation":{"shipping_address":{"country_id":"US","regionId":"12","region_code":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname"},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}} + = + + + + + + + + + + ${base_path}rest/default/V1/guest-carts/${cart_id}/shipping-information + POST + true + false + true + false + false + + + + + + + Referer + ${base_path}checkout/onepage/ + + + Content-Type + application/json; charset=UTF-8 + + + X-Requested-With + XMLHttpRequest + + + Accept + application/json + + + + + + + {"payment_methods": + + Assertion.response_data + false + 2 + + + + + true + + + + false + {"email":"test@example.com","paymentMethod":{"method":"checkmo","po_number":null,"additional_data":null},"billingAddress":{"country_id":"US","region_id":"12","region_code":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname"}} + = + + + + + + + + + + ${base_path}rest/default/V1/guest-carts/${cart_id}/payment-information + POST + true + false + true + false + false + + + + + + + Referer + ${base_path}checkout/onepage/ + + + Content-Type + application/json; charset=UTF-8 + + + X-Requested-With + XMLHttpRequest + + + Accept + application/json + + + + + + + "[0-9]+" + + Assertion.response_data + false + 2 + + + + order_id + $ + + + BODY + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + order_id + + + + + + + + + + + + + + ${base_path}checkout/onepage/success/ + GET + true + false + true + false + false + + + + + + Thank you for your purchase! + Your order # is + + Assertion.response_data + false + 2 + + + + + + + continue + + false + ${loops} - - - - - - - ${base_path} - GET - true - false - true - false - false - - + ${__javaScript(Math.round(${numberOfThreads}*${frontEndPoolPercentage}*${checkoutByCustomerPercentage}/10000))} + 0 + 1437177203000 + 1437177203000 + false + + + - - - <title>Home page</title> - - Assertion.response_data - false - 2 - + + + true + - - - - - - - true - ["customer_form_login"] - = - true - blocks - - - true - ["default","customer_account_login"] - = - true - handles - - - true - {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} - = - true - originalRequest - - - true - true - = - true - ajax - - - true - true - = - true - isAjax - - - - - - - - - - ${base_path}page_cache/block/render/ - GET - true - false - true - false - false - - - - - - "customer_form_login" - Registered Customers - form_key - - Assertion.response_data - false - 2 - - - - false - form_key - <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> - $1$ - - 1 - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - form_key - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${category_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <span class="base" data-ui-id="page-title">${category_name}</span> - - Assertion.response_data - false - 6 - - - - false - category_id - <li class="item category([^'"]+)">\s*<strong>${category_name}</strong>\s*</li> - $1$ - - 1 - simple_product_1_url_key - - - - - ^[0-9]+$ - - Assertion.response_data - false - 1 - variable - category_id - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${simple_product_1_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${simple_product_1_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - product_id - .//input[@type="hidden" and @name="product"]/@value - false - true - false - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - product_id - - - - - - - - - - - - - - ${base_path}review/product/listAjax/id/${product_id}/ - GET - true - false - true - false - false - - - - - - 200 - - Assertion.response_code - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - false - ${simple_product_1_id} - = - true - product - - - false - - = - true - related_product - - - false - 1 - = - true - qty - - - false - ${form_key} - = - true - form_key - - - - - - - - - - ${base_path}checkout/cart/add/ - POST - true - false - true - false - false - - + + ${test_duration} + + + + Passing arguments between threads + import org.apache.jmeter.samplers.SampleResult; - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - - - - true - cart,messages - = - true - sections - - - true - true - = - true - update_section_id - - - false - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} - = - true - _ - - - - - - - - - - ${base_path}customer/section/load/ - GET - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - You added ${simple_product_1_name} to your shopping cart. - - Assertion.response_data - false - 2 - - - - - This product is out of stock. - - Assertion.response_data - false - 6 - - - - - \"summary_count\":1 - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${simple_product_2_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${simple_product_2_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - product_id - .//input[@type="hidden" and @name="product"]/@value - false - true - false - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - product_id - - - - - - - - - - - - - - ${base_path}review/product/listAjax/id/${product_id}/ - GET - true - false - true - false - false - - - - - - 200 - - Assertion.response_code - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - false - ${simple_product_2_id} - = - true - product - - - false - - = - true - related_product - - - false - 1 - = - true - qty - - - false - ${form_key} - = - true - form_key - - - - - - - - - - ${base_path}checkout/cart/add/ - POST - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - - - - true - cart,messages - = - true - sections - true - - - true - true - = - true - update_section_id - true - - - false - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} - = - true - _ - true - - - - - - - - - - ${base_path}customer/section/load/ - GET - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - You added ${simple_product_2_name} to your shopping cart. - - Assertion.response_data - false - 2 - - - - - This product is out of stock. - - Assertion.response_data - false - 6 - - - - - \"summary_count\":2 - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${configurable_product_1_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${configurable_product_1_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - false - configurable_product_sku - itemprop="sku">([^<]*)<\/ - $1$ - NOT_FOUND - 1 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - true - 1 - - - - - - Content-Type - application/json - - - Accept - */* - - - - - - true - - - - false - {"username":"${admin_user}","password":"${admin_password}"} - = + number = (int)(Math.random() * props.get("simple_products_list").size()); + simpleList = props.get("simple_products_list").get(number); + vars.put("simple_product_1_url_key", simpleList.get("url_key")); + vars.put("simple_product_1_name", simpleList.get("title")); + vars.put("simple_product_1_id", simpleList.get("id")); + vars.put("simple_product_1_uenc", simpleList.get("uenc")); + + + do { + number1 = (int)(Math.random() * props.get("simple_products_list").size()); + } while(number == number1); + simpleList = props.get("simple_products_list").get(number1); + vars.put("simple_product_2_url_key", simpleList.get("url_key")); + vars.put("simple_product_2_name", simpleList.get("title")); + vars.put("simple_product_2_id", simpleList.get("id")); + vars.put("simple_product_2_uenc", simpleList.get("uenc")); + + + + number = (int)(Math.random() * props.get("configurable_products_list").size()); + configurableList = props.get("configurable_products_list").get(number); + vars.put("configurable_product_1_url_key", configurableList.get("url_key")); + vars.put("configurable_product_1_name", configurableList.get("title")); + vars.put("configurable_product_1_sku", configurableList.get("sku")); + vars.put("configurable_product_1_id", configurableList.get("id")); + vars.put("configurable_product_1_uenc", simpleList.get("uenc")); + + + + number = (int)(Math.random() * props.get("category_url_keys_list").size()); + vars.put("category_url_key", props.get("category_url_keys_list").get(number)); + vars.put("category_name", props.get("category_names_list").get(number)); + + + customers_index = 0; + if (!props.containsKey("customer_ids_index")) { + props.put("customer_ids_index", customers_index); + } + + try { + customers_index = props.get("customer_ids_index"); + customers_list = props.get("customer_emails_list"); + + if (customers_index == customers_list.size()) { + customers_index=0; + } + vars.put("customer_email", customers_list.get(customers_index)); + props.put("customer_ids_index", ++customers_index); + } + catch (java.lang.Exception e) { + log.error("Caught Exception in 'Checkout By Customer' thread."); + SampleResult.setStopThread(true); + } + vars.put("loadType", "Customer"); + vars.put("testLabel", "Checkout By Customer"); + + + true + + + + + + + true + ["customer_form_login"] + = + true + blocks + + + true + ["default","customer_account_login"] + = + true + handles + + + true + {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} + = + true + originalRequest + + + true + true + = + true + ajax + + + true + true + = + true + isAjax + + - + + + + + + + ${base_path}page_cache/block/render/ + GET + true + false + true + false + false + + + + + + "customer_form_login" + Registered Customers + form_key + + Assertion.response_data + false + 2 + + + + false + form_key + <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + form_key + + + + + + + + + + + + + + ${base_path} + GET + true + false + true + false + false + + + + + + <title>Home page</title> + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${category_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <span class="base" data-ui-id="page-title">${category_name}</span> + + Assertion.response_data + false + 6 + + + + false + category_id + <li class="item category([^'"]+)">\s*<strong>${category_name}</strong>\s*</li> + $1$ + + 1 + simple_product_1_url_key + + + + + ^[0-9]+$ + + Assertion.response_data + false + 1 + variable + category_id + + + + + + + + + + + + + + ${base_path}${simple_product_1_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${simple_product_1_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + false + ${simple_product_1_id} + = + true + product + + + false + + = + true + related_product + + + false + 1 + = + true + qty + + + false + ${form_key} + = + true + form_key + + + + + + + + + + ${base_path}checkout/cart/add/uenc/${simple_product_1_uenc}/product/${simple_product_1_id}/ + POST + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + + + + true + cart,messages + = + true + sections + + + true + true + = + true + update_section_id + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + You added ${simple_product_1_name} to your shopping cart. + + Assertion.response_data + false + 2 + + + + + This product is out of stock. + + Assertion.response_data + false + 6 + + + + + \"summary_count\":1 + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${simple_product_2_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${simple_product_2_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + false + ${simple_product_2_id} + = + true + product + + + false + + = + true + related_product + + + false + 1 + = + true + qty + + + false + ${form_key} + = + true + form_key + + + + + + + + + + ${base_path}checkout/cart/add/uenc/${simple_product_2_uenc}/product/${simple_product_2_id}/ + POST + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + + + + true + cart,messages + = + true + sections + true + + + true + true + = + true + update_section_id + true + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + true + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + You added ${simple_product_2_name} to your shopping cart. + + Assertion.response_data + false + 2 + + + + + This product is out of stock. + + Assertion.response_data + false + 6 + + + + + \"summary_count\":2 + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${configurable_product_1_url_key}${url_suffix} + GET + true + false + true + false + false + + + + + + <title>${configurable_product_1_name} + <span>In stock</span> + + Assertion.response_data + false + 2 + + + + + + + + + Content-Type + application/json + + + Accept + */* + + + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + + + + + + + ${base_path}rest/V1/configurable-products/${configurable_product_1_sku}/options/all + GET + true + false + true + false + false + + + + + attribute_ids + $.[*].attribute_id + NO_VALUE + + BODY + + + + option_values + $.[*].values[0].value_index + NO_VALUE + + BODY + + + + + + + + + false + ${configurable_product_1_id} + = + true + product + + + false + + = + true + related_product + + + false + 1 + = + true + qty + + + false + ${form_key} + = + true + form_key + + + + + + + + + + ${base_path}checkout/cart/add/uenc/${configurable_product_1_uenc}/product/${configurable_product_1_id}/ + POST + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + false + + + try { + attribute_ids = vars.get("attribute_ids"); + option_values = vars.get("option_values"); + attribute_ids = attribute_ids.replace("[","").replace("]","").replace("\"", ""); + option_values = option_values.replace("[","").replace("]","").replace("\"", ""); + attribute_ids_array = attribute_ids.split(","); + option_values_array = option_values.split(","); + args = ctx.getCurrentSampler().getArguments(); + it = args.iterator(); + while (it.hasNext()) { + argument = it.next(); + if (argument.getStringValue().contains("${")) { + args.removeArgument(argument.getName()); + } + } + for (int i = 0; i < attribute_ids_array.length; i++) { + ctx.getCurrentSampler().addArgument("super_attribute[" + attribute_ids_array[i] + "]", option_values_array[i]); + } +} catch (Exception e) { + log.error("error…", e); +} + + + + + + + + true + cart,messages + = + true + sections + true + + + true + true + = + true + update_section_id + true + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + _ + true + + + + + + + + + + ${base_path}customer/section/load/ + GET + true + false + true + false + false + + + + + + + X-Requested-With + XMLHttpRequest + + + + + + + You added ${configurable_product_1_name} to your shopping cart. + + Assertion.response_data + false + 2 + + + + + We don't have as many &quot;${configurable_product_1_name}&quot; as you requested. + + Assertion.response_data + false + 6 + + + + + \"summary_count\":3 + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}customer/account/login/ + GET + true + false + true + false + false + + + + + + <title>Customer Login</title> + + Assertion.response_data + false + 2 + + + + + + + + true + ["customer_form_login"] + = + true + blocks + + + true + ["default","customer_account_login"] + = + true + handles + + + true + {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} + = + true + originalRequest + + + true + true + = + true + ajax + + + true + true + = + true + isAjax + + + + + + + + + + ${base_path}page_cache/block/render/ + GET + true + false + true + false + false + + + + + + "customer_form_login" + Registered Customers + form_key + + Assertion.response_data + false + 2 + + + + false + form_key + <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + form_key + + + + + + + + true + ${form_key} + = + true + form_key + + + true + ${customer_email} + = + true + login[username] + + + true + ${customer_password} + = + true + login[password] + + + true + + = + true + send + + + + + + + + + + ${base_path}customer/account/loginPost/ + POST + true + false + true + false + false + + + + + + <title>My Account</title> + + Assertion.response_data + false + 2 + + + + false + addressId + customer/address/edit/id/([^'"]+)/ + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + addressId + + + + + + + + + + + + + + ${base_path}checkout/ + GET + true + false + true + false + false + + + + + + <title>Checkout</title> + + Assertion.response_data + false + 2 + + + + + <title>Shopping Cart</title> + + Assertion.response_data + false + 6 + + + + false + cart_id + "quoteData":{"entity_id":"([^'"]+)", + $1$ + + 1 + + + + false + form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + + + + false + address_id + "default_billing":"([^'"]+)", + $1$ + + 1 + + + + false + customer_id + "customer_id":([^'",]+), + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + cart_id + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + form_key + + + + + [0-9]+$ + + Assertion.response_data + false + 1 + variable + address_id + + + + + [0-9]+$ + + Assertion.response_data + false + 1 + variable + customer_id + + + + + true + + + + false + {"addressId":"${addressId}"} + = + + + + + + + + + + ${base_path}rest/default/V1/carts/mine/estimate-shipping-methods-by-address-id + POST + true + false + true + false + false + + + + + + + Referer + ${base_path}checkout/onepage/ + + + Content-Type + application/json; charset=UTF-8 + + + X-Requested-With + XMLHttpRequest + + + Accept + application/json + + + + + + + "available":true + + Assertion.response_data + false + 2 + + + + + true + + + + false + {"addressInformation":{"shipping_address":{"customer_address_id":"${address_id}","country_id":"US","region_id":5,"region_code":"AR","region":"Arkansas","customer_id":"${customer_id}","street":["123 Freedom Blvd. #123"],"telephone":"022-333-4455","postcode":"123123","city":"Fayetteville","firstname":"Anthony","lastname":"Nealy"},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}} + = + + + + + + + + + + ${base_path}rest/default/V1/carts/mine/shipping-information + POST + true + false + true + false + false + + + + + + + Referer + ${host}${base_path}checkout/onepage + + + Content-Type + application/json; charset=UTF-8 + + + X-Requested-With + XMLHttpRequest + + + Accept + application/json + + + + + + + {"payment_methods" + + Assertion.response_data + false + 2 + + + + + true + + + + false + {"paymentMethod":{"method":"checkmo","po_number":null,"additional_data":null},"billingAddress":{"customer_address_id":"${address_id}","country_id":"US","region_id":5,"region_code":"AR","region":"Arkansas","customer_id":"${customer_id}","street":["123 Freedom Blvd. #123"],"telephone":"022-333-4455","postcode":"123123","city":"Fayetteville","firstname":"Anthony","lastname":"Nealy"}} + = + + + + + + + + + + ${base_path}rest/default/V1/carts/mine/payment-information + POST + true + false + true + false + false + + + + + + + Referer + ${host}${base_path}checkout/onepage + + + Content-Type + application/json; charset=UTF-8 + + + Accept + application/json + + + X-Requested-With + XMLHttpRequest + + + + + + + "[0-9]+" + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}checkout/onepage/success/ + GET + true + false + true + false + false + + + + + + Thank you for your purchase! + Your order number is + + Assertion.response_data + false + 2 + + + + + false + + + curSampler = ctx.getCurrentSampler(); + if(curSampler.getName().contains("Checkout success")) { + manager = curSampler.getCookieManager(); + manager.clear(); + } + + + + + + + startnextloop + + false + ${loops} - - - - - - - ${base_path}rest/V1/integration/admin/token - POST - true - false - true - false - false - - + ${__javaScript(Math.round(${numberOfThreads}*${adminPoolPercentage}*${merchandizingPercentage}*${adminProductManagementPercentage}*${adminProductEditingPercentage}/100000000))} + 0 + 1304708488000 + 1304708488000 + false + + + - - admin_token - $ - - - BODY - - - - - ^[a-z0-9-]+$ - - Assertion.response_data - false - 1 - variable - admin_token - - + + + + + + + + + + + + + ${base_path}${admin_path} + GET + true + false + true + false + false + + + + + + Welcome + <title>Magento Admin</title> + + Assertion.response_data + false + 2 + + + + false + admin_form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_form_key + + + + + + + + false + ${admin_form_key} + = + true + form_key + + + true + ${admin_password} + = + true + login[password] + + + true + ${admin_user} + = + true + login[username] + + + + + + + + + + ${base_path}${admin_path}/admin/dashboard/ + POST + true + false + true + false + Java + false + + Implementation needs to be set to Java as per http://stackoverflow.com/questions/19636282/jmeter-error-in-redirect-url-for-get + + + + + ${test_duration} + + + + + + Passing arguments between threads + import java.util.ArrayList; +import java.util.HashMap; + +int simpleCount = props.get("simple_products_list").size(); +int configCount = props.get("configurable_products_list").size(); +int productCount; +if (simpleCount > configCount) { + productCount = configCount; +} else { + productCount = simpleCount; +} +int threadsNumber = ctx.getThreadGroup().getNumThreads(); +if (threadsNumber == 0) { + threadsNumber = 1; +} +//Current thread number starts from 0 +int currentThreadNum = ctx.getThreadNum(); + +String siterator = vars.get("threadIterator_" + currentThreadNum.toString()); +int iterator; +if(siterator == null){ + iterator = 0; + vars.put("threadIterator_" + currentThreadNum.toString() , "0"); +} else { + iterator = Integer.parseInt(siterator); + iterator ++; + vars.put("threadIterator_" + currentThreadNum.toString() , iterator.toString()); +} + +//Number of products for one thread +int productClusterLength = productCount / threadsNumber; +//Index of the current product from the cluster +int i = productClusterLength * currentThreadNum + iterator; + +if (iterator >= productClusterLength) { + vars.put("threadIterator_" + currentThreadNum.toString(), "0"); + iterator = 0; +} + +//ids of simple and configurable products to edit +vars.put("simple_product_id", props.get("simple_products_list").get(i).get("id")); +vars.put("configurable_product_id", props.get("configurable_products_list").get(i).get("id")); + +//id of related product +do { + relatedIndex = (int)(Math.random() * props.get("simple_products_list").size()); +} while(i == relatedIndex); +vars.put("related_product_id", props.get("simple_products_list").get(relatedIndex).get("id")); + + + false + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product/edit/id/${simple_product_id}/ + GET + true + false + true + false + false + + + + + + Product + + Assertion.response_data + false + 16 + + + + false + simple_product_name + ,"name":"([^'"]+)", + $1$ + + 1 + + + + false + simple_product_sku + ,"sku":"([^'"]+)", + $1$ + + 1 + + + + false + simple_product_category_id + ,"category_ids":."(\d+)". + $1$ + + 1 + + + + + Passing arguments between threads + //Additional category to be added + +int categoryId = Integer.parseInt(vars.get("simple_product_category_id")); +vars.put("category_additional", (categoryId + 1).toString()); +//New price +vars.put("price_new", "9999"); +//New special price +vars.put("special_price_new", "8888"); +//New quantity +vars.put("quantity_new", "100600"); + + + false + + + + + + + false + true + = + true + ajax + false + + + false + true + = + true + isAjax + false + + + false + ${admin_form_key} + = + true + form_key + false + + + false + ${simple_product_name} + = + true + product[name] + false + + + false + ${simple_product_sku} + = + true + product[sku] + false + + + false + ${price_new} + = + true + product[price] + false + + + false + 2 + = + true + product[tax_class_id] + false + + + false + ${quantity_new} + = + true + product[quantity_and_stock_status][qty] + false + + + false + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + false + + + false + 1.0000 + = + true + product[weight] + false + + + false + 1 + = + true + product[product_has_weight] + false + + + false + ${simple_product_category_id} + = + true + product[category_ids][] + false + + + false + <p>Full simple product Description ${simple_product_id} Edited</p> + = + true + product[description] + false + + + false + 1 + = + true + product[status] + false + + + false + + = + true + product[configurable_variations] + false + + + false + 1 + = + true + affect_configurable_product_attributes + false + + + false + + = + true + product[image] + false + + + false + + = + true + product[small_image] + false + + + false + + = + true + product[thumbnail] + false + + + false + ${simple_product_name} + = + true + product[url_key] + false + + + false + ${simple_product_name} Meta Title Edited + = + true + product[meta_title] + false + + + false + ${simple_product_name} Meta Keyword Edited + = + true + product[meta_keyword] + false + + + false + ${simple_product_name} Meta Description Edited + = + true + product[meta_description] + false + + + false + 1 + = + true + product[website_ids][] + false + + + false + ${special_price_new} + = + true + product[special_price] + false + + + false + + = + true + product[special_from_date] + false + + + false + + = + true + product[special_to_date] + false + + + false + + = + true + product[cost] + false + + + false + 1 + = + true + product[stock_data][use_config_manage_stock] + false + + + false + ${quantity_new} + = + true + product[stock_data][original_inventory_qty] + false + + + false + ${quantity_new} + = + true + product[stock_data][qty] + false + + + false + 0 + = + true + product[stock_data][min_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_min_qty] + false + + + false + 1 + = + true + product[stock_data][min_sale_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_min_sale_qty] + false + + + false + 10000 + = + true + product[stock_data][max_sale_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_max_sale_qty] + false + + + false + 0 + = + true + product[stock_data][is_qty_decimal] + false + + + false + 0 + = + true + product[stock_data][is_decimal_divided] + false + + + false + 0 + = + true + product[stock_data][backorders] + false + + + false + 1 + = + true + product[stock_data][use_config_backorders] + false + + + false + 1 + = + true + product[stock_data][notify_stock_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + false + + + false + 0 + = + true + product[stock_data][enable_qty_increments] + false + + + false + 0 + = + true + product[stock_data][qty_increments] + false + + + false + 1 + = + true + product[stock_data][use_config_qty_increments] + false + + + false + 1 + = + true + product[stock_data][is_in_stock] + false + + + false + + = + true + product[custom_design] + false + + + false + + = + true + product[custom_design_from] + false + + + false + + = + true + product[custom_design_to] + false + + + false + + = + true + product[custom_layout_update] + false + + + false + + = + true + product[page_layout] + false + + + false + container2 + = + true + product[options_container] + false + + + false + + = + true + new-variations-attribute-set-id + false + + + + + + + + + + ${base_path}${admin_path}/catalog/product/validate/id/${simple_product_id}/?isAjax=true + POST + true + false + true + false + false + + + + + + {"error":false} + + Assertion.response_data + false + 2 + + + + + + + + false + true + = + true + ajax + false + + + false + true + = + true + isAjax + false + + + false + ${admin_form_key} + = + true + form_key + false + + + false + ${simple_product_name} + = + true + product[name] + false + + + false + ${simple_product_sku} + = + true + product[sku] + false + + + false + ${price_new} + = + true + product[price] + false + + + false + 2 + = + true + product[tax_class_id] + false + + + false + ${quantity_new} + = + true + product[quantity_and_stock_status][qty] + false + + + false + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + false + + + false + 1.0000 + = + true + product[weight] + false + + + false + 1 + = + true + product[product_has_weight] + false + + + false + ${simple_product_category_id} + = + true + product[category_ids][] + false + + + false + ${category_additional} + = + true + product[category_ids][] + + + false + <p>Full simple product Description ${simple_product_id} Edited</p> + = + true + product[description] + false + + + false + 1 + = + true + product[status] + false + + + false + + = + true + product[configurable_variations] + false + + + false + 1 + = + true + affect_configurable_product_attributes + false + + + false + + = + true + product[image] + false + + + false + + = + true + product[small_image] + false + + + false + + = + true + product[thumbnail] + false + + + false + ${simple_product_name} + = + true + product[url_key] + false + + + false + ${simple_product_name} Meta Title Edited + = + true + product[meta_title] + false + + + false + ${simple_product_name} Meta Keyword Edited + = + true + product[meta_keyword] + false + + + false + ${simple_product_name} Meta Description Edited + = + true + product[meta_description] + false + + + false + 1 + = + true + product[website_ids][] + false + + + false + ${special_price_new} + = + true + product[special_price] + false + + + false + + = + true + product[special_from_date] + false + + + false + + = + true + product[special_to_date] + false + + + false + + = + true + product[cost] + false + + + false + 1 + = + true + product[stock_data][use_config_manage_stock] + false + + + false + ${quantity_new} + = + true + product[stock_data][original_inventory_qty] + false + + + false + ${quantity_new} + = + true + product[stock_data][qty] + false + + + false + 0 + = + true + product[stock_data][min_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_min_qty] + false + + + false + 1 + = + true + product[stock_data][min_sale_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_min_sale_qty] + false + + + false + 10000 + = + true + product[stock_data][max_sale_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_max_sale_qty] + false + + + false + 0 + = + true + product[stock_data][is_qty_decimal] + false + + + false + 0 + = + true + product[stock_data][is_decimal_divided] + false + + + false + 0 + = + true + product[stock_data][backorders] + false + + + false + 1 + = + true + product[stock_data][use_config_backorders] + false + + + false + 1 + = + true + product[stock_data][notify_stock_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + false + + + false + 0 + = + true + product[stock_data][enable_qty_increments] + false + + + false + 0 + = + true + product[stock_data][qty_increments] + false + + + false + 1 + = + true + product[stock_data][use_config_qty_increments] + false + + + false + 1 + = + true + product[stock_data][is_in_stock] + false + + + false + + = + true + product[custom_design] + false + + + false + + = + true + product[custom_design_from] + false + + + false + + = + true + product[custom_design_to] + false + + + false + + = + true + product[custom_layout_update] + false + + + false + + = + true + product[page_layout] + false + + + false + container2 + = + true + product[options_container] + false + + + false + + = + true + new-variations-attribute-set-id + false + + + + + + + + + + ${base_path}${admin_path}/catalog/product/save/id/${simple_product_id}/back/edit/active_tab/product-details/ + POST + true + false + true + false + false + + + + + + You saved the product + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product/edit/id/${configurable_product_id}/ + GET + true + false + true + false + false + + + + + + Product + + Assertion.response_data + false + 16 + + + + false + configurable_product_name + ,"name":"([^'"]+)", + $1$ + + 1 + + + + false + configurable_product_sku + ,"sku":"([^'"]+)", + $1$ + + 1 + + + + false + configurable_product_category_id + ,"category_ids":."(\d+)" + $1$ + + 1 + + + + false + configurable_attribute_id + ,"configurable_variation":"([^'"]+)", + $1$ + + 1 + true + + + + false + configurable_matrix + "configurable-matrix":(\[.*?\]) + $1$ + + 1 + true + + + + associated_products_ids + $.[*].id + + configurable_matrix + VAR + + + + false + configurable_product_data + (\{"product":.*?configurable_attributes_data.*?\})\s*< + $1$ + + 1 + + + + configurable_attributes_data + $.product.configurable_attributes_data + + configurable_product_data + VAR + + + + false + configurable_attribute_ids + "attribute_id":"(\d+)" + $1$ + + -1 + variable + configurable_attributes_data + + + + false + configurable_attribute_codes + "code":"(\w+)" + $1$ + + -1 + variable + configurable_attributes_data + + + + false + configurable_attribute_labels + "label":"(.*?)" + $1$ + + -1 + variable + configurable_attributes_data + + + + false + configurable_attribute_values + "values":(\{(?:\}|.*?\}\})) + $1$ + + -1 + variable + configurable_attributes_data + + + + + configurable_attribute_ids + configurable_attribute_id + true + + + + 1 + ${configurable_attribute_ids_matchNr} + 1 + attribute_counter + + true + true + + + + return vars.get("configurable_attribute_values_" + vars.get("attribute_counter")); + + + false + + + + false + attribute_${configurable_attribute_id}_values + "value_index":"(\d+)" + $1$ + + -1 + configurable_attribute_values_${attribute_counter} + + + + + + + + + false + true + = + true + isAjax + false + + + false + ${admin_form_key} + = + true + form_key + false + + + false + ${configurable_product_name} + = + true + product[name] + false + + + false + ${configurable_product_sku} + = + true + product[sku] + false + + + false + ${price_new} + = + true + product[price] + false + + + false + 2 + = + true + product[tax_class_id] + false + + + false + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + false + + + false + 3 + = + true + product[weight] + false + + + false + ${configurable_product_category_id} + = + true + product[category_ids][] + false + + + false + ${category_additional} + = + true + product[category_ids][] + false + + + false + <p>Configurable product description ${configurable_product_id} Edited</p> + = + true + product[description] + false + + + false + 1 + = + true + product[status] + false + + + false + ${configurable_product_name} Meta Title Edited + = + true + product[meta_title] + false + + + false + ${configurable_product_name} Meta Keyword Edited + = + true + product[meta_keyword] + false + + + false + ${configurable_product_name} Meta Description Edited + = + true + product[meta_description] + false + + + false + 1 + = + true + product[website_ids][] + false + + + false + ${special_price_new} + = + true + product[special_price] + false + + + false + + = + true + product[special_from_date] + false + + + false + + = + true + product[special_to_date] + false + + + false + + = + true + product[cost] + false + + + false + 1 + = + true + product[stock_data][use_config_manage_stock] + false + + + false + 0 + = + true + product[stock_data][min_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_min_qty] + false + + + false + 1 + = + true + product[stock_data][min_sale_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_min_sale_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_max_sale_qty] + false + + + false + 0 + = + true + product[stock_data][is_qty_decimal] + false + + + false + 0 + = + true + product[stock_data][is_decimal_divided] + false + + + false + 0 + = + true + product[stock_data][backorders] + false + + + false + 1 + = + true + product[stock_data][use_config_backorders] + false + + + false + 1 + = + true + product[stock_data][notify_stock_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + false + + + false + 0 + = + true + product[stock_data][enable_qty_increments] + false + + + false + 0 + = + true + product[stock_data][qty_increments] + false + + + false + 1 + = + true + product[stock_data][use_config_qty_increments] + false + + + false + 1 + = + true + product[stock_data][is_in_stock] + false + + + false + + = + true + product[custom_design] + false + + + false + + = + true + product[custom_design_from] + false + + + false + + = + true + product[custom_design_to] + false + + + false + + = + true + product[custom_layout_update] + false + + + false + + = + true + product[page_layout] + false + + + false + container2 + = + true + product[options_container] + false + + + false + ${configurable_attribute_id} + = + true + product[configurable_variation] + false + + + false + ${configurable_product_name} + = + true + product[url_key] + + + false + 1 + = + true + product[use_config_gift_message_available] + + + false + 1 + = + true + product[use_config_gift_wrapping_available] + + + false + 4 + = + true + product[visibility] + + + false + 1 + = + true + product[product_has_weight] + true + + + false + 50 + = + true + product[stock_data][qty] + false + + + false + configurable + = + true + product[stock_data][type_id] + false + + + + + + + + + + ${base_path}${admin_path}/catalog/product/validate/id/${configurable_product_id}/ + POST + true + false + true + false + false + + + + + false + + + try { + int attributesCount = Integer.parseInt(vars.get("configurable_attribute_ids_matchNr")); + for (int i = 1; i <= attributesCount; i++) { + attributeId = vars.get("configurable_attribute_ids_" + i.toString()); + attributeCode = vars.get("configurable_attribute_codes_" + i.toString()); + attributeLabel = vars.get("configurable_attribute_labels_" + i.toString()); + ctx.getCurrentSampler().addArgument("attributes[" + (i - 1).toString() + "]", attributeId); + ctx.getCurrentSampler().addArgument("attribute_codes[" + (i - 1).toString() + "]", attributeCode); + ctx.getCurrentSampler().addArgument("product[" + attributeCode + "]", attributeId); + ctx.getCurrentSampler().addArgument("product[configurable_attributes_data][" + attributeId + "][attribute_id]", attributeId); + ctx.getCurrentSampler().addArgument("product[configurable_attributes_data][" + attributeId + "][position]", (i - 1).toString()); + ctx.getCurrentSampler().addArgument("product[configurable_attributes_data][" + attributeId + "][code]", attributeCode); + ctx.getCurrentSampler().addArgument("product[configurable_attributes_data][" + attributeId + "][label]", attributeLabel); + + int valuesCount = Integer.parseInt(vars.get("attribute_" + attributeId + "_values_matchNr")); + for (int j = 1; j <= valuesCount; j++) { + attributeValue = vars.get("attribute_" + attributeId + "_values_" + j.toString()); + ctx.getCurrentSampler().addArgument( + "product[configurable_attributes_data][" + attributeId + "][values][" + attributeValue + "][include]", + "1" + ); + ctx.getCurrentSampler().addArgument( + "product[configurable_attributes_data][" + attributeId + "][values][" + attributeValue + "][value_index]", + attributeValue + ); + } + } + ctx.getCurrentSampler().addArgument("associated_product_ids_serialized", vars.get("associated_products_ids").toString()); +} catch (Exception e) { + log.error("error…", e); +} + + + + + {"error":false} + + Assertion.response_data + false + 2 + + + + + + + + false + true + = + true + ajax + false + + + false + true + = + true + isAjax + false + + + false + ${admin_form_key} + = + true + form_key + false + + + false + ${configurable_product_name} + = + true + product[name] + false + + + false + ${configurable_product_sku} + = + true + product[sku] + false + + + false + ${price_new} + = + true + product[price] + false + + + false + 2 + = + true + product[tax_class_id]admin + false + + + false + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + false + + + false + 3 + = + true + product[weight] + false + + + false + ${configurable_product_category_id} + = + true + product[category_ids][] + false + + + false + ${category_additional} + = + true + product[category_ids][] + false + + + false + <p>Configurable product description ${configurable_product_id} Edited</p> + = + true + product[description] + false + + + false + 1 + = + true + product[status] + false + + + false + ${configurable_product_name} Meta Title Edited + = + true + product[meta_title] + false + + + false + ${configurable_product_name} Meta Keyword Edited + = + true + product[meta_keyword] + false + + + false + ${configurable_product_name} Meta Description Edited + = + true + product[meta_description] + false + + + false + 1 + = + true + product[website_ids][] + false + + + false + ${special_price_new} + = + true + product[special_price] + false + + + false + + = + true + product[special_from_date] + false + + + false + + = + true + product[special_to_date] + false + + + false + + = + true + product[cost] + false + + + false + 1 + = + true + product[stock_data][use_config_manage_stock] + false + + + false + 0 + = + true + product[stock_data][min_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_min_qty] + false + + + false + 1 + = + true + product[stock_data][min_sale_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_min_sale_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_max_sale_qty] + false + + + false + 0 + = + true + product[stock_data][is_qty_decimal] + false + + + false + 0 + = + true + product[stock_data][is_decimal_divided] + false + + + false + 0 + = + true + product[stock_data][backorders] + false + + + false + 1 + = + true + product[stock_data][use_config_backorders] + false + + + false + 1 + = + true + product[stock_data][notify_stock_qty] + false + + + false + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + false + + + false + 0 + = + true + product[stock_data][enable_qty_increments] + false + + + false + 0 + = + true + product[stock_data][qty_increments] + false + + + false + 1 + = + true + product[stock_data][use_config_qty_increments] + false + + + false + 1 + = + true + product[stock_data][is_in_stock] + false + + + false + + = + true + product[custom_design] + false + + + false + + = + true + product[custom_design_from] + false + + + false + + = + true + product[custom_design_to] + false + + + false + + = + true + product[custom_layout_update] + false + + + false + + = + true + product[page_layout] + false + + + false + container2 + = + true + product[options_container] + false + + + false + ${configurable_attribute_id} + = + true + product[configurable_variation] + false + + + false + ${configurable_product_name} + = + true + product[url_key] + + + false + 1 + = + true + product[use_config_gift_message_available] + + + false + 1 + = + true + product[use_config_gift_wrapping_available] + + + false + 4 + = + true + product[visibility] + + + false + 1 + = + true + product[product_has_weight] + true + + + false + 50 + = + true + product[stock_data][qty] + false + + + false + configurable + = + true + product[stock_data][type_id] + false + + + + + + + + + + ${base_path}${admin_path}/catalog/product/save/id/${configurable_product_id}/back/edit/active_tab/product-details/ + POST + true + false + true + false + false + + + + + false + + + try { + int attributesCount = Integer.parseInt(vars.get("configurable_attribute_ids_matchNr")); + for (int i = 1; i <= attributesCount; i++) { + attributeId = vars.get("configurable_attribute_ids_" + i.toString()); + attributeCode = vars.get("configurable_attribute_codes_" + i.toString()); + attributeLabel = vars.get("configurable_attribute_labels_" + i.toString()); + ctx.getCurrentSampler().addArgument("attributes[" + (i - 1).toString() + "]", attributeId); + ctx.getCurrentSampler().addArgument("attribute_codes[" + (i - 1).toString() + "]", attributeCode); + ctx.getCurrentSampler().addArgument("product[" + attributeCode + "]", attributeId); + ctx.getCurrentSampler().addArgument("product[configurable_attributes_data][" + attributeId + "][attribute_id]", attributeId); + ctx.getCurrentSampler().addArgument("product[configurable_attributes_data][" + attributeId + "][position]", (i - 1).toString()); + ctx.getCurrentSampler().addArgument("product[configurable_attributes_data][" + attributeId + "][code]", attributeCode); + ctx.getCurrentSampler().addArgument("product[configurable_attributes_data][" + attributeId + "][label]", attributeLabel); + + int valuesCount = Integer.parseInt(vars.get("attribute_" + attributeId + "_values_matchNr")); + for (int j = 1; j <= valuesCount; j++) { + attributeValue = vars.get("attribute_" + attributeId + "_values_" + j.toString()); + ctx.getCurrentSampler().addArgument( + "product[configurable_attributes_data][" + attributeId + "][values][" + attributeValue + "][include]", + "1" + ); + ctx.getCurrentSampler().addArgument( + "product[configurable_attributes_data][" + attributeId + "][values][" + attributeValue + "][value_index]", + attributeValue + ); + } + } + ctx.getCurrentSampler().addArgument("associated_product_ids_serialized", vars.get("associated_products_ids").toString()); +} catch (Exception e) { + log.error("error…", e); +} + + + + + You saved the product + + Assertion.response_data + false + 2 + if have trouble see messages-message-error + + + + + - - - - Authorization - Bearer ${admin_token} - - - - - - - + + startnextloop + + false + ${loops} - - - - - - - ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all - GET - true - false - true - false - false - - + ${__javaScript(Math.round(${numberOfThreads}*${adminPoolPercentage}*${merchandizingPercentage}*${adminProductManagementPercentage}*${adminProductCreationPercentage}/100000000))} + 0 + 1304708488000 + 1304708488000 + false + + + - - attribute_ids - $.[*].attribute_id - NO_VALUE - - BODY - - - - option_values - $.[*].values[0].value_index - NO_VALUE - - BODY - - + + + + + + + + + + + + + ${base_path}${admin_path} + GET + true + false + true + false + false + + + + + + Welcome + <title>Magento Admin</title> + + Assertion.response_data + false + 2 + + + + false + admin_form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_form_key + + + + + + + + false + ${admin_form_key} + = + true + form_key + + + true + ${admin_password} + = + true + login[password] + + + true + ${admin_user} + = + true + login[username] + + + + + + + + + + ${base_path}${admin_path}/admin/dashboard/ + POST + true + false + true + false + Java + false + + Implementation needs to be set to Java as per http://stackoverflow.com/questions/19636282/jmeter-error-in-redirect-url-for-get + + + + Passing arguments between threads + import org.apache.jmeter.samplers.SampleResult; + +relatedIndex = (int)(Math.random() * props.get("simple_products_list").size()); +vars.put("related_product_id", props.get("simple_products_list").get(relatedIndex).get("id")); + + + true + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product_attribute/index/filter/YXR0cmlidXRlX2NvZGU9Y29sb3I=/ + GET + true + false + true + false + false + + + + + false + color_id + product_attribute\/edit\/attribute_id\/([\d]+)\/" >.*\s*(color).* + $1$ + + 1 + + + + + + ${test_duration} + + + + Passing arguments between threads + import org.apache.jmeter.samplers.SampleResult; + +number = (int)(Math.random() * props.get("simple_products_list").size()); +simpleList = props.get("simple_products_list").get(number); +vars.put("simple_product_1_id", simpleList.get("id")); + +do { +number1 = (int)(Math.random() * props.get("simple_products_list").size()); +} while(number == number1); +simpleList = props.get("simple_products_list").get(number1); +vars.put("simple_product_2_id", simpleList.get("id")); + +number2 = (int)(Math.random() * props.get("configurable_products_list").size()); +configurableList = props.get("configurable_products_list").get(number2); +vars.put("configurable_product_1_id", configurableList.get("id")); +vars.put("configurable_product_1_url_key", configurableList.get("url_key")); +vars.put("configurable_product_1_name", configurableList.get("title")); + +//New price +vars.put("price_new", "9999"); +//New special price +vars.put("special_price_new", "8888"); +//New quantity +vars.put("quantity_new", "100600"); + + + true + + + + 1 + + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product/ + GET + true + false + true + false + false + + + + + + records found + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product/new/set/4/type/bundle/ + GET + true + false + true + false + false + + + + + + New Product + + Assertion.response_data + false + 2 + + + + + + + + true + true + = + true + ajax + false + + + true + true + = + true + isAjax + false + + + true + ${admin_form_key} + = + true + form_key + false + + + true + Bundle Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[name] + false + + + true + SKU ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[sku] + false + + + true + 123 + = + true + product[price] + + + true + 2 + = + true + product[tax_class_id] + + + true + 111 + = + true + product[quantity_and_stock_status][qty] + + + true + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + + + true + 1.0000 + = + true + product[weight] + + + true + 1 + = + true + product[product_has_weight] + true + + + true + 2 + = + true + product[category_ids][] + + + true + <p>Full bundle product description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[description] + + + true + <p>Short bundle product description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[short_description] + + + true + 1 + = + true + product[status] + + + true + + = + true + product[configurable_variations] + + + true + 1 + = + true + affect_configurable_product_attributes + + + true + + = + true + product[image] + + + true + + = + true + product[small_image] + + + true + + = + true + product[thumbnail] + + + true + bundle-product-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[url_key] + + + true + Bundle Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Title + = + true + product[meta_title] + + + true + Bundle Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Keyword + = + true + product[meta_keyword] + + + true + Bundle Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Description + = + true + product[meta_description] + + + true + 1 + = + true + product[website_ids][] + + + true + 99 + = + true + product[special_price] + + + true + 1 + = + true + product[stock_data][notify_stock_qty] + + + true + + = + true + product[special_from_date] + + + true + + = + true + product[special_to_date] + + + true + + = + true + product[cost] + + + true + 0 + = + true + product[tier_price][0][website_id] + + + true + 32000 + = + true + product[tier_price][0][cust_group] + + + true + 100 + = + true + product[tier_price][0][price_qty] + + + true + 90 + = + true + product[tier_price][0][price] + + + true + + = + true + product[tier_price][0][delete] + + + true + 0 + = + true + product[tier_price][1][website_id] + + + true + 1 + = + true + product[tier_price][1][cust_group] + + + true + 101 + = + true + product[tier_price][1][price_qty] + + + true + 99 + = + true + product[tier_price][1][price] + + + true + + = + true + product[tier_price][1][delete] + + + true + 1 + = + true + product[stock_data][use_config_manage_stock] + + + true + 100500 + = + true + product[stock_data][original_inventory_qty] + + + true + 100500 + = + true + product[stock_data][qty] + + + true + 0 + = + true + product[stock_data][min_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_qty] + + + true + 1 + = + true + product[stock_data][min_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_sale_qty] + + + true + 10000 + = + true + product[stock_data][max_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_max_sale_qty] + + + true + 0 + = + true + product[stock_data][is_qty_decimal] + + + true + 0 + = + true + product[stock_data][is_decimal_divided] + + + true + 0 + = + true + product[stock_data][backorders] + + + true + 1 + = + true + product[stock_data][use_config_backorders] + + + true + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + + + true + 0 + = + true + product[stock_data][enable_qty_increments] + + + true + 0 + = + true + product[stock_data][qty_increments] + + + true + 1 + = + true + product[stock_data][use_config_qty_increments] + + + true + 1 + = + true + product[stock_data][is_in_stock] + + + true + + = + true + product[custom_design] + + + true + + = + true + product[custom_design_from] + + + true + + = + true + product[custom_design_to] + + + true + + = + true + product[custom_layout_update] + + + true + + = + true + product[page_layout] + + + true + container2 + = + true + product[options_container] + + + true + + = + true + new-variations-attribute-set-id + + + true + 0 + = + true + product[shipment_type] + + + true + option title one + = + true + bundle_options[0][title] + + + true + + = + true + bundle_options[0][option_id] + + + true + + = + true + bundle_options[0][delete] + + + true + select + = + true + bundle_options[0][type] + + + true + 1 + = + true + bundle_options[0][required] + + + true + 0 + = + true + bundle_options[0][position] + + + true + + = + true + bundle_selections[0][0][selection_id] + + + true + + = + true + bundle_selections[0][0][option_id] + + + true + ${simple_product_1_id} + = + true + bundle_selections[0][0][product_id] + + + true + + = + true + bundle_selections[0][0][delete] + + + true + 0.00 + = + true + bundle_selections[0][0][selection_price_value] + + + true + 0 + = + true + bundle_selections[0][0][selection_price_type] + + + true + 1 + = + true + bundle_selections[0][0][selection_qty] + + + true + 1 + = + true + bundle_selections[0][0][selection_can_change_qty] + + + true + 0 + = + true + bundle_selections[0][0][position] + + + true + + = + true + bundle_selections[0][1][selection_id] + + + true + + = + true + bundle_selections[0][1][option_id] + + + true + ${simple_product_2_id} + = + true + bundle_selections[0][1][product_id] + + + true + + = + true + bundle_selections[0][1][delete] + + + true + 0.00 + = + true + bundle_selections[0][1][selection_price_value] + + + true + 0 + = + true + bundle_selections[0][1][selection_price_type] + + + true + 1 + = + true + bundle_selections[0][1][selection_qty] + + + true + 1 + = + true + bundle_selections[0][1][selection_can_change_qty] + + + true + 1 + = + true + bundle_selections[0][1][position] + + + true + option title two + = + true + bundle_options[1][title] + + + true + + = + true + bundle_options[1][option_id] + + + true + + = + true + bundle_options[1][delete] + + + true + select + = + true + bundle_options[1][type] + + + true + 1 + = + true + bundle_options[1][required] + + + true + 1 + = + true + bundle_options[1][position] + + + true + + = + true + bundle_selections[1][0][selection_id] + true + + + true + + = + true + bundle_selections[1][0][option_id] + true + + + true + ${simple_product_1_id} + = + true + bundle_selections[1][0][product_id] + true + + + true + + = + true + bundle_selections[1][0][delete] + true + + + true + 0.00 + = + true + bundle_selections[1][0][selection_price_value] + true + + + true + 0 + = + true + bundle_selections[1][0][selection_price_type] + true + + + true + 1 + = + true + bundle_selections[1][0][selection_qty] + true + + + true + 1 + = + true + bundle_selections[1][0][selection_can_change_qty] + true + + + true + 0 + = + true + bundle_selections[1][0][position] + true + + + true + + = + true + bundle_selections[1][1][selection_id] + true + + + true + + = + true + bundle_selections[1][1][option_id] + true + + + true + ${simple_product_2_id} + = + true + bundle_selections[1][1][product_id] + true + + + true + + = + true + bundle_selections[1][1][delete] + true + + + true + 0.00 + = + true + bundle_selections[1][1][selection_price_value] + true + + + true + 0 + = + true + bundle_selections[1][1][selection_price_type] + true + + + true + 1 + = + true + bundle_selections[1][1][selection_qty] + true + + + true + 1 + = + true + bundle_selections[1][1][selection_can_change_qty] + true + + + true + 1 + = + true + bundle_selections[1][1][position] + true + + + true + 2 + = + true + affect_bundle_product_selections + true + + + + + + + + + + ${base_path}${admin_path}/catalog/product/validate/set/4/ + POST + true + false + true + false + false + + + + + + {"error":false} + + Assertion.response_data + false + 2 + + + + + + + + true + true + = + true + ajax + false + + + true + true + = + true + isAjax + false + + + true + ${admin_form_key} + = + true + form_key + false + + + true + Bundle Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[name] + false + + + true + SKU ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[sku] + false + + + true + 123 + = + true + product[price] + + + true + 2 + = + true + product[tax_class_id] + + + true + 111 + = + true + product[quantity_and_stock_status][qty] + + + true + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + + + true + 1.0000 + = + true + product[weight] + + + true + 1 + = + true + product[product_has_weight] + true + + + true + 2 + = + true + product[category_ids][] + + + true + <p>Full bundle product Description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[description] + + + true + <p>Short bundle product description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[short_description] + + + true + 1 + = + true + product[status] + + + true + + = + true + product[configurable_variations] + + + true + 1 + = + true + affect_configurable_product_attributes + + + true + + = + true + product[image] + + + true + + = + true + product[small_image] + + + true + + = + true + product[thumbnail] + + + true + bundle-product-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[url_key] + + + true + Bundle Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Title + = + true + product[meta_title] + + + true + Bundle Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Keyword + = + true + product[meta_keyword] + + + true + Bundle Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Description + = + true + product[meta_description] + + + true + 1 + = + true + product[website_ids][] + + + true + 99 + = + true + product[special_price] + + + true + + = + true + product[special_from_date] + + + true + + = + true + product[special_to_date] + + + true + + = + true + product[cost] + + + true + 0 + = + true + product[tier_price][0][website_id] + + + true + 32000 + = + true + product[tier_price][0][cust_group] + + + true + 100 + = + true + product[tier_price][0][price_qty] + + + true + 90 + = + true + product[tier_price][0][price] + + + true + + = + true + product[tier_price][0][delete] + + + true + 0 + = + true + product[tier_price][1][website_id] + + + true + 1 + = + true + product[tier_price][1][cust_group] + + + true + 101 + = + true + product[tier_price][1][price_qty] + + + true + 99 + = + true + product[tier_price][1][price] + + + true + + = + true + product[tier_price][1][delete] + + + true + 1 + = + true + product[stock_data][use_config_manage_stock] + + + true + 100500 + = + true + product[stock_data][original_inventory_qty] + + + true + 100500 + = + true + product[stock_data][qty] + + + true + 0 + = + true + product[stock_data][min_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_qty] + + + true + 1 + = + true + product[stock_data][min_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_sale_qty] + + + true + 10000 + = + true + product[stock_data][max_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_max_sale_qty] + + + true + 0 + = + true + product[stock_data][is_qty_decimal] + + + true + 0 + = + true + product[stock_data][is_decimal_divided] + + + true + 0 + = + true + product[stock_data][backorders] + + + true + 1 + = + true + product[stock_data][use_config_backorders] + + + true + 1 + = + true + product[stock_data][notify_stock_qty] + + + true + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + + + true + 0 + = + true + product[stock_data][enable_qty_increments] + + + true + 0 + = + true + product[stock_data][qty_increments] + + + true + 1 + = + true + product[stock_data][use_config_qty_increments] + + + true + 1 + = + true + product[stock_data][is_in_stock] + + + true + + = + true + product[custom_design] + + + true + + = + true + product[custom_design_from] + + + true + + = + true + product[custom_design_to] + + + true + + = + true + product[custom_layout_update] + + + true + + = + true + product[page_layout] + + + true + container2 + = + true + product[options_container] + + + true + + = + true + new-variations-attribute-set-id + + + true + 0 + = + true + product[shipment_type] + false + + + true + option title one + = + true + bundle_options[0][title] + false + + + true + + = + true + bundle_options[0][option_id] + false + + + true + + = + true + bundle_options[0][delete] + false + + + true + select + = + true + bundle_options[0][type] + false + + + true + 1 + = + true + bundle_options[0][required] + false + + + true + 0 + = + true + bundle_options[0][position] + false + + + true + + = + true + bundle_selections[0][0][selection_id] + false + + + true + + = + true + bundle_selections[0][0][option_id] + false + + + true + ${simple_product_1_id} + = + true + bundle_selections[0][0][product_id] + false + + + true + + = + true + bundle_selections[0][0][delete] + false + + + true + 0.00 + = + true + bundle_selections[0][0][selection_price_value] + false + + + true + 0 + = + true + bundle_selections[0][0][selection_price_type] + false + + + true + 1 + = + true + bundle_selections[0][0][selection_qty] + false + + + true + 1 + = + true + bundle_selections[0][0][selection_can_change_qty] + false + + + true + 0 + = + true + bundle_selections[0][0][position] + false + + + true + + = + true + bundle_selections[0][1][selection_id] + false + + + true + + = + true + bundle_selections[0][1][option_id] + false + + + true + ${simple_product_2_id} + = + true + bundle_selections[0][1][product_id] + false + + + true + + = + true + bundle_selections[0][1][delete] + false + + + true + 0.00 + = + true + bundle_selections[0][1][selection_price_value] + false + + + true + 0 + = + true + bundle_selections[0][1][selection_price_type] + false + + + true + 1 + = + true + bundle_selections[0][1][selection_qty] + false + + + true + 1 + = + true + bundle_selections[0][1][selection_can_change_qty] + false + + + true + 1 + = + true + bundle_selections[0][1][position] + false + + + true + option title two + = + true + bundle_options[1][title] + false + + + true + + = + true + bundle_options[1][option_id] + false + + + true + + = + true + bundle_options[1][delete] + false + + + true + select + = + true + bundle_options[1][type] + false + + + true + 1 + = + true + bundle_options[1][required] + false + + + true + 1 + = + true + bundle_options[1][position] + false + + + true + + = + true + bundle_selections[1][0][selection_id] + false + + + true + + = + true + bundle_selections[1][0][option_id] + false + + + true + ${simple_product_1_id} + = + true + bundle_selections[1][0][product_id] + false + + + true + + = + true + bundle_selections[1][0][delete] + false + + + true + 0.00 + = + true + bundle_selections[1][0][selection_price_value] + false + + + true + 0 + = + true + bundle_selections[1][0][selection_price_type] + false + + + true + 1 + = + true + bundle_selections[1][0][selection_qty] + false + + + true + 1 + = + true + bundle_selections[1][0][selection_can_change_qty] + false + + + true + 0 + = + true + bundle_selections[1][0][position] + false + + + true + + = + true + bundle_selections[1][1][selection_id] + false + + + true + + = + true + bundle_selections[1][1][option_id] + false + + + true + ${simple_product_2_id} + = + true + bundle_selections[1][1][product_id] + false + + + true + + = + true + bundle_selections[1][1][delete] + false + + + true + 0.00 + = + true + bundle_selections[1][1][selection_price_value] + false + + + true + 0 + = + true + bundle_selections[1][1][selection_price_type] + false + + + true + 1 + = + true + bundle_selections[1][1][selection_qty] + false + + + true + 1 + = + true + bundle_selections[1][1][selection_can_change_qty] + false + + + true + 1 + = + true + bundle_selections[1][1][position] + false + + + true + 2 + = + true + affect_bundle_product_selections + false + + + + + + + + + + ${base_path}${admin_path}/catalog/product/save/set/4/type/bundle/back/edit/active_tab/product-details/ + POST + true + false + true + false + false + + + + + + You saved the product + + Assertion.response_data + false + 2 + + + + + violation + + Assertion.response_data + false + 6 + + + + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product/ + GET + true + false + true + false + false + + + + + + records found + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product/new/set/4/type/configurable/ + GET + true + false + true + false + false + + + + + + New Product + + Assertion.response_data + false + 2 + + + + + + + + true + form_key + ${admin_form_key} + = + true + + + true + options[0][attribute_id] + ${color_id} + = + true + + + true + options[0][id] + PQFYFAT + = + true + + + true + options[0][is_new] + true + = + true + + + true + options[0][label] + green-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + + + true + options[0][value] + 0 + = + true + + + true + ${color_id} + = + true + options[1][attribute_id] + true + + + true + PQFYFAT1 + = + true + options[1][id] + true + + + true + true + = + true + options[1][is_new] + true + + + true + red-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + options[1][label] + true + + + true + 0 + = + true + options[1][value] + true + + + + + + + + + + ${base_path}${admin_path}/catalog/product_attribute/createOptions/?isAjax=true + POST + true + false + true + false + false + + + + + first_option + $.PQFYFAT + + + BODY + + + + second_option + $.PQFYFAT1 + + + BODY + + + + + + + + true + true + = + true + ajax + false + + + true + true + = + true + isAjax + false + + + true + 1 + = + true + affect_configurable_product_attributes + true + + + true + color + = + true + attribute_codes[0] + true + + + true + ${color_id} + = + true + attributes[0] + true + + + true + Color:green ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[0][attributes] + true + + + true + 1 + = + true + configurable-matrix[0][canEdit] + true + + + true + {"color":"${first_option}"} + = + true + configurable-matrix[0][configurable_attribute] + true + + + true + green ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[0][name] + true + + + true + 1 + = + true + configurable-matrix[0][newProduct] + true + + + true + 100 + = + true + configurable-matrix[0][price] + true + + + true + $ + = + true + configurable-matrix[0][price_currency] + true + + + true + $100 + = + true + configurable-matrix[0][price_string] + true + + + true + 150 + = + true + configurable-matrix[0][qty] + true + + + true + 0 + = + true + configurable-matrix[0][record_id] + true + + + true + green-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[0][sku] + true + + + true + + = + true + configurable-matrix[0][small_image] + true + + + true + 1 + = + true + configurable-matrix[0][status] + true + + + true + + = + true + configurable-matrix[0][swatch_image] + true + + + true + + = + true + configurable-matrix[0][thumbnail] + true + + + true + ${first_option} + = + true + configurable-matrix[0][variationKey] + true + + + true + 6 + = + true + configurable-matrix[0][weight] + true + + + true + Color:red ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[1][attributes] + true + + + true + 1 + = + true + configurable-matrix[1][canEdit] + true + + + true + {"color":"${second_option}"} + = + true + configurable-matrix[1][configurable_attribute] + true + + + true + red ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[1][name] + true + + + true + 1 + = + true + configurable-matrix[1][newProduct] + true + + + true + 100 + = + true + configurable-matrix[1][price] + true + + + true + $ + = + true + configurable-matrix[1][price_currency] + true + + + true + $100 + = + true + configurable-matrix[1][price_string] + true + + + true + 50 + = + true + configurable-matrix[1][qty] + true + + + true + 1 + = + true + configurable-matrix[1][record_id] + true + + + true + red ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[1][sku] + true + + + true + + = + true + configurable-matrix[1][small_image] + true + + + true + 1 + = + true + configurable-matrix[1][status] + true + + + true + + = + true + configurable-matrix[1][swatch_image] + true + + + true + + = + true + configurable-matrix[1][thumbnail] + true + + + true + ${second_option} + = + true + configurable-matrix[1][variationKey] + true + + + true + 6 + = + true + configurable-matrix[1][weight] + true + + + true + ${admin_form_key} + = + true + form_key + true + + + true + 4 + = + true + new-variations-attribute-set-id + true + + + true + 1 + = + true + product[affect_product_custom_options] + true + + + true + 4 + = + true + product[attribute_set_id] + true + + + true + 4 + = + true + product[category_ids][0] + true + + + true + ${color_id} + = + true + product[configurable_attributes_data][${color_id}][attribute_id] + true + + + true + color + = + true + product[configurable_attributes_data][${color_id}][code] + true + + + true + Color + = + true + product[configurable_attributes_data][${color_id}][label] + true + + + true + 0 + = + true + product[configurable_attributes_data][${color_id}][position] + true + + + true + 1 + = + true + product[configurable_attributes_data][${color_id}][values][${first_option}][include] + true + + + true + ${first_option} + = + true + product[configurable_attributes_data][${color_id}][values][${first_option}][value_index] + true + + + true + 1 + = + true + product[configurable_attributes_data][${color_id}][values][${second_option}][include] + true + + + true + ${second_option} + = + true + product[configurable_attributes_data][${color_id}][values][${second_option}][value_index] + true + + + true + + = + true + product[custom_layout_update] + true + + + true + + = + true + product[description] + true + + + true + 0 + = + true + product[gift_message_available] + true + + + true + 1 + = + true + product[gift_wrapping_available] + true + + + true + + = + true + product[gift_wrapping_price] + true + + + true + + = + true + product[image] + true + + + true + 2 + = + true + product[is_returnable] + true + + + true + Configurable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Description + = + true + product[meta_description] + true + + + true + Configurable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Keyword + = + true + product[meta_keyword] + true + + + true + Configurable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Title + = + true + product[meta_title] + true + + + true + Configurable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[name] + true + + + true + container2 + = + true + product[options_container] + true + + + true + ${price_new} + = + true + product[price] + true + + + true + 1 + = + true + product[product_has_weight] + true + + + true + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + true + + + true + 1000 + = + true + product[quantity_and_stock_status][qty] + true + + + true + + = + true + product[short_description] + true + + + true + SKU ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[sku] + true + + + true + + = + true + product[small_image] + true + + + true + ${special_price_new} + = + true + product[special_price] + true + + + true + 1 + = + true + product[status] + true + + + true + 0 + = + true + product[stock_data][backorders] + true + + + true + 1 + = + true + product[stock_data][deferred_stock_update] + true + + + true + 0 + = + true + product[stock_data][enable_qty_increments] + true + + + true + 0 + = + true + product[stock_data][is_decimal_divided] + true + + + true + 0 + = + true + product[stock_data][is_qty_decimal] + true + + + true + 1 + = + true + product[stock_data][manage_stock] + true + + + true + 10000 + = + true + product[stock_data][max_sale_qty] + true + + + true + 0 + = + true + product[stock_data][min_qty] + true + + + true + 1 + = + true + product[stock_data][min_sale_qty] + true + + + true + 1 + = + true + product[stock_data][notify_stock_qty] + true + + + true + 1 + = + true + product[stock_data][qty_increments] + true + + + true + 1 + = + true + product[stock_data][use_config_backorders] + true + + + true + 1 + = + true + product[stock_data][use_config_deferred_stock_update] + true + + + true + 1 + = + true + product[stock_data][use_config_enable_qty_increments] + true + + + true + 1 + = + true + product[stock_data][use_config_manage_stock] + true + + + true + 1 + = + true + product[stock_data][use_config_max_sale_qty] + true + + + true + 1 + = + true + product[stock_data][use_config_min_qty] + true + + + true + 1 + = + true + product[stock_data][use_config_min_sale_qty] + true + + + true + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + true + + + true + 1 + = + true + product[stock_data][use_config_qty_increments] + true + + + true + 2 + = + true + product[tax_class_id] + true + + + true + + = + true + product[thumbnail] + true + + + true + + = + true + product[url_key] + true + + + true + 1 + = + true + product[use_config_gift_message_available] + true + + + true + 1 + = + true + product[use_config_gift_wrapping_available] + true + + + true + 1 + = + true + product[use_config_is_returnable] + true + + + true + 4 + = + true + product[visibility] + true + + + true + 1 + = + true + product[website_ids][1] + true + + + + + + + + + + ${base_path}${admin_path}/catalog/product/validate/set/4/ + POST + true + false + true + false + false + + + + + + {"error":false} + + Assertion.response_data + false + 2 + + + + + + + + true + true + = + true + ajax + false + + + true + true + = + true + isAjax + false + + + true + 1 + = + true + affect_configurable_product_attributes + false + + + true + color + = + true + attribute_codes[0] + false + + + true + ${color_id} + = + true + attributes[0] + false + + + true + Color:green ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[0][attributes] + false + + + true + 1 + = + true + configurable-matrix[0][canEdit] + false + + + true + {"color":"${first_option}"} + = + true + configurable-matrix[0][configurable_attribute] + false + + + true + green ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[0][name] + false + + + true + 1 + = + true + configurable-matrix[0][newProduct] + false + + + true + 100 + = + true + configurable-matrix[0][price] + false + + + true + $ + = + true + configurable-matrix[0][price_currency] + false + + + true + $100 + = + true + configurable-matrix[0][price_string] + false + + + true + 150 + = + true + configurable-matrix[0][qty] + false + + + true + 0 + = + true + configurable-matrix[0][record_id] + false + + + true + green-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[0][sku] + false + + + true + + = + true + configurable-matrix[0][small_image] + false + + + true + 1 + = + true + configurable-matrix[0][status] + false + + + true + + = + true + configurable-matrix[0][swatch_image] + false + + + true + + = + true + configurable-matrix[0][thumbnail] + false + + + true + ${first_option} + = + true + configurable-matrix[0][variationKey] + false + + + true + 6 + = + true + configurable-matrix[0][weight] + false + + + true + Color:red ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[1][attributes] + false + + + true + 1 + = + true + configurable-matrix[1][canEdit] + false + + + true + {"color":"${second_option}"} + = + true + configurable-matrix[1][configurable_attribute] + false + + + true + red ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[1][name] + false + + + true + 1 + = + true + configurable-matrix[1][newProduct] + false + + + true + 100 + = + true + configurable-matrix[1][price] + false + + + true + $ + = + true + configurable-matrix[1][price_currency] + false + + + true + $100 + = + true + configurable-matrix[1][price_string] + false + + + true + 50 + = + true + configurable-matrix[1][qty] + false + + + true + 1 + = + true + configurable-matrix[1][record_id] + false + + + true + red ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + configurable-matrix[1][sku] + false + + + true + + = + true + configurable-matrix[1][small_image] + false + + + true + 1 + = + true + configurable-matrix[1][status] + false + + + true + + = + true + configurable-matrix[1][swatch_image] + false + + + true + + = + true + configurable-matrix[1][thumbnail] + false + + + true + ${second_option} + = + true + configurable-matrix[1][variationKey] + false + + + true + 6 + = + true + configurable-matrix[1][weight] + false + + + true + ${admin_form_key} + = + true + form_key + false + + + true + 4 + = + true + new-variations-attribute-set-id + false + + + true + 1 + = + true + product[affect_product_custom_options] + false + + + true + 4 + = + true + product[attribute_set_id] + false + + + true + 4 + = + true + product[category_ids][0] + false + + + true + ${color_id} + = + true + product[configurable_attributes_data][${color_id}][attribute_id] + false + + + true + color + = + true + product[configurable_attributes_data][${color_id}][code] + false + + + true + Color + = + true + product[configurable_attributes_data][${color_id}][label] + false + + + true + 0 + = + true + product[configurable_attributes_data][${color_id}][position] + false + + + true + 1 + = + true + product[configurable_attributes_data][${color_id}][values][${first_option}][include] + false + + + true + ${first_option} + = + true + product[configurable_attributes_data][${color_id}][values][${first_option}][value_index] + false + + + true + 1 + = + true + product[configurable_attributes_data][${color_id}][values][${second_option}][include] + false + + + true + ${second_option} + = + true + product[configurable_attributes_data][${color_id}][values][${second_option}][value_index] + false + + + true + + = + true + product[custom_layout_update] + false + + + true + + = + true + product[description] + false + + + true + 0 + = + true + product[gift_message_available] + false + + + true + 1 + = + true + product[gift_wrapping_available] + false + + + true + + = + true + product[gift_wrapping_price] + false + + + true + + = + true + product[image] + false + + + true + 2 + = + true + product[is_returnable] + false + + + true + Configurable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Description + = + true + product[meta_description] + false + + + true + Configurable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Keyword + = + true + product[meta_keyword] + false + + + true + Configurable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Title + = + true + product[meta_title] + false + + + true + Configurable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[name] + false + + + true + container2 + = + true + product[options_container] + false + + + true + ${price_new} + = + true + product[price] + false + + + true + 1 + = + true + product[product_has_weight] + false + + + true + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + false + + + true + 1000 + = + true + product[quantity_and_stock_status][qty] + false + + + true + + = + true + product[short_description] + false + + + true + SKU ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[sku] + false + + + true + + = + true + product[small_image] + false + + + true + ${special_price_new} + = + true + product[special_price] + false + + + true + 1 + = + true + product[status] + false + + + true + 0 + = + true + product[stock_data][backorders] + false + + + true + 1 + = + true + product[stock_data][deferred_stock_update] + false + + + true + 0 + = + true + product[stock_data][enable_qty_increments] + false + + + true + 0 + = + true + product[stock_data][is_decimal_divided] + false + + + true + 0 + = + true + product[stock_data][is_qty_decimal] + false + + + true + 1 + = + true + product[stock_data][manage_stock] + false + + + true + 10000 + = + true + product[stock_data][max_sale_qty] + false + + + true + 0 + = + true + product[stock_data][min_qty] + false + + + true + 1 + = + true + product[stock_data][min_sale_qty] + false + + + true + 1 + = + true + product[stock_data][notify_stock_qty] + false + + + true + 1 + = + true + product[stock_data][qty_increments] + false + + + true + 1 + = + true + product[stock_data][use_config_backorders] + false + + + true + 1 + = + true + product[stock_data][use_config_deferred_stock_update] + false + + + true + 1 + = + true + product[stock_data][use_config_enable_qty_increments] + false + + + true + 1 + = + true + product[stock_data][use_config_manage_stock] + false + + + true + 1 + = + true + product[stock_data][use_config_max_sale_qty] + false + + + true + 1 + = + true + product[stock_data][use_config_min_qty] + false + + + true + 1 + = + true + product[stock_data][use_config_min_sale_qty] + false + + + true + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + false + + + true + 1 + = + true + product[stock_data][use_config_qty_increments] + false + + + true + 2 + = + true + product[tax_class_id] + false + + + true + + = + true + product[thumbnail] + false + + + true + + = + true + product[url_key] + false + + + true + 1 + = + true + product[use_config_gift_message_available] + false + + + true + 1 + = + true + product[use_config_gift_wrapping_available] + false + + + true + 1 + = + true + product[use_config_is_returnable] + false + + + true + 4 + = + true + product[visibility] + false + + + true + 1 + = + true + product[website_ids][1] + false + + + + + + + + + + ${base_path}${admin_path}/catalog/product/save/set/4/type/configurable/back/edit/active_tab/product-details/ + POST + true + false + true + false + false + + + + + + You saved the product + + Assertion.response_data + false + 2 + + + + + violation + + Assertion.response_data + false + 6 + + + + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product/ + GET + true + false + true + false + false + + + + + + records found + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product/new/set/4/type/downloadable/ + GET + true + false + true + false + false + + + + + + New Product + + Assertion.response_data + false + 2 + + + + + + + + ${files_folder}downloadable_original.txt + links + text/plain + + + + + + + true + ${admin_form_key} + = + true + form_key + false + + + + + + + + + + ${base_path}${admin_path}/admin/downloadable_file/upload/type/links/?isAjax=true + POST + false + false + true + true + false + + + + + original_file + $.file + + + BODY + + + + + + + + ${files_folder}downloadable_sample.txt + samples + text/plain + + + + + + + true + ${admin_form_key} + = + true + form_key + false + + + + + + + + + + ${base_path}${admin_path}/admin/downloadable_file/upload/type/samples/?isAjax=true + POST + false + false + true + true + false + + + + + sample_file + $.file + + + BODY + + + + + + + + true + true + = + true + ajax + false + + + true + true + = + true + isAjax + false + + + true + ${admin_form_key} + = + true + form_key + false + + + true + Downloadable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[name] + false + + + true + SKU ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[sku] + false + + + true + 123 + = + true + product[price] + + + true + 2 + = + true + product[tax_class_id] + + + true + 111 + = + true + product[quantity_and_stock_status][qty] + + + true + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + + + true + 1.0000 + = + true + product[weight] + + + true + 2 + = + true + product[category_ids][] + + + true + <p>Full downloadable product description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[description] + + + true + <p>Short downloadable product description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[short_description] + + + true + 1 + = + true + product[status] + + + true + + = + true + product[image] + + + true + + = + true + product[small_image] + + + true + + = + true + product[thumbnail] + + + true + downloadable-product-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[url_key] + + + true + Downloadable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Title + = + true + product[meta_title] + + + true + Downloadable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Keyword + = + true + product[meta_keyword] + + + true + Downloadable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Description + = + true + product[meta_description] + + + true + 1 + = + true + product[website_ids][] + + + true + 99 + = + true + product[special_price] + + + true + 1 + = + true + product[stock_data][notify_stock_qty] + + + true + + = + true + product[special_from_date] + + + true + + = + true + product[special_to_date] + + + true + + = + true + product[cost] + + + true + 0 + = + true + product[tier_price][0][website_id] + + + true + 32000 + = + true + product[tier_price][0][cust_group] + + + true + 100 + = + true + product[tier_price][0][price_qty] + + + true + 90 + = + true + product[tier_price][0][price] + + + true + + = + true + product[tier_price][0][delete] + + + true + 0 + = + true + product[tier_price][1][website_id] + + + true + 1 + = + true + product[tier_price][1][cust_group] + + + true + 101 + = + true + product[tier_price][1][price_qty] + + + true + 99 + = + true + product[tier_price][1][price] + + + true + + = + true + product[tier_price][1][delete] + + + true + 1 + = + true + product[stock_data][use_config_manage_stock] + + + true + 100500 + = + true + product[stock_data][original_inventory_qty] + + + true + 100500 + = + true + product[stock_data][qty] + + + true + 0 + = + true + product[stock_data][min_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_qty] + + + true + 1 + = + true + product[stock_data][min_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_sale_qty] + + + true + 10000 + = + true + product[stock_data][max_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_max_sale_qty] + + + true + 0 + = + true + product[stock_data][is_qty_decimal] + + + true + 0 + = + true + product[stock_data][is_decimal_divided] + + + true + 0 + = + true + product[stock_data][backorders] + + + true + 1 + = + true + product[stock_data][use_config_backorders] + + + true + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + + + true + 0 + = + true + product[stock_data][enable_qty_increments] + + + true + 0 + = + true + product[stock_data][qty_increments] + + + true + 1 + = + true + product[stock_data][use_config_qty_increments] + + + true + 1 + = + true + product[stock_data][is_in_stock] + + + true + + = + true + product[custom_design] + + + true + + = + true + product[custom_design_from] + + + true + + = + true + product[custom_design_to] + + + true + + = + true + product[custom_layout_update] + + + true + + = + true + product[page_layout] + + + true + container2 + = + true + product[options_container] + + + true + on + = + true + is_downloadable + + + true + Links + = + true + product[links_title] + + + true + 0 + = + true + product[links_purchased_separately] + + + true + ${original_file} + = + true + downloadable[link][0][file][0][file] + false + + + true + downloadable_original.txt + = + true + downloadable[link][0][file][0][name] + false + + + true + 13 + = + true + downloadable[link][0][file][0][size] + false + + + true + new + = + true + downloadable[link][0][file][0][status] + false + + + true + 1 + = + true + downloadable[link][0][is_shareable] + + + true + 0 + = + true + downloadable[link][0][is_unlimited] + + + true + + = + true + downloadable[link][0][link_url] + + + true + 0 + = + true + downloadable[link][0][number_of_downloads] + true + + + true + 120 + = + true + downloadable[link][0][price] + true + + + true + 0 + = + true + downloadable[link][0][record_id] + true + + + true + file + = + true + downloadable[link][0][sample][type] + + + true + + = + true + downloadable[link][0][sample][url] + + + true + 1 + = + true + downloadable[link][0][sort_order] + + + true + Original Link + = + true + downloadable[link][0][title] + + + true + file + = + true + downloadable[link][0][type] + + + true + ${sample_file} + = + true + downloadable[sample][0][file][0][file] + true + + + true + downloadable_sample.txt + = + true + downloadable[sample][0][file][0][name] + true + + + true + 14 + = + true + downloadable[sample][0][file][0][size] + true + + + true + new + = + true + downloadable[sample][0][file][0][status] + true + + + true + 0 + = + true + downloadable[sample][0][record_id] + true + + + true + + = + true + downloadable[sample][0][sample_url] + true + + + true + 1 + = + true + downloadable[sample][0][sort_order] + true + + + true + Sample Link + = + true + downloadable[sample][0][title] + true + + + true + file + = + true + downloadable[sample][0][type] + true + + + true + 1 + = + true + affect_configurable_product_attributes + false + + + true + 4 + = + true + new-variations-attribute-set-id + false + + + true + + = + true + product[configurable_variation] + false + + + + + + + + + + ${base_path}${admin_path}/catalog/product/validate/set/4/type/downloadable/ + POST + true + false + true + false + false + + + + + + {"error":false} + + Assertion.response_data + false + 2 + + + + + + + + true + true + = + true + ajax + false + + + true + true + = + true + isAjax + false + + + true + ${admin_form_key} + = + true + form_key + false + + + true + Downloadable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[name] + false + + + true + SKU ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[sku] + false + + + true + 123 + = + true + product[price] + + + true + 2 + = + true + product[tax_class_id] + + + true + 111 + = + true + product[quantity_and_stock_status][qty] + + + true + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + + + true + 1.0000 + = + true + product[weight] + + + true + 2 + = + true + product[category_ids][] + + + true + <p>Full downloadable product description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[description] + + + true + <p>Short downloadable product description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[short_description] + false + + + true + 1 + = + true + product[status] + + + true + + = + true + product[image] + + + true + + = + true + product[small_image] + + + true + + = + true + product[thumbnail] + + + true + downloadable-product-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[url_key] + + + true + Downloadable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Title + = + true + product[meta_title] + + + true + Downloadable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Keyword + = + true + product[meta_keyword] + + + true + Downloadable Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Description + = + true + product[meta_description] + + + true + 1 + = + true + product[website_ids][] + + + true + 99 + = + true + product[special_price] + + + true + + = + true + product[special_from_date] + + + true + + = + true + product[special_to_date] + + + true + + = + true + product[cost] + + + true + 0 + = + true + product[tier_price][0][website_id] + + + true + 32000 + = + true + product[tier_price][0][cust_group] + + + true + 100 + = + true + product[tier_price][0][price_qty] + + + true + 90 + = + true + product[tier_price][0][price] + + + true + + = + true + product[tier_price][0][delete] + + + true + 0 + = + true + product[tier_price][1][website_id] + + + true + 1 + = + true + product[tier_price][1][cust_group] + + + true + 101 + = + true + product[tier_price][1][price_qty] + + + true + 99 + = + true + product[tier_price][1][price] + + + true + + = + true + product[tier_price][1][delete] + + + true + 1 + = + true + product[stock_data][use_config_manage_stock] + + + true + 100500 + = + true + product[stock_data][original_inventory_qty] + + + true + 100500 + = + true + product[stock_data][qty] + + + true + 0 + = + true + product[stock_data][min_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_qty] + + + true + 1 + = + true + product[stock_data][min_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_sale_qty] + + + true + 10000 + = + true + product[stock_data][max_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_max_sale_qty] + + + true + 0 + = + true + product[stock_data][is_qty_decimal] + + + true + 0 + = + true + product[stock_data][is_decimal_divided] + + + true + 0 + = + true + product[stock_data][backorders] + + + true + 1 + = + true + product[stock_data][use_config_backorders] + + + true + 1 + = + true + product[stock_data][notify_stock_qty] + + + true + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + + + true + 0 + = + true + product[stock_data][enable_qty_increments] + + + true + 0 + = + true + product[stock_data][qty_increments] + + + true + 1 + = + true + product[stock_data][use_config_qty_increments] + + + true + 1 + = + true + product[stock_data][is_in_stock] + + + true + + = + true + product[custom_design] + + + true + + = + true + product[custom_design_from] + + + true + + = + true + product[custom_design_to] + + + true + + = + true + product[custom_layout_update] + + + true + + = + true + product[page_layout] + + + true + container2 + = + true + product[options_container] + + + true + ${original_file} + = + true + downloadable[link][0][file][0][file] + false + + + true + downloadable_original.txt + = + true + downloadable[link][0][file][0][name] + false + + + true + 13 + = + true + downloadable[link][0][file][0][size] + false + + + true + new + = + true + downloadable[link][0][file][0][status] + false + + + true + 1 + = + true + downloadable[link][0][is_shareable] + true + + + true + 0 + = + true + downloadable[link][0][is_unlimited] + true + + + true + + = + true + downloadable[link][0][link_url] + true + + + true + 0 + = + true + downloadable[link][0][number_of_downloads] + false + + + true + 120 + = + true + downloadable[link][0][price] + false + + + true + 0 + = + true + downloadable[link][0][record_id] + false + + + true + file + = + true + downloadable[link][0][sample][type] + true + + + true + + = + true + downloadable[link][0][sample][url] + true + + + true + 1 + = + true + downloadable[link][0][sort_order] + true + + + true + Original Link + = + true + downloadable[link][0][title] + true + + + true + file + = + true + downloadable[link][0][type] + true + + + true + ${sample_file} + = + true + downloadable[sample][0][file][0][file] + true + + + true + downloadable_sample.txt + = + true + downloadable[sample][0][file][0][name] + true + + + true + 14 + = + true + downloadable[sample][0][file][0][size] + true + + + true + new + = + true + downloadable[sample][0][file][0][status] + true + + + true + 0 + = + true + downloadable[sample][0][record_id] + true + + + true + + = + true + downloadable[sample][0][sample_url] + true + + + true + 1 + = + true + downloadable[sample][0][sort_order] + true + + + true + Sample Link + = + true + downloadable[sample][0][title] + true + + + true + file + = + true + downloadable[sample][0][type] + true + + + true + 1 + = + true + affect_configurable_product_attributes + false + + + true + 4 + = + true + new-variations-attribute-set-id + false + + + true + + = + true + product[configurable_variation] + false + + + + + + + + + + ${base_path}${admin_path}/catalog/product/save/set/4/type/downloadable/back/edit/active_tab/product-details/ + POST + true + false + true + false + false + + + + + + You saved the product + + Assertion.response_data + false + 2 + + + + + violation + + Assertion.response_data + false + 6 + + + + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product/ + GET + true + false + true + false + false + + + + + + records found + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/product/new/set/4/type/simple/ + GET + true + false + true + false + false + + + + + + New Product + + Assertion.response_data + false + 2 + + + + + + + + true + true + = + true + ajax + false + + + true + true + = + true + isAjax + false + + + true + ${admin_form_key} + = + true + form_key + false + + + true + Simple Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[name] + false + + + true + SKU ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[sku] + false + + + true + 123 + = + true + product[price] + + + true + 2 + = + true + product[tax_class_id] + + + true + 111 + = + true + product[quantity_and_stock_status][qty] + + + true + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + + + true + 1.0000 + = + true + product[weight] + + + true + 1 + = + true + product[product_has_weight] + true + + + true + 2 + = + true + product[category_ids][] + + + true + <p>Full simple product description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[description] + + + true + <p>Short simple product description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[short_description] + + + true + 1 + = + true + product[status] + + + true + + = + true + product[image] + + + true + + = + true + product[small_image] + + + true + + = + true + product[thumbnail] + + + true + simple-product-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[url_key] + + + true + Simple Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Title + = + true + product[meta_title] + + + true + Simple Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Keyword + = + true + product[meta_keyword] + + + true + Simple Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Description + = + true + product[meta_description] + + + true + 1 + = + true + product[website_ids][] + + + true + 99 + = + true + product[special_price] + + + true + 1 + = + true + product[stock_data][notify_stock_qty] + + + true + + = + true + product[special_from_date] + + + true + + = + true + product[special_to_date] + + + true + + = + true + product[cost] + + + true + 0 + = + true + product[tier_price][0][website_id] + + + true + 32000 + = + true + product[tier_price][0][cust_group] + + + true + 100 + = + true + product[tier_price][0][price_qty] + + + true + 90 + = + true + product[tier_price][0][price] + + + true + + = + true + product[tier_price][0][delete] + + + true + 0 + = + true + product[tier_price][1][website_id] + + + true + 1 + = + true + product[tier_price][1][cust_group] + + + true + 101 + = + true + product[tier_price][1][price_qty] + + + true + 99 + = + true + product[tier_price][1][price] + + + true + + = + true + product[tier_price][1][delete] + + + true + 1 + = + true + product[stock_data][use_config_manage_stock] + + + true + 100500 + = + true + product[stock_data][original_inventory_qty] + + + true + 100500 + = + true + product[stock_data][qty] + + + true + 0 + = + true + product[stock_data][min_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_qty] + + + true + 1 + = + true + product[stock_data][min_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_sale_qty] + + + true + 10000 + = + true + product[stock_data][max_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_max_sale_qty] + + + true + 0 + = + true + product[stock_data][is_qty_decimal] + + + true + 0 + = + true + product[stock_data][is_decimal_divided] + + + true + 0 + = + true + product[stock_data][backorders] + + + true + 1 + = + true + product[stock_data][use_config_backorders] + + + true + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + + + true + 0 + = + true + product[stock_data][enable_qty_increments] + + + true + 0 + = + true + product[stock_data][qty_increments] + + + true + 1 + = + true + product[stock_data][use_config_qty_increments] + + + true + 1 + = + true + product[stock_data][is_in_stock] + + + true + + = + true + product[custom_design] + + + true + + = + true + product[custom_design_from] + + + true + + = + true + product[custom_design_to] + + + true + + = + true + product[custom_layout_update] + + + true + + = + true + product[page_layout] + + + true + container2 + = + true + product[options_container] + + + true + + = + true + product[options][1][is_delete] + false + + + true + 1 + = + true + product[options][1][is_require] + false + + + true + select + = + true + product[options][1][previous_group] + false + + + true + drop_down + = + true + product[options][1][previous_type] + false + + + true + 0 + = + true + product[options][1][sort_order] + false + + + true + Product Option Title One + = + true + product[options][1][title] + false + + + true + drop_down + = + true + product[options][1][type] + false + + + true + + = + true + product[options][1][values][1][is_delete] + false + + + true + 200 + = + true + product[options][1][values][1][price] + false + + + true + fixed + = + true + product[options][1][values][1][price_type] + false + + + true + sku-one + = + true + product[options][1][values][1][sku] + false + + + true + 0 + = + true + product[options][1][values][1][sort_order] + false + + + true + Row Title + = + true + product[options][1][values][1][title] + false + + + true + + = + true + product[options][2][is_delete] + false + + + true + 1 + = + true + product[options][2][is_require] + false + + + true + 250 + = + true + product[options][2][max_characters] + false + + + true + text + = + true + product[options][2][previous_group] + false + + + true + field + = + true + product[options][2][previous_type] + false + + + true + 500 + = + true + product[options][2][price] + false + + + true + fixed + = + true + product[options][2][price_type] + false + + + true + sku-two + = + true + product[options][2][sku] + false + + + true + 1 + = + true + product[options][2][sort_order] + false + + + true + Field Title + = + true + product[options][2][title] + false + + + true + field + = + true + product[options][2][type] + false + + + true + 1 + = + true + affect_configurable_product_attributes + true + + + true + 4 + = + true + new-variations-attribute-set-id + true + + + true + + = + true + product[configurable_variation] + true + + + + + + + + + + ${base_path}${admin_path}/catalog/product/validate/set/4/ + POST + true + false + true + false + false + + + + + + {"error":false} + + Assertion.response_data + false + 2 + + + + + + + + true + true + = + true + ajax + false + + + true + true + = + true + isAjax + false + + + true + ${admin_form_key} + = + true + form_key + false + + + true + Simple Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[name] + false + + + true + SKU ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[sku] + false + + + true + 123 + = + true + product[price] + + + true + 2 + = + true + product[tax_class_id] + + + true + 111 + = + true + product[quantity_and_stock_status][qty] + + + true + 1 + = + true + product[quantity_and_stock_status][is_in_stock] + + + true + 1.0000 + = + true + product[weight] + + + true + 1 + = + true + product[product_has_weight] + true + + + true + 2 + = + true + product[category_ids][] + + + true + <p>Full simple product Description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[description] + + + true + <p>Short simple product description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)}</p> + = + true + product[short_description] + + + true + 1 + = + true + product[status] + + + true + + = + true + product[image] + + + true + + = + true + product[small_image] + + + true + + = + true + product[thumbnail] + + + true + simple-product-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + product[url_key] + + + true + Simple Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Title + = + true + product[meta_title] + + + true + Simple Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Keyword + = + true + product[meta_keyword] + + + true + Simple Product ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} Meta Description + = + true + product[meta_description] + + + true + 1 + = + true + product[website_ids][] + + + true + 99 + = + true + product[special_price] + + + true + + = + true + product[special_from_date] + + + true + + = + true + product[special_to_date] + + + true + + = + true + product[cost] + + + true + 0 + = + true + product[tier_price][0][website_id] + + + true + 32000 + = + true + product[tier_price][0][cust_group] + + + true + 100 + = + true + product[tier_price][0][price_qty] + + + true + 90 + = + true + product[tier_price][0][price] + + + true + + = + true + product[tier_price][0][delete] + + + true + 0 + = + true + product[tier_price][1][website_id] + + + true + 1 + = + true + product[tier_price][1][cust_group] + + + true + 101 + = + true + product[tier_price][1][price_qty] + + + true + 99 + = + true + product[tier_price][1][price] + + + true + + = + true + product[tier_price][1][delete] + + + true + 1 + = + true + product[stock_data][use_config_manage_stock] + + + true + 100500 + = + true + product[stock_data][original_inventory_qty] + + + true + 100500 + = + true + product[stock_data][qty] + + + true + 0 + = + true + product[stock_data][min_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_qty] + + + true + 1 + = + true + product[stock_data][min_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_min_sale_qty] + + + true + 10000 + = + true + product[stock_data][max_sale_qty] + + + true + 1 + = + true + product[stock_data][use_config_max_sale_qty] + + + true + 0 + = + true + product[stock_data][is_qty_decimal] + + + true + 0 + = + true + product[stock_data][is_decimal_divided] + + + true + 0 + = + true + product[stock_data][backorders] + + + true + 1 + = + true + product[stock_data][use_config_backorders] + + + true + 1 + = + true + product[stock_data][notify_stock_qty] + + + true + 1 + = + true + product[stock_data][use_config_notify_stock_qty] + + + true + 0 + = + true + product[stock_data][enable_qty_increments] + + + true + 0 + = + true + product[stock_data][qty_increments] + + + true + 1 + = + true + product[stock_data][use_config_qty_increments] + + + true + 1 + = + true + product[stock_data][is_in_stock] + + + true + + = + true + product[custom_design] + + + true + + = + true + product[custom_design_from] + + + true + + = + true + product[custom_design_to] + + + true + + = + true + product[custom_layout_update] + + + true + + = + true + product[page_layout] + + + true + container2 + = + true + product[options_container] + + + true + + = + true + product[options][1][is_delete] + true + + + true + 1 + = + true + product[options][1][is_require] + + + true + select + = + true + product[options][1][previous_group] + false + + + true + drop_down + = + true + product[options][1][previous_type] + false + + + true + 0 + = + true + product[options][1][sort_order] + false + + + true + Product Option Title One + = + true + product[options][1][title] + + + true + drop_down + = + true + product[options][1][type] + + + true + + = + true + product[options][1][values][1][is_delete] + false + + + true + 200 + = + true + product[options][1][values][1][price] + + + true + fixed + = + true + product[options][1][values][1][price_type] + + + true + sku-one + = + true + product[options][1][values][1][sku] + + + true + 0 + = + true + product[options][1][values][1][sort_order] + + + true + Row Title + = + true + product[options][1][values][1][title] + + + true + + = + true + product[options][2][is_delete] + false + + + true + 1 + = + true + product[options][2][is_require] + + + true + 250 + = + true + product[options][2][max_characters] + + + true + text + = + true + product[options][2][previous_group] + + + true + field + = + true + product[options][2][previous_type] + + + true + 500 + = + true + product[options][2][price] + + + true + fixed + = + true + product[options][2][price_type] + + + true + sku-two + = + true + product[options][2][sku] + + + true + 1 + = + true + product[options][2][sort_order] + + + true + Field Title + = + true + product[options][2][title] + + + true + field + = + true + product[options][2][type] + + + true + 1 + = + true + affect_configurable_product_attributes + true + + + true + 4 + = + true + new-variations-attribute-set-id + true + + + true + + = + true + product[configurable_variation] + true + + + + + + + + + + ${base_path}${admin_path}/catalog/product/save/set/4/type/simple/back/edit/active_tab/product-details/ + POST + true + false + true + false + false + + + + + + You saved the product + + Assertion.response_data + false + 2 + + + + + violation + + Assertion.response_data + false + 6 + + + + + + - - - - - - - false - ${configurable_product_1_id} - = - true - product - - - false - - = - true - related_product - - - false - 1 - = - true - qty - - - false - ${configurable_option_id} - = - true - super_attribute[${configurable_attribute_id}] - - - false - ${form_key} - = - true - form_key - - - - - - - - - - ${base_path}checkout/cart/add/ - POST - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest + + startnextloop + + false + ${loops} - - - - - - false - - - - try { - attribute_ids = vars.get("attribute_ids"); - option_values = vars.get("option_values"); - attribute_ids = attribute_ids.replace("[","").replace("]","").replace("\"", ""); - option_values = option_values.replace("[","").replace("]","").replace("\"", ""); - attribute_ids_array = attribute_ids.split(","); - option_values_array = option_values.split(","); - args = ctx.getCurrentSampler().getArguments(); - it = args.iterator(); - while (it.hasNext()) { - argument = it.next(); - if (argument.getStringValue().contains("${")) { - args.removeArgument(argument.getName()); - } - } - for (int i = 0; i < attribute_ids_array.length; i++) { - ctx.getCurrentSampler().addArgument("super_attribute[" + attribute_ids_array[i] + "]", option_values_array[i]); - } - } catch (Exception e) { - log.error("eror…", e); - } - - - - - - - - - - true - cart,messages - = - true - sections - true - - - true - true - = - true - update_section_id - true - - - false - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} - = - true - _ - true - - - - - - - - - - ${base_path}customer/section/load/ - GET - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - You added ${configurable_product_1_name} to your shopping cart. - - Assertion.response_data - false - 2 - - - - - We don't have as many &quot;${configurable_product_1_name}&quot; as you requested. - - Assertion.response_data - false - 6 - - - - - \"summary_count\":3 - - Assertion.response_data - false - 2 - - - - - - - continue - - false - ${loops} - - ${__javaScript(Math.round(props.get("users")*${guest_checkout_percent}/100>>0))} - ${ramp_period} - 1437409133000 - 1437409133000 - false - - - - - - Passing arguments between threads - -number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); -simpleList = props.get("simple_products_list").get(number); -vars.put("simple_product_1_url_key", simpleList.get("url_key")); -vars.put("simple_product_1_name", simpleList.get("title")); -vars.put("simple_product_1_id", simpleList.get("id")); -vars.put("simple_product_1_uenc", simpleList.get("uenc")); - -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); -simpleList = props.get("simple_products_list").get(number1); -vars.put("simple_product_2_url_key", simpleList.get("url_key")); -vars.put("simple_product_2_name", simpleList.get("title")); -vars.put("simple_product_2_id", simpleList.get("id")); -vars.put("simple_product_2_uenc", simpleList.get("uenc")); - -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); -configurableList = props.get("configurable_products_list").get(number); -vars.put("configurable_product_1_url_key", configurableList.get("url_key")); -vars.put("configurable_product_1_name", configurableList.get("title")); -vars.put("configurable_product_1_id", configurableList.get("id")); -vars.put("configurable_attribute_id", configurableList.get("attribute_id")); -vars.put("configurable_option_id", configurableList.get("attribute_option_id")); -vars.put("configurable_product_1_uenc", simpleList.get("uenc")); - -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); -vars.put("category_url_key", props.get("category_url_keys_list").get(number)); -vars.put("category_name", props.get("category_names_list").get(number)); -vars.put("testLabel", "GuestChkt"); -vars.put("loadType", "Guest"); - - - true - - - - - - - - - - - - - - ${base_path} - GET - true - false - true - false - false - - + ${__javaScript(Math.round(${numberOfThreads}*${adminPoolPercentage}*${merchandizingPercentage}*${adminCategoryManagementPercentage}/1000000))} + 0 + 1304708488000 + 1304708488000 + false + + + - - - <title>Home page</title> - - Assertion.response_data - false - 2 - - - - - - - - - true - ["customer_form_login"] - = - true - blocks - - - true - ["default","customer_account_login"] - = - true - handles - - - true - {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} - = - true - originalRequest - - - true - true - = - true - ajax - - - true - true - = - true - isAjax - - - - - - - - - - ${base_path}page_cache/block/render/ - GET - true - false - true - false - false - - - - - - "customer_form_login" - Registered Customers - form_key - - Assertion.response_data - false - 2 - - - - false - form_key - <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> - $1$ - - 1 - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - form_key - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${category_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <span class="base" data-ui-id="page-title">${category_name}</span> - - Assertion.response_data - false - 6 - - - - false - category_id - <li class="item category([^'"]+)">\s*<strong>${category_name}</strong>\s*</li> - $1$ - - 1 - simple_product_1_url_key - - - - - ^[0-9]+$ - - Assertion.response_data - false - 1 - variable - category_id - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${simple_product_1_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${simple_product_1_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - product_id - .//input[@type="hidden" and @name="product"]/@value - false - true - false - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - product_id - - - - - - - - - - - - - - ${base_path}review/product/listAjax/id/${product_id}/ - GET - true - false - true - false - false - - - - - - 200 - - Assertion.response_code - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - false - ${simple_product_1_id} - = - true - product - - - false - - = - true - related_product - - - false - 1 - = - true - qty - - - false - ${form_key} - = - true - form_key - - - - - - - - - - ${base_path}checkout/cart/add/ - POST - true - false - true - false - false - - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - - - - true - cart,messages - = - true - sections - - - true - true - = - true - update_section_id - - - false - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} - = - true - _ - - - - - - - - - - ${base_path}customer/section/load/ - GET - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - You added ${simple_product_1_name} to your shopping cart. - - Assertion.response_data - false - 2 - - - - - This product is out of stock. - - Assertion.response_data - false - 6 - - - - - \"summary_count\":1 - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${simple_product_2_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${simple_product_2_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - product_id - .//input[@type="hidden" and @name="product"]/@value - false - true - false - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - product_id - - - - - - - - - - - - - - ${base_path}review/product/listAjax/id/${product_id}/ - GET - true - false - true - false - false - - - - - - 200 - - Assertion.response_code - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - false - ${simple_product_2_id} - = - true - product - - - false - - = - true - related_product - - - false - 1 - = - true - qty - - - false - ${form_key} - = - true - form_key - - - - - - - - - - ${base_path}checkout/cart/add/ - POST - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - - - - true - cart,messages - = - true - sections - true - - - true - true - = - true - update_section_id - true - - - false - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} - = - true - _ - true - - - - - - - - - - ${base_path}customer/section/load/ - GET - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - You added ${simple_product_2_name} to your shopping cart. - - Assertion.response_data - false - 2 - - - - - This product is out of stock. - - Assertion.response_data - false - 6 - - - - - \"summary_count\":2 - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${configurable_product_1_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${configurable_product_1_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - false - configurable_product_sku - itemprop="sku">([^<]*)<\/ - $1$ - NOT_FOUND - 1 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - true - 1 - - - - - - Content-Type - application/json - - - Accept - */* - - - - - - true - - - - false - {"username":"${admin_user}","password":"${admin_password}"} - = - - - - - - - - - - ${base_path}rest/V1/integration/admin/token - POST - true - false - true - false - false - - - - - admin_token - $ - - - BODY - - - - - ^[a-z0-9-]+$ - - Assertion.response_data - false - 1 - variable - admin_token - - - - - - - Authorization - Bearer ${admin_token} - - - - - - - - - - - - - - - ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all - GET - true - false - true - false - false - - - - - attribute_ids - $.[*].attribute_id - NO_VALUE - - BODY - - - - option_values - $.[*].values[0].value_index - NO_VALUE - - BODY - - - - - - - - - - false - ${configurable_product_1_id} - = - true - product - - - false - - = - true - related_product - - - false - 1 - = - true - qty - - - false - ${configurable_option_id} - = - true - super_attribute[${configurable_attribute_id}] - - - false - ${form_key} - = - true - form_key - - - - - - - - - - ${base_path}checkout/cart/add/ - POST - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - false - - - - try { - attribute_ids = vars.get("attribute_ids"); - option_values = vars.get("option_values"); - attribute_ids = attribute_ids.replace("[","").replace("]","").replace("\"", ""); - option_values = option_values.replace("[","").replace("]","").replace("\"", ""); - attribute_ids_array = attribute_ids.split(","); - option_values_array = option_values.split(","); - args = ctx.getCurrentSampler().getArguments(); - it = args.iterator(); - while (it.hasNext()) { - argument = it.next(); - if (argument.getStringValue().contains("${")) { - args.removeArgument(argument.getName()); - } - } - for (int i = 0; i < attribute_ids_array.length; i++) { - ctx.getCurrentSampler().addArgument("super_attribute[" + attribute_ids_array[i] + "]", option_values_array[i]); - } - } catch (Exception e) { - log.error("eror…", e); - } - - - - - - - - - - true - cart,messages - = - true - sections - true - - - true - true - = - true - update_section_id - true - - - false - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} - = - true - _ - true - - - - - - - - - - ${base_path}customer/section/load/ - GET - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - You added ${configurable_product_1_name} to your shopping cart. - - Assertion.response_data - false - 2 - - - - - We don't have as many &quot;${configurable_product_1_name}&quot; as you requested. - - Assertion.response_data - false - 6 - - - - - \"summary_count\":3 - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}checkout/ - GET - true - false - true - false - false - - - - - - <title>Checkout</title> - - Assertion.response_data - false - 2 - - - - - <title>Shopping Cart</title> - - Assertion.response_data - false - 6 - - - - false - cart_id - "quoteData":{"entity_id":"([^'"]+)", - $1$ - - 1 - - - - false - form_key - <input name="form_key" type="hidden" value="([^'"]+)" /> - $1$ - - 1 - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - cart_id - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - form_key - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - true - - - - false - {"customerEmail":"test@example.com"} - = - - - - - - - - - - ${base_path}rest/default/V1/customers/isEmailAvailable - POST - true - false - true - false - false - - - - - - - Referer - ${base_path}checkout/onepage/ - - - Content-Type - application/json; charset=UTF-8 - - - X-Requested-With - XMLHttpRequest - - - Accept - application/json - - - - - - - true - - Assertion.response_data - false - 8 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - true - - - - false - {"address":{"country_id":"US","postcode":"95630"}} - = - - - - - - - - - - ${base_path}rest/default/V1/guest-carts/${cart_id}/estimate-shipping-methods - POST - true - false - true - false - false - - - - - - - Referer - ${base_path}checkout/onepage/ - - - Content-Type - application/json; charset=UTF-8 - - - X-Requested-With - XMLHttpRequest - - - Accept - application/json - - - - - - - "available":true - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - true - - - - false - {"addressInformation":{"shipping_address":{"countryId":"US","regionId":"12","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname"},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}} - = - - - - - - - - - - ${base_path}rest/default/V1/guest-carts/${cart_id}/shipping-information - POST - true - false - true - false - false - - - - - - - Referer - ${base_path}checkout/onepage/ - - - Content-Type - application/json; charset=UTF-8 - - - X-Requested-With - XMLHttpRequest - - - Accept - application/json - - - - - - - {"payment_methods": - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - true - - - - false - {"cartId":"${cart_id}","email":"test@example.com","paymentMethod":{"method":"checkmo","po_number":null,"additional_data":null},"billingAddress":{"countryId":"US","regionId":"12","regionCode":"CA","region":"California","street":["10441 Jefferson Blvd ste 200"],"company":"","telephone":"3109450345","fax":"","postcode":"90232","city":"Culver City","firstname":"Name","lastname":"Lastname"}} - = - - - - - - - - - - ${base_path}rest/default/V1/guest-carts/${cart_id}/payment-information - POST - true - false - true - false - false - - - - - - - Referer - ${base_path}checkout/onepage/ - - - Content-Type - application/json; charset=UTF-8 - - - X-Requested-With - XMLHttpRequest - - - Accept - application/json - - - - - - - "[0-9]+" - - Assertion.response_data - false - 2 - - - - order_id - $ - - - BODY - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - order_id - - - - - - - - - - - - - - - ${base_path}checkout/onepage/success/ - GET - true - false - true - false - false - - - - - - Thank you for your purchase! - Your order # is - - Assertion.response_data - false - 2 - - - - - - - continue - - false - ${loops} - - ${__javaScript(Math.round(props.get("users")*${customer_checkout_percent}/100>>0))} - ${ramp_period} - 1437177203000 - 1437177203000 - false - - - - - - Passing arguments between threads - import org.apache.jmeter.samplers.SampleResult; + + + + + + + + + + + + + ${base_path}${admin_path} + GET + true + false + true + false + false + + + + + + Welcome + <title>Magento Admin</title> + + Assertion.response_data + false + 2 + + + + false + admin_form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_form_key + + + + + + + + false + ${admin_form_key} + = + true + form_key + + + true + ${admin_password} + = + true + login[password] + + + true + ${admin_user} + = + true + login[username] + + + + + + + + + + ${base_path}${admin_path}/admin/dashboard/ + POST + true + false + true + false + Java + false + + Implementation needs to be set to Java as per http://stackoverflow.com/questions/19636282/jmeter-error-in-redirect-url-for-get + + + + + ${test_duration} + + + + + + Passing arguments between threads + import org.apache.jmeter.samplers.SampleResult; +import java.util.ArrayList; -number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); -simpleList = props.get("simple_products_list").get(number); -vars.put("simple_product_1_url_key", simpleList.get("url_key")); -vars.put("simple_product_1_name", simpleList.get("title")); -vars.put("simple_product_1_id", simpleList.get("id")); -vars.put("simple_product_1_uenc", simpleList.get("uenc")); +number = (int)(Math.random() * props.get("simple_products_list").size()); +simpleList = props.get("simple_products_list").get(number); +vars.put("simple_product_1_url_key", simpleList.get("url_key")); +vars.put("simple_product_1_name", simpleList.get("title")); +vars.put("simple_product_1_id", simpleList.get("id")); -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); -simpleList = props.get("simple_products_list").get(number1); -vars.put("simple_product_2_url_key", simpleList.get("url_key")); -vars.put("simple_product_2_name", simpleList.get("title")); -vars.put("simple_product_2_id", simpleList.get("id")); -vars.put("simple_product_2_uenc", simpleList.get("uenc")); +do { + number1 = (int)(Math.random() * props.get("simple_products_list").size()); +} while(number == number1); +simpleList = props.get("simple_products_list").get(number1); +vars.put("simple_product_2_url_key", simpleList.get("url_key")); +vars.put("simple_product_2_name", simpleList.get("title")); +vars.put("simple_product_2_id", simpleList.get("id")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); -configurableList = props.get("configurable_products_list").get(number); -vars.put("configurable_product_1_url_key", configurableList.get("url_key")); -vars.put("configurable_product_1_name", configurableList.get("title")); -vars.put("configurable_product_1_id", configurableList.get("id")); -vars.put("configurable_attribute_id", configurableList.get("attribute_id")); -vars.put("configurable_option_id", configurableList.get("attribute_option_id")); -vars.put("configurable_product_1_uenc", simpleList.get("uenc")); +do { + number2 = (int)(Math.random() * props.get("simple_products_list").size()); +} while(number2 == number1 || number2 == number); +simpleList = props.get("simple_products_list").get(number2); +vars.put("simple_product_3_url_key", simpleList.get("url_key")); +vars.put("simple_product_3_name", simpleList.get("title")); +vars.put("simple_product_3_id", simpleList.get("id")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); -vars.put("category_url_key", props.get("category_url_keys_list").get(number)); -vars.put("category_name", props.get("category_names_list").get(number)); +do { + number3 = (int)(Math.random() * props.get("simple_products_list").size()); +} while(number3 == number2 || number3 == number1 || number3 == number); +simpleList = props.get("simple_products_list").get(number3); +vars.put("simple_product_4_url_key", simpleList.get("url_key")); +vars.put("simple_product_4_name", simpleList.get("title")); +vars.put("simple_product_4_id", simpleList.get("id")); -emails_index = 0; -if (!props.containsKey("customer_emails_index")) { - props.put("customer_emails_index", emails_index); -} +do { + number4 = (int)(Math.random() * props.get("simple_products_list").size()); +} while(number4 == number3 || number4 == number2 || number4 == number1 || number4 == number); +simpleList = props.get("simple_products_list").get(number4); +vars.put("simple_product_5_url_key", simpleList.get("url_key")); +vars.put("simple_product_5_name", simpleList.get("title")); +vars.put("simple_product_5_id", simpleList.get("id")); -try { - emails_index = props.get("customer_emails_index"); - emails_list = props.get("customer_emails_list"); - if (emails_index == emails_list.size()) { - emails_index=0; +categoryIndex = (int)(Math.random() * props.get("categories_ids_list").size()); +vars.put("parent_category_id", props.get("categories_ids_list").get(categoryIndex)); +do { + categoryIndexNew = (int)(Math.random() * props.get("categories_ids_list").size()); +} while(categoryIndex == categoryIndexNew); +vars.put("new_parent_category_id", props.get("categories_ids_list").get(categoryIndexNew)); + + + true + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/category/ + GET + true + false + true + false + false + + + + + + + Accept-Language + en-US,en;q=0.5 + + + Accept + text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + + + User-Agent + Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0 + + + Accept-Encoding + gzip, deflate + + + + + + false + position_cache_key + \\"positionCacheKey\\": \\"([^\\]*)\\" + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + position_cache_key + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/category/edit/id/${parent_category_id}/ + GET + true + false + true + false + false + + + + + + + Accept-Language + en-US,en;q=0.5 + + + Accept + text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + + + User-Agent + Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0 + + + Accept-Encoding + gzip, deflate + + + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/category/add/store/0/parent/${parent_category_id} + GET + true + false + true + false + false + + + + + + <title>New Category + + Assertion.response_data + false + 2 + + + + + + + + true + + = + true + id + + + true + ${parent_category_id} + = + true + parent + + + true + + = + true + path + + + true + + = + true + store_id + + + true + 0 + = + true + is_active + + + true + 0 + = + true + include_in_menu + + + true + 1 + = + true + is_anchor + + + true + true + = + true + use_config[available_sort_by] + + + true + true + = + true + use_config[default_sort_by] + + + true + true + = + true + use_config[filter_price_range] + + + true + false + = + true + use_default[url_key] + + + true + 0 + = + true + url_key_create_redirect + + + true + 0 + = + true + custom_use_parent_settings + + + true + 0 + = + true + custom_apply_to_products + + + true + Admin Category Management ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + name + + + true + + = + true + filter_price_range + + + true + admin-category-management-${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + url_key + + + true + + = + true + meta_title + + + true + + = + true + description + + + true + PRODUCTS + = + true + display_mode + + + true + position + = + true + default_sort_by + + + true + + = + true + meta_keywords + + + true + + = + true + meta_description + + + true + + = + true + custom_layout_update + + + true + ${position_cache_key} + = + true + position_cache_key + + + true + 0 + = + true + is_smart_category + + + true + 0 + = + true + sort_order + + + true + [] + = + true + vm_category_products + + + true + ${admin_form_key} + = + true + form_key + + + + + + + + + + ${base_path}${admin_path}/catalog/category/save/ + POST + true + false + true + false + false + + + + + URL + admin_category_id + /catalog/category/edit/id/(\d+)/ + $1$ + + 1 + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + admin_category_id + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/category/edit/id/${admin_category_id}/ + GET + true + false + true + false + false + + + + + + + Accept-Language + en-US,en;q=0.5 + + + Accept + text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 + + + User-Agent + Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0 + + + Accept-Encoding + gzip, deflate + + + + + + false + admin_category_attribute_set_id + "attribute_set_id":"([^"]+)" + $1$ + + 1 + + + + false + admin_category_parent_id + "parent_id":"([^"]+)" + $1$ + + 1 + + + + false + admin_category_created_at + "created_at":"([^"]+)" + $1$ + + 1 + + + + false + admin_category_updated_at + "updated_at":"([^"]+)" + $1$ + + 1 + + + + false + admin_category_path + "entity_id":(.+)"path":"([^\"]+)" + $2$ + + 1 + + + + false + admin_category_level + "level":"([^"]+)" + $1$ + + 1 + + + + false + admin_category_name + "entity_id":(.+)"name":"([^"]+)" + $2$ + + 1 + + + + false + admin_category_url_key + "url_key":"([^"]+)" + $1$ + + 1 + + + + false + admin_category_url_path + "url_path":"([^"]+)" + $1$ + + 1 + + + + false + row_id + "row_id":"([^"]+)" + $1$ + + 1 + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + admin_category_attribute_set_id + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + admin_category_parent_id + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_category_created_at + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_category_updated_at + + + + + ^[\d\\\/]+$ + + Assertion.response_data + false + 1 + variable + admin_category_path + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + admin_category_level + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_category_name + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_category_url_key + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_category_url_path + + + + + + + + true + ${admin_category_id} + = + true + category_id + + + true + 0 + = + true + positions[${simple_product_1_id}] + + + true + 1 + = + true + positions[${simple_product_2_id}] + + + true + 2 + = + true + positions[${simple_product_3_id}] + + + true + 3 + = + true + positions[${simple_product_4_id}] + + + true + 4 + = + true + positions[${simple_product_5_id}] + + + true + 0 + = + true + sort_order + + + true + ${position_cache_key} + = + true + position_cache_key + + + true + ${admin_form_key} + = + true + form_key + + + true + true + = + true + isAjax + + + + + + + + + + ${base_path}${admin_path}/merchandiser/position/save/ + POST + true + false + true + false + false + + + + + + + + true + ${position_cache_key} + = + true + position_cache_key + true + + + true + ${admin_form_key} + = + true + form_key + true + + + true + true + = + true + ajax + + + true + true + = + true + isAjax + true + + + + + + + + + + ${base_path}${admin_path}/merchandiser/category/grid/id/${admin_category_id}/ + POST + true + false + true + false + false + + + + + + ${simple_product_1_name} + ${simple_product_2_name} + ${simple_product_3_name} + ${simple_product_4_name} + ${simple_product_5_name} + + Assertion.response_data + false + 2 + + + + + + + + true + 0 + = + true + store_id + + + true + ${row_id} + = + true + row_id + + + true + ${admin_category_id} + = + true + entity_id + + + true + ${admin_category_attribute_set_id} + = + true + attribute_set_id + + + true + ${parent_category_id} + = + true + parent_id + + + true + ${admin_category_level} + = + true + level + + + true + 0 + = + true + children_count + + + true + ${admin_category_name} + = + true + name + + + true + + = + true + meta_title + + + true + PRODUCTS + = + true + display_mode + + + true + ${admin_category_url_key} + = + true + url_key + + + true + 0 + = + true + is_active + + + true + 1 + = + true + is_anchor + + + true + 1 + = + true + include_in_menu + + + true + 0 + = + true + custom_user_parent_settings + + + true + 0 + = + true + custom_apply_to_products + + + true + + = + true + description + + + true + + = + true + meta_keywords + + + true + + = + true + custom_layout_update + + + true + false + = + true + use_default[url_key] + + + true + true + = + true + use_config[available_sort_by] + + + true + true + = + true + use_config[default_sort_by] + + + true + true + = + true + use_config[filter_price_range] + + + true + + = + true + id + + + true + 0 + = + true + parent + + + true + ${admin_category_url_key} + = + true + url_key_create_redirect + + + true + + = + true + filter_price_range + + + true + position + = + true + default_sort_by + + + true + ${position_cache_key} + = + true + position_cache_key + + + true + 0 + = + true + is_smart_category + + + true + + = + true + smart_category_rules + + + true + 0 + = + true + sort_order + + + true + {"${simple_product_1_id}":0,"${simple_product_2_id}":1,"${simple_product_3_id}":2,"${simple_product_4_id}":3,"${simple_product_5_id}":4} + = + true + vm_category_products + + + true + ${admin_form_key} + = + true + form_key + + + true + ${admin_category_created_at} + = + true + created_at + + + true + ${admin_category_updated_at} + = + true + updated_at + + + true + 0 + = + true + automatic_sorting + + + true + + = + true + meta_description + + + + + + + + + + ${base_path}${admin_path}/catalog/category/save/ + POST + true + false + true + false + false + + + + + false + + + try { + path = vars.get("admin_category_path").replaceAll("\\\\", ""); + ctx.getCurrentSampler().addArgument("path", path); + pathParts = path.split("/"); + for (int i = 0; i < pathParts.length; i++) { + ctx.getCurrentSampler().addArgument("path_ids[" + i + "]", pathParts[i]); } - vars.put("customer_email", emails_list.get(emails_index)); - props.put("customer_emails_index", ++emails_index); -} -catch (java.lang.Exception e) { - log.error("Caught Exception in 'Customer Checkout' thread."); - log.info("Using default email address - user_1@example.com"); - vars.put("customer_email", "user_1@example.com"); -} -vars.put("testLabel", "CustomerChkt"); -vars.put("loadType", "Customer"); - - - true - - - - - - + + urlPath = vars.get("admin_category_url_path").replaceAll("\\\\", ""); + ctx.getCurrentSampler().addArgument("url_path", urlPath); +} catch (Exception e) { + log.error("error…", e); +} + + + + + You saved the category. + + Assertion.response_data + false + 2 + + + + + + + + true + ${admin_category_id} + = + true + id + + + true + ${admin_form_key} + = + true + form_key + + + true + append + = + true + point + + + true + ${new_parent_category_id} + = + true + pid + + + true + ${parent_category_id} + = + true + paid + + + true + 0 + = + true + aid + + + true + true + = + true + isAjax + + + + + + + + + + ${base_path}${admin_path}/catalog/category/move/ + POST + true + false + true + false + false + + + + + + + + + + + + + + ${base_path}${admin_path}/catalog/category/delete/id/${admin_category_id}/ + GET + true + false + true + false + false + + + + + + You deleted the category. + + Assertion.response_data + false + 2 + + + + + 1 + 0 + ${__javaScript(Math.round(${adminCategoryManagementDelay}*1000))} + + + + + + + continue + + false + ${loops} - - - - - - - ${base_path} - GET - true - false - true - false - false - - + ${__javaScript(Math.round(${numberOfThreads}*${adminPoolPercentage}*${promotionRulesPercentage}/10000))} + 0 + 1462819418000 + 1462819418000 + false + + + - - - <title>Home page</title> - - Assertion.response_data - false - 2 - - + + + + + + + + + + + + + ${base_path}${admin_path} + GET + true + false + true + false + false + + + + + + Welcome + <title>Magento Admin</title> + + Assertion.response_data + false + 2 + + + + false + admin_form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_form_key + + + + + + + + false + ${admin_form_key} + = + true + form_key + + + true + ${admin_password} + = + true + login[password] + + + true + ${admin_user} + = + true + login[username] + + + + + + + + + + ${base_path}${admin_path}/admin/dashboard/ + POST + true + false + true + false + Java + false + + Implementation needs to be set to Java as per http://stackoverflow.com/questions/19636282/jmeter-error-in-redirect-url-for-get + + + + + ${test_duration} + + + + + + + + + + + + + + + ${base_path}${admin_path}/sales_rule/promo_quote/ + GET + true + false + true + false + false + + + + + + + + + + + + + + ${base_path}${admin_path}/sales_rule/promo_quote/new + GET + true + false + true + false + false + + + + + + + + true + true + = + true + isAjax + + + true + ${admin_form_key} + = + true + form_key + true + + + true + 1--1 + = + true + id + + + true + Magento\SalesRule\Model\Rule\Condition\Address|base_subtotal + = + true + type + + + + + + + + + + ${base_path}${admin_path}/sales_rule/promo_quote/newConditionHtml/form/sales_rule_formrule_conditions_fieldset_/form_namespace/sales_rule_form + POST + true + false + true + false + false + + + + + + + + true + Rule Name ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + name + + + true + 0 + = + true + is_active + + + true + 0 + = + true + use_auto_generation + + + true + 1 + = + true + is_rss + + + true + 0 + = + true + apply_to_shipping + + + true + 0 + = + true + stop_rules_processing + + + true + + = + true + coupon_code + + + true + + = + true + uses_per_coupon + + + true + + = + true + uses_per_customer + + + true + + = + true + sort_order + + + true + 5 + = + true + discount_amount + + + true + 0 + = + true + discount_qty + + + true + + = + true + discount_step + + + true + + = + true + reward_points_delta + + + true + + = + true + store_labels[0] + + + true + Rule Description ${__time(YMDHMS)}-${__threadNum}-${__Random(1,1000000)} + = + true + description + + + true + 1 + = + true + coupon_type + + + true + cart_fixed + = + true + simple_action + + + true + 1 + = + true + website_ids[0] + + + true + 0 + = + true + customer_group_ids[0] + + + true + + = + true + from_date + + + true + + = + true + to_date + + + true + Magento\SalesRule\Model\Rule\Condition\Combine + = + true + rule[conditions][1][type] + + + true + all + = + true + rule[conditions][1][aggregator] + + + true + 1 + = + true + rule[conditions][1][value] + + + true + Magento\SalesRule\Model\Rule\Condition\Address + = + true + rule[conditions][1--1][type] + + + true + base_subtotal + = + true + rule[conditions][1--1][attribute] + + + true + >= + = + true + rule[conditions][1--1][operator] + + + true + 100 + = + true + rule[conditions][1--1][value] + + + true + + = + true + rule[conditions][1][new_chlid] + + + true + Magento\SalesRule\Model\Rule\Condition\Product\Combine + = + true + rule[actions][1][type] + + + true + all + = + true + rule[actions][1][aggregator] + + + true + 1 + = + true + rule[actions][1][value] + + + true + + = + true + rule[actions][1][new_child] + + + true + + = + true + store_labels[1] + + + true + + = + true + store_labels[2] + + + true + + = + true + related_banners + + + true + ${admin_form_key} + = + true + form_key + + + + + + + + + + ${base_path}${admin_path}/sales_rule/promo_quote/save/ + POST + true + false + true + false + false + + + + + + You saved the rule. + + Assertion.response_data + false + 16 + + + + + 1 + 0 + ${__javaScript(Math.round(${adminPromotionsManagementDelay}*1000))} + + + + - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}customer/account/login/ - GET - true - false - true - false - false - - - - - - <title>Customer Login</title> - - Assertion.response_data - false - 2 - - - - - - - - - true - ["customer_form_login"] - = - true - blocks - - - true - ["default","customer_account_login"] - = - true - handles - - - true - {"route":"customer","controller":"account","action":"login","uri":"/customer/account/login/"} - = - true - originalRequest - - - true - true - = - true - ajax - - - true - true - = - true - isAjax - - - - - - - - - - ${base_path}page_cache/block/render/ - GET - true - false - true - false - false - - - - - - "customer_form_login" - Registered Customers - form_key - - Assertion.response_data - false - 2 - - - - false - form_key - <input name=\\"form_key\\" type=\\"hidden\\" value=\\"([^'"]+)\\" \\/> - $1$ - - 1 - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - form_key - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - true - ${form_key} - = - true - form_key - - - true - ${customer_email} - = - true - login[username] - - - true - ${customer_password} - = - true - login[password] - - - true - - = - true - send - - - - - - - - - - ${base_path}customer/account/loginPost/ - POST - true - false - true - false - false - - - - - - <title>My Account</title> - - Assertion.response_data - false - 2 - - - - false - addressId - customer/address/edit/id/([^'"]+)/ - $1$ - - 1 - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - addressId - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${category_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <span class="base" data-ui-id="page-title">${category_name}</span> - - Assertion.response_data - false - 6 - - - - false - category_id - <li class="item category([^'"]+)">\s*<strong>${category_name}</strong>\s*</li> - $1$ - - 1 - simple_product_1_url_key - - - - - ^[0-9]+$ - - Assertion.response_data - false - 1 - variable - category_id - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${simple_product_1_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${simple_product_1_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - product_id - .//input[@type="hidden" and @name="product"]/@value - false - true - false - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - product_id - - - - - - - - - - - - - - ${base_path}review/product/listAjax/id/${product_id}/ - GET - true - false - true - false - false - - - - - - 200 - - Assertion.response_code - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - false - ${simple_product_1_id} - = - true - product - - - false - - = - true - related_product - - - false - 1 - = - true - qty - - - false - ${form_key} - = - true - form_key - - - - - - - - - - ${base_path}checkout/cart/add/ - POST - true - false - true - false - false - - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - - - - true - cart,messages - = - true - sections - - - true - true - = - true - update_section_id - - - false - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} - = - true - _ - - - - - - - - - - ${base_path}customer/section/load/ - GET - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - You added ${simple_product_1_name} to your shopping cart. - - Assertion.response_data - false - 2 - - - - - This product is out of stock. - - Assertion.response_data - false - 6 - - - - - \"summary_count\":1 - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${simple_product_2_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${simple_product_2_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - product_id - .//input[@type="hidden" and @name="product"]/@value - false - true - false - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - product_id - - - - - - - - - - - - - - ${base_path}review/product/listAjax/id/${product_id}/ - GET - true - false - true - false - false - - - - - - 200 - - Assertion.response_code - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - false - ${simple_product_2_id} - = - true - product - - - false - - = - true - related_product - - - false - 1 - = - true - qty - - - false - ${form_key} - = - true - form_key - - - - - - - - - - ${base_path}checkout/cart/add/ - POST - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - - - - true - cart,messages - = - true - sections - true - - - true - true - = - true - update_section_id - true - - - false - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} - = - true - _ - true - - - - - - - - - - ${base_path}customer/section/load/ - GET - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest + + continue + + false + ${loops} - - - - - - - You added ${simple_product_2_name} to your shopping cart. - - Assertion.response_data - false - 2 - - - - - This product is out of stock. - - Assertion.response_data - false - 6 - - - - - \"summary_count\":2 - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}${configurable_product_1_url_key}${url_suffix} - GET - true - false - true - false - false - - - - - - <title>${configurable_product_1_name} - <span>In stock</span> - - Assertion.response_data - false - 2 - - - - - false - configurable_product_sku - itemprop="sku">([^<]*)<\/ - $1$ - NOT_FOUND - 1 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - true - 1 - - - - - - Content-Type - application/json - - - Accept - */* - - - - - - true - - - - false - {"username":"${admin_user}","password":"${admin_password}"} - = + ${__javaScript(Math.round(${numberOfThreads}*${adminPoolPercentage}*${apiProcessOrdersPercentage}/10000))} + 0 + 1437411833000 + 1437411833000 + false + ${test_duration} + + + + + ${test_duration} + + + + // Each thread gets an equal number of orders, based on how many orders are available. + +int numberOfOrders = Integer.parseInt(vars.get("orders_page_size")); +int totalNumberOfThreads = Integer.parseInt(vars.get("numberOfThreads")); +int adminPoolPercentage = Integer.parseInt(vars.get("adminPoolPercentage")); +int apiProcessOrdersPercentage = Integer.parseInt(vars.get("apiProcessOrdersPercentage")); +int numberOfThreads = Math.round(totalNumberOfThreads*adminPoolPercentage*apiProcessOrdersPercentage/10000.); +int ordersPerThread = Math.round(numberOfOrders/1./numberOfThreads); + +var startIndex = (${__threadNum} - 1) * ordersPerThread; +var ordersList = props.get("orders_list"); +int j = 1; +for (int i=startIndex; i < startIndex + ordersPerThread; i++) { + if (i >= ordersList.size()) { + break; + } + vars.put("order_list_id_" + j.toString(), ordersList.get(i)); + j++; +} +vars.put("ordersPerThread", String.valueOf(ordersPerThread)); + + + + false + + + + + + Content-Type + application/json + + + Accept + */* + + + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + - + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + order_list_id + order_id + true + + + + + + + + + + + + + ${base_path}rest/default/V1/order/${order_id}/invoice + POST + true + false + true + false + false + + + + + + "\d+" + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}rest/default/V1/order/${order_id}/ship + POST + true + false + true + false + false + + + + + + "\d+" + + Assertion.response_data + false + 2 + + + + + + int ordersPerThread = Integer.parseInt(vars.get("ordersPerThread")); + +for (int i=1; i <= ordersPerThread; i++) { + vars.remove("order_list_id_" + i.toString()); +} + +SampleResult.setStopThread(true); + + + false + + + + + + continue + + false + ${loops} - - - - - - - ${base_path}rest/V1/integration/admin/token - POST - true - false - true - false - false - - + ${__javaScript(Math.round(${numberOfThreads}*${adminPoolPercentage}*${adminProcessReturnsPercentage}/10000))} + 0 + 1494585345000 + 1494585345000 + false + + + - - admin_token - $ - - - BODY - - - - - ^[a-z0-9-]+$ - - Assertion.response_data - false - 1 - variable - admin_token - - + + + + + + + + + + + + + ${base_path}${admin_path} + GET + true + false + true + false + false + + + + + + Welcome + <title>Magento Admin</title> + + Assertion.response_data + false + 2 + + + + false + admin_form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_form_key + + + + + + + + false + ${admin_form_key} + = + true + form_key + + + true + ${admin_password} + = + true + login[password] + + + true + ${admin_user} + = + true + login[username] + + + + + + + + + + ${base_path}${admin_path}/admin/dashboard/ + POST + true + false + true + false + Java + false + + Implementation needs to be set to Java as per http://stackoverflow.com/questions/19636282/jmeter-error-in-redirect-url-for-get + + + + + + + true + sales_order_grid + = + true + namespace + + + true + + = + true + search + + + true + true + = + true + filters[placeholder] + + + true + 200 + = + true + paging[pageSize] + + + true + 1 + = + true + paging[current] + + + true + increment_id + = + true + sorting[field] + + + true + desc + = + true + sorting[direction] + + + true + true + = + true + isAjax + + + true + ${admin_form_key} + = + true + form_key + false + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 2 + + + + false + orders_number + \"totalRecords\":(\d+)\, + $1$ + + 1 + simple_products + + + + + + + + true + ${admin_form_key} + = + true + form_key + + + true + sales_order_grid + = + true + namespace + true + + + true + + = + true + search + true + + + true + true + = + true + filters[placeholder] + true + + + true + 200 + = + true + paging[pageSize] + true + + + true + 1 + = + true + paging[current] + true + + + true + increment_id + = + true + sorting[field] + true + + + true + desc + = + true + sorting[direction] + true + + + true + true + = + true + isAjax + true + + + true + pending + = + true + filters[status] + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + POST + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 2 + + + + false + order_numbers + \"increment_id\":\"(\d+)\"\, + $1$ + + -1 + simple_products + + + + false + order_ids + \"entity_id\":\"(\d+)\"\, + $1$ + + -1 + simple_products + + + + + + ${test_duration} + + + + + + Passing arguments between threads + import java.util.ArrayList; +import java.util.HashMap; +import org.apache.jmeter.protocol.http.util.Base64Encoder; + +int ordersCount = Integer.parseInt(vars.get("order_numbers_matchNr")); +int threadsCount = Integer.parseInt(vars.get("numberOfThreads")); +int adminPoolPercentage = Integer.parseInt(vars.get("adminPoolPercentage")); +int processOrdersPercentage = Integer.parseInt(vars.get("processOrdersPercentage")); +int threadsNumber = Math.round(threadsCount*adminPoolPercentage*processOrdersPercentage/10000.); + +if (threadsNumber == 0) { + threadsNumber = 1; +} +//Current thread number starts from 0 +int currentThreadNum = ctx.getThreadNum(); + +String siterator = vars.get("threadIterator_" + currentThreadNum.toString()); +int iterator; +if(siterator == null){ + iterator = 1; + vars.put("threadIterator_" + currentThreadNum.toString() , "1"); +} else { + iterator = Integer.parseInt(siterator); + iterator ++; + vars.put("threadIterator_" + currentThreadNum.toString() , iterator.toString()); +} + +//Number of orders for one thread +int clusterLength = ordersCount / threadsNumber; +//Index of the current product from the cluster +int i = clusterLength * currentThreadNum + iterator; + +if (iterator >= clusterLength) { + vars.put("threadIterator_" + currentThreadNum.toString(), "1"); + iterator = 1; +} + +orderNumber = vars.get("order_numbers_" + i.toString()); +orderId = vars.get("order_ids_" + i.toString()); +vars.put("order_number", orderNumber); +vars.put("order_id", orderId); + +//Search info +vars.put("search_data", orderNumber); + +//Debug info +vars.put("threadNum" , currentThreadNum.toString()); +vars.put("clusterLength", clusterLength.toString()); +vars.put("i", i.toString()); + + + + + false + + + + + + + + + + + + + ${base_path}${admin_path}/sales/order/ + GET + true + false + true + false + false + + + + + + Create New Order + + Assertion.response_data + false + 2 + + + + + + + + true + sales_order_grid + = + true + namespace + + + true + + = + true + search + + + true + true + = + true + filters[placeholder] + + + true + 200 + = + true + paging[pageSize] + + + true + 1 + = + true + paging[current] + + + true + increment_id + = + true + sorting[field] + + + true + desc + = + true + sorting[direction] + + + true + true + = + true + isAjax + + + true + ${admin_form_key} + = + true + form_key + false + + + true + pending + = + true + filters[status] + true + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 2 + + + + false + orders_number + \"totalRecords\":(\d+)\, + $1$ + + 1 + simple_products + + + + + + + + true + sales_order_grid + = + true + namespace + + + true + + = + true + search + + + true + true + = + true + filters[placeholder] + + + true + 20 + = + true + paging[pageSize] + + + true + 1 + = + true + paging[current] + + + true + increment_id + = + true + sorting[field] + + + true + desc + = + true + sorting[direction] + + + true + true + = + true + isAjax + + + true + ${admin_form_key} + = + true + form_key + false + + + true + pending + = + true + filters[status] + true + + + true + ${search_data} + = + true + filters[increment_id] + + + true + en_US + = + true + created_at[locale] + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + "totalRecords":1 + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/sales/order/view/order_id/${order_id}/ + GET + true + false + true + false + false + + + + + + #${order_number} + Invoice + Ship + Hold + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/sales/order_invoice/start/order_id/${order_id}/ + GET + true + false + true + false + false + + + + + + Invoice Totals + + Assertion.response_data + false + 2 + + + + false + item_ids + <div id="order_item_(\d+)_title"\s*class="product-title"> + $1$ + + -1 + simple_products + + + + + + + + false + ${admin_form_key} + = + true + form_key + false + + + false + 1 + = + true + invoice[items][${item_ids_1}] + + + false + 1 + = + true + invoice[items][${item_ids_2}] + + + false + Invoiced + = + true + invoice[comment_text] + + + + + + + + + + ${base_path}${admin_path}/sales/order_invoice/save/order_id/${order_id}/ + POST + true + false + true + false + false + + + + + + The invoice has been created + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/sales/order_creditmemo/start/order_id/${order_id}/ + GET + true + false + true + false + false + + + + + + New Memo + + Assertion.response_data + false + 2 + + + + + + + + false + ${admin_form_key} + = + true + form_key + false + + + false + 1 + = + true + creditmemo[items][${item_ids_1}][qty] + + + false + 1 + = + true + creditmemo[items][${item_ids_2}][qty] + + + false + 1 + = + true + creditmemo[do_offline] + + + false + Credit Memo added + = + true + creditmemo[comment_text] + + + false + 10 + = + true + creditmemo[shipping_amount] + + + false + 0 + = + true + creditmemo[adjustment_positive] + + + false + 0 + = + true + creditmemo[adjustment_negative] + + + + + + + + + + ${base_path}${admin_path}/sales/order_creditmemo/save/order_id/${order_id}/ + POST + true + false + true + false + false + + + + + + You created the credit memo + + Assertion.response_data + false + 2 + + + + + - - - - Authorization - Bearer ${admin_token} - - - - - - - + + continue + + false + ${loops} - - - - - - - ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all - GET - true - false - true - false - false - - + ${__javaScript(Math.round(${numberOfThreads}*${csrPoolPercentage}*${csrBrowseCustomersPercentage}/10000))} + 0 + 1494592921000 + 1494592921000 + false + + + - - attribute_ids - $.[*].attribute_id - NO_VALUE - - BODY - - - - option_values - $.[*].values[0].value_index - NO_VALUE - - BODY - - + + + + + + + + + + + + + ${base_path}${admin_path} + GET + true + false + true + false + false + + + + + + Welcome + <title>Magento Admin</title> + + Assertion.response_data + false + 2 + + + + false + admin_form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_form_key + + + + + + + + false + ${admin_form_key} + = + true + form_key + + + true + ${admin_password} + = + true + login[password] + + + true + ${admin_user} + = + true + login[username] + + + + + + + + + + ${base_path}${admin_path}/admin/dashboard/ + POST + true + false + true + false + Java + false + + Implementation needs to be set to Java as per http://stackoverflow.com/questions/19636282/jmeter-error-in-redirect-url-for-get + + + + + ${test_duration} + + + + 1 + + + + + + + + + true + customer_listing + = + true + namespace + true + + + true + + = + true + search + true + + + true + true + = + true + filters[placeholder] + true + + + true + ${customers_page_size} + = + true + paging[pageSize] + true + + + true + 1 + = + true + paging[current] + true + + + true + entity_id + = + true + sorting[field] + true + + + true + asc + = + true + sorting[direction] + true + + + true + true + = + true + isAjax + true + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + $.totalRecords + 0 + true + false + true + true + + + + customers_number + $.totalRecords + + + BODY + + + + false + + + var customersPageSize = Integer.parseInt(vars.get("customers_page_size")); +var customersTotal = Integer.parseInt(vars.get("customers_number")); +var pageCountCustomers = Math.round(customersTotal/customersPageSize); + +vars.put("pages_count_customer", String.valueOf(pageCountCustomers)); + + + + + 1 + ${pages_count_customer} + 2 + page_number + + true + + + + + + + true + customer_listing + = + true + namespace + true + + + true + + = + true + search + true + + + true + true + = + true + filters[placeholder] + true + + + true + ${customers_page_size} + = + true + paging[pageSize] + true + + + true + ${page_number} + = + true + paging[current] + true + + + true + entity_id + = + true + sorting[field] + true + + + true + asc + = + true + sorting[direction] + true + + + true + true + = + true + isAjax + true + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 16 + + + + + + + + + + + true + customer_listing + = + true + namespace + true + + + true + + = + true + search + true + + + true + true + = + true + filters[placeholder] + true + + + true + ${customers_page_size} + = + true + paging[pageSize] + true + + + true + 1 + = + true + paging[current] + true + + + true + entity_id + = + true + sorting[field] + true + + + true + asc + = + true + sorting[direction] + true + + + true + true + = + true + isAjax + true + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + $.totalRecords + 0 + true + false + true + true + + + + customers_number + $.totalRecords + + + BODY + + + + false + + + var customersPageSize = Integer.parseInt(vars.get("customers_page_size")); +var customersTotal = Integer.parseInt(vars.get("customers_number")); +var pageCountCustomers = Math.round(customersTotal/customersPageSize); + +vars.put("pages_count_customer", String.valueOf(pageCountCustomers)); + + + + + + ${pages_count_customer} > 1 + false + + + + 2 + ${pages_count_customer} + 2 + page_number + + true + true + + + + + + + true + customer_listing + = + true + namespace + true + + + true + + = + true + search + true + + + true + true + = + true + filters[placeholder] + true + + + true + ${customers_page_size} + = + true + paging[pageSize] + true + + + true + ${page_number} + = + true + paging[current] + true + + + true + entity_id + = + true + sorting[field] + true + + + true + asc + = + true + sorting[direction] + true + + + true + true + = + true + isAjax + true + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 16 + + + + + + + + + + + + true + customer_listing + = + true + namespace + true + + + true + + = + true + search + true + + + true + ${admin_browse_customer_filter_text} + = + true + filters[placeholder] + true + + + true + ${customers_page_size} + = + true + paging[pageSize] + true + + + true + 1 + = + true + paging[current] + true + + + true + entity_id + = + true + sorting[field] + true + + + true + asc + = + true + sorting[direction] + true + + + true + true + = + true + isAjax + true + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + $.totalRecords + 0 + true + false + true + true + + + + customers_number + $.totalRecords + + + BODY + + + + false + + + var customersPageSize = Integer.parseInt(vars.get("customers_page_size")); + var customersTotal = Integer.parseInt(vars.get("customers_number")); + var pageCountCustomers = Math.round(customersTotal/customersPageSize); + + vars.put("pages_count_filtered_customer", String.valueOf(pageCountCustomers)); + + + + + 1 + ${pages_count_filtered_customer} + 1 + page_number + + true + true + + + + + + + true + customer_listing + = + true + namespace + false + + + true + + = + true + search + false + + + true + ${admin_browse_customer_filter_text} + = + true + filters[placeholder] + false + + + true + ${customers_page_size} + = + true + paging[pageSize] + false + + + true + ${page_number} + = + true + paging[current] + false + + + true + entity_id + = + true + sorting[field] + false + + + true + asc + = + true + sorting[direction] + false + + + true + true + = + true + isAjax + false + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 16 + + + + + + + + + + + true + customer_listing + = + true + namespace + true + + + true + + = + true + search + true + + + true + true + = + true + filters[placeholder] + true + + + true + ${customers_page_size} + = + true + paging[pageSize] + true + + + true + 1 + = + true + paging[current] + true + + + true + entity_id + = + true + sorting[field] + true + + + true + asc + = + true + sorting[direction] + true + + + true + true + = + true + isAjax + true + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + $.totalRecords + 0 + true + false + true + true + + + + customers_number + $.totalRecords + + + BODY + + + + false + + + var customersPageSize = Integer.parseInt(vars.get("customers_page_size")); + var customersTotal = Integer.parseInt(vars.get("customers_number")); + var pageCountCustomers = Math.round(customersTotal/customersPageSize); + + vars.put("pages_count_customer", String.valueOf(pageCountCustomers)); + + + + + + + customer_sort_field_1 + name + = + + + customer_sort_field_2 + group + = + + + customer_sort_field_3 + billing_country_id + = + + + customer_sort_order_1 + asc + = + + + customer_sort_order_2 + desc + = + + + + + + 1 + ${pages_count_customer} + 1 + page_number + + true + true + + + + customer_sort_field + customer_sort_field + true + 0 + 3 + + + + customer_sort_order + customer_sort_order + true + 0 + 2 + + + + + + + true + customer_listing + = + true + namespace + false + + + true + + = + true + search + false + + + true + true + = + true + filters[placeholder] + false + + + true + ${customers_page_size} + = + true + paging[pageSize] + false + + + true + ${page_number} + = + true + paging[current] + false + + + true + ${customer_sort_field} + = + true + sorting[field] + false + + + true + ${customer_sort_order} + = + true + sorting[direction] + false + + + true + true + = + true + isAjax + false + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 16 + + + + + + + + + + + + + true + customer_listing + = + true + namespace + true + + + true + + = + true + search + true + + + true + ${admin_browse_customer_filter_text} + = + true + filters[placeholder] + true + + + true + ${customers_page_size} + = + true + paging[pageSize] + true + + + true + 1 + = + true + paging[current] + true + + + true + entity_id + = + true + sorting[field] + true + + + true + asc + = + true + sorting[direction] + true + + + true + true + = + true + isAjax + true + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + $.totalRecords + 0 + true + false + true + true + + + + customers_number + $.totalRecords + + + BODY + + + + false + + + var customersPageSize = Integer.parseInt(vars.get("customers_page_size")); + var customersTotal = Integer.parseInt(vars.get("customers_number")); + var pageCountCustomers = Math.round(customersTotal/customersPageSize); + + vars.put("pages_count_filtered_customer", String.valueOf(pageCountCustomers)); + + + + + + + customer_sort_field_1 + name + = + + + customer_sort_field_2 + group + = + + + customer_sort_field_3 + billing_country_id + = + + + + + + 1 + ${pages_count_filtered_customer} + 1 + page_number + + true + true + + + + customer_sort_field + customer_sort_field + true + 0 + 3 + + + + + + + true + customer_listing + = + true + namespace + false + + + true + + = + true + search + false + + + true + ${admin_browse_customer_filter_text} + = + true + filters[placeholder] + false + + + true + ${customers_page_size} + = + true + paging[pageSize] + false + + + true + ${page_number} + = + true + paging[current] + false + + + true + ${customer_sort_field} + = + true + sorting[field] + false + + + true + asc + = + true + sorting[direction] + false + + + true + true + = + true + isAjax + false + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 16 + + + + + + + - - - - - - - false - ${configurable_product_1_id} - = - true - product - - - false - - = - true - related_product - - - false - 1 - = - true - qty - - - false - ${configurable_option_id} - = - true - super_attribute[${configurable_attribute_id}] - - - false - ${form_key} - = - true - form_key - - - - - - - - - - ${base_path}checkout/cart/add/ - POST - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest + + startnextloop + + false + ${loops} - - - - - + ${__javaScript(Math.round(${numberOfThreads}*${csrPoolPercentage}*${csrCreateOrderPercentage}/10000))} + 0 + 1304708488000 + 1304708488000 + false + + + + + + + + + + + + + + + + + ${base_path}${admin_path} + GET + true + false + true + false + false + + + + + + Welcome + <title>Magento Admin</title> + + Assertion.response_data + false + 2 + + + + false + admin_form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_form_key + + + + + + + + false + ${admin_form_key} + = + true + form_key + + + true + ${admin_password} + = + true + login[password] + + + true + ${admin_user} + = + true + login[username] + + + + + + + + + + ${base_path}${admin_path}/admin/dashboard/ + POST + true + false + true + false + Java + false + + Implementation needs to be set to Java as per http://stackoverflow.com/questions/19636282/jmeter-error-in-redirect-url-for-get + + + + + ${test_duration} + + + + + + Passing arguments between threads + import org.apache.jmeter.samplers.SampleResult; + + number = (int)(Math.random() * props.get("simple_products_list").size()); + simpleList = props.get("simple_products_list").get(number); + vars.put("simple_product_1_url_key", simpleList.get("url_key")); + vars.put("simple_product_1_name", simpleList.get("title")); + vars.put("simple_product_1_id", simpleList.get("id")); + + do { + number1 = (int)(Math.random() * props.get("simple_products_list").size()); + } while(number == number1); + simpleList = props.get("simple_products_list").get(number1); + vars.put("simple_product_2_url_key", simpleList.get("url_key")); + vars.put("simple_product_2_name", simpleList.get("title")); + vars.put("simple_product_2_id", simpleList.get("id")); + + number = (int)(Math.random() * props.get("configurable_products_list").size()); + configurableList = props.get("configurable_products_list").get(number); + vars.put("configurable_product_1_url_key", configurableList.get("url_key")); + vars.put("configurable_product_1_name", configurableList.get("title")); + vars.put("configurable_product_1_id", configurableList.get("id")); + vars.put("configurable_product_1_sku", configurableList.get("sku")); + + + customers_index = 0; + if (!props.containsKey("customer_ids_index")) { + props.put("customer_ids_index", customers_index); + } + + try { + customers_index = props.get("customer_ids_index"); + customers_list = props.get("customer_ids_list"); + + if (customers_index == customers_list.size()) { + customers_index=0; + } + vars.put("customer_id", customers_list.get(customers_index)); + props.put("customer_ids_index", ++customers_index); + } + catch (java.lang.Exception e) { + log.error("Caught Exception in 'Admin Create Order' thread."); + SampleResult.setStopThread(true); + } + + + true + + + + + + + + + + + + + ${base_path}${admin_path}/sales/order_create/start/ + GET + true + false + true + false + false + + Detected the start of a redirect chain + + + + + + + + Content-Type + application/json + + + Accept + */* + + + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + + + + + + + ${base_path}rest/V1/configurable-products/${configurable_product_1_sku}/options/all + GET + true + false + true + false + false + + + + + attribute_ids + $.[*].attribute_id + NO_VALUE + + BODY + + + + option_values + $.[*].values[0].value_index + NO_VALUE + + BODY + + + + + + + + + false + item[${simple_product_1_id}][qty] + 1 + = + true + + + false + item[${simple_product_2_id}][qty] + 1 + = + true + + + false + item[${configurable_product_1_id}][qty] + 1 + = + true + + + false + customer_id + ${customer_id} + = + true + + + false + store_id + 1 + = + true + + + false + currency_id + + = + true + + + false + form_key + ${admin_form_key} + = + true + + + false + payment[method] + checkmo + = + true + + + false + reset_shipping + 1 + = + true + + + false + json + 1 + = + true + + + false + as_js_varname + iFrameResponse + = + true + + + false + form_key + ${admin_form_key} + = + true + + + + + + + + + + ${base_path}${admin_path}/sales/order_create/loadBlock/block/search,items,shipping_method,totals,giftmessage,billing_method?isAjax=true + POST + true + false + true + false + false + + Detected the start of a redirect chain + + + false - - - - try { - attribute_ids = vars.get("attribute_ids"); - option_values = vars.get("option_values"); - attribute_ids = attribute_ids.replace("[","").replace("]","").replace("\"", ""); - option_values = option_values.replace("[","").replace("]","").replace("\"", ""); - attribute_ids_array = attribute_ids.split(","); - option_values_array = option_values.split(","); - args = ctx.getCurrentSampler().getArguments(); - it = args.iterator(); - while (it.hasNext()) { - argument = it.next(); - if (argument.getStringValue().contains("${")) { - args.removeArgument(argument.getName()); - } - } - for (int i = 0; i < attribute_ids_array.length; i++) { - ctx.getCurrentSampler().addArgument("super_attribute[" + attribute_ids_array[i] + "]", option_values_array[i]); - } - } catch (Exception e) { - log.error("eror…", e); - } - + + + try { + attribute_ids = vars.get("attribute_ids"); + option_values = vars.get("option_values"); + attribute_ids = attribute_ids.replace("[","").replace("]","").replace("\"", ""); + option_values = option_values.replace("[","").replace("]","").replace("\"", ""); + attribute_ids_array = attribute_ids.split(","); + option_values_array = option_values.split(","); + args = ctx.getCurrentSampler().getArguments(); + it = args.iterator(); + while (it.hasNext()) { + argument = it.next(); + if (argument.getStringValue().contains("${")) { + args.removeArgument(argument.getName()); + } + } + for (int i = 0; i < attribute_ids_array.length; i++) { + + ctx.getCurrentSampler().addArgument("item[" + vars.get("configurable_product_1_id") + "][super_attribute][" + attribute_ids_array[i] + "]", option_values_array[i]); + } +} catch (Exception e) { + log.error("error…", e); +} - - - - - - - - true - cart,messages - = - true - sections - true - - - true - true - = - true - update_section_id - true - - - false - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} - = - true - _ - true - - - - - - - - - - ${base_path}customer/section/load/ - GET - true - false - true - false - false - - - - - - - X-Requested-With - XMLHttpRequest - - - - - - - - You added ${configurable_product_1_name} to your shopping cart. - - Assertion.response_data - false - 2 - - - - - We don't have as many &quot;${configurable_product_1_name}&quot; as you requested. - - Assertion.response_data - false - 6 - - - - - \"summary_count\":3 - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}checkout/ - GET - true - false - true - false - false - - - - - - <title>Checkout</title> - - Assertion.response_data - false - 2 - - - - - <title>Shopping Cart</title> - - Assertion.response_data - false - 6 - - - - false - cart_id - "quoteData":{"entity_id":"([^'"]+)", - $1$ - - 1 - - - - false - form_key - <input name="form_key" type="hidden" value="([^'"]+)" /> - $1$ - - 1 - - - - false - address_id - "default_billing":"([^'"]+)", - $1$ - - 1 - - - - false - customer_id - "customer_id":([^'",]+), - $1$ - - 1 - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - cart_id - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - form_key - - - - - [0-9]+$ - - Assertion.response_data - false - 1 - variable - address_id - - - - - [0-9]+$ - - Assertion.response_data - false - 1 - variable - customer_id - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - true - - - - false - {"addressId":"${addressId}"} - = - - - - - - - - - - ${base_path}rest/default/V1/carts/mine/estimate-shipping-methods-by-address-id - POST - true - false - true - false - false - - - - - - - Referer - ${base_path}checkout/onepage/ - - - Content-Type - application/json; charset=UTF-8 - - - X-Requested-With - XMLHttpRequest - - - Accept - application/json - - - - - - - "available":true - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - true - - - - false - {"addressInformation":{"shipping_address":{"customerAddressId":"${address_id}","countryId":"US","regionId":5,"regionCode":"AR","region":"Arkansas","customerId":"${customer_id}","street":["123 Freedom Blvd. #123"],"telephone":"022-333-4455","postcode":"123123","city":"Fayetteville","firstname":"Anthony","lastname":"Nealy"},"shipping_method_code":"flatrate","shipping_carrier_code":"flatrate"}} - = - - - - - - - - - - ${base_path}rest/default/V1/carts/mine/shipping-information - POST - true - false - true - false - false - - - - - - - Referer - ${host}${base_path}checkout/onepage - - - Content-Type - application/json; charset=UTF-8 - - - X-Requested-With - XMLHttpRequest - - - Accept - application/json - - - - - - - {"payment_methods" - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - true - - - - false - {"cartId":"${cart_id}","paymentMethod":{"method":"checkmo","po_number":null,"additional_data":null},"billingAddress":{"customerAddressId":"${address_id}","countryId":"US","regionId":5,"regionCode":"AR","region":"Arkansas","customerId":"${customer_id}","street":["123 Freedom Blvd. #123"],"telephone":"022-333-4455","postcode":"123123","city":"Fayetteville","firstname":"Anthony","lastname":"Nealy"}} - = - - - - - - - - - - ${base_path}rest/default/V1/carts/mine/payment-information - POST - true - false - true - false - false - - - - - - - Referer - ${host}${base_path}checkout/onepage - - - Content-Type - application/json; charset=UTF-8 - - - Accept - application/json - - - X-Requested-With - XMLHttpRequest - - - - - - - "[0-9]+" - - Assertion.response_data - false - 2 - - - - - - ${think_time_delay_offset} - ${think_time_deviation} - - - - - - - - - - - - - - ${base_path}checkout/onepage/success/ - GET - true - false - true - false - false - - - - - - Thank you for your purchase! - Your order number is - - Assertion.response_data - false - 2 - - - - - - - stoptest - - false - 1 - - 1 - 1 - 1395324075000 - 1395324075000 - false - - - - - - "${dashboard_enabled}" == "1" - false - - - - - - - false - ${__property(environment)} - = - true - environment + + + + + + + false + collect_shipping_rates + 1 + = + true + + + false + customer_id + ${customer_id} + = + true + + + false + store_id + 1 + = + true + + + false + currency_id + false + = + true + + + false + form_key + ${admin_form_key} + = + true + + + true + payment[method] + checkmo + = + true + + + false + json + true + = + true + + - - false - ${start_time} - = - true - startTime + + + + + + + ${base_path}${admin_path}/sales/order_create/loadBlock/block/shipping_method,totals?isAjax=true + POST + true + false + true + false + false + + + + + + shipping_method + Flat Rate + + Assertion.response_data + false + 2 + + + + + + + + false + form_key + ${admin_form_key} + = + true + + + false + limit + 20 + = + true + + + false + entity_id + + = + true + + + false + name + + = + true + + + false + email + + = + true + + + false + Telephone + + = + true + + + false + billing_postcode + + = + true + + + false + billing_country_id + + = + true + + + false + billing_regione + + = + true + + + false + store_name + + = + true + + + false + page + 1 + = + true + + + false + order[currency] + USD + = + true + + + false + sku + + = + true + + + false + qty + + = + true + + + false + limit + 20 + = + true + + + false + entity_id + + = + true + + + false + name + + = + true + + + false + sku + + = + true + + + false + price[from] + + = + true + + + false + price[to] + + = + true + + + false + in_products + + = + true + + + false + page + 1 + = + true + + + false + coupon_code + + = + true + + + false + order[account][group_id] + 1 + = + true + + + false + order[account][email] + user_${customer_id}@example.com + = + true + + + false + order[billing_address][customer_address_id] + ${customer_id} + = + true + + + false + order[billing_address][prefix] + + = + true + + + false + order[billing_address][firstname] + Anthony + = + true + + + false + order[billing_address][middlename] + + = + true + + + false + order[billing_address][lastname] + Nealy + = + true + + + false + order[billing_address][suffix] + + = + true + + + false + order[billing_address][company] + + = + true + + + false + order[billing_address][street][0] + 123 Freedom Blvd. #123 + = + true + + + false + order[billing_address][street][1] + + = + true + + + false + order[billing_address][city] + Fayetteville + = + true + + + false + order[billing_address][country_id] + US + = + true + + + false + order[billing_address][region] + + = + true + + + false + order[billing_address][region_id] + 5 + = + true + + + false + order[billing_address][postcode] + 123123 + = + true + + + false + order[billing_address][telephone] + 022-333-4455 + = + true + + + false + order[billing_address][fax] + + = + true + + + false + order[billing_address][vat_id] + + = + true + + + false + shipping_same_as_billing + on + = + true + + + false + payment[method] + checkmo + = + true + + + false + order[shipping_method] + flatrate_flatrate + = + true + + + false + giftwrapping[quote][863][design] + + = + true + + + false + order[comment][customer_note] + + = + true + + + false + order[comment][customer_note_notify] + 1 + = + true + + + false + order[send_confirmation] + 1 + = + true + + - - false - ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} - = - true - endTime + + + + + + + ${base_path}${admin_path}/sales/order_create/save/ + POST + true + false + true + true + false + + Detected the start of a redirect chain + + + + false + order_id + ${host}${base_path}${admin_path}/sales/order/index/order_id/(\d+)/ + $1$ + + 1 + + + + false + order_item_1 + order_item_(\d+)_title + $1$ + + 1 + + + + false + order_item_2 + order_item_(\d+)_title + $1$ + + 2 + + + + false + order_item_3 + order_item_(\d+)_title + $1$ + + 3 + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + order_id + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + order_item_1 + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + order_item_2 + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + order_item_3 + + + + + You created the order. + + Assertion.response_data + false + 2 + + + + + + + + true + form_key + ${admin_form_key} + = + true + + + true + invoice[items][${order_item_1}] + 1 + = + true + + + true + invoice[items][${order_item_2}] + 1 + = + true + + + true + invoice[items][${order_item_3}] + 1 + = + true + + + true + invoice[comment_text] + + = + true + + - - false - ${redis_host} - = - true - stats_server + + + + + + + ${base_path}${admin_path}/sales/order_invoice/save/order_id/${order_id}/ + POST + true + false + true + false + false + + Detected the start of a redirect chain + + + + + The invoice has been created. + + Assertion.response_data + false + 2 + + + + + + + + true + form_key + ${admin_form_key} + = + true + + + true + shipment[items][${order_item_1}] + 1 + = + true + + + true + shipment[items][${order_item_2}] + 1 + = + true + + + true + shipment[items][${order_item_3}] + 1 + = + true + + + true + shipment[comment_text] + + = + true + + + + + + + + + + ${base_path}${admin_path}/admin/order_shipment/save/order_id/${order_id}/ + POST + true + false + true + false + false + + Detected the start of a redirect chain + + + + + The shipment has been created. + + Assertion.response_data + false + 2 + + + + + + + + continue + + false + ${loops} + + ${__javaScript(Math.round(${numberOfThreads}*${csrPoolPercentage}*${csrCreateProcessReturnsPercentage}/10000))} + 1 + 1494595324000 + 1494595324000 + false + + + + + + + + + + + + + + + + + ${base_path}${admin_path} + GET + true + false + true + false + false + + + + + + Welcome + <title>Magento Admin</title> + + Assertion.response_data + false + 2 + + + + false + admin_form_key + <input name="form_key" type="hidden" value="([^'"]+)" /> + $1$ + + 1 + + + + + ^.+$ + + Assertion.response_data + false + 1 + variable + admin_form_key + + + + + + + + false + ${admin_form_key} + = + true + form_key + + + true + ${admin_password} + = + true + login[password] + + + true + ${admin_user} + = + true + login[username] + + + + + + + + + + ${base_path}${admin_path}/admin/dashboard/ + POST + true + false + true + false + Java + false + + Implementation needs to be set to Java as per http://stackoverflow.com/questions/19636282/jmeter-error-in-redirect-url-for-get + + + + + + + true + sales_order_grid + = + true + namespace + + + true + + = + true + search + + + true + true + = + true + filters[placeholder] + + + true + 200 + = + true + paging[pageSize] + + + true + 1 + = + true + paging[current] + + + true + increment_id + = + true + sorting[field] + + + true + desc + = + true + sorting[direction] + + + true + true + = + true + isAjax + + + true + ${admin_form_key} + = + true + form_key + false + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 2 + + + + false + orders_number + \"totalRecords\":(\d+)\, + $1$ + + 1 + simple_products + + + + + + + + true + ${admin_form_key} + = + true + form_key + + + true + sales_order_grid + = + true + namespace + true + + + true + + = + true + search + true + + + true + true + = + true + filters[placeholder] + true + + + true + 200 + = + true + paging[pageSize] + true + + + true + 1 + = + true + paging[current] + true + + + true + increment_id + = + true + sorting[field] + true + + + true + desc + = + true + sorting[direction] + true + + + true + true + = + true + isAjax + true + + + true + pending + = + true + filters[status] + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + POST + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 2 + + + + false + order_numbers + \"increment_id\":\"(\d+)\"\, + $1$ + + -1 + simple_products + + + + false + order_ids + \"entity_id\":\"(\d+)\"\, + $1$ + + -1 + simple_products + + + + + + ${test_duration} + + + + Passing arguments between threads + import java.util.ArrayList; +import java.util.HashMap; +import org.apache.jmeter.protocol.http.util.Base64Encoder; + +int ordersCount = Integer.parseInt(vars.get("order_numbers_matchNr")); +int threadsCount = Integer.parseInt(vars.get("numberOfThreads")); +int csrPoolPercentage = Integer.parseInt(vars.get("csrPoolPercentage")); +int csrCreateProcessReturnsPercentage = Integer.parseInt(vars.get("csrCreateProcessReturnsPercentage")); +int threadsNumber = Math.round(threadsCount*csrPoolPercentage*csrCreateProcessReturnsPercentage/10000.); + +if (threadsNumber == 0) { + threadsNumber = 1; +} +//Current thread number starts from 0 +int currentThreadNum = ctx.getThreadNum(); +//log.error(String.valueOf(currentThreadNum)); +String siterator = vars.get("threadIterator_" + currentThreadNum.toString()); +int iterator; +if(siterator == null){ + iterator = 1; + vars.put("threadIterator_" + currentThreadNum.toString() , "1"); +} else { + iterator = Integer.parseInt(siterator); + iterator ++; + vars.put("threadIterator_" + currentThreadNum.toString() , iterator.toString()); +} + +//Number of orders for one thread +int clusterLength = ordersCount / threadsNumber; +//Index of the current product from the cluster +int i = clusterLength * currentThreadNum + iterator; +if (iterator >= clusterLength) { + vars.put("threadIterator_" + currentThreadNum.toString(), "1"); + iterator = 1; +} +orderNumber = vars.get("order_numbers_" + i.toString()); +orderId = vars.get("order_ids_" + i.toString()); +vars.put("order_number", orderNumber); +vars.put("order_id", orderId); +//Search info +vars.put("search_data", orderNumber); + +//Debug info +vars.put("threadNum" , currentThreadNum.toString()); +vars.put("clusterLength", clusterLength.toString()); +vars.put("i", i.toString()); + + + + + false + + + + + + + + + + + + + ${base_path}${admin_path}/sales/order/ + GET + true + false + true + false + false + + + + + + Create New Order + + Assertion.response_data + false + 2 + + + + + + + + true + sales_order_grid + = + true + namespace + + + true + + = + true + search + + + true + true + = + true + filters[placeholder] + + + true + 200 + = + true + paging[pageSize] + + + true + 1 + = + true + paging[current] + + + true + increment_id + = + true + sorting[field] + + + true + desc + = + true + sorting[direction] + + + true + true + = + true + isAjax + + + true + ${admin_form_key} + = + true + form_key + false + + + true + pending + = + true + filters[status] + true + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + totalRecords + + Assertion.response_data + false + 2 + + + + false + orders_number + \"totalRecords\":(\d+)\, + $1$ + + 1 + simple_products + + + + + + + + true + sales_order_grid + = + true + namespace + + + true + + = + true + search + + + true + true + = + true + filters[placeholder] + + + true + 20 + = + true + paging[pageSize] + + + true + 1 + = + true + paging[current] + + + true + increment_id + = + true + sorting[field] + + + true + desc + = + true + sorting[direction] + + + true + true + = + true + isAjax + + + true + ${admin_form_key} + = + true + form_key + false + + + true + pending + = + true + filters[status] + true + + + true + ${search_data} + = + true + filters[increment_id] + + + true + en_US + = + true + created_at[locale] + + + + + + + + + + ${base_path}${admin_path}/mui/index/render/ + GET + true + false + true + false + false + + + + + + "totalRecords":1 + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/sales/order/view/order_id/${order_id}/ + GET + true + false + true + false + false + + + + + + #${order_number} + Invoice + Ship + Hold + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/sales/order_invoice/start/order_id/${order_id}/ + GET + true + false + true + false + false + + + + + + Invoice Totals + + Assertion.response_data + false + 2 + + + + false + item_ids + <div id="order_item_(\d+)_title"\s*class="product-title"> + $1$ + + -1 + simple_products + + + + + + + + false + ${admin_form_key} + = + true + form_key + false + + + false + 1 + = + true + invoice[items][${item_ids_1}] + + + false + 1 + = + true + invoice[items][${item_ids_2}] + + + false + Invoiced + = + true + invoice[comment_text] + + + + + + + + + + ${base_path}${admin_path}/sales/order_invoice/save/order_id/${order_id}/ + POST + true + false + true + false + false + + + + + + The invoice has been created + + Assertion.response_data + false + 2 + + + + + + + + + + + + + + ${base_path}${admin_path}/sales/order_creditmemo/start/order_id/${order_id}/ + GET + true + false + true + false + false + + + + + + New Memo + + Assertion.response_data + false + 2 + + + + + 1 + + + + + + + false + ${admin_form_key} + = + true + form_key + false + + + false + 1 + = + true + creditmemo[items][${item_ids_1}][qty] + + + false + 1 + = + true + creditmemo[items][${item_ids_2}][qty] + + + false + 1 + = + true + creditmemo[do_offline] + + + false + Credit Memo added + = + true + creditmemo[comment_text] + + + false + 10 + = + true + creditmemo[shipping_amount] + + + false + 0 + = + true + creditmemo[adjustment_positive] + + + false + 0 + = + true + creditmemo[adjustment_negative] + + + + + + + + + + ${base_path}${admin_path}/sales/order_creditmemo/save/order_id/${order_id}/ + POST + true + false + true + false + false + + + + + + You created the credit memo + + Assertion.response_data + false + 2 + + + + + + + + false + ${admin_form_key} + = + true + form_key + false + + + false + 1 + = + true + creditmemo[items][${item_ids_1}][qty] + + + false + 1 + = + true + creditmemo[do_offline] + + + false + Credit Memo added + = + true + creditmemo[comment_text] + + + false + 10 + = + true + creditmemo[shipping_amount] + + + false + 0 + = + true + creditmemo[adjustment_positive] + + + false + 0 + = + true + creditmemo[adjustment_negative] + + + + + + + + + ${base_path}${admin_path}/sales/order_creditmemo/save/order_id/${order_id}/ + POST + true + false + true + false + false + + + + + + You created the credit memo + + Assertion.response_data + false + 2 + + + + + + 1 + 0 + ${__javaScript(Math.round(${csrCreateProcessReturnsDelay}*1000))} + + + + + + stoptest + + false + 1 + + 1 + 1 + 1395324075000 + 1395324075000 + false + + + + + + "${dashboard_enabled}" == "1" + false + + + + + + + false + ${__property(environment)} + = + true + environment + + + false + ${start_time} + = + true + startTime + + + false + ${__time(yyyy-MM-dd'T'HH:mm:ss.SSSZ)} + = + true + endTime + + + false + ${redis_host} + = + true + stats_server + + + + + + + + + + ${base_path}DeploymentEvent.php + POST + true + false + true + false + false + + + + + + Errors: - - - - - - - - ${base_path}DeploymentEvent.php - POST - true - false - true - false - false - - - - - - Errors: + Assertion.response_data + false + 6 + + + + + + + 30 + ${host} + / + false + 0 + true + true + - Assertion.response_data - false - 6 - + true + + + + props.remove("category_url_key"); +props.remove("category_name"); +props.remove("simple_products_list"); +props.remove("configurable_products_list"); +props.remove("users"); +props.remove("customer_emails_list"); + + + false + - - - - 30 - ${host} - / - false - 0 - true - true - - - true - - - - props.remove("category_url_key"); -props.remove("category_name"); -props.remove("simple_products_list"); -props.remove("configurable_products_list"); -props.remove("users"); -props.remove("customer_emails_list"); - - - false - - - - - false - - saveConfig - - - true - true - true - - true - true - true - true - false - true - true - false - false - false - false - false - false - false - false - 0 - true - true - - - - - - - true - true - true - - true - true - true - true - false - true - true - false - false - true - false - false - true - false - false - 0 - true - true - true - true - - - - - - - - false - - saveConfig - - - false - false - false - - false - false - false - false - false - false - false - false - false - false - true - false - false - false - false - 0 - true - true - true - true - - - ${report_save_path}/detailed-urls-report.log - - - - - false - - saveConfig - - - true - true - true - - true - true - true - true - false - true - true - false - false - false - false - false - false - false - false - 0 - true - true - true - true - - - ${report_save_path}/summary-report.log - - - - - true - diff --git a/setup/performance-toolkit/files/downloadable_original.txt b/setup/performance-toolkit/files/downloadable_original.txt new file mode 100644 index 0000000000000..9fbb20e6aa426 --- /dev/null +++ b/setup/performance-toolkit/files/downloadable_original.txt @@ -0,0 +1 @@ +original text \ No newline at end of file diff --git a/setup/performance-toolkit/files/downloadable_sample.txt b/setup/performance-toolkit/files/downloadable_sample.txt new file mode 100644 index 0000000000000..679aa535f6a97 --- /dev/null +++ b/setup/performance-toolkit/files/downloadable_sample.txt @@ -0,0 +1 @@ +sample text \ No newline at end of file diff --git a/setup/performance-toolkit/files/search_terms.csv b/setup/performance-toolkit/files/search_terms.csv new file mode 100644 index 0000000000000..fa0f847d22068 --- /dev/null +++ b/setup/performance-toolkit/files/search_terms.csv @@ -0,0 +1,10 @@ +"searchTerm","priceTo" +"the of and a in to it is to was","1000" +"I for that you he be with on by at","1000" +"have are not this but had they his from she","1000" +"that which or we an were as do been their","1000" +"has would there what will all if can her said","1000" +"who one so up as them some when could him","1000" +"into its then two out time my about did your","1000" +"now me no other only just more these also people","1000" +"know any first see very new may well should like","1000" diff --git a/setup/performance-toolkit/files/search_terms_filter.csv b/setup/performance-toolkit/files/search_terms_filter.csv new file mode 100644 index 0000000000000..0924e8caad56c --- /dev/null +++ b/setup/performance-toolkit/files/search_terms_filter.csv @@ -0,0 +1,10 @@ +"searchTerm","mycolor","mysize" +the of and a in to it is to was,my red,my small +I for that you he be with on by at,my red,my medium +have are not this but had they his from she,my red,my large +that which or we an were as do been their,my green,my small +has would there what will all if can her said,my green,my medium +who one so up as them some when could him,my green,my large +into its then two out time my about did your,my yellow,my small +now me no other only just more these also people,my yellow,my medium +know any first see very new may well should like,my yellow,my large From e4c12a467c194a48652445198c8e962e93ed2745 Mon Sep 17 00:00:00 2001 From: Robert He Date: Tue, 29 Aug 2017 13:13:00 -0500 Subject: [PATCH 032/151] MAGETWO-71666: Unable to save product after failed attempt - add better check for the configurable-matrix-serialized variable --- .../Helper/Plugin/Configurable.php | 4 +- .../Helper/Plugin/UpdateConfigurations.php | 4 +- .../ReSavingProductAfterInitialSaveTest.php | 60 +++++++++---------- 3 files changed, 33 insertions(+), 35 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php index d4d68b570a21f..cfadde3c4a18f 100644 --- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php @@ -153,8 +153,8 @@ private function setLinkedProducts(ProductInterface $product, ProductExtensionIn protected function getVariationMatrix() { $result = []; - $configurableMatrix = $this->request->getParam('configurable-matrix-serialized', '[]'); - if (isset($configurableMatrix) && $configurableMatrix != "") { + $configurableMatrix = $this->request->getParam('configurable-matrix-serialized', "[]"); + if (isset($configurableMatrix) && $configurableMatrix != "[]") { $configurableMatrix = json_decode($configurableMatrix, true); foreach ($configurableMatrix as $item) { diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php index 44b36859837de..a22e28aa2e6ae 100644 --- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php +++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php @@ -93,8 +93,8 @@ public function afterInitialize( protected function getConfigurations() { $result = []; - $configurableMatrix = $this->request->getParam('configurable-matrix-serialized', '[]'); - if (isset($configurableMatrix) && $configurableMatrix != "") { + $configurableMatrix = $this->request->getParam('configurable-matrix-serialized', "[]"); + if (isset($configurableMatrix) && $configurableMatrix != "[]") { $configurableMatrix = json_decode($configurableMatrix, true); foreach ($configurableMatrix as $item) { diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php index fa49f61867cd0..0ff4f056be290 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php @@ -6,7 +6,6 @@ namespace Magento\Catalog\Test\TestCase\Product; - use Magento\Catalog\Test\Constraint\AssertDateInvalidErrorMessage as AssertDateErrorMessage; use Magento\Catalog\Test\Page\Adminhtml\CatalogProductEdit; use Magento\Catalog\Test\Fixture\CatalogProductSimple; @@ -24,8 +23,7 @@ * 4. Modify the dates to valid values * 5. Save the product again * 6. Product is saved successfully - */ - + */ class ReSavingProductAfterInitialSaveTest extends Injectable { /** @@ -66,22 +64,20 @@ class ReSavingProductAfterInitialSaveTest extends Injectable * @param CatalogProductEdit $catalogProductEdit * @param FixtureFactory $fixtureFactory */ - public function __inject - ( - CatalogProductEdit $catalogProductEdit, - CatalogProductIndex $productGrid, - CatalogProductNew $newProductPage, - FixtureFactory $fixtureFactory, - AssertDateErrorMessage $assertDateErrorMessage - ) - { - $this->productGrid = $productGrid; - $this->newProductPage = $newProductPage; - $this->catalogProductEdit = $catalogProductEdit; - $this->fixtureFactory = $fixtureFactory; - $this->assertDateErrorMessage = $assertDateErrorMessage; + public function __inject( + CatalogProductEdit $catalogProductEdit, + CatalogProductIndex $productGrid, + CatalogProductNew $newProductPage, + FixtureFactory $fixtureFactory, + AssertDateErrorMessage $assertDateErrorMessage + ) { + $this->productGrid = $productGrid; + $this->newProductPage = $newProductPage; + $this->catalogProductEdit = $catalogProductEdit; + $this->fixtureFactory = $fixtureFactory; + $this->assertDateErrorMessage = $assertDateErrorMessage; - } + } /** * Verify the product can be saved successfully after its initial save is failed. @@ -89,16 +85,18 @@ public function __inject * @param CatalogProductSimple $productWithValidFromDate * @param CatalogProductSimple $productWithValidToDate */ - - public function test(CatalogProductSimple $originalProduct, CatalogProductSimple $productWithValidFromDate, CatalogProductSimple $productWithValidToDate ) - { - $this->productGrid->open(); - $this->productGrid->getGridPageActionBlock()->addProduct('simple'); - $this->newProductPage->getProductForm()->fill($originalProduct); - $this->catalogProductEdit->getProductForm()->fill($productWithValidFromDate); - $this->catalogProductEdit->getFormPageActions()->save(); - $this->assertDateErrorMessage->processAssert($this->catalogProductEdit); - $this->catalogProductEdit->getProductForm()->fill($productWithValidToDate); - $this->catalogProductEdit->getFormPageActions()->save(); - } -} \ No newline at end of file + public function test( + CatalogProductSimple $originalProduct, + CatalogProductSimple $productWithValidFromDate, + CatalogProductSimple $productWithValidToDate + ) { + $this->productGrid->open(); + $this->productGrid->getGridPageActionBlock()->addProduct('simple'); + $this->newProductPage->getProductForm()->fill($originalProduct); + $this->catalogProductEdit->getProductForm()->fill($productWithValidFromDate); + $this->catalogProductEdit->getFormPageActions()->save(); + $this->assertDateErrorMessage->processAssert($this->catalogProductEdit); + $this->catalogProductEdit->getProductForm()->fill($productWithValidToDate); + $this->catalogProductEdit->getFormPageActions()->save(); + } +} From 2c332e8a5f3dce1a4a0e3d07d456644c71c7c93d Mon Sep 17 00:00:00 2001 From: Robert He Date: Tue, 29 Aug 2017 13:27:06 -0500 Subject: [PATCH 033/151] MAGETWO-71666: Unable to save product after failed attempt - add better check for the configurable-matrix-serialized variable --- .../Initialization/Helper/Plugin/ConfigurableTest.php | 6 +++--- .../Helper/Plugin/UpdateConfigurationsTest.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/ConfigurableTest.php index 2b278c6f411a4..90306de598895 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/ConfigurableTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/ConfigurableTest.php @@ -150,7 +150,7 @@ public function testAfterInitializeWithAttributesAndVariations() ] ]; $paramValueMap = [ - ['configurable-matrix-serialized', '[]', json_encode($simpleProducts)], + ['configurable-matrix-serialized', "[]", json_encode($simpleProducts)], ['attributes', null, $attributes], ]; @@ -212,11 +212,11 @@ public function testAfterInitializeWithAttributesAndWithoutVariations() ]; $valueMap = [ ['new-variations-attribute-set-id', null, 24], - ['associated_product_ids_serialized', '[]', []], + ['associated_product_ids_serialized', "[]", "[]"], ['product', [], ['configurable_attributes_data' => $attributes]], ]; $paramValueMap = [ - ['configurable-matrix-serialized', '[]', []], + ['configurable-matrix-serialized', "[]", "[]"], ['attributes', null, $attributes], ]; diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php index a2976e918065e..2df6fbecb73cd 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php @@ -153,7 +153,7 @@ public function testAfterInitialize() ->willReturnMap( [ ['store', 0, 0], - ['configurable-matrix-serialized', '[]', json_encode($configurableMatrix)] + ['configurable-matrix-serialized', "[]", json_encode($configurableMatrix)] ] ); $this->variationHandlerMock->expects(static::once()) From 333bcbf3ffb7431380200ada9341a8f72d084f18 Mon Sep 17 00:00:00 2001 From: Robert He Date: Tue, 29 Aug 2017 13:28:05 -0500 Subject: [PATCH 034/151] MAGETWO-71666: Unable to save product after failed attempt - add better check for the configurable-matrix-serialized variable --- .../TestCase/Product/ReSavingProductAfterInitialSaveTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php index 0ff4f056be290..87c91288fe7df 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php @@ -76,7 +76,6 @@ public function __inject( $this->catalogProductEdit = $catalogProductEdit; $this->fixtureFactory = $fixtureFactory; $this->assertDateErrorMessage = $assertDateErrorMessage; - } /** From 1896790621db26d59c92c5cd1a313bedbcfe4ab2 Mon Sep 17 00:00:00 2001 From: Krissy Hiserote Date: Tue, 29 Aug 2017 14:23:40 -0500 Subject: [PATCH 035/151] MAGETWO-69470: Coupon with type 'Auto' can't be generated. - fix sales rule coupon layout and allow Auto to generate coupons --- .../Model/Service/CouponManagementService.php | 2 +- .../ui_component/sales_rule_form.xml | 34 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php b/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php index 79bb7cbe1ab0a..2d9d7dd491c1c 100644 --- a/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php +++ b/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php @@ -88,7 +88,7 @@ public function generate(\Magento\SalesRule\Api\Data\CouponGenerationSpecInterfa $couponSpec->getRuleId() ); } - if (!$rule->getUseAutoGeneration()) { + if (!$rule->getUseAutoGeneration() && $rule->getCouponType() != $rule::COUPON_TYPE_AUTO) { throw new \Magento\Framework\Exception\LocalizedException( __('Specified rule does not allow automatic coupon generation') ); diff --git a/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml b/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml index 02cab73f63896..921bcc50ebd21 100644 --- a/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml +++ b/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml @@ -47,23 +47,6 @@ - - - - - Manage Coupon Codes - true - false - 50 - false - fieldset - Magento_SalesRule/js/form/element/manage-coupon-codes - - - - - -
    @@ -548,4 +531,21 @@
    +
    + + + Magento_SalesRule/js/form/element/manage-coupon-codes + + + + true + + + + + + + + +
    From 6f1569956ce1ca4f9440ee8ec73b13721c2b090a Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Tue, 29 Aug 2017 15:01:13 -0500 Subject: [PATCH 036/151] MAGETWO-71765 Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Added unit testing for Payflowpro --- .../Paypal/Test/Unit/Model/PayflowproTest.php | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php index 5b6ead7d3e6f5..573a2ffb5e1d4 100644 --- a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php +++ b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php @@ -267,6 +267,98 @@ public function testCaptureWithBuildPlaceRequest() static::assertFalse((bool)$paymentMock->getIsTransactionPending()); } + /** + * @return array + */ + public function dataProviderCaptureAmountRounding() + { + return [ + [ + 'amount' => 14.13999999999999999999999999999999999999999999999999, + 'setAmount' => 49.99, + 'expectedResult' => 14.14 + ], + [ + 'amount' => 14.13199999999999999999999999999999999999999999999999, + 'setAmount' => 49.99, + 'expectedResult' => 14.13, + ], + [ + 'amount' => 14.14, + 'setAmount' => 49.99, + 'expectedResult' => 14.14, + ], + [ + 'amount' => 14.13999999999999999999999999999999999999999999999999, + 'setAmount' => 14.14, + 'expectedResult' => 0, + ] + ]; + } + + /** + * @param float $amount + * @param float $setAmount + * @param float $expectedResult + * @dataProvider dataProviderCaptureAmountRounding + */ + public function testCaptureAmountRounding($amount, $setAmount, $expectedResult) + { + $paymentMock = $this->getPaymentMock(); + $orderMock = $this->getMockBuilder(\Magento\Sales\Model\Order::class) + ->disableOriginalConstructor() + ->getMock(); + + $infoInstanceMock = $this->getMockForAbstractClass( + InfoInterface::class, + [], + '', + false, + false, + false, + ['getAmountAuthorized','hasAmountPaid'] + ); + + $infoInstanceMock->expects($this->once()) + ->method('getAmountAuthorized') + ->willReturn($setAmount); + $infoInstanceMock->expects($this->once()) + ->method('hasAmountPaid') + ->willReturn(true); + $this->payflowpro->setData('info_instance', $infoInstanceMock); + + // test case to build basic request + $paymentMock->expects($this->once()) + ->method('getAdditionalInformation') + ->with('pnref') + ->willReturn(false); + $paymentMock->expects($this->any()) + ->method('getParentTransactionId') + ->willReturn(true); + + $paymentMock->expects($this->once()) + ->method('getOrder') + ->willReturn($orderMock); + + $this->initStoreMock(); + $response = $this->getGatewayResponseObject(); + $this->gatewayMock->expects($this->once()) + ->method('postRequest') + ->with( + $this->callback(function($request) use ($expectedResult){ + return is_callable([$request, 'getAmt']) && + $request->getAmt() == $expectedResult; + }), + $this->isInstanceOf(PayflowConfig::class) + ) + ->willReturn($response); + + $this->payflowpro->capture($paymentMock, $amount); + + $this->assertEquals($response['pnref'], $paymentMock->getTransactionId()); + $this->assertFalse((bool)$paymentMock->getIsTransactionPending()); + } + /** * @covers \Magento\Paypal\Model\Payflowpro::authorize */ From 47b736cea771654951e0881feabf190bd5f9dc4a Mon Sep 17 00:00:00 2001 From: Krissy Hiserote Date: Tue, 29 Aug 2017 15:46:48 -0500 Subject: [PATCH 037/151] MAGETWO-69470: Coupon with type 'Auto' can't be generated. - remove argument and component item --- .../view/adminhtml/ui_component/sales_rule_form.xml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml b/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml index 921bcc50ebd21..9b579f47759a6 100644 --- a/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml +++ b/app/code/Magento/SalesRule/view/adminhtml/ui_component/sales_rule_form.xml @@ -531,12 +531,7 @@ -
    - - - Magento_SalesRule/js/form/element/manage-coupon-codes - - +
    true From 01840903ae2add59f089096e93cfa43206bb9b23 Mon Sep 17 00:00:00 2001 From: Andrei Malets Date: Wed, 30 Aug 2017 11:49:52 +0300 Subject: [PATCH 038/151] MAGETWO-72076: Update benchmark.jmx and README files in Performance Toolkit, add performance analytics script - Coding style fixes --- .../aggregate-report/b2c_mappings.php | 16 +++++++++++----- .../aggregate-report/generate.php | 9 +++++++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/setup/performance-toolkit/aggregate-report/b2c_mappings.php b/setup/performance-toolkit/aggregate-report/b2c_mappings.php index 3bc1620ffec7a..5de2acb15b97d 100644 --- a/setup/performance-toolkit/aggregate-report/b2c_mappings.php +++ b/setup/performance-toolkit/aggregate-report/b2c_mappings.php @@ -1,5 +1,8 @@ 'Open Home Page', @@ -580,7 +583,8 @@ ], [ 'label' => 'Admin - Save New Configurable Product', - 'uri' => '\/admin\/catalog\/product\/save\/set\/4\/type\/configurable\/back\/edit\/active_tab\/product-details\/', + 'uri' => '\/admin\/catalog\/product\/save\/set\/4\/type\/configurable' + . '\/back\/edit\/active_tab\/product-details\/', 'title' => 'Admin Create Product - New Configurable Product Save', 'scenario' => 'Admin - Create Product', ], @@ -610,7 +614,8 @@ ], [ 'label' => 'Admin - Save New Downloadable Product', - 'uri' => '\/admin\/catalog\/product\/save\/set\/4\/type\/downloadable\/back\/edit\/active_tab\/product-details\/', + 'uri' => '\/admin\/catalog\/product\/save\/set\/4\/type\/downloadable' + . '\/back\/edit\/active_tab\/product-details\/', 'title' => 'Admin Create Product - New Downloadable Product Save', 'scenario' => 'Admin - Create Product', ], @@ -700,7 +705,8 @@ ], [ 'label' => 'Admin - Create New Condition For Promotion Rule', - 'uri' => '\/admin\/sales_rule\/promo_quote\/newConditionHtml\/form\/sales_rule_formrule_conditions_fieldset_\/form_namespace\/sales_rule_form', + 'uri' => '\/admin\/sales_rule\/promo_quote\/newConditionHtml\/form\/sales_rule_formrule_conditions_fieldset_' + . '\/form_namespace\/sales_rule_form', 'title' => 'Admin Promotions Management - Create New Conditional', 'scenario' => 'Admin - Promotion Rules', ], @@ -776,4 +782,4 @@ 'title' => 'Admin Edit Order - Search Orders$', 'scenario' => 'Admin - Create/Process Returns', ], -]; \ No newline at end of file +]; diff --git a/setup/performance-toolkit/aggregate-report/generate.php b/setup/performance-toolkit/aggregate-report/generate.php index f4e973e585772..cf4ca6f06a862 100644 --- a/setup/performance-toolkit/aggregate-report/generate.php +++ b/setup/performance-toolkit/aggregate-report/generate.php @@ -4,6 +4,11 @@ * See COPYING.txt for license details. */ +/** +* @SuppressWarnings(PHPMD.CyclomaticComplexity) +* @SuppressWarnings(PHPMD.NPathComplexity) +*/ + $usageMessage = 'Usage:' . PHP_EOL . ' php generate.php -j jmeter_report.jtl -m memory_usage.log -o output_file.csv' . PHP_EOL @@ -286,9 +291,9 @@ function calculate_percentile(array $arr, $percentile) $allindex = ($count - 1) * $percentile; $intvalindex = intval($allindex); $floatval = $allindex - $intvalindex; - if (!is_float($floatval)){ + if (!is_float($floatval)) { $result = $arr[$intvalindex]; - }else { + } else { if ($count > $intvalindex + 1) { $result = $floatval * ($arr[$intvalindex + 1] - $arr[$intvalindex]) + $arr[$intvalindex]; } else { From 0b392252d2300908e4eeb40407d85ff9d1be79b9 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Wed, 30 Aug 2017 12:19:15 +0300 Subject: [PATCH 039/151] MAGETWO-71613: [AP: New Order] Tier-prices are not applied on add complex product by SKU --- app/code/Magento/Quote/Model/Quote.php | 3 +++ app/code/Magento/Quote/Model/Quote/Item/Processor.php | 3 --- .../Magento/Sales/Controller/Adminhtml/Order/Create.php | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index 0cc6ece969f74..22640015856cd 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -1620,6 +1620,9 @@ public function addProduct( $item = $this->getItemByProduct($candidate); if (!$item) { $item = $this->itemProcessor->init($candidate, $request); + $item->setQuote($this); + $item->setOptions($candidate->getCustomOptions()); + $item->setProduct($candidate); // Add only item that is not in quote already $this->addItem($item); } diff --git a/app/code/Magento/Quote/Model/Quote/Item/Processor.php b/app/code/Magento/Quote/Model/Quote/Item/Processor.php index 74b25ea7f4976..f34591cfad143 100644 --- a/app/code/Magento/Quote/Model/Quote/Item/Processor.php +++ b/app/code/Magento/Quote/Model/Quote/Item/Processor.php @@ -71,9 +71,6 @@ public function init(Product $product, $request) return $item; } - $item->setOptions($product->getCustomOptions()); - $item->setProduct($product); - if ($request->getResetCount() && !$product->getStickWithinParent() && $item->getId() === $request->getId()) { $item->setData(CartItemInterface::KEY_QTY, 0); } diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php index 9cbcc28442bdd..21ccf52078b01 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php @@ -151,15 +151,15 @@ protected function _processActionData($action = null) 'session' => $this->_getSession(), ]; - $this->_eventManager->dispatch('adminhtml_sales_order_create_process_data_before', $eventData); - /** - * Saving order data + * Import post data, in order to make order quote valid */ if ($data = $this->getRequest()->getPost('order')) { $this->_getOrderCreateModel()->importPostData($data); } + $this->_eventManager->dispatch('adminhtml_sales_order_create_process_data_before', $eventData); + /** * Initialize catalog rule data */ From b2368938ba7dd8b31d7640988298fe5189d6df47 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Wed, 30 Aug 2017 12:31:51 +0300 Subject: [PATCH 040/151] MAGETWO-71613: [AP: New Order] Tier-prices are not applied on add complex product by SKU --- .../Quote/Test/Unit/Model/QuoteTest.php | 73 ++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php index 68194d384e935..359d5f95d7356 100644 --- a/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php +++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteTest.php @@ -142,6 +142,11 @@ class QuoteTest extends \PHPUnit\Framework\TestCase */ private $customerDataFactoryMock; + /** + * @var \PHPUnit_Framework_MockObject_MockObject + */ + private $itemProcessor; + /** * @SuppressWarnings(PHPMD.ExcessiveMethodLength) */ @@ -223,7 +228,9 @@ protected function setUp() $this->filterBuilderMock = $this->getMockBuilder(\Magento\Framework\Api\FilterBuilder::class) ->disableOriginalConstructor() ->getMock(); - + $this->itemProcessor = $this->getMockBuilder(\Magento\Quote\Model\Quote\Item\Processor::class) + ->disableOriginalConstructor() + ->getMock(); $this->extensionAttributesJoinProcessorMock = $this->createMock(\Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface::class); $this->customerDataFactoryMock = $this->createPartialMock(\Magento\Customer\Api\Data\CustomerInterfaceFactory::class, ['create']); $this->quote = (new ObjectManager($this)) @@ -249,6 +256,7 @@ protected function setUp() 'objectCopyService' => $this->objectCopyServiceMock, 'extensionAttributesJoinProcessor' => $this->extensionAttributesJoinProcessorMock, 'customerDataFactory' => $this->customerDataFactoryMock, + 'itemProcessor' => $this->itemProcessor, 'data' => [ 'reserved_order_id' => 1000001 ] @@ -853,6 +861,69 @@ public function testAddProductItemPreparation() $this->assertEquals($expectedResult, $result); } + public function testAddProductItemNew() + { + $itemMock = $this->createMock(\Magento\Quote\Model\Quote\Item::class); + + $expectedResult = $itemMock; + $requestMock = $this->createMock( + \Magento\Framework\DataObject::class + ); + $this->objectFactoryMock->expects($this->once()) + ->method('create') + ->with($this->equalTo(['qty' => 1])) + ->will($this->returnValue($requestMock)); + + $typeInstanceMock = $this->createPartialMock(\Magento\Catalog\Model\Product\Type\Simple::class, [ + 'prepareForCartAdvanced' + ]); + + $productMock = $this->createPartialMock(\Magento\Catalog\Model\Product::class, [ + 'getParentProductId', + 'setStickWithinParent', + '__wakeup' + ]); + + $collectionMock = $this->createMock(\Magento\Quote\Model\ResourceModel\Quote\Item\Collection::class); + + $itemMock->expects($this->any()) + ->method('representProduct') + ->will($this->returnValue(false)); + + $iterator = new \ArrayIterator([$itemMock]); + $collectionMock->expects($this->any()) + ->method('getIterator') + ->will($this->returnValue($iterator)); + + $this->quoteItemCollectionFactoryMock->expects($this->once()) + ->method('create') + ->will($this->returnValue($collectionMock)); + + $this->productMock->expects($this->once()) + ->method('isSalable') + ->willReturn(true); + $this->itemProcessor + ->expects($this->once()) + ->method('init') + ->willReturn($itemMock); + $itemMock->expects($this->once()) + ->method('setProduct'); + $itemMock->expects($this->once()) + ->method('setOptions'); + $itemMock->expects($this->any()) + ->method('setQuote') + ->with($this->quote); + $typeInstanceMock->expects($this->once()) + ->method('prepareForCartAdvanced') + ->will($this->returnValue([$productMock])); + $this->productMock->expects($this->once()) + ->method('getTypeInstance') + ->will($this->returnValue($typeInstanceMock)); + + $result = $this->quote->addProduct($this->productMock, null); + $this->assertEquals($expectedResult, $result); + } + public function testValidateMiniumumAmount() { $storeId = 1; From d636119db267cc94a46cfce2b1182f577789ef01 Mon Sep 17 00:00:00 2001 From: RomanKis Date: Tue, 15 Aug 2017 17:47:31 +0300 Subject: [PATCH 041/151] MAGETWO-70634: Issues in customizable options section of add/edit product pages --- .../Config/Source/Product/Options/Price.php | 38 +++++++++++ .../Option/Validator/DefaultValidatorTest.php | 3 +- .../Product/Option/Validator/FileTest.php | 3 +- .../Product/Option/Validator/SelectTest.php | 3 +- .../Product/Option/Validator/TextTest.php | 3 +- .../Product/Form/Modifier/CustomOptions.php | 26 +++++++- .../js/components/custom-options-component.js | 35 +++++++++++ .../components/custom-options-price-type.js | 62 ++++++++++++++++++ .../adminhtml/web/template/form/field.html | 43 +++++++++++++ .../Helper/Plugin/UpdateConfigurations.php | 2 +- .../Plugin/UpdateConfigurationsTest.php | 28 ++++++++- .../Product/Form/Modifier/CustomOptions.php | 4 +- .../components/custom-options-price-type.js | 6 +- .../Product/Edit/Section/Options.php | 40 +++++++++++- .../Edit/Section/Options/AbstractOptions.php | 21 +++++++ .../Edit/Section/Options/Type/Area.xml | 3 + .../Edit/Section/Options/Type/Checkbox.xml | 3 + .../Edit/Section/Options/Type/Date.xml | 3 + .../Edit/Section/Options/Type/DateTime.xml | 3 + .../Edit/Section/Options/Type/DropDown.xml | 3 + .../Edit/Section/Options/Type/Field.xml | 3 + .../Edit/Section/Options/Type/File.xml | 3 + .../Section/Options/Type/MultipleSelect.xml | 3 + .../Section/Options/Type/RadioButtons.xml | 3 + .../Edit/Section/Options/Type/Time.xml | 3 + .../Constraint/AssertAddBeforeForPrice.php | 63 +++++++++++++++++++ .../CreateSimpleProductEntityPartTwoTest.xml | 26 ++++++++ 27 files changed, 423 insertions(+), 13 deletions(-) create mode 100644 app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-component.js create mode 100644 app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js create mode 100644 app/code/Magento/Catalog/view/adminhtml/web/template/form/field.html create mode 100644 dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddBeforeForPrice.php diff --git a/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Price.php b/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Price.php index 2385bcfd035d4..bd00ba0a73fbc 100644 --- a/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Price.php +++ b/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Price.php @@ -14,6 +14,21 @@ */ class Price implements ProductPriceOptionsInterface { + /** + * Store manager. + * + * @var \Magento\Store\Model\StoreManagerInterface + */ + private $storeManager; + + /** + * @param \Magento\Store\Model\StoreManagerInterface $storeManager + */ + public function __construct(\Magento\Store\Model\StoreManagerInterface $storeManager) + { + $this->storeManager = $storeManager; + } + /** * {@inheritdoc} * @@ -26,4 +41,27 @@ public function toOptionArray() ['value' => self::VALUE_PERCENT, 'label' => __('Percent')], ]; } + + /** + * Get option array of prefixes. + * + * @return array + */ + public function prefixesToOptionArray() + { + return [ + ['value' => self::VALUE_FIXED, 'label' => $this->getCurrencySymbol()], + ['value' => self::VALUE_PERCENT, 'label' => '%'], + ]; + } + + /** + * Get currency symbol. + * + * @return string + */ + private function getCurrencySymbol() + { + return $this->storeManager->getStore()->getBaseCurrency()->getCurrencySymbol(); + } } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/DefaultValidatorTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/DefaultValidatorTest.php index b79a5400e0a61..1eb5f1a2dacd2 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/DefaultValidatorTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/DefaultValidatorTest.php @@ -21,7 +21,8 @@ class DefaultValidatorTest extends \PHPUnit\Framework\TestCase protected function setUp() { $configMock = $this->createMock(\Magento\Catalog\Model\ProductOptions\ConfigInterface::class); - $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price(); + $storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); + $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price($storeManagerMock); $config = [ [ 'label' => 'group label 1', diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/FileTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/FileTest.php index 6003a8e412b42..3c06db0e7ce5f 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/FileTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/FileTest.php @@ -21,7 +21,8 @@ class FileTest extends \PHPUnit\Framework\TestCase protected function setUp() { $configMock = $this->createMock(\Magento\Catalog\Model\ProductOptions\ConfigInterface::class); - $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price(); + $storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); + $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price($storeManagerMock); $config = [ [ 'label' => 'group label 1', diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/SelectTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/SelectTest.php index 1b1ec5ed5b490..046ee703c850e 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/SelectTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/SelectTest.php @@ -21,7 +21,8 @@ class SelectTest extends \PHPUnit\Framework\TestCase protected function setUp() { $configMock = $this->createMock(\Magento\Catalog\Model\ProductOptions\ConfigInterface::class); - $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price(); + $storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); + $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price($storeManagerMock); $config = [ [ 'label' => 'group label 1', diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/TextTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/TextTest.php index 8a5818b02a031..cf31d67817684 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/TextTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Option/Validator/TextTest.php @@ -21,7 +21,8 @@ class TextTest extends \PHPUnit\Framework\TestCase protected function setUp() { $configMock = $this->createMock(\Magento\Catalog\Model\ProductOptions\ConfigInterface::class); - $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price(); + $storeManagerMock = $this->createMock(\Magento\Store\Model\StoreManagerInterface::class); + $priceConfigMock = new \Magento\Catalog\Model\Config\Source\Product\Options\Price($storeManagerMock); $config = [ [ 'label' => 'group label 1', diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php index 28e64d5d24c7a..b3e0f1174aad9 100755 --- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php +++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php @@ -603,6 +603,8 @@ protected function getStaticTypeContainerConfig($sortOrder) 'showLabel' => false, 'additionalClasses' => 'admin__field-group-columns admin__control-group-equal', 'sortOrder' => $sortOrder, + 'fieldTemplate' => 'Magento_Catalog/form/field', + 'visible' => false, ], ], ], @@ -677,7 +679,7 @@ protected function getSelectTypeGridConfig($sortOrder) 10, $this->locator->getProduct()->getStoreId() ? $options : [] ), - static::FIELD_PRICE_NAME => $this->getPriceFieldConfig(20), + static::FIELD_PRICE_NAME => $this->getPriceFieldConfigForSelectType(20), static::FIELD_PRICE_TYPE_NAME => $this->getPriceTypeFieldConfig(30, ['fit' => true]), static::FIELD_SKU_NAME => $this->getSkuFieldConfig(40), static::FIELD_SORT_ORDER_NAME => $this->getPositionFieldConfig(50), @@ -912,10 +914,12 @@ protected function getPriceFieldConfig($sortOrder) 'config' => [ 'label' => __('Price'), 'componentType' => Field::NAME, + 'component' => 'Magento_Catalog/js/components/custom-options-component', 'formElement' => Input::NAME, 'dataScope' => static::FIELD_PRICE_NAME, 'dataType' => Number::NAME, 'addbefore' => $this->getCurrencySymbol(), + 'addbeforePool' => $this->productOptionsPrice->prefixesToOptionArray(), 'sortOrder' => $sortOrder, 'validation' => [ 'validate-zero-or-greater' => true @@ -926,6 +930,20 @@ protected function getPriceFieldConfig($sortOrder) ]; } + /** + * Get config for "Price" field for select type. + * + * @param int $sortOrder + * @return array + */ + private function getPriceFieldConfigForSelectType(int $sortOrder) + { + $priceFieldConfig = $this->getPriceFieldConfig($sortOrder); + $priceFieldConfig['arguments']['data']['config']['template'] = 'Magento_Catalog/form/field'; + + return $priceFieldConfig; + } + /** * Get config for "Price Type" field * @@ -942,12 +960,16 @@ protected function getPriceTypeFieldConfig($sortOrder, array $config = []) 'data' => [ 'config' => [ 'label' => __('Price Type'), + 'component' => 'Magento_Catalog/js/components/custom-options-price-type', 'componentType' => Field::NAME, 'formElement' => Select::NAME, 'dataScope' => static::FIELD_PRICE_TYPE_NAME, 'dataType' => Text::NAME, 'sortOrder' => $sortOrder, 'options' => $this->productOptionsPrice->toOptionArray(), + 'imports' => [ + 'priceIndex' => self::FIELD_PRICE_NAME, + ], ], ], ], @@ -1050,6 +1072,7 @@ protected function getImageSizeXFieldConfig($sortOrder) 'label' => __('Maximum Image Size'), 'notice' => __('Please leave blank if it is not an image.'), 'addafter' => __('px.'), + 'component' => 'Magento_Catalog/js/components/custom-options-component', 'componentType' => Field::NAME, 'formElement' => Input::NAME, 'dataScope' => static::FIELD_IMAGE_SIZE_X_NAME, @@ -1079,6 +1102,7 @@ protected function getImageSizeYFieldConfig($sortOrder) 'config' => [ 'label' => ' ', 'addafter' => __('px.'), + 'component' => 'Magento_Catalog/js/components/custom-options-component', 'componentType' => Field::NAME, 'formElement' => Input::NAME, 'dataScope' => static::FIELD_IMAGE_SIZE_Y_NAME, diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-component.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-component.js new file mode 100644 index 0000000000000..6695619419f89 --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-component.js @@ -0,0 +1,35 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'underscore', + 'Magento_Ui/js/form/element/abstract' +], function (_, Abstract) { + 'use strict'; + + return Abstract.extend({ + /** + * {@inheritdoc} + */ + setInitialValue: function () { + this._super(); + + this.addBefore(this.addbefore); + + return this; + }, + + /** + * {@inheritdoc} + */ + initObservable: function () { + this._super(); + + this.observe('addBefore'); + + return this; + } + }); +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js new file mode 100644 index 0000000000000..4c631ee612a80 --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js @@ -0,0 +1,62 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define([ + 'underscore', + 'Magento_Ui/js/form/element/select', + 'uiRegistry' +], function (_, Select, uiRegistry) { + 'use strict'; + + return Select.extend({ + /** + * {@inheritdoc} + */ + onUpdate: function () { + this._super(); + + this.updateAddBeforeForPrice(); + }, + + /** + * {@inheritdoc} + */ + setInitialValue: function () { + this._super(); + + this.updateAddBeforeForPrice(); + + return this; + }, + + /** + * Update addbefore for price field. Change it to currency or % depends of price_type value. + */ + updateAddBeforeForPrice: function () { + var priceIndex = typeof this.imports.priceIndex == 'undefined' + ? 'price' + : this.imports.priceIndex; + + var priceName = this.parentName + '.' + priceIndex; + + var uiPrice = uiRegistry.get(priceName); + + if (uiPrice && uiPrice.addbeforePool) { + var currentValue = this.value(); + var addBefore; + + uiPrice.addbeforePool.forEach(function (item) { + if (item.value == currentValue) { + addBefore = item.label; + } + }); + + if (typeof addBefore != 'undefined') { + uiPrice.addBefore(addBefore); + } + } + } + }); +}); diff --git a/app/code/Magento/Catalog/view/adminhtml/web/template/form/field.html b/app/code/Magento/Catalog/view/adminhtml/web/template/form/field.html new file mode 100644 index 0000000000000..205d08d748af5 --- /dev/null +++ b/app/code/Magento/Catalog/view/adminhtml/web/template/form/field.html @@ -0,0 +1,43 @@ + +
    + +
    + + +
    + + + + +
    + + + + + +
    +
    diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php index aa9470867fd28..5a92f462d8377 100644 --- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php +++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php @@ -93,7 +93,7 @@ public function afterInitialize( protected function getConfigurations() { $result = []; - $configurableMatrix = $this->request->getParam('configurable-matrix-serialized', '[]'); + $configurableMatrix = $this->request->getParam('configurable-matrix-serialized') ?: []; if ($configurableMatrix != null && !empty($configurableMatrix)) { $configurableMatrix = json_decode($configurableMatrix, true); } diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php index a2976e918065e..57e3d8e47648c 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurationsTest.php @@ -153,7 +153,7 @@ public function testAfterInitialize() ->willReturnMap( [ ['store', 0, 0], - ['configurable-matrix-serialized', '[]', json_encode($configurableMatrix)] + ['configurable-matrix-serialized', null, json_encode($configurableMatrix)], ] ); $this->variationHandlerMock->expects(static::once()) @@ -210,4 +210,30 @@ protected function getProductMock(array $expectedData = null, $hasDataChanges = } return $productMock; } + + /** + * Test for no exceptions if configurable matrix is empty string. + */ + public function testAfterInitializeEmptyMatrix() + { + $productMock = $this->getProductMock(); + + $this->requestMock->expects(static::any()) + ->method('getParam') + ->willReturnMap( + [ + ['store', 0, 0], + ['configurable-matrix-serialized', null, ''], + ] + ); + + $this->variationHandlerMock->expects(static::once()) + ->method('duplicateImagesForVariations') + ->with([]) + ->willReturn([]); + + $this->updateConfigurations->afterInitialize($this->subjectMock, $productMock); + + $this->assertEmpty($productMock->getData()); + } } diff --git a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php index d384fc82094e8..636d832842f92 100644 --- a/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php +++ b/app/code/Magento/ConfigurableProduct/Ui/DataProvider/Product/Form/Modifier/CustomOptions.php @@ -127,8 +127,8 @@ private function modifyPriceTypeFields(array $meta) 'bannedOptions' => ['percent'], 'imports' => [ 'updateOptions' => 'ns = ${ $.ns }, index = ' - . ConfigurablePanel::CONFIGURABLE_MATRIX . ':isEmpty' - ] + . ConfigurablePanel::CONFIGURABLE_MATRIX . ':isEmpty', + ], ] ); } diff --git a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-price-type.js b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-price-type.js index b502f986c5af4..8425d12d4c763 100644 --- a/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-price-type.js +++ b/app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/components/custom-options-price-type.js @@ -5,11 +5,11 @@ define([ 'underscore', - 'Magento_Ui/js/form/element/select' -], function (_, Select) { + 'Magento_Catalog/js/components/custom-options-price-type' +], function (_, PriceType) { 'use strict'; - return Select.extend({ + return PriceType.extend({ defaults: { isConfigurable: false, isFiltered: null, diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options.php index b39631f3b355e..bb12146360c04 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options.php @@ -8,7 +8,6 @@ use Magento\Mtf\Client\Element\SimpleElement; use Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Options\Search\Grid; -use Magento\Mtf\ObjectManager; use Magento\Mtf\Client\ElementInterface; use Magento\Mtf\Client\Locator; use Magento\Ui\Test\Block\Adminhtml\Section; @@ -347,4 +346,43 @@ protected function optionNameConvert($inputType) return $option; } + + /** + * Get values data for option as array. + * + * @param array $options + * @param string $optionType + * @param string $optionTitle + * @return array + */ + public function getValuesDataForOption(array $options, string $optionType, string $optionTitle) + { + $rootLocator = sprintf($this->customOptionRow, $optionTitle); + $rootElement = $this->_rootElement->find($rootLocator, Locator::SELECTOR_XPATH); + + $formDataItem = []; + /** @var AbstractOptions $optionsForm */ + $optionsForm = $this->blockFactory->create( + __NAMESPACE__ . '\Options\Type\\' . $this->optionNameConvert($optionType), + ['element' => $rootElement] + ); + $context = $rootElement->find($this->addValue)->isVisible() + ? $this->dynamicDataRow + : $this->staticDataRow; + foreach (array_keys($options) as $key) { + $element = $rootElement->find(sprintf($context, $key + 1)); + + $dataOptions = $optionsForm->getDataOptions(null, $element); + + $addBefore = $optionsForm->getTextForOptionValues( + [ + 'add_before' => [] + ], + $element + ); + $formDataItem[$key] = array_merge($dataOptions, $addBefore); + } + + return $formDataItem; + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/AbstractOptions.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/AbstractOptions.php index b487bad5d6200..6b42092a45336 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/AbstractOptions.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/AbstractOptions.php @@ -44,4 +44,25 @@ public function getDataOptions(array $fields = null, SimpleElement $element = nu return $this->_getData($mapping, $element); } + + /** + * Getting text for options. + * + * @param array $fields + * @param SimpleElement $element + * @return array + */ + public function getTextForOptionValues(array $fields = null, SimpleElement $element = null) + { + $element = $element === null ? $this->_rootElement : $element; + $mapping = $this->dataMapping($fields); + $data = []; + + foreach ($mapping as $key => $field) { + $element = $this->getElement($element, $field); + $data[$key] = $element->getText(); + } + + return $data; + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Area.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Area.xml index f7d6316f346c8..c127183f8de0d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Area.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Area.xml @@ -20,5 +20,8 @@ [name$='[max_characters]'] + + [class*="admin__addon-prefix"] + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Checkbox.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Checkbox.xml index 5eebba7132040..edd1f4b250162 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Checkbox.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Checkbox.xml @@ -20,5 +20,8 @@ [name$='[sku]'] + + [class*="admin__addon-prefix"] + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Date.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Date.xml index 9a64d73fbfb33..82677e187813f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Date.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Date.xml @@ -17,5 +17,8 @@ [name$='[sku]'] + + [class*="admin__addon-prefix"] + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DateTime.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DateTime.xml index 9a64d73fbfb33..82677e187813f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DateTime.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DateTime.xml @@ -17,5 +17,8 @@ [name$='[sku]'] + + [class*="admin__addon-prefix"] + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.xml index 5eebba7132040..edd1f4b250162 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/DropDown.xml @@ -20,5 +20,8 @@ [name$='[sku]'] + + [class*="admin__addon-prefix"] + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Field.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Field.xml index f7d6316f346c8..c127183f8de0d 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Field.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Field.xml @@ -20,5 +20,8 @@ [name$='[max_characters]'] + + [class*="admin__addon-prefix"] + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/File.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/File.xml index 9d6a085b32ed2..ead45c262d4fa 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/File.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/File.xml @@ -26,5 +26,8 @@ [name$='[image_size_y]'] + + [class*="admin__addon-prefix"] + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/MultipleSelect.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/MultipleSelect.xml index 5eebba7132040..edd1f4b250162 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/MultipleSelect.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/MultipleSelect.xml @@ -20,5 +20,8 @@ [name$='[sku]'] + + [class*="admin__addon-prefix"] + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/RadioButtons.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/RadioButtons.xml index 5eebba7132040..edd1f4b250162 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/RadioButtons.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/RadioButtons.xml @@ -20,5 +20,8 @@ [name$='[sku]'] + + [class*="admin__addon-prefix"] + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Time.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Time.xml index 9a64d73fbfb33..82677e187813f 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Time.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Edit/Section/Options/Type/Time.xml @@ -17,5 +17,8 @@ [name$='[sku]'] + + [class*="admin__addon-prefix"] + diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddBeforeForPrice.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddBeforeForPrice.php new file mode 100644 index 0000000000000..e0672b3b7ead4 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertAddBeforeForPrice.php @@ -0,0 +1,63 @@ + $product->getSku()]; + $productGrid->open(); + $productGrid->getProductGrid()->searchAndOpen($filter); + + $catalogProductNew->getProductForm()->openSection('customer-options'); + + /** @var \Magento\Catalog\Test\Block\Adminhtml\Product\Edit\Section\Options $options */ + $options = $catalogProductNew->getProductForm()->getSection('customer-options'); + $customOptions = $product->getCustomOptions()['import']['options']; + + foreach ($customOptions as $customOption) { + /** @var array $valuesFromForm */ + $valuesFromForm = $options->getValuesDataForOption( + $customOption['options'], + $customOption['type'], + $customOption['title'] + ); + + foreach ($valuesFromForm as $value) { + \PHPUnit_Framework_Assert::assertEquals($priceTypeSymbol, $value['add_before']); + } + } + } + + /** + * {@inheritdoc} + */ + public function toString() + { + return 'Price for custom options has correct addbefore.'; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityPartTwoTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityPartTwoTest.xml index b3952263d3a5c..a40c715bb3ac3 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityPartTwoTest.xml +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/CreateSimpleProductEntityPartTwoTest.xml @@ -159,5 +159,31 @@ + + simple-product-%isolation% + Simple Product %isolation% + simple_sku_%isolation% + 10017 + Simple Product short_description %isolation% + Simple Product description %isolation% + 67 + $ + catalogProductSimple::with_fixed_custom_option_price_100 + + + + + simple-product-%isolation% + Simple Product %isolation% + simple_sku_%isolation% + 10017 + Simple Product short_description %isolation% + Simple Product description %isolation% + 67 + % + catalogProductSimple::with_one_custom_option_and_category + + + From 2345a1fe87a35577fdec1c5f7a99b588aebde8b2 Mon Sep 17 00:00:00 2001 From: RomanKis Date: Wed, 30 Aug 2017 15:55:47 +0300 Subject: [PATCH 042/151] MAGETWO-70634: Issues in customizable options section of add/edit product pages --- .../web/js/components/custom-options-price-type.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js index 4c631ee612a80..a0785c8548464 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js @@ -35,20 +35,17 @@ define([ * Update addbefore for price field. Change it to currency or % depends of price_type value. */ updateAddBeforeForPrice: function () { - var priceIndex = typeof this.imports.priceIndex == 'undefined' - ? 'price' - : this.imports.priceIndex; - + var addBefore, currentValue; + var priceIndex = typeof this.imports.priceIndex == 'undefined' ? 'price' : this.imports.priceIndex; var priceName = this.parentName + '.' + priceIndex; var uiPrice = uiRegistry.get(priceName); if (uiPrice && uiPrice.addbeforePool) { - var currentValue = this.value(); - var addBefore; + currentValue = this.value(); uiPrice.addbeforePool.forEach(function (item) { - if (item.value == currentValue) { + if (item.value === currentValue) { addBefore = item.label; } }); From 5f039579786978a7f02c961f99d90c69d166a17b Mon Sep 17 00:00:00 2001 From: Dmytro Voskoboinikov Date: Wed, 30 Aug 2017 16:06:10 +0300 Subject: [PATCH 043/151] MAGETWO-71982: bundle_values required for import - for 2.2 --- .../BundleImportExport/Model/Import/Product/Type/Bundle.php | 4 ++++ .../Test/Unit/Model/Import/Product/Type/BundleTest.php | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php index f9ef1c7768674..96b7c7b1430b0 100644 --- a/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php +++ b/app/code/Magento/BundleImportExport/Model/Import/Product/Type/Bundle.php @@ -168,6 +168,10 @@ public function __construct( */ protected function parseSelections($rowData, $entityId) { + if (empty($rowData['bundle_values'])) { + return []; + } + $rowData['bundle_values'] = str_replace( self::BEFORE_OPTION_VALUE_DELIMITER, $this->_entityModel->getMultipleValueSeparator(), diff --git a/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php b/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php index d5298c9bbfb00..8e1243b5eb3af 100644 --- a/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php +++ b/app/code/Magento/BundleImportExport/Test/Unit/Model/Import/Product/Type/BundleTest.php @@ -294,6 +294,11 @@ public function saveDataProvider() 'bunch' => ['bundle_values' => 'value1', 'sku' => 'sku', 'name' => 'name'], 'allowImport' => false ], + 'Import without bundle values' => [ + 'skus' => ['newSku' => ['sku' => ['sku' => 'sku', 'entity_id' => 3, 'type_id' => 'bundle']]], + 'bunch' => ['sku' => 'sku', 'name' => 'name'], + 'allowImport' => true, + ], [ 'skus' => ['newSku' => [ 'sku' => ['sku' => 'sku', 'entity_id' => 3, 'type_id' => 'bundle'], From e16c0bfd1465daa16acb4132eb1b9aa1b04aa33e Mon Sep 17 00:00:00 2001 From: RomanKis Date: Wed, 30 Aug 2017 16:11:24 +0300 Subject: [PATCH 044/151] MAGETWO-70634: Issues in customizable options section of add/edit product pages --- .../web/js/components/custom-options-price-type.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js index a0785c8548464..10578ed9432ed 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js @@ -35,9 +35,10 @@ define([ * Update addbefore for price field. Change it to currency or % depends of price_type value. */ updateAddBeforeForPrice: function () { - var addBefore, currentValue; - var priceIndex = typeof this.imports.priceIndex == 'undefined' ? 'price' : this.imports.priceIndex; - var priceName = this.parentName + '.' + priceIndex; + var addBefore, currentValue, priceIndex, priceName; + + priceIndex = typeof this.imports.priceIndex == 'undefined' ? 'price' : this.imports.priceIndex; + priceName = this.parentName + '.' + priceIndex; var uiPrice = uiRegistry.get(priceName); From e66d8a0f09d201ab6f261391964f187173ebd46c Mon Sep 17 00:00:00 2001 From: RomanKis Date: Wed, 30 Aug 2017 16:21:59 +0300 Subject: [PATCH 045/151] MAGETWO-70634: Issues in customizable options section of add/edit product pages --- .../adminhtml/web/js/components/custom-options-price-type.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js index 10578ed9432ed..e433f711a13fb 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/custom-options-price-type.js @@ -35,12 +35,12 @@ define([ * Update addbefore for price field. Change it to currency or % depends of price_type value. */ updateAddBeforeForPrice: function () { - var addBefore, currentValue, priceIndex, priceName; + var addBefore, currentValue, priceIndex, priceName, uiPrice; priceIndex = typeof this.imports.priceIndex == 'undefined' ? 'price' : this.imports.priceIndex; priceName = this.parentName + '.' + priceIndex; - var uiPrice = uiRegistry.get(priceName); + uiPrice = uiRegistry.get(priceName); if (uiPrice && uiPrice.addbeforePool) { currentValue = this.value(); From 717a56cbb039b33fde4280b56d4ae3d2ca53b91f Mon Sep 17 00:00:00 2001 From: Iryna Lagno Date: Wed, 30 Aug 2017 16:20:58 +0300 Subject: [PATCH 046/151] MAGETWO-72001: 'Asymmetric transaction rollback' error after saving product with FPT attribute --- .../js/components/disable-on-option/yesno.js | 34 +++++++++++++++- .../product_attribute_add_form.xml | 3 ++ .../js/disable-on-option/yesno.test.js | 40 +++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/disable-on-option/yesno.test.js diff --git a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/yesno.js b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/yesno.js index da113dbf825a2..dbca27402fef5 100644 --- a/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/yesno.js +++ b/app/code/Magento/Catalog/view/adminhtml/web/js/components/disable-on-option/yesno.js @@ -8,5 +8,37 @@ define([ ], function (Element, strategy) { 'use strict'; - return Element.extend(strategy); + var comp = Element.extend(strategy).extend({ + + defaults: { + listens: { + disabled: 'updateValueForDisabledField', + visible: 'updateValueForDisabledField' + } + }, + + /** + * {@inheritdoc} + */ + initialize: function () { + this._super(); + this.updateValueForDisabledField(); + + return this; + }, + + /** + * Set element value to O(No) if element is invisible and disabled + * Set element value to initialValue if element becomes visible and enable + */ + updateValueForDisabledField: function () { + if (!this.disabled() && this.visible()) { + this.set('value', this.initialValue); + } else { + this.set('value', 0); + } + } + }); + + return comp.extend(strategy); }); diff --git a/app/code/Magento/LayeredNavigation/view/adminhtml/ui_component/product_attribute_add_form.xml b/app/code/Magento/LayeredNavigation/view/adminhtml/ui_component/product_attribute_add_form.xml index 460567667825a..000e10197af1b 100644 --- a/app/code/Magento/LayeredNavigation/view/adminhtml/ui_component/product_attribute_add_form.xml +++ b/app/code/Magento/LayeredNavigation/view/adminhtml/ui_component/product_attribute_add_form.xml @@ -48,6 +48,9 @@ Can be used only with catalog input type Dropdown, Multiple Select and Price. is_filterable_in_search + + ${ $.parentName}:visible +
    diff --git a/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/disable-on-option/yesno.test.js b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/disable-on-option/yesno.test.js new file mode 100644 index 0000000000000..c49f447d4f65b --- /dev/null +++ b/dev/tests/js/jasmine/tests/app/code/Magento/Catalog/adminhtml/js/disable-on-option/yesno.test.js @@ -0,0 +1,40 @@ +/** + * Copyright © Magento, Inc. All rights reserved. + * See COPYING.txt for license details. + */ + +define(['Magento_Catalog/js/components/disable-on-option/yesno'], function (YesNo) { + 'use strict'; + + var model; + + describe('Magento_Catalog/js/components/disable-on-option/yesno', function () { + beforeEach(function () { + model = new YesNo({ + name: 'dynamic_rows', + dataScope: '', + value: 12, + visible: true, + disabled: false + + }); + }); + + it('Verify initial value', function () { + expect(model.get('value')).toBe(12); + }); + it('Verify value when element becomes invisible', function () { + model.set('visible', false); + expect(model.get('value')).toBe(0); + }); + it('Verify value when element becomes disabled', function () { + model.set('disabled', false); + expect(model.get('value')).toBe(12); + }); + it('Verify value when element becomes invisable and disabled', function () { + model.set('disabled', true); + model.set('visible', false); + expect(model.get('value')).toBe(0); + }); + }); +}); From e94f498d40d67285082c822c13f747ab69060f30 Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Wed, 30 Aug 2017 10:21:42 -0500 Subject: [PATCH 047/151] MAGETWO-71765 Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Used helper formatter function instead of sprintf. --- app/code/Magento/Paypal/Model/Payflowpro.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Paypal/Model/Payflowpro.php b/app/code/Magento/Paypal/Model/Payflowpro.php index 0a988ffd8abc5..d86aff2bfdb7d 100644 --- a/app/code/Magento/Paypal/Model/Payflowpro.php +++ b/app/code/Magento/Paypal/Model/Payflowpro.php @@ -7,6 +7,7 @@ use Magento\Framework\DataObject; use Magento\Framework\Exception\LocalizedException; +use Magento\Payment\Helper\Formatter; use Magento\Payment\Model\InfoInterface; use Magento\Payment\Model\Method\ConfigInterface; use Magento\Payment\Model\Method\ConfigInterfaceFactory; @@ -83,6 +84,8 @@ class Payflowpro extends \Magento\Payment\Model\Method\Cc implements GatewayInte const PNREF = 'pnref'; + use Formatter; + /**#@-*/ /**#@-*/ @@ -396,8 +399,8 @@ public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount protected function _getCaptureAmount($amount) { $infoInstance = $this->getInfoInstance(); - $amountToPay = sprintf('%.2F', $amount); - $authorizedAmount = sprintf('%.2F', $infoInstance->getAmountAuthorized()); + $amountToPay = $this->formatPrice($amount); + $authorizedAmount = $this->formatPrice($infoInstance->getAmountAuthorized()); return $amountToPay != $authorizedAmount ? $amountToPay : 0; } From 929103ed5bf7318538374418edcdeacea328d0c1 Mon Sep 17 00:00:00 2001 From: Krissy Hiserote Date: Wed, 30 Aug 2017 11:31:33 -0500 Subject: [PATCH 048/151] MAGETWO-69470: Coupon with type 'Auto' can't be generated. - use path and not variable to get COUPON_TYPE_AUTO --- .../Magento/SalesRule/Model/Service/CouponManagementService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php b/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php index 2d9d7dd491c1c..27673a717f7a2 100644 --- a/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php +++ b/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php @@ -88,7 +88,7 @@ public function generate(\Magento\SalesRule\Api\Data\CouponGenerationSpecInterfa $couponSpec->getRuleId() ); } - if (!$rule->getUseAutoGeneration() && $rule->getCouponType() != $rule::COUPON_TYPE_AUTO) { + if (!$rule->getUseAutoGeneration() && $rule->getCouponType() != \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO) { throw new \Magento\Framework\Exception\LocalizedException( __('Specified rule does not allow automatic coupon generation') ); From 788455b4aced2d4a447418177bd97e3edcf971f1 Mon Sep 17 00:00:00 2001 From: Robert He Date: Wed, 30 Aug 2017 11:45:42 -0500 Subject: [PATCH 049/151] MAGETWO-71666: Unable to save product after failed attempt - add better check for the configurable-matrix-serialized variable --- .../Product/Initialization/Helper/Plugin/Configurable.php | 2 +- .../Initialization/Helper/Plugin/UpdateConfigurations.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php index cfadde3c4a18f..5cd8b6a7d0b95 100644 --- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php +++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/Configurable.php @@ -154,7 +154,7 @@ protected function getVariationMatrix() { $result = []; $configurableMatrix = $this->request->getParam('configurable-matrix-serialized', "[]"); - if (isset($configurableMatrix) && $configurableMatrix != "[]") { + if (isset($configurableMatrix) && $configurableMatrix != "") { $configurableMatrix = json_decode($configurableMatrix, true); foreach ($configurableMatrix as $item) { diff --git a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php index a22e28aa2e6ae..442c48a4554d0 100644 --- a/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php +++ b/app/code/Magento/ConfigurableProduct/Controller/Adminhtml/Product/Initialization/Helper/Plugin/UpdateConfigurations.php @@ -94,7 +94,7 @@ protected function getConfigurations() { $result = []; $configurableMatrix = $this->request->getParam('configurable-matrix-serialized', "[]"); - if (isset($configurableMatrix) && $configurableMatrix != "[]") { + if (isset($configurableMatrix) && $configurableMatrix != "") { $configurableMatrix = json_decode($configurableMatrix, true); foreach ($configurableMatrix as $item) { From a0444a1a38b5aa23f485bde761e7bda41e3aae19 Mon Sep 17 00:00:00 2001 From: Daniel Renaud Date: Wed, 30 Aug 2017 14:03:42 -0500 Subject: [PATCH 050/151] MAGETWO-71771: imposible perform full refund for Order Paid with PayPal Payments Standart - Format price before sending to API --- app/code/Magento/Paypal/Model/Api/Nvp.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Paypal/Model/Api/Nvp.php b/app/code/Magento/Paypal/Model/Api/Nvp.php index 238534a8cf929..9e3018940fcee 100644 --- a/app/code/Magento/Paypal/Model/Api/Nvp.php +++ b/app/code/Magento/Paypal/Model/Api/Nvp.php @@ -991,7 +991,7 @@ public function callRefundTransaction() { $request = $this->_exportToRequest($this->_refundTransactionRequest); if ($this->getRefundType() === \Magento\Paypal\Model\Config::REFUND_TYPE_PARTIAL) { - $request['AMT'] = $this->getAmount(); + $request['AMT'] = $this->formatPrice($this->getAmount()); } $response = $this->call(self::REFUND_TRANSACTION, $request); $this->_importFromResponse($this->_refundTransactionResponse, $response); From e41f6ccdc12ddab53c9b9436ca30a0dda5918fc3 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 31 Aug 2017 09:08:47 +0300 Subject: [PATCH 051/151] MAGETWO-49796: Catalog top nav, CSS class not set to active when using Varnish --- lib/web/mage/menu.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index 667c86cec6454..5a51dcb26583e 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -199,12 +199,17 @@ define([ */ _setActiveMenuForProduct: function (currentUrl) { var categoryUrlExtension, + lastUrlSection, possibleCategoryUrl, //retrieve first category URL to know what extension is used for category URLs firstCategoryUrl = this.element.find('> li a').attr('href'); if (firstCategoryUrl) { - categoryUrlExtension = firstCategoryUrl.substr(firstCategoryUrl.lastIndexOf('.')); + lastUrlSection = firstCategoryUrl.substr(firstCategoryUrl.lastIndexOf('/')); + categoryUrlExtension = (lastUrlSection.lastIndexOf('.') !== -1) + ? lastUrlSection.substr(lastUrlSection.lastIndexOf('.')) : ''; + + //categoryUrlExtension = lastUrlSection.substr(lastUrlSection.lastIndexOf('.')); possibleCategoryUrl = currentUrl.substr(0, currentUrl.lastIndexOf('/')) + categoryUrlExtension; this._setActiveMenuForCategory(possibleCategoryUrl); } From 72f831b1f4143418bb207646972c996cc1df979e Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 31 Aug 2017 09:53:03 +0300 Subject: [PATCH 052/151] MAGETWO-49796: Catalog top nav, CSS class not set to active when using Varnish --- lib/web/mage/menu.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index 5a51dcb26583e..8a212b2bd445d 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -209,7 +209,6 @@ define([ categoryUrlExtension = (lastUrlSection.lastIndexOf('.') !== -1) ? lastUrlSection.substr(lastUrlSection.lastIndexOf('.')) : ''; - //categoryUrlExtension = lastUrlSection.substr(lastUrlSection.lastIndexOf('.')); possibleCategoryUrl = currentUrl.substr(0, currentUrl.lastIndexOf('/')) + categoryUrlExtension; this._setActiveMenuForCategory(possibleCategoryUrl); } From 77c6b5e4597f3660c2412f78c5448a15d3b431ee Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi Date: Thu, 31 Aug 2017 11:02:55 +0300 Subject: [PATCH 053/151] MAGETWO-71870: Unable to place new order for a New Customer from backend - Fixed issue with empty customer email and second place order attempt --- .../Magento/Sales/Model/AdminOrder/Create.php | 3 ++ .../Sales/Model/AdminOrder/CreateTest.php | 45 +++++++++++++++++-- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Sales/Model/AdminOrder/Create.php b/app/code/Magento/Sales/Model/AdminOrder/Create.php index 9177962926776..ccc5c134514f6 100644 --- a/app/code/Magento/Sales/Model/AdminOrder/Create.php +++ b/app/code/Magento/Sales/Model/AdminOrder/Create.php @@ -1586,6 +1586,9 @@ public function applyCoupon($code) public function setAccountData($accountData) { $customer = $this->getQuote()->getCustomer(); + if (empty($accountData['email'])) { + $accountData['email'] = $customer->getEmail(); + } $form = $this->_createCustomerForm($customer); // emulate request diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php index b0d83c52a3a2b..a4dac0f285f58 100644 --- a/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/AdminOrder/CreateTest.php @@ -430,14 +430,19 @@ public function testCreateOrderNewCustomer() * @magentoDataFixture Magento/Catalog/_files/product_simple.php * @magentoDbIsolation enabled * @magentoAppIsolation enabled + * @dataProvider createOrderNewCustomerWithFailedFirstPlaceOrderActionDataProvider + * @param string $customerEmailFirstAttempt + * @param string $customerEmailSecondAttempt */ - public function testCreateOrderNewCustomerWithFailedFirstPlaceOrderAction() - { + public function testCreateOrderNewCustomerWithFailedFirstPlaceOrderAction( + $customerEmailFirstAttempt, + $customerEmailSecondAttempt + ) { $productIdFromFixture = 1; $shippingMethod = 'freeshipping_freeshipping'; $paymentMethod = 'checkmo'; $shippingAddressAsBilling = 1; - $customerEmail = 'new_customer@example.com'; + $customerEmail = $customerEmailFirstAttempt; $orderData = [ 'currency' => 'USD', 'account' => ['group_id' => '1', 'email' => $customerEmail], @@ -469,10 +474,44 @@ public function testCreateOrderNewCustomerWithFailedFirstPlaceOrderAction() Bootstrap::getObjectManager()->removeSharedInstance(OrderManagementInterface::class); } + $customerEmail = $customerEmailSecondAttempt ? :$this->_model->getQuote()->getCustomer()->getEmail(); + $orderData['account']['email'] = $customerEmailSecondAttempt; + + $this->_preparePreconditionsForCreateOrder( + $productIdFromFixture, + $customerEmail, + $shippingMethod, + $shippingAddressAsBilling, + $paymentData, + $orderData, + $paymentMethod + ); + $order = $this->_model->createOrder(); $this->_verifyCreatedOrder($order, $shippingMethod); } + /** + * Email before and after failed first place order action. + * + * @case #1 Is the same. + * @case #2 Is empty. + * @case #3 Filled after failed first place order action. + * @case #4 Empty after failed first place order action. + * @case #5 Changed after failed first place order action. + * @return array + */ + public function createOrderNewCustomerWithFailedFirstPlaceOrderActionDataProvider() + { + return [ + 1 => ['customer@email.com', 'customer@email.com'], + 2 => ['', ''], + 3 => ['', 'customer@email.com'], + 4 => ['customer@email.com', ''], + 5 => ['customer@email.com', 'changed_customer@email.com'], + ]; + } + /** * @magentoDataFixture Magento/Catalog/_files/product_simple.php * @magentoDataFixture Magento/Customer/_files/customer.php From 72949d9fa051142aa74f9f366dd08758d1a0927f Mon Sep 17 00:00:00 2001 From: Andrew Boudnikov Date: Fri, 23 Jun 2017 10:34:14 +0300 Subject: [PATCH 054/151] MAGETWO-70163: Add quote generaion ability for fixtures generation tool - Implemented quote generator --- .../Fixtures/Quote/QuoteConfiguration.php | 139 +++ .../Setup/Fixtures/Quote/QuoteGenerator.php | 801 ++++++++++++++++++ .../Fixtures/Quote/QuoteGeneratorFactory.php | 50 ++ .../Fixtures/_files/quote_fixture_data.json | 188 ++++ 4 files changed, 1178 insertions(+) create mode 100644 setup/src/Magento/Setup/Fixtures/Quote/QuoteConfiguration.php create mode 100644 setup/src/Magento/Setup/Fixtures/Quote/QuoteGenerator.php create mode 100644 setup/src/Magento/Setup/Fixtures/Quote/QuoteGeneratorFactory.php create mode 100644 setup/src/Magento/Setup/Fixtures/_files/quote_fixture_data.json diff --git a/setup/src/Magento/Setup/Fixtures/Quote/QuoteConfiguration.php b/setup/src/Magento/Setup/Fixtures/Quote/QuoteConfiguration.php new file mode 100644 index 0000000000000..b2169a2b33200 --- /dev/null +++ b/setup/src/Magento/Setup/Fixtures/Quote/QuoteConfiguration.php @@ -0,0 +1,139 @@ + 'simple_count_to', + 'order_simple_product_count_from' => 'simple_count_from', + 'order_configurable_product_count_to' => 'configurable_count_to', + 'order_configurable_product_count_from' => 'configurable_count_from', + 'order_big_configurable_product_count_to' => 'big_configurable_count_to', + 'order_big_configurable_product_count_from' => 'big_configurable_count_from', + 'order_quotes_enable' => 'order_quotes_enable', + ]; + + /** + * @var string + */ + protected $fixtureDataFilename = 'orders_fixture_data.json'; + + /** + * @var FixtureModel + */ + private $fixtureModel; + + /** + * @param FixtureModel $fixtureModel + */ + public function __construct(FixtureModel $fixtureModel) + { + $this->fixtureModel = $fixtureModel; + } + + /** + * Fills object with data. + * + * @return $this + */ + public function load() + { + $this->addData([ + 'simple_count_to' => self::SIMPLE_PRODUCT_COUNT_TO, + 'simple_count_from' => self::SIMPLE_PRODUCT_COUNT_FROM, + 'configurable_count_to' => self::CONFIGURABLE_PRODUCT_COUNT_TO, + 'configurable_count_from' => self::CONFIGURABLE_PRODUCT_COUNT_FROM, + 'big_configurable_count_to' => self::BIG_CONFIGURABLE_PRODUCT_COUNT_TO, + 'big_configurable_count_from' => self::BIG_CONFIGURABLE_PRODUCT_COUNT_FROM, + ]); + + $this->setData( + 'fixture_data_filename', + dirname(__DIR__) . DIRECTORY_SEPARATOR . "_files" . DIRECTORY_SEPARATOR . $this->fixtureDataFilename + ); + + \Magento\Framework\DataObject\Mapper::accumulateByMap( + [$this->fixtureModel, 'getValue'], + [$this, 'setNotEmptyData'], + $this->_globalMap + ); + return $this; + } + + /** + * @param string|array $key + * @param mixed $value + * @return $this + */ + public function setNotEmptyData($key, $value) + { + if (null === $value) { + return $this; + } + return $this->setData($key, $value); + } +} diff --git a/setup/src/Magento/Setup/Fixtures/Quote/QuoteGenerator.php b/setup/src/Magento/Setup/Fixtures/Quote/QuoteGenerator.php new file mode 100644 index 0000000000000..979818759addb --- /dev/null +++ b/setup/src/Magento/Setup/Fixtures/Quote/QuoteGenerator.php @@ -0,0 +1,801 @@ +storeManager = $storeManager; + $this->productCollectionFactory = $productCollectionFactory; + $this->productRepository = $productRepository; + $this->optionRepository = $optionRepository; + $this->linkManagement = $linkManagement; + $this->serializer = $serializer; + $this->config = $config; + $this->fixtureModel = $fixtureModel; + } + + /** + * Prepare and save quotes in database + * + * @throws \Exception + * @return void + */ + public function generateQuotes() + { + $maxItemsPerOrder = $this->config->getSimpleCountTo() + + ($this->config->getConfigurableCountTo() + $this->config->getBigConfigurableCountTo()) * 2; + + $maxItemId = $this->getMaxEntityId( + 'quote_item', + \Magento\Quote\Model\ResourceModel\Quote\Item::class, + 'item_id' + ); + /** @var \Generator $itemIdSequence */ + $itemIdSequence = $this->getItemIdSequence( + $maxItemId, + $this->config->getRequiredQuoteQuantity(), + $maxItemsPerOrder + ); + $this->productStubData = $this->prepareProductsForQuote(); + + $this->prepareQueryTemplates(); + + $entityId = $this->getMaxEntityId('quote', \Magento\Quote\Model\ResourceModel\Quote::class, 'entity_id'); + $quoteQty = $this->config->getExistsQuoteQuantity(); + $batchNumber = 0; + while ($quoteQty <= $this->config->getRequiredQuoteQuantity()) { + $entityId++; + $batchNumber++; + $quoteQty++; + + try { + $this->saveQuoteWithQuoteItems($entityId, $itemIdSequence); + } catch (\Exception $lastException) { + foreach ($this->resourceConnections as $connection) { + if ($connection->getTransactionLevel() > 0) { + $connection->rollBack(); + } + } + throw $lastException; + } + + if ($batchNumber >= self::BATCH_SIZE) { + $this->commitBatch(); + $batchNumber = 0; + } + } + + foreach ($this->resourceConnections as $connection) { + if ($connection->getTransactionLevel() > 0) { + $connection->commit(); + } + } + } + + /** + * Save quote and quote items + * + * @param int $entityId + * @param \Generator $itemIdSequence + * @return void + */ + private function saveQuoteWithQuoteItems($entityId, \Generator $itemIdSequence) + { + $productCount = [ + Type::TYPE_SIMPLE => mt_rand( + $this->config->getSimpleCountFrom(), + $this->config->getSimpleCountTo() + ), + Configurable::TYPE_CODE => mt_rand( + $this->config->getConfigurableCountFrom(), + $this->config->getConfigurableCountTo() + ), + QuoteConfiguration::BIG_CONFIGURABLE_TYPE => mt_rand( + $this->config->getBigConfigurableCountFrom(), + $this->config->getBigConfigurableCountTo() + ) + ]; + $quote = [ + '%itemsPerOrder%' => array_sum($productCount), + '%orderNumber%' => 100000000 * $this->getStubProductStoreId($entityId) + $entityId, + '%email%' => "quote_{$entityId}@example.com", + '%time%' => date(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT), + '%productStoreId%' => $this->getStubProductStoreId($entityId), + '%productStoreName%' => $this->getStubProductStoreName($entityId), + '%entityId%' => $entityId, + ]; + $shippingAddress = ['%orderAddressId%' => $entityId * 2 - 1, '%addressType%' => 'shipping']; + $billingAddress = ['%orderAddressId%' => $entityId * 2, '%addressType%' => 'billing']; + $address = $this->getAddressDataFixture(); + + $this->query('quote', $quote); + $this->query('quote_address', $quote, $address, $shippingAddress); + $this->query('quote_address', $quote, $address, $billingAddress); + + for ($i = 0; $i < $productCount[Type::TYPE_SIMPLE]; $i++) { + $this->saveItemSimpleData($entityId, $i, $itemIdSequence->current(), $quote); + $itemIdSequence->next(); + } + + $type = Configurable::TYPE_CODE; + for ($i = 0; $i < $productCount[$type]; $i++) { + // Generate parent item + $parentItemId = $itemIdSequence->current(); + $this->saveParentItemConfigurableData($entityId, $i, $parentItemId, Configurable::TYPE_CODE, $quote); + $itemIdSequence->next(); + + // Generate child item + $itemId = $itemIdSequence->current(); + $this->saveChildItemConfigurable($entityId, $i, $itemId, $parentItemId, Configurable::TYPE_CODE, $quote); + $itemIdSequence->next(); + } + + $type = QuoteConfiguration::BIG_CONFIGURABLE_TYPE; + for ($i = 0; $i < $productCount[$type]; $i++) { + // Generate parent item + $parentItemId = $itemIdSequence->current(); + $this->saveParentItemConfigurableData($entityId, $i, $parentItemId, $type, $quote); + $itemIdSequence->next(); + + // Generate child item + $itemId = $itemIdSequence->current(); + $this->saveChildItemConfigurable($entityId, $i, $itemId, $parentItemId, $type, $quote); + $itemIdSequence->next(); + } + } + + /** + * Prepare and save quote item with simple product. + * + * @param int $entityId + * @param int $index + * @param int $itemId + * @param array $quote + * @return void + */ + private function saveItemSimpleData($entityId, $index, $itemId, array $quote) + { + $itemData = [ + '%productId%' => $this->getStubProductId($entityId, $index, Type::TYPE_SIMPLE), + '%sku%' => $this->getStubProductSku($entityId, $index, Type::TYPE_SIMPLE), + '%name%' => $this->getStubProductName($entityId, $index, Type::TYPE_SIMPLE), + '%itemId%' => $itemId, + '%productType%' => Type::TYPE_SIMPLE, + '%productOptions%' => $this->getStubProductBuyRequest($entityId, $index, Type::TYPE_SIMPLE), + '%parentItemId%' => 'null', + ]; + $this->query('quote_item', $quote, $itemData); + $this->query('quote_item_option', $quote, $itemData, [ + '%code%' => 'info_buyRequest', + '%value%' => $this->serializer->serialize([ + 'product' => $this->getStubProductId($entityId, $index, Type::TYPE_SIMPLE), + 'qty' => "1", + 'uenc' => 'aHR0cDovL21hZ2UyLmNvbS9jYXRlZ29yeS0xLmh0bWw' + ]) + ]); + } + + /** + * Prepare and save parent quote item for configurable product. + * + * @param int $entityId + * @param int $index + * @param int $parentItemId + * @param string $productType + * @param array $quote + * @return void + */ + private function saveParentItemConfigurableData($entityId, $index, $parentItemId, $productType, array $quote) + { + $itemData = [ + '%productId%' => $this->getStubProductId($entityId, $index, $productType), + '%sku%' => $this->getStubProductSku($entityId, $index, $productType), + '%name%' => $this->getStubProductName($entityId, $index, $productType), + '%productOptions%' => $this->getStubProductBuyRequest($entityId, $index, $productType)['order'], + '%itemId%' => $parentItemId, + '%parentItemId%' => 'null', + '%productType%' => Configurable::TYPE_CODE + ]; + $this->query('quote_item', $quote, $itemData); + $this->query('quote_item_option', $quote, $itemData, [ + '%code%' => 'info_buyRequest', + '%value%' => $this->getStubProductBuyRequest($entityId, $index, $productType)['quote'] + ]); + $this->query('quote_item_option', $quote, $itemData, [ + '%code%' => 'attributes', + '%value%' => $this->getStubProductBuyRequest($entityId, $index, $productType)['super_attribute'] + ]); + $itemData['%productId%'] = $this->getStubProductChildId($entityId, $index, $productType); + $this->query('quote_item_option', $itemData, [ + '%code%' => "product_qty_" . $this->getStubProductChildId($entityId, $index, $productType), + '%value%' => "1" + ]); + $this->query('quote_item_option', $itemData, [ + '%code%' => "simple_product", + '%value%' => $this->getStubProductChildId($entityId, $index, $productType) + ]); + } + + /** + * Prepare and save child quote item for configurable product. + * + * @param int $entityId + * @param int $index + * @param int $itemId + * @param int $parentItemId + * @param string $productType + * @param array $quote + * @return void + */ + private function saveChildItemConfigurable($entityId, $index, $itemId, $parentItemId, $productType, array $quote) + { + $itemData = [ + '%productId%' => $this->getStubProductChildId($entityId, $index, $productType), + '%sku%' => $this->getStubProductSku($entityId, $index, $productType), + '%name%' => $this->getStubProductName($entityId, $index, $productType), + '%productOptions%' => $this->getStubProductChildBuyRequest($entityId, $index, $productType)['order'], + '%itemId%' => $itemId, + '%parentItemId%' => $parentItemId, + '%productType%' => Type::TYPE_SIMPLE + ]; + + $this->query('quote_item', $quote, $itemData); + $this->query('quote_item_option', $itemData, [ + '%code%' => "info_buyRequest", + '%value%' => $this->getStubProductChildBuyRequest($entityId, $index, $productType)['quote'] + ]); + $this->query('quote_item_option', $itemData, [ + '%code%' => "parent_product_id", + '%value%' => $this->getStubProductId($entityId, $index, $productType) + ]); + } + + /** + * Get store id for quote item by product index. + * + * @param int $index + * @return int + */ + private function getStubProductStoreId($index) + { + return $this->productStubData[$index % count($this->productStubData)][0]; + } + + /** + * Get store name for quote item by product index. + * + * @param int $index + * @return string + */ + private function getStubProductStoreName($index) + { + return $this->productStubData[$index % count($this->productStubData)][1]; + } + + /** + * Get product id for quote item by product index. + * + * @param int $entityId + * @param int $index + * @param string $type + * @return int + */ + private function getStubProductId($entityId, $index, $type) + { + return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['id']; + } + + /** + * Get product SKU for quote item by product index. + * + * @param int $entityId + * @param int $index + * @param string $type + * @return string + */ + private function getStubProductSku($entityId, $index, $type) + { + return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['sku']; + } + + /** + * Get product name for quote item by product index. + * + * @param int $entityId + * @param int $index + * @param string $type + * @return string + */ + private function getStubProductName($entityId, $index, $type) + { + return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['name']; + } + + /** + * Get product buy request for quote item by product index. + * + * @param int $entityId + * @param int $index + * @param string $type + * @return string + */ + private function getStubProductBuyRequest($entityId, $index, $type) + { + return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['buyRequest']; + } + + /** + * Get configurable product child id for quote item by product index. + * + * @param int $entityId + * @param int $index + * @param string $type + * @return string + */ + private function getStubProductChildBuyRequest($entityId, $index, $type) + { + return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['childBuyRequest']; + } + + /** + * Get configurable product child id for quote item by product index. + * + * @param int $entityId + * @param int $index + * @param string $type + * @return int + */ + private function getStubProductChildId($entityId, $index, $type) + { + return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['childId']; + } + + /** + * Get quote address mock data. + * + * @return array + */ + private function getAddressDataFixture() + { + return [ + '%firstName%' => 'First Name', + '%lastName%' => 'Last Name', + '%company%' => 'Company', + '%address%' => 'Address', + '%city%' => 'city', + '%state%' => 'Alabama', + '%country%' => 'US', + '%zip%' => '11111', + '%phone%' => '911' + ]; + } + + /** + * Prepare mock of products for quotes. + * + * @return array + */ + private function prepareProductsForQuote() + { + $result = []; + foreach ($this->storeManager->getStores() as $store) { + $productsResult = []; + $this->storeManager->setCurrentStore($store->getId()); + + if ($this->config->getSimpleCountTo() > 0) { + $productsResult[Type::TYPE_SIMPLE] = $this->prepareSimpleProducts( + $this->getProductIds($store, Type::TYPE_SIMPLE, $this->config->getSimpleCountTo()) + ); + } + if ($this->config->getConfigurableCountTo() > 0) { + $productsResult[Configurable::TYPE_CODE] = $this->prepareConfigurableProducts( + $this->getProductIds( + $store, + Configurable::TYPE_CODE, + $this->config->getConfigurableCountTo() + ) + ); + } + if ($this->config->getBigConfigurableCountTo() > 0) { + $productsResult[QuoteConfiguration::BIG_CONFIGURABLE_TYPE] = $this->prepareConfigurableProducts( + $this->getProductIds( + $store, + QuoteConfiguration::BIG_CONFIGURABLE_TYPE, + $this->config->getBigConfigurableCountTo() + ) + ); + } + + $result[] = [ + $store->getId(), + implode(PHP_EOL, [ + $this->storeManager->getWebsite($store->getWebsiteId())->getName(), + $this->storeManager->getGroup($store->getStoreGroupId())->getName(), + $store->getName() + ]), + $productsResult + ]; + } + return $result; + } + + /** + * Load and prepare INSERT query templates data from external file. + * + * Queries are prepared using external json file, where keys are DB column names and values represent data, + * to be inserted to the table. Data may contain a default value or a placeholder which is replaced later during + * flow (in the query method of this class). + * Additionally, in case if multiple DB connections are set up, transaction is started for each connection. + * + * @return void + */ + private function prepareQueryTemplates() + { + $fileName = $this->config->getFixtureDataFilename(); + $templateData = json_decode(file_get_contents(realpath($fileName)), true); + foreach ($templateData as $table => $template) { + if (isset($template['_table'])) { + $table = $template['_table']; + unset($template['_table']); + } + if (isset($template['_resource'])) { + $resource = $template['_resource']; + unset($template['_resource']); + } else { + $resource = explode("_", $table); + foreach ($resource as &$item) { + $item = ucfirst($item); + } + $resource = "Magento\\" + . array_shift($resource) + . "\\Model\\ResourceModel\\" + . implode("\\", $resource); + } + + $tableName = $this->getTableName($table, $resource); + + $querySuffix = ""; + if (isset($template['_query_suffix'])) { + $querySuffix = $template['_query_suffix']; + unset($template['_query_suffix']); + } + + $fields = implode(', ', array_keys($template)); + $values = implode(', ', array_values($template)); + + $connection = $this->getConnection($resource); + if ($connection->getTransactionLevel() == 0) { + $connection->beginTransaction(); + } + + $this->queryTemplates[$table] = "INSERT INTO `{$tableName}` ({$fields}) VALUES ({$values}){$querySuffix};"; + $this->resourceConnections[$table] = $connection; + } + } + + /** + * Build and execute query. + * + * Builds a database query by replacing placeholder values in the cached queries and executes query in appropriate + * DB connection (if setup). Additionally filters out quote-related queries, if appropriate flag is set. + * + * @param string $table + * @param array ...$replacements + * @return void + */ + protected function query($table, ... $replacements) + { + $query = $this->queryTemplates[$table]; + foreach ($replacements as $data) { + $query = str_replace(array_keys($data), array_values($data), $query); + } + + $this->resourceConnections[$table]->query($query); + } + + /** + * Get maximum order id currently existing in the database. + * + * To support incremental generation of the orders it is necessary to get the maximum order entity_id currently. + * existing in the database. + * + * @param string $tableName + * @param string $resourceName + * @param string $column [optional] + * @return int + */ + private function getMaxEntityId($tableName, $resourceName, $column = 'entity_id') + { + $tableName = $this->getTableName($tableName, $resourceName); + $connection = $this->getConnection($resourceName); + return (int)$connection->query("SELECT MAX(`{$column}`) FROM `{$tableName}`;")->fetchColumn(0); + } + + /** + * Get a limited amount of product id's from a collection filtered by store and specific product type. + * + * @param \Magento\Store\Api\Data\StoreInterface $store + * @param string $typeId + * @param int $limit [optional] + * @return array + */ + private function getProductIds(\Magento\Store\Api\Data\StoreInterface $store, $typeId, $limit = null) + { + /** @var $productCollection \Magento\Catalog\Model\ResourceModel\Product\Collection */ + $productCollection = $this->productCollectionFactory->create(); + $productCollection->addStoreFilter($store->getId()); + $productCollection->addWebsiteFilter($store->getWebsiteId()); + + // "Big%" should be replaced with a configurable value. + if ($typeId === QuoteConfiguration::BIG_CONFIGURABLE_TYPE) { + $productCollection->getSelect()->where(" type_id = '" . Configurable::TYPE_CODE . "' "); + $productCollection->getSelect()->where(" sku LIKE 'Big%' "); + } else { + $productCollection->getSelect()->where(" type_id = '$typeId' "); + $productCollection->getSelect()->where(" sku NOT LIKE 'Big%' "); + } + + return $productCollection->getAllIds($limit); + } + + /** + * Prepare data for the simple products to be used as order items. + * + * Based on the Product Id's load data, which is required to replace placeholders in queries. + * + * @param array $productIds [optional] + * @return array + */ + private function prepareSimpleProducts(array $productIds = []) + { + $productsResult = []; + foreach ($productIds as $key => $simpleId) { + $simpleProduct = $this->productRepository->getById($simpleId); + $productsResult[$key]['id'] = $simpleId; + $productsResult[$key]['sku'] = $simpleProduct->getSku(); + $productsResult[$key]['name'] = $simpleProduct->getName(); + $productsResult[$key]['buyRequest'] = $this->serializer->serialize([ + "info_buyRequest" => [ + "uenc" => "aHR0cDovL21hZ2VudG8uZGV2L2NvbmZpZ3VyYWJsZS1wcm9kdWN0LTEuaHRtbA,,", + "product" => $simpleId, + "qty" => "1" + ] + ]); + } + return $productsResult; + } + + /** + * Prepare data for the configurable products to be used as order items. + * + * Based on the Product Id's load data, which is required to replace placeholders in queries. + * + * @param array $productIds [optional] + * @return array + */ + private function prepareConfigurableProducts(array $productIds = []) + { + $productsResult = []; + foreach ($productIds as $key => $configurableId) { + $configurableProduct = $this->productRepository->getById($configurableId); + $options = $this->optionRepository->getList($configurableProduct->getSku()); + $configurableChild = $this->linkManagement->getChildren($configurableProduct->getSku())[0]; + $simpleSku = $configurableChild->getSku(); + $simpleId = $this->productRepository->get($simpleSku)->getId(); + + $attributesInfo = []; + $superAttribute = []; + foreach ($options as $option) { + $attributesInfo[] = [ + "label" => $option->getLabel(), + "value" => $option['options']['0']['label'], + "option_id" => $option->getAttributeId(), + "option_value" => $option->getValues()[0]->getValueIndex() + ]; + $superAttribute[$option->getAttributeId()] = $option->getValues()[0]->getValueIndex(); + } + + $configurableBuyRequest = [ + "info_buyRequest" => [ + "uenc" => "aHR0cDovL21hZ2UyLmNvbS9jYXRlZ29yeS0xLmh0bWw", + "product" => $configurableId, + "selected_configurable_option" => $simpleId, + "related_product" => "", + "super_attribute" => $superAttribute, + "qty" => 1 + ], + "attributes_info" => $attributesInfo, + "simple_name" => $configurableChild->getName(), + "simple_sku" => $configurableChild->getSku(), + ]; + $simpleBuyRequest = [ + "info_buyRequest" => [ + "uenc" => "aHR0cDovL21hZ2VudG8uZGV2L2NvbmZpZ3VyYWJsZS1wcm9kdWN0LTEuaHRtbA,,", + "product" => $configurableId, + "selected_configurable_option" => $simpleId, + "related_product" => "", + "super_attribute" => $superAttribute, + "qty" => "1" + ] + ]; + + $quoteConfigurableBuyRequest = $configurableBuyRequest['info_buyRequest']; + $quoteSimpleBuyRequest = $simpleBuyRequest['info_buyRequest']; + unset($quoteConfigurableBuyRequest['selected_configurable_option']); + unset($quoteSimpleBuyRequest['selected_configurable_option']); + + $productsResult[$key]['id'] = $configurableId; + $productsResult[$key]['sku'] = $simpleSku; + $productsResult[$key]['name'] = $configurableProduct->getName(); + $productsResult[$key]['childId'] = $simpleId; + $productsResult[$key]['buyRequest'] = [ + 'order' => $this->serializer->serialize($configurableBuyRequest), + 'quote' => $this->serializer->serialize($quoteConfigurableBuyRequest), + 'super_attribute' => $this->serializer->serialize($superAttribute) + ]; + $productsResult[$key]['childBuyRequest'] = [ + 'order' => $this->serializer->serialize($simpleBuyRequest), + 'quote' => $this->serializer->serialize($quoteSimpleBuyRequest), + ]; + } + return $productsResult; + } + + /** + * Commit all active transactions at the end of the batch. + * + * Many transactions may exist, since generation process creates a transaction per each available DB connection. + * + * @return void + */ + private function commitBatch() + { + foreach ($this->resourceConnections as $connection) { + if ($connection->getTransactionLevel() > 0) { + $connection->commit(); + $connection->beginTransaction(); + } + } + } + + /** + * Get sequence for order items. + * + * @param int $maxItemId + * @param int $requestedOrders + * @param int $maxItemsPerOrder + * @return \Generator + */ + private function getItemIdSequence($maxItemId, $requestedOrders, $maxItemsPerOrder) + { + $requestedItems = $maxItemId + ($requestedOrders + 1) * $maxItemsPerOrder; + for ($i = $maxItemId + 1; $i <= $requestedItems; $i++) { + yield $i; + } + } + + /** + * Get real table name for db table, validated by db adapter. + * In case prefix or other features mutating default table names are used. + * + * @param string $tableName + * @param string $resourceName + * @return string + */ + private function getTableName($tableName, $resourceName) + { + /** @var \Magento\Framework\Model\ResourceModel\Db\AbstractDb $resource */ + $resource = $this->fixtureModel->getObjectManager()->get($resourceName); + return $this->getConnection($resourceName)->getTableName($resource->getTable($tableName)); + } + + /** + * Get connection to database for specified resource. + * + * @param string $resourceName + * @return \Magento\Framework\DB\Adapter\AdapterInterface + */ + private function getConnection($resourceName) + { + $resource = $this->fixtureModel->getObjectManager()->get($resourceName); + return $resource->getConnection(); + } +} diff --git a/setup/src/Magento/Setup/Fixtures/Quote/QuoteGeneratorFactory.php b/setup/src/Magento/Setup/Fixtures/Quote/QuoteGeneratorFactory.php new file mode 100644 index 0000000000000..e904d21e0980c --- /dev/null +++ b/setup/src/Magento/Setup/Fixtures/Quote/QuoteGeneratorFactory.php @@ -0,0 +1,50 @@ +objectManager = $objectManager; + $this->instanceName = $instanceName; + } + + /** + * Create class instance with specified parameters. + * + * @param array $data [optional] + * @return mixed + */ + public function create(array $data = []) + { + return $this->objectManager->create($this->instanceName, $data); + } +} diff --git a/setup/src/Magento/Setup/Fixtures/_files/quote_fixture_data.json b/setup/src/Magento/Setup/Fixtures/_files/quote_fixture_data.json new file mode 100644 index 0000000000000..f1a8710af4114 --- /dev/null +++ b/setup/src/Magento/Setup/Fixtures/_files/quote_fixture_data.json @@ -0,0 +1,188 @@ +{ + "quote": { + "entity_id": "'%entityId%'", + "store_id": "'%productStoreId%'", + "created_at": "'%time%'", + "updated_at": "'1970-01-01 03:00:00'", + "converted_at": "NULL", + "is_active": 0, + "is_virtual": 0, + "is_multi_shipping": 0, + "items_count": "'%itemsPerOrder%'", + "items_qty": "'%itemsPerOrder%'", + "orig_order_id": 0, + "store_to_base_rate": 0.0000, + "store_to_quote_rate": 0.0000, + "base_currency_code": "'USD'", + "store_currency_code": "'USD'", + "quote_currency_code": "'USD'", + "grand_total": 25.3000, + "base_grand_total": 25.3000, + "checkout_method": "'guest'", + "customer_id": "NULL", + "customer_tax_class_id": 3, + "customer_group_id": 0, + "customer_email": "'%email%'", + "customer_prefix": "NULL", + "customer_firstname": "NULL", + "customer_middlename": "NULL", + "customer_lastname": "NULL", + "customer_suffix": "NULL", + "customer_dob": "NULL", + "customer_note": "NULL", + "customer_note_notify": 1, + "customer_is_guest": 1, + "remote_ip": "'127.0.0.1'", + "applied_rule_ids": "'1'", + "reserved_order_id": "NULL", + "password_hash": "NULL", + "coupon_code": "NULL", + "global_currency_code": "'USD'", + "base_to_global_rate": 1.0000, + "base_to_quote_rate": 1.0000, + "customer_taxvat": "NULL", + "customer_gender": "NULL", + "subtotal": 17.0000, + "base_subtotal": 17.0000, + "subtotal_with_discount": 15.3000, + "base_subtotal_with_discount": 15.3000, + "is_changed": 1, + "trigger_recollect": 0, + "ext_shipping_info": "NULL", + "is_persistent": 0, + "gift_message_id": "NULL", + "_table": "quote", + "_resource": "Magento\\Quote\\Model\\ResourceModel\\Quote" + }, + "quote_address": { + "address_id": "'%orderAddressId%'", + "quote_id": "'%entityId%'", + "created_at": "'%time%'", + "updated_at": "'1970-01-01 03:00:00'", + "customer_id": "NULL", + "save_in_address_book": 1, + "customer_address_id": "NULL", + "address_type": "'%addressType%'", + "email": "'%email%'", + "prefix": "NULL", + "firstname": "'%firstName%'", + "middlename": "NULL", + "lastname": "'%lastName%'", + "suffix": "NULL", + "company": "'%company%'", + "street": "'%address%'", + "city": "'%city%'", + "region": "'%state%'", + "region_id": "1", + "postcode": "'%zip%'", + "country_id": "'%country%'", + "telephone": "'%phone%'", + "fax": "NULL", + "same_as_billing": 0, + "collect_shipping_rates": 0, + "shipping_method": "'flatrate_flatrate'", + "shipping_description": "'Flat Rate - Fixed'", + "weight": 0.0000, + "subtotal": 0.0000, + "base_subtotal": 0.0000, + "subtotal_with_discount": 0.0000, + "base_subtotal_with_discount": 0.0000, + "tax_amount": 0.0000, + "base_tax_amount": 0.0000, + "shipping_amount": 0.0000, + "base_shipping_amount": 0.0000, + "shipping_tax_amount": "NULL", + "base_shipping_tax_amount": "NULL", + "discount_amount": 0.0000, + "base_discount_amount": 0.0000, + "grand_total": 0.0000, + "base_grand_total": 0.0000, + "customer_notes": "NULL", + "applied_taxes": "NULL", + "discount_description": "NULL", + "shipping_discount_amount": "NULL", + "base_shipping_discount_amount": "NULL", + "subtotal_incl_tax": 0.0000, + "base_subtotal_total_incl_tax": "NULL", + "discount_tax_compensation_amount": 0.0000, + "base_discount_tax_compensation_amount": 0.0000, + "shipping_discount_tax_compensation_amount": 0.0000, + "base_shipping_discount_tax_compensation_amnt": "NULL", + "shipping_incl_tax": "NULL", + "base_shipping_incl_tax": "NULL", + "free_shipping": 0, + "vat_id": "NULL", + "vat_is_valid": "NULL", + "vat_request_id": "NULL", + "vat_request_date": "NULL", + "vat_request_success": "NULL", + "gift_message_id": "NULL", + "_table": "quote_address", + "_resource": "Magento\\Quote\\Model\\ResourceModel\\Quote\\Address" + }, + "quote_item": { + "item_id": "'%itemId%'", + "quote_id": "'%entityId%'", + "created_at": "'1970-01-01 03:00:00'", + "updated_at": "'1970-01-01 03:00:00'", + "product_id": "'%productId%'", + "store_id": "'%productStoreId%'", + "parent_item_id": "%parentItemId%", + "is_virtual": "0", + "sku": "'%sku%'", + "name": "'%name%'", + "description": "NULL", + "applied_rule_ids": "'1'", + "additional_data": "NULL", + "is_qty_decimal": "0", + "no_discount": "0", + "weight": "1.0000", + "qty": "1.0000", + "price": "8.5000", + "base_price": "8.5000", + "custom_price": "NULL", + "discount_percent": "10.0000", + "discount_amount": "0.8500", + "base_discount_amount": "0.8500", + "tax_percent": "0.0000", + "tax_amount": "0.0000", + "base_tax_amount": "0.0000", + "row_total": "8.5000", + "base_row_total": "8.5000", + "row_total_with_discount": "0.0000", + "row_weight": "1.0000", + "product_type": "'simple'", + "base_tax_before_discount": "NULL", + "tax_before_discount": "NULL", + "original_custom_price": "NULL", + "redirect_url": "NULL", + "base_cost": "NULL", + "price_incl_tax": "8.5000", + "base_price_incl_tax": "8.5000", + "row_total_incl_tax": "8.5000", + "base_row_total_incl_tax": "8.5000", + "discount_tax_compensation_amount": "0.0000", + "base_discount_tax_compensation_amount": "0.0000", + "free_shipping": "0", + "gift_message_id": "NULL", + "weee_tax_applied": "NULL", + "weee_tax_applied_amount": "NULL", + "weee_tax_applied_row_amount": "NULL", + "weee_tax_disposition": "NULL", + "weee_tax_row_disposition": "NULL", + "base_weee_tax_applied_amount": "NULL", + "base_weee_tax_applied_row_amnt": "NULL", + "base_weee_tax_disposition": "NULL", + "base_weee_tax_row_disposition": "NULL", + "_table": "quote_item", + "_resource": "Magento\\Quote\\Model\\ResourceModel\\Quote\\Item" + }, + "quote_item_option": { + "item_id": "'%itemId%'", + "product_id": "'%productId%'", + "code": "'%code%'", + "value": "'%value%'", + "_table": "quote_item_option", + "_resource": "Magento\\Quote\\Model\\ResourceModel\\Quote\\Item\\Option" + } +} From c219919b8d07dc7cb8c89c15deb79b6e8a783635 Mon Sep 17 00:00:00 2001 From: Yauheni Grouk Date: Wed, 28 Jun 2017 18:16:49 +0300 Subject: [PATCH 055/151] MAGETWO-70163: Add quote generaion ability for fixtures generation tool - Fix issues in quote generator - Covered code with unit tests - Static tests fixes - Code style issues are fixed - Fix integration tests fail - Fix unit tests fails --- .../Fixtures/Quote/QuoteConfiguration.php | 21 +- .../Setup/Fixtures/Quote/QuoteGenerator.php | 114 +++---- .../Fixtures/Quote/QuoteConfigurationTest.php | 74 +++++ .../Quote/QuoteGeneratorFactoryTest.php | 60 ++++ .../Fixtures/Quote/QuoteGeneratorTest.php | 290 ++++++++++++++++++ 5 files changed, 491 insertions(+), 68 deletions(-) create mode 100644 setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteConfigurationTest.php create mode 100644 setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteGeneratorFactoryTest.php create mode 100644 setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteGeneratorTest.php diff --git a/setup/src/Magento/Setup/Fixtures/Quote/QuoteConfiguration.php b/setup/src/Magento/Setup/Fixtures/Quote/QuoteConfiguration.php index b2169a2b33200..0e6f8559ed54a 100644 --- a/setup/src/Magento/Setup/Fixtures/Quote/QuoteConfiguration.php +++ b/setup/src/Magento/Setup/Fixtures/Quote/QuoteConfiguration.php @@ -115,25 +115,24 @@ public function load() 'fixture_data_filename', dirname(__DIR__) . DIRECTORY_SEPARATOR . "_files" . DIRECTORY_SEPARATOR . $this->fixtureDataFilename ); + $this->accumulateData(); - \Magento\Framework\DataObject\Mapper::accumulateByMap( - [$this->fixtureModel, 'getValue'], - [$this, 'setNotEmptyData'], - $this->_globalMap - ); return $this; } /** - * @param string|array $key - * @param mixed $value + * Accumulate data from fixute model to object values. + * * @return $this */ - public function setNotEmptyData($key, $value) + private function accumulateData() { - if (null === $value) { - return $this; + foreach ($this->_globalMap as $getKey => $setKey) { + $value = $this->fixtureModel->getValue($getKey); + if (null !== $value) { + $this->setData($setKey, $value); + } } - return $this->setData($key, $value); + return $this; } } diff --git a/setup/src/Magento/Setup/Fixtures/Quote/QuoteGenerator.php b/setup/src/Magento/Setup/Fixtures/Quote/QuoteGenerator.php index 979818759addb..0a63fa5799715 100644 --- a/setup/src/Magento/Setup/Fixtures/Quote/QuoteGenerator.php +++ b/setup/src/Magento/Setup/Fixtures/Quote/QuoteGenerator.php @@ -113,7 +113,7 @@ public function __construct( } /** - * Prepare and save quotes in database + * Prepare and save quotes in database. * * @throws \Exception * @return void @@ -135,13 +135,12 @@ public function generateQuotes() $maxItemsPerOrder ); $this->productStubData = $this->prepareProductsForQuote(); - $this->prepareQueryTemplates(); $entityId = $this->getMaxEntityId('quote', \Magento\Quote\Model\ResourceModel\Quote::class, 'entity_id'); $quoteQty = $this->config->getExistsQuoteQuantity(); $batchNumber = 0; - while ($quoteQty <= $this->config->getRequiredQuoteQuantity()) { + while ($quoteQty < $this->config->getRequiredQuoteQuantity()) { $entityId++; $batchNumber++; $quoteQty++; @@ -171,7 +170,7 @@ public function generateQuotes() } /** - * Save quote and quote items + * Save quote and quote items. * * @param int $entityId * @param \Generator $itemIdSequence @@ -215,30 +214,18 @@ private function saveQuoteWithQuoteItems($entityId, \Generator $itemIdSequence) $itemIdSequence->next(); } - $type = Configurable::TYPE_CODE; - for ($i = 0; $i < $productCount[$type]; $i++) { - // Generate parent item - $parentItemId = $itemIdSequence->current(); - $this->saveParentItemConfigurableData($entityId, $i, $parentItemId, Configurable::TYPE_CODE, $quote); - $itemIdSequence->next(); - - // Generate child item - $itemId = $itemIdSequence->current(); - $this->saveChildItemConfigurable($entityId, $i, $itemId, $parentItemId, Configurable::TYPE_CODE, $quote); - $itemIdSequence->next(); - } - - $type = QuoteConfiguration::BIG_CONFIGURABLE_TYPE; - for ($i = 0; $i < $productCount[$type]; $i++) { - // Generate parent item - $parentItemId = $itemIdSequence->current(); - $this->saveParentItemConfigurableData($entityId, $i, $parentItemId, $type, $quote); - $itemIdSequence->next(); - - // Generate child item - $itemId = $itemIdSequence->current(); - $this->saveChildItemConfigurable($entityId, $i, $itemId, $parentItemId, $type, $quote); - $itemIdSequence->next(); + foreach ([Configurable::TYPE_CODE, QuoteConfiguration::BIG_CONFIGURABLE_TYPE] as $type) { + for ($i = 0; $i < $productCount[$type]; $i++) { + // Generate parent item + $parentItemId = $itemIdSequence->current(); + $this->saveParentItemConfigurableData($entityId, $i, $parentItemId, $type, $quote); + $itemIdSequence->next(); + + // Generate child item + $itemId = $itemIdSequence->current(); + $this->saveChildItemConfigurable($entityId, $i, $itemId, $parentItemId, $type, $quote); + $itemIdSequence->next(); + } } } @@ -351,23 +338,23 @@ private function saveChildItemConfigurable($entityId, $index, $itemId, $parentIt /** * Get store id for quote item by product index. * - * @param int $index + * @param int $entityId * @return int */ - private function getStubProductStoreId($index) + private function getStubProductStoreId($entityId) { - return $this->productStubData[$index % count($this->productStubData)][0]; + return $this->productStubData[$this->getProductStubIndex($entityId)][0]; } /** * Get store name for quote item by product index. * - * @param int $index + * @param int $entityId * @return string */ - private function getStubProductStoreName($index) + private function getStubProductStoreName($entityId) { - return $this->productStubData[$index % count($this->productStubData)][1]; + return $this->productStubData[$this->getProductStubIndex($entityId)][1]; } /** @@ -380,7 +367,7 @@ private function getStubProductStoreName($index) */ private function getStubProductId($entityId, $index, $type) { - return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['id']; + return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['id']; } /** @@ -393,7 +380,7 @@ private function getStubProductId($entityId, $index, $type) */ private function getStubProductSku($entityId, $index, $type) { - return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['sku']; + return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['sku']; } /** @@ -406,7 +393,7 @@ private function getStubProductSku($entityId, $index, $type) */ private function getStubProductName($entityId, $index, $type) { - return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['name']; + return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['name']; } /** @@ -419,7 +406,7 @@ private function getStubProductName($entityId, $index, $type) */ private function getStubProductBuyRequest($entityId, $index, $type) { - return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['buyRequest']; + return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['buyRequest']; } /** @@ -432,7 +419,7 @@ private function getStubProductBuyRequest($entityId, $index, $type) */ private function getStubProductChildBuyRequest($entityId, $index, $type) { - return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['childBuyRequest']; + return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['childBuyRequest']; } /** @@ -445,7 +432,20 @@ private function getStubProductChildBuyRequest($entityId, $index, $type) */ private function getStubProductChildId($entityId, $index, $type) { - return $this->productStubData[$entityId % count($this->productStubData)][2][$type][$index]['childId']; + return $this->productStubData[$this->getProductStubIndex($entityId)][2][$type][$index]['childId']; + } + + /** + * Get index of item in product stub array. + * + * @param int $entityId + * @return int + */ + private function getProductStubIndex($entityId) + { + $storeCount = count($this->productStubData); + $qty = intdiv($this->config->getRequiredQuoteQuantity(), $storeCount); + return intdiv($entityId, $qty) % $storeCount; } /** @@ -476,6 +476,7 @@ private function getAddressDataFixture() private function prepareProductsForQuote() { $result = []; + foreach ($this->storeManager->getStores() as $store) { $productsResult = []; $this->storeManager->setCurrentStore($store->getId()); @@ -485,23 +486,21 @@ private function prepareProductsForQuote() $this->getProductIds($store, Type::TYPE_SIMPLE, $this->config->getSimpleCountTo()) ); } - if ($this->config->getConfigurableCountTo() > 0) { - $productsResult[Configurable::TYPE_CODE] = $this->prepareConfigurableProducts( - $this->getProductIds( - $store, - Configurable::TYPE_CODE, - $this->config->getConfigurableCountTo() - ) - ); - } - if ($this->config->getBigConfigurableCountTo() > 0) { - $productsResult[QuoteConfiguration::BIG_CONFIGURABLE_TYPE] = $this->prepareConfigurableProducts( - $this->getProductIds( - $store, - QuoteConfiguration::BIG_CONFIGURABLE_TYPE, - $this->config->getBigConfigurableCountTo() - ) - ); + $configurables = [ + Configurable::TYPE_CODE => $this->config->getConfigurableCountTo(), + QuoteConfiguration::BIG_CONFIGURABLE_TYPE => $this->config->getBigConfigurableCountTo(), + ]; + + foreach ($configurables as $type => $qty) { + if ($qty > 0) { + $productsResult[$type] = $this->prepareConfigurableProducts( + $this->getProductIds( + $store, + $type, + $qty + ) + ); + } } $result[] = [ @@ -514,6 +513,7 @@ private function prepareProductsForQuote() $productsResult ]; } + return $result; } diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteConfigurationTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteConfigurationTest.php new file mode 100644 index 0000000000000..8a35fe5f0a76b --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteConfigurationTest.php @@ -0,0 +1,74 @@ +fixtureModelMock = $this->getMockBuilder(\Magento\Setup\Fixtures\FixtureModel::class) + ->disableOriginalConstructor() + ->getMock(); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->fixture = $objectManager->getObject( + \Magento\Setup\Fixtures\Quote\QuoteConfiguration::class, + [ + 'fixtureModel' => $this->fixtureModelMock + ] + ); + } + + /** + * Test load method. + * + * @return void + */ + public function testLoad() + { + $dir = str_replace('Test/Unit/', '', dirname(__DIR__)); + $expectedResult = [ + 'simple_count_to' => 1, + 'simple_count_from' => 1, + 'configurable_count_to' => 1, + 'configurable_count_from' => 1, + 'big_configurable_count_to' => 1, + 'big_configurable_count_from' => 1, + 'fixture_data_filename' => + $dir . DIRECTORY_SEPARATOR . "_files" . DIRECTORY_SEPARATOR . 'orders_fixture_data.json', + 'order_quotes_enable' => 1, + ]; + $this->fixtureModelMock->expects($this->atLeastOnce()) + ->method('getValue') + ->withConsecutive( + ['order_simple_product_count_to'], + ['order_simple_product_count_from'], + ['order_configurable_product_count_to'], + ['order_configurable_product_count_from'], + ['order_big_configurable_product_count_to'], + ['order_big_configurable_product_count_from'], + ['order_quotes_enable',] + )->willReturn(1); + $this->assertSame($expectedResult, $this->fixture->load()->getData()); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteGeneratorFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteGeneratorFactoryTest.php new file mode 100644 index 0000000000000..5b5b6b2b571d1 --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteGeneratorFactoryTest.php @@ -0,0 +1,60 @@ +objectManager = $this->getMockBuilder(\Magento\Framework\ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->fixture = $objectManager->getObject( + \Magento\Setup\Fixtures\Quote\QuoteGeneratorFactory::class, + [ + 'objectManager' => $this->objectManager, + 'instanceName' => \Magento\Setup\Fixtures\Quote\QuoteGenerator::class, + ] + ); + } + + /** + * Test create method. + * + * @return void + */ + public function testCreate() + { + $result = $this->getMockBuilder(\Magento\Setup\Fixtures\Quote\QuoteGenerator::class) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManager->expects($this->once()) + ->method('create') + ->with(\Magento\Setup\Fixtures\Quote\QuoteGenerator::class, []) + ->willReturn($result); + + $this->assertSame($result, $this->fixture->create([])); + } +} diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteGeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteGeneratorTest.php new file mode 100644 index 0000000000000..02e0fe271a552 --- /dev/null +++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/Quote/QuoteGeneratorTest.php @@ -0,0 +1,290 @@ +fixtureModelMock = $this->getMockBuilder(\Magento\Setup\Fixtures\FixtureModel::class) + ->disableOriginalConstructor() + ->getMock(); + $this->storeManager = $this->getMockBuilder(\Magento\Store\Model\StoreManagerInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->productRepository = $this->getMockBuilder(\Magento\Catalog\Api\ProductRepositoryInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->optionRepository = $this->getMockBuilder( + \Magento\ConfigurableProduct\Api\OptionRepositoryInterface::class + ) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->productCollectionFactory = $this->getMockBuilder( + \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class + ) + ->disableOriginalConstructor() + ->setMethods(['create']) + ->getMock(); + $this->linkManagement = $this->getMockBuilder(\Magento\ConfigurableProduct\Api\LinkManagementInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->serializer = $this->getMockBuilder(\Magento\Framework\Serialize\SerializerInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->config = $this->getMockBuilder(\Magento\Setup\Fixtures\Quote\QuoteConfiguration::class) + ->disableOriginalConstructor() + ->setMethods( + [ + 'getSimpleCountTo', + 'getConfigurableCountTo', + 'getBigConfigurableCountTo', + 'getRequiredQuoteQuantity', + 'getFixtureDataFilename', + 'getExistsQuoteQuantity', + ] + ) + ->getMock(); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + + $this->fixture = $objectManager->getObject( + \Magento\Setup\Fixtures\Quote\QuoteGenerator::class, + [ + 'fixtureModel' => $this->fixtureModelMock, + 'storeManager' => $this->storeManager, + 'productRepository' => $this->productRepository, + 'optionRepository' => $this->optionRepository, + 'productCollectionFactory' => $this->productCollectionFactory, + 'linkManagement' => $this->linkManagement, + 'serializer' => $this->serializer, + 'config' => $this->config, + ] + ); + } + + /** + * Test generateQuotes method. + * + * @return void + */ + public function testGenerateQuotes() + { + $storeId = 1; + $websiteId = 1; + $storeGroupId = 1; + $simpleProductIds = [1, 2]; + $configurableProductId = [3]; + $bigConfigurableProductId = [4]; + $dir = str_replace('Test/Unit/', '', dirname(__DIR__)); + $store = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $website = $this->getMockBuilder(\Magento\Store\Api\Data\WebsiteInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $storeGroup = $this->getMockBuilder(\Magento\Store\Api\Data\GroupInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $productCollection = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $select = $this->getMockBuilder(\Magento\Framework\DB\Select::class) + ->disableOriginalConstructor() + ->getMock(); + $this->config->expects($this->atLeastOnce())->method('getSimpleCountTo')->willReturn(2); + $this->config->expects($this->atLeastOnce())->method('getConfigurableCountTo')->willReturn(1); + $this->config->expects($this->atLeastOnce())->method('getBigConfigurableCountTo')->willReturn(1); + $this->config->expects($this->atLeastOnce())->method('getRequiredQuoteQuantity')->willReturn(1); + $this->config->expects($this->atLeastOnce())->method('getExistsQuoteQuantity')->willReturn(0); + $this->config->expects($this->atLeastOnce()) + ->method('getFixtureDataFilename') + ->willReturn($dir . DIRECTORY_SEPARATOR . "_files" . DIRECTORY_SEPARATOR . 'orders_fixture_data.json'); + $this->storeManager->expects($this->atLeastOnce())->method('getStores')->willReturn([$store]); + $this->storeManager->expects($this->atLeastOnce()) + ->method('getWebsite')->with($websiteId)->willReturn($website); + $this->storeManager->expects($this->atLeastOnce()) + ->method('getGroup')->with($storeGroupId)->willReturn($storeGroup); + $store->expects($this->atLeastOnce())->method('getId')->willReturn($storeId); + $store->expects($this->atLeastOnce())->method('getWebsiteId')->willReturn($websiteId); + $store->expects($this->atLeastOnce())->method('getStoreGroupId')->willReturn($storeGroupId); + $website->expects($this->atLeastOnce())->method('getName')->willReturn('Default'); + $store->expects($this->atLeastOnce())->method('getName')->willReturn('Default'); + $storeGroup->expects($this->atLeastOnce())->method('getName')->willReturn('Default'); + $this->storeManager->expects($this->atLeastOnce())->method('setCurrentStore')->with($storeId); + $this->productCollectionFactory->expects($this->atLeastOnce()) + ->method('create')->willReturn($productCollection); + $productCollection->expects($this->atLeastOnce())->method('addStoreFilter')->with(1)->willReturnSelf(); + $productCollection->expects($this->atLeastOnce())->method('addWebsiteFilter')->with(1)->willReturnSelf(); + $productCollection->expects($this->atLeastOnce())->method('getSelect')->willReturn($select); + $select->expects($this->atLeastOnce()) + ->method('where') + ->withConsecutive( + [' type_id = \'simple\' '], + [' sku NOT LIKE \'Big%\' '], + [' type_id = \'configurable\' '], + [' sku NOT LIKE \'Big%\' '], + [' type_id = \'configurable\' '], + [' sku LIKE \'Big%\' '] + )->willReturnSelf(); + $productCollection->expects($this->atLeastOnce()) + ->method('getAllIds') + ->withConsecutive([2], [1], [1]) + ->willReturnOnConsecutiveCalls($simpleProductIds, $configurableProductId, $bigConfigurableProductId); + $this->prepareProducts(); + $this->mockConnection(); + $this->fixture->generateQuotes(); + } + + /** + * Prepare products mocks. + * + * @return void + */ + private function prepareProducts() + { + $product = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $configurableChild = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $childProduct = $this->getMockBuilder(\Magento\Catalog\Api\Data\ProductInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $option = $this->getMockBuilder(\Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class) + ->disableOriginalConstructor() + ->getMock(); + $optionValue = $this->getMockBuilder(\Magento\ConfigurableProduct\Api\Data\OptionValueInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $this->productRepository->expects($this->atLeastOnce()) + ->method('getById') + ->withConsecutive([1], [2], [3], [4]) + ->willReturn($product); + $product->expects($this->atLeastOnce()) + ->method('getSku')->willReturnOnConsecutiveCalls('sku1', 'sku2', 'sku3', 'sku3', 'sku4', 'sku4'); + $product->expects($this->atLeastOnce()) + ->method('getName')->willReturnOnConsecutiveCalls('name1', 'name2', 'name3', 'name4'); + $this->serializer->expects($this->atLeastOnce()) + ->method('serialize') + ->willReturn('a:1:{i:10;i:1;}'); + $this->optionRepository->expects($this->atLeastOnce()) + ->method('getList') + ->withConsecutive(['sku3'], ['sku4']) + ->willReturn([$option]); + $this->linkManagement->expects($this->atLeastOnce()) + ->method('getChildren') + ->withConsecutive(['sku3'], ['sku4']) + ->willReturn([$configurableChild]); + $configurableChild->expects($this->atLeastOnce()) + ->method('getSku') + ->willReturnOnConsecutiveCalls('childSku3', 'childSku3', 'childSku4', 'childSku4'); + $this->productRepository->expects($this->atLeastOnce()) + ->method('get') + ->withConsecutive(['childSku3'], ['childSku4']) + ->willReturn($childProduct); + $childProduct->expects($this->atLeastOnce())->method('getId')->willReturnOnConsecutiveCalls(10, 11); + $option->expects($this->atLeastOnce())->method('getLabel')->willReturnOnConsecutiveCalls('label3', 'label4'); + $option->expects($this->atLeastOnce()) + ->method('getAttributeId')->willReturnOnConsecutiveCalls(10, 10, 20, 20); + $option->expects($this->atLeastOnce())->method('getValues')->willReturn([$optionValue]); + $optionValue->expects($this->atLeastOnce())->method('getValueIndex')->willReturn(1); + $configurableChild->expects($this->atLeastOnce()) + ->method('getName')->willReturnOnConsecutiveCalls('childName3', 'childName4'); + } + + /** + * Mock connection to DB and queries. + * + * @return void + */ + private function mockConnection() + { + $objectManager = $this->getMockBuilder(\Magento\Framework\ObjectManagerInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $resource = $this->getMockBuilder(\Magento\Framework\Model\ResourceModel\Db\AbstractDb::class) + ->disableOriginalConstructor() + ->getMock(); + $connection = $this->getMockBuilder(\Magento\Framework\DB\Adapter\AdapterInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + $statement = $this->getMockBuilder(\Magento\Framework\DB\Statement\Pdo\Mysql::class) + ->disableOriginalConstructor() + ->getMock(); + $this->fixtureModelMock->expects($this->atLeastOnce())->method('getObjectManager')->willReturn($objectManager); + $objectManager->expects($this->atLeastOnce()) + ->method('get') + ->willReturn($resource); + $resource->expects($this->atLeastOnce())->method('getConnection')->willReturn($connection); + $connection->expects($this->atLeastOnce()) + ->method('getTableName') + ->willReturn('table_name'); + $resource->expects($this->atLeastOnce()) + ->method('getTable') + ->willReturn('table_name'); + $connection->expects($this->atLeastOnce()) + ->method('query') + ->willReturn($statement); + $connection->expects($this->atLeastOnce())->method('getTransactionLevel')->willReturn(0); + $connection->expects($this->atLeastOnce())->method('beginTransaction')->willReturnSelf(); + $statement->expects($this->atLeastOnce())->method('fetchColumn')->with(0)->willReturn(25); + } +} From 41a71ab3d3a5ba57b4421a44fff252b2bd4405ca Mon Sep 17 00:00:00 2001 From: Andrei Malets Date: Thu, 31 Aug 2017 15:02:47 +0300 Subject: [PATCH 056/151] MAGETWO-72076: Update benchmark.jmx and README files in Performance Toolkit, add performance analytics script - Refactored script for generation of aggregate reports --- setup/performance-toolkit/README.md | 4 +- .../{generate.php => common.php} | 94 ++++++++++--------- .../aggregate-report/generate-b2c.php | 30 ++++++ 3 files changed, 84 insertions(+), 44 deletions(-) rename setup/performance-toolkit/aggregate-report/{generate.php => common.php} (79%) create mode 100644 setup/performance-toolkit/aggregate-report/generate-b2c.php diff --git a/setup/performance-toolkit/README.md b/setup/performance-toolkit/README.md index d29e752a34985..2c1c92d4ca919 100644 --- a/setup/performance-toolkit/README.md +++ b/setup/performance-toolkit/README.md @@ -259,7 +259,7 @@ By default, the percentage ratio between thread groups is as follows: ### Results Interpretation -In order to build an aggregate report from the results of the `benchmark.kmx` scenario run, use the script `generate.php` in the folder `setup/performance-toolkit/aggregate-report`. +In order to build an aggregate report from the results of the `benchmark.kmx` scenario run, use the script `generate-b2c.php` in the folder `setup/performance-toolkit/aggregate-report`. The script parses the JTL file and generates an aggregate report in CSV format. The report consists of the 4 sections separated by two empty lines: @@ -281,7 +281,7 @@ After that, the information about memory usage for each request will be logged i To generate the aggregate report, run the following command from the Magento root directory: - php setup/performance-toolkit/aggregate-report/generate.php -j {path to folder with JTL file}/jmeter_report.jtl -m var/log/memory_usage.log -o aggregate_report.csv + php setup/performance-toolkit/aggregate-report/generate-b2c.php -j {path to folder with JTL file}/jmeter_report.jtl -m var/log/memory_usage.log -o aggregate_report.csv **Legacy Scenario** diff --git a/setup/performance-toolkit/aggregate-report/generate.php b/setup/performance-toolkit/aggregate-report/common.php similarity index 79% rename from setup/performance-toolkit/aggregate-report/generate.php rename to setup/performance-toolkit/aggregate-report/common.php index cf4ca6f06a862..cd0d11c8b1acc 100644 --- a/setup/performance-toolkit/aggregate-report/generate.php +++ b/setup/performance-toolkit/aggregate-report/common.php @@ -5,32 +5,41 @@ */ /** -* @SuppressWarnings(PHPMD.CyclomaticComplexity) -* @SuppressWarnings(PHPMD.NPathComplexity) -*/ - -$usageMessage = - 'Usage:' . PHP_EOL - . ' php generate.php -j jmeter_report.jtl -m memory_usage.log -o output_file.csv' . PHP_EOL - . PHP_EOL - . 'Parameters:' . PHP_EOL - . ' -j - jmeter report file' . PHP_EOL - . ' -m - memory usage report file (optional)' . PHP_EOL - . ' -o - output report file' . PHP_EOL - . ' -f - include failed requests in report (optional)' . PHP_EOL; + * @SuppressWarnings(PHPMD.CyclomaticComplexity) + * @SuppressWarnings(PHPMD.NPathComplexity) + */ -$args = getopt('j:m:o:f'); -if (empty($args['j']) || empty($args['o'])) { - echo $usageMessage; - exit(0); -} +/** + * Generate aggregate report in CSV format based on JTL file. + * + * @param array $mapping + * @param callable $generateSummary + * @param callable $rowCallback [optional] + * @return void + */ +function generateReport(array $mapping, callable $generateSummary, callable $rowCallback = null) +{ + $usageMessage = + 'Usage:' . PHP_EOL + . ' php generate.php -j jmeter_report.jtl -m memory_usage.log -o output_file.csv' . PHP_EOL + . PHP_EOL + . 'Parameters:' . PHP_EOL + . ' -j - jmeter report file' . PHP_EOL + . ' -m - memory usage report file (optional)' . PHP_EOL + . ' -o - output report file' . PHP_EOL + . ' -f - include failed requests in report (optional)' . PHP_EOL; -require_once("b2c_mappings.php"); + $args = getopt('j:m:o:f'); + if (empty($args['j']) || empty($args['o'])) { + echo $usageMessage; + exit(0); + } -list($jmeterData, $executionTime) = parseJmeterReport($args['j'], isset($args['f'])); -$memoryUsageData = !empty($args['m']) ? parseMemoryUsageLog($args['m']) : []; -$aggregatedResult = prepareAggregatedResult($jmeterData, $memoryUsageData, $mapping); -parseReportAndWriteToCsv($aggregatedResult, $executionTime, $args['o']); + list($jmeterData, $executionTime) = parseJmeterReport($args['j'], isset($args['f'])); + $memoryUsageData = !empty($args['m']) ? parseMemoryUsageLog($args['m']) : []; + $aggregatedResult = prepareAggregatedResult($jmeterData, $memoryUsageData, $mapping); + parseReportAndWriteToCsv($aggregatedResult, $executionTime, $args['o'], $generateSummary, $rowCallback); +} /** * Read memory usage log into array. @@ -116,6 +125,7 @@ function prepareAggregatedResult(array $jmeterData, array $memoryUsageData, arra $aggregatedResult[$key]['label'] = $mapping['label']; $aggregatedResult[$key]['scenario'] = $mapping['scenario'] ?? 'Total'; $aggregatedResult[$key]['is_service_url'] = $mapping['is_service_url'] ?? false; + $aggregatedResult[$key]['is_requisition'] = $mapping['is_requisition'] ?? false; $aggregatedResult[$key]['is_storefront'] = $mapping['is_storefront'] ?? false; $aggregatedResult[$key]['time'] = []; $aggregatedResult[$key]['labels'] = []; @@ -161,10 +171,17 @@ function ($a, $b) { * @param array $aggregatedResult * @param int $executionTime * @param string $outputFile Path to the output report + * @param callable $generateSummary + * @param callable $rowCallback [optional] * @return void */ -function parseReportAndWriteToCsv(array $aggregatedResult, $executionTime, $outputFile) -{ +function parseReportAndWriteToCsv( + array $aggregatedResult, + $executionTime, + $outputFile, + callable $generateSummary, + callable $rowCallback = null +) { $headersArray = [ 'Scenario', 'Label', @@ -179,23 +196,7 @@ function parseReportAndWriteToCsv(array $aggregatedResult, $executionTime, $outp 'Memory Usage, Mb' ]; $fp = fopen($outputFile, 'w'); - - $pageViews = 0; - $checkoutCount = 0; - foreach ($aggregatedResult as $row) { - if ($row['is_storefront']) { - $pageViews += count($row['time']); - } - if (strpos($row['label'], 'Checkout Success Page') !== false) { - $checkoutCount += count($row['time']); - } - } - fputcsv($fp, ['Checkouts Per Hour:', round($checkoutCount / $executionTime * 3600000, 2)]); - fputcsv($fp, ['Page Views Per Hour:', round($pageViews / $executionTime * 3600000, 2)]); - fputcsv($fp, ['Test Duration, s:', round($executionTime / 1000)]); - fputcsv($fp, ['']); - fputcsv($fp, ['']); - fputcsv($fp, $headersArray); + $generateSummary($fp, $aggregatedResult, $headersArray, $executionTime); foreach ($aggregatedResult as $row) { if (count($row['time']) && !$row['is_service_url']) { sort($row['time']); @@ -212,6 +213,9 @@ function parseReportAndWriteToCsv(array $aggregatedResult, $executionTime, $outp round(count($row['time']) / $executionTime * 3600000, 2), $row['memory'] ]; + if ($rowCallback) { + $rowCallback($row, $ar); + } fputcsv($fp, $ar); } } @@ -233,6 +237,9 @@ function parseReportAndWriteToCsv(array $aggregatedResult, $executionTime, $outp round(count($row['time']) / $executionTime * 3600000, 2), $row['memory'] ]; + if ($rowCallback) { + $rowCallback($row, $ar); + } fputcsv($fp, $ar); } } @@ -241,6 +248,9 @@ function parseReportAndWriteToCsv(array $aggregatedResult, $executionTime, $outp foreach ($aggregatedResult as $row) { if (count($row['time']) == 0) { $ar = [$row['scenario'], $row['label'], '-', '-', '-', '-', '-', '-', '-', 0, '-']; + if ($rowCallback) { + $rowCallback($row, $ar); + } fputcsv($fp, $ar); } } diff --git a/setup/performance-toolkit/aggregate-report/generate-b2c.php b/setup/performance-toolkit/aggregate-report/generate-b2c.php new file mode 100644 index 0000000000000..2fa9339f35b7e --- /dev/null +++ b/setup/performance-toolkit/aggregate-report/generate-b2c.php @@ -0,0 +1,30 @@ + Date: Thu, 31 Aug 2017 15:49:36 +0300 Subject: [PATCH 057/151] MAGETWO-72076: Update benchmark.jmx and README files in Performance Toolkit, add performance analytics script - Coding style fixes --- setup/performance-toolkit/aggregate-report/common.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/setup/performance-toolkit/aggregate-report/common.php b/setup/performance-toolkit/aggregate-report/common.php index cd0d11c8b1acc..ae332ecbf9e70 100644 --- a/setup/performance-toolkit/aggregate-report/common.php +++ b/setup/performance-toolkit/aggregate-report/common.php @@ -4,11 +4,6 @@ * See COPYING.txt for license details. */ -/** - * @SuppressWarnings(PHPMD.CyclomaticComplexity) - * @SuppressWarnings(PHPMD.NPathComplexity) - */ - /** * Generate aggregate report in CSV format based on JTL file. * @@ -32,7 +27,7 @@ function generateReport(array $mapping, callable $generateSummary, callable $row $args = getopt('j:m:o:f'); if (empty($args['j']) || empty($args['o'])) { echo $usageMessage; - exit(0); + return; } list($jmeterData, $executionTime) = parseJmeterReport($args['j'], isset($args['f'])); @@ -73,6 +68,7 @@ function parseMemoryUsageLog($memoryUsageReport) * @param string $jmeterReport Path to the JTL report * @param bool $includeErrors If true failed requests are included in report * @return array First element - requests grouped by title, second - total execution time of the scenario + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ function parseJmeterReport($jmeterReport, $includeErrors) { @@ -117,6 +113,7 @@ function parseJmeterReport($jmeterReport, $includeErrors) * @param array $memoryUsageData * @param array $mappings * @return array + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ function prepareAggregatedResult(array $jmeterData, array $memoryUsageData, array $mappings) { @@ -174,6 +171,7 @@ function ($a, $b) { * @param callable $generateSummary * @param callable $rowCallback [optional] * @return void + * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ function parseReportAndWriteToCsv( array $aggregatedResult, From 6bf9e1b31583946f9b52b8793d74545f72a0877a Mon Sep 17 00:00:00 2001 From: Joan He Date: Thu, 31 Aug 2017 08:12:08 -0500 Subject: [PATCH 058/151] MAGETWO-71706: PayPal Express Checkout payment method doesn't appear after enabling PayPal Payments Advanced on website level --- app/code/Magento/Paypal/Model/AbstractConfig.php | 5 +++++ app/code/Magento/Paypal/view/adminhtml/web/js/rules.js | 2 ++ 2 files changed, 7 insertions(+) diff --git a/app/code/Magento/Paypal/Model/AbstractConfig.php b/app/code/Magento/Paypal/Model/AbstractConfig.php index 5b0ef45431bb6..3b0f7b974829c 100644 --- a/app/code/Magento/Paypal/Model/AbstractConfig.php +++ b/app/code/Magento/Paypal/Model/AbstractConfig.php @@ -61,6 +61,11 @@ abstract class AbstractConfig implements ConfigInterface */ private static $bnCode = 'Magento_Cart_%s'; + /** + * @var \Magento\Framework\App\Config\ScopeConfigInterface + */ + protected $_scopeConfig; + /** * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig */ diff --git a/app/code/Magento/Paypal/view/adminhtml/web/js/rules.js b/app/code/Magento/Paypal/view/adminhtml/web/js/rules.js index ac888c8c39cc5..102e05048e29a 100644 --- a/app/code/Magento/Paypal/view/adminhtml/web/js/rules.js +++ b/app/code/Magento/Paypal/view/adminhtml/web/js/rules.js @@ -117,6 +117,7 @@ define([ * @param {String} enabler */ disableSolution = function (solution, enabler) { + setSolutionUsedefaultEnabled(solution, enabler); setSolutionMarkEnabled(solution, enabler, false); setSolutionSelectEnabled(solution, enabler, false); setSolutionPropEnabled(solution, enabler, false); @@ -129,6 +130,7 @@ define([ * @param {String} enabler */ enableSolution = function (solution, enabler) { + setSolutionUsedefaultEnabled(solution, enabler); setSolutionPropEnabled(solution, enabler); setSolutionSelectEnabled(solution, enabler); setSolutionMarkEnabled(solution, enabler); From 329c459ead315d55c92cdeb43c77f5ac2381a187 Mon Sep 17 00:00:00 2001 From: Yauheni Grouk Date: Thu, 31 Aug 2017 16:53:18 +0300 Subject: [PATCH 059/151] MAGETWO-70163: Add quote generaion ability for fixtures generation tool - Fix issues in quote generator - Covered code with unit tests - Static tests fixes - Code style issues are fixed - Fix integration tests fail - Fix unit tests fails --- .../Fixtures/_files/quote_fixture_data.json | 188 ------------------ 1 file changed, 188 deletions(-) delete mode 100644 setup/src/Magento/Setup/Fixtures/_files/quote_fixture_data.json diff --git a/setup/src/Magento/Setup/Fixtures/_files/quote_fixture_data.json b/setup/src/Magento/Setup/Fixtures/_files/quote_fixture_data.json deleted file mode 100644 index f1a8710af4114..0000000000000 --- a/setup/src/Magento/Setup/Fixtures/_files/quote_fixture_data.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "quote": { - "entity_id": "'%entityId%'", - "store_id": "'%productStoreId%'", - "created_at": "'%time%'", - "updated_at": "'1970-01-01 03:00:00'", - "converted_at": "NULL", - "is_active": 0, - "is_virtual": 0, - "is_multi_shipping": 0, - "items_count": "'%itemsPerOrder%'", - "items_qty": "'%itemsPerOrder%'", - "orig_order_id": 0, - "store_to_base_rate": 0.0000, - "store_to_quote_rate": 0.0000, - "base_currency_code": "'USD'", - "store_currency_code": "'USD'", - "quote_currency_code": "'USD'", - "grand_total": 25.3000, - "base_grand_total": 25.3000, - "checkout_method": "'guest'", - "customer_id": "NULL", - "customer_tax_class_id": 3, - "customer_group_id": 0, - "customer_email": "'%email%'", - "customer_prefix": "NULL", - "customer_firstname": "NULL", - "customer_middlename": "NULL", - "customer_lastname": "NULL", - "customer_suffix": "NULL", - "customer_dob": "NULL", - "customer_note": "NULL", - "customer_note_notify": 1, - "customer_is_guest": 1, - "remote_ip": "'127.0.0.1'", - "applied_rule_ids": "'1'", - "reserved_order_id": "NULL", - "password_hash": "NULL", - "coupon_code": "NULL", - "global_currency_code": "'USD'", - "base_to_global_rate": 1.0000, - "base_to_quote_rate": 1.0000, - "customer_taxvat": "NULL", - "customer_gender": "NULL", - "subtotal": 17.0000, - "base_subtotal": 17.0000, - "subtotal_with_discount": 15.3000, - "base_subtotal_with_discount": 15.3000, - "is_changed": 1, - "trigger_recollect": 0, - "ext_shipping_info": "NULL", - "is_persistent": 0, - "gift_message_id": "NULL", - "_table": "quote", - "_resource": "Magento\\Quote\\Model\\ResourceModel\\Quote" - }, - "quote_address": { - "address_id": "'%orderAddressId%'", - "quote_id": "'%entityId%'", - "created_at": "'%time%'", - "updated_at": "'1970-01-01 03:00:00'", - "customer_id": "NULL", - "save_in_address_book": 1, - "customer_address_id": "NULL", - "address_type": "'%addressType%'", - "email": "'%email%'", - "prefix": "NULL", - "firstname": "'%firstName%'", - "middlename": "NULL", - "lastname": "'%lastName%'", - "suffix": "NULL", - "company": "'%company%'", - "street": "'%address%'", - "city": "'%city%'", - "region": "'%state%'", - "region_id": "1", - "postcode": "'%zip%'", - "country_id": "'%country%'", - "telephone": "'%phone%'", - "fax": "NULL", - "same_as_billing": 0, - "collect_shipping_rates": 0, - "shipping_method": "'flatrate_flatrate'", - "shipping_description": "'Flat Rate - Fixed'", - "weight": 0.0000, - "subtotal": 0.0000, - "base_subtotal": 0.0000, - "subtotal_with_discount": 0.0000, - "base_subtotal_with_discount": 0.0000, - "tax_amount": 0.0000, - "base_tax_amount": 0.0000, - "shipping_amount": 0.0000, - "base_shipping_amount": 0.0000, - "shipping_tax_amount": "NULL", - "base_shipping_tax_amount": "NULL", - "discount_amount": 0.0000, - "base_discount_amount": 0.0000, - "grand_total": 0.0000, - "base_grand_total": 0.0000, - "customer_notes": "NULL", - "applied_taxes": "NULL", - "discount_description": "NULL", - "shipping_discount_amount": "NULL", - "base_shipping_discount_amount": "NULL", - "subtotal_incl_tax": 0.0000, - "base_subtotal_total_incl_tax": "NULL", - "discount_tax_compensation_amount": 0.0000, - "base_discount_tax_compensation_amount": 0.0000, - "shipping_discount_tax_compensation_amount": 0.0000, - "base_shipping_discount_tax_compensation_amnt": "NULL", - "shipping_incl_tax": "NULL", - "base_shipping_incl_tax": "NULL", - "free_shipping": 0, - "vat_id": "NULL", - "vat_is_valid": "NULL", - "vat_request_id": "NULL", - "vat_request_date": "NULL", - "vat_request_success": "NULL", - "gift_message_id": "NULL", - "_table": "quote_address", - "_resource": "Magento\\Quote\\Model\\ResourceModel\\Quote\\Address" - }, - "quote_item": { - "item_id": "'%itemId%'", - "quote_id": "'%entityId%'", - "created_at": "'1970-01-01 03:00:00'", - "updated_at": "'1970-01-01 03:00:00'", - "product_id": "'%productId%'", - "store_id": "'%productStoreId%'", - "parent_item_id": "%parentItemId%", - "is_virtual": "0", - "sku": "'%sku%'", - "name": "'%name%'", - "description": "NULL", - "applied_rule_ids": "'1'", - "additional_data": "NULL", - "is_qty_decimal": "0", - "no_discount": "0", - "weight": "1.0000", - "qty": "1.0000", - "price": "8.5000", - "base_price": "8.5000", - "custom_price": "NULL", - "discount_percent": "10.0000", - "discount_amount": "0.8500", - "base_discount_amount": "0.8500", - "tax_percent": "0.0000", - "tax_amount": "0.0000", - "base_tax_amount": "0.0000", - "row_total": "8.5000", - "base_row_total": "8.5000", - "row_total_with_discount": "0.0000", - "row_weight": "1.0000", - "product_type": "'simple'", - "base_tax_before_discount": "NULL", - "tax_before_discount": "NULL", - "original_custom_price": "NULL", - "redirect_url": "NULL", - "base_cost": "NULL", - "price_incl_tax": "8.5000", - "base_price_incl_tax": "8.5000", - "row_total_incl_tax": "8.5000", - "base_row_total_incl_tax": "8.5000", - "discount_tax_compensation_amount": "0.0000", - "base_discount_tax_compensation_amount": "0.0000", - "free_shipping": "0", - "gift_message_id": "NULL", - "weee_tax_applied": "NULL", - "weee_tax_applied_amount": "NULL", - "weee_tax_applied_row_amount": "NULL", - "weee_tax_disposition": "NULL", - "weee_tax_row_disposition": "NULL", - "base_weee_tax_applied_amount": "NULL", - "base_weee_tax_applied_row_amnt": "NULL", - "base_weee_tax_disposition": "NULL", - "base_weee_tax_row_disposition": "NULL", - "_table": "quote_item", - "_resource": "Magento\\Quote\\Model\\ResourceModel\\Quote\\Item" - }, - "quote_item_option": { - "item_id": "'%itemId%'", - "product_id": "'%productId%'", - "code": "'%code%'", - "value": "'%value%'", - "_table": "quote_item_option", - "_resource": "Magento\\Quote\\Model\\ResourceModel\\Quote\\Item\\Option" - } -} From e0470a4c47a9363b0d8ad526464db921c22dcd9c Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Thu, 31 Aug 2017 11:29:26 -0500 Subject: [PATCH 060/151] MAGETWO-71765: Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Move formatter call out from group comment block. - Fix function spacing. - Updated rounding to use the same function as well in other sale payment action cases. --- app/code/Magento/Paypal/Model/Payflowpro.php | 8 +++----- .../Magento/Paypal/Test/Unit/Model/PayflowproTest.php | 9 +++++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app/code/Magento/Paypal/Model/Payflowpro.php b/app/code/Magento/Paypal/Model/Payflowpro.php index d86aff2bfdb7d..8d59a9578a17d 100644 --- a/app/code/Magento/Paypal/Model/Payflowpro.php +++ b/app/code/Magento/Paypal/Model/Payflowpro.php @@ -28,6 +28,8 @@ */ class Payflowpro extends \Magento\Payment\Model\Method\Cc implements GatewayInterface { + use Formatter; + /** * Transaction action codes */ @@ -84,10 +86,6 @@ class Payflowpro extends \Magento\Payment\Model\Method\Cc implements GatewayInte const PNREF = 'pnref'; - use Formatter; - - /**#@-*/ - /**#@-*/ protected $_responseParamsMappings = [ 'firstname' => 'billtofirstname', @@ -417,7 +415,7 @@ public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount) { if ($payment->getAdditionalInformation(self::PNREF)) { $request = $this->buildBasicRequest(); - $request->setAmt(round($amount, 2)); + $request->setAmt($this->formatPrice($amount)); $request->setTrxtype(self::TRXTYPE_SALE); $request->setOrigid($payment->getAdditionalInformation(self::PNREF)); $payment->unsAdditionalInformation(self::PNREF); diff --git a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php index 573a2ffb5e1d4..1c622e6f2ff8e 100644 --- a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php +++ b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php @@ -345,10 +345,11 @@ public function testCaptureAmountRounding($amount, $setAmount, $expectedResult) $this->gatewayMock->expects($this->once()) ->method('postRequest') ->with( - $this->callback(function($request) use ($expectedResult){ - return is_callable([$request, 'getAmt']) && - $request->getAmt() == $expectedResult; - }), + $this->callback(function($request) use ($expectedResult) + { + return is_callable([$request, 'getAmt']) && $request->getAmt() == $expectedResult; + } + ), $this->isInstanceOf(PayflowConfig::class) ) ->willReturn($response); From 414338bd17fae8d7541acbf7c46ad993ea8e7d39 Mon Sep 17 00:00:00 2001 From: Deepty Thampy Date: Thu, 31 Aug 2017 12:17:34 -0500 Subject: [PATCH 061/151] MAGETWO-71666: Unable to save product after failed attempt - Added functional test changes to avoid failure in EE --- .../Block/Adminhtml/Product/ProductForm.php | 17 +++++++++++++++++ .../ReSavingProductAfterInitialSaveTest.php | 5 +++++ 2 files changed, 22 insertions(+) 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 fe20855033bed..9331c2c987549 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 @@ -30,6 +30,13 @@ class ProductForm extends FormSections */ protected $attribute = './/*[contains(@class,"label")]/span[text()="%s"]'; + /** + * Product new from date field on the product form + * + * @var string + */ + protected $news_from_date ='[name="product[news_from_date]"]'; + /** * Attributes Search modal locator. * @@ -261,4 +268,14 @@ public function getAttributeElement(CatalogProductAttribute $attribute) \Magento\Catalog\Test\Block\Adminhtml\Product\Attribute\CustomAttribute::class ); } + + /** + * @param $sectionName + * @return bool + */ + public function isProductNewFromDateVisible($sectionName) + { + $this->openSection($sectionName); + return $this->_rootElement->find($this->news_from_date, Locator::SELECTOR_CSS)->isVisible(); + } } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php index 87c91288fe7df..01a71ce07fcac 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php @@ -91,6 +91,11 @@ public function test( ) { $this->productGrid->open(); $this->productGrid->getGridPageActionBlock()->addProduct('simple'); + + if(!($this->newProductPage->getProductForm()->isProductNewFromDateVisible('product-details'))) + { + $this->markTestSkipped('This is a CE only test.'); + } $this->newProductPage->getProductForm()->fill($originalProduct); $this->catalogProductEdit->getProductForm()->fill($productWithValidFromDate); $this->catalogProductEdit->getFormPageActions()->save(); From 427379305e23f9b41d5cf129d509244ba899a776 Mon Sep 17 00:00:00 2001 From: Andrei Malets Date: Fri, 1 Sep 2017 10:18:37 +0300 Subject: [PATCH 062/151] MAGETWO-72076: Update benchmark.jmx and README files in Performance Toolkit, add performance analytics script - Benchmarks updated --- setup/performance-toolkit/benchmark.jmx | 7 - setup/performance-toolkit/benchmark_2015.jmx | 1977 +++++++++++++----- 2 files changed, 1421 insertions(+), 563 deletions(-) diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index a7884bbbca194..9c165bdf3d7de 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -22502,13 +22502,6 @@ vars.put("pages_count_customer", String.valueOf(pageCountCustomers)); = true - - false - giftwrapping[quote][863][design] - - = - true - false order[comment][customer_note] diff --git a/setup/performance-toolkit/benchmark_2015.jmx b/setup/performance-toolkit/benchmark_2015.jmx index aa7a160ebe72f..55220815fee2c 100644 --- a/setup/performance-toolkit/benchmark_2015.jmx +++ b/setup/performance-toolkit/benchmark_2015.jmx @@ -389,6 +389,11 @@ ${__P(catalogBrowsingByCustomerPercent,100)} = + + categories_count + ${__P(categories_count,100)} + = + checkoutByGuest ${__P(checkoutByGuest,0)} @@ -409,6 +414,11 @@ ${__P(checkoutByCustomerPercent,100)} = + + configurable_products_count + ${__P(configurable_products_count,30)} + = + customer_checkout_percent ${__P(customer_checkout_percent,4)} @@ -539,6 +549,11 @@ ${__P(scenario,)} = + + seedForRandom + ${__P(seedForRandom,1)} + = + searchQuick ${__P(searchQuick,0)} @@ -574,6 +589,11 @@ ${__P(setupAndTearDownThread,1)} = + + simple_products_count + ${__P(simple_products_count,30)} + = + sprint_identifier ${__P(sprint_identifier,)} @@ -663,7 +683,7 @@ 4 - + @@ -685,7 +705,7 @@ - + @@ -701,7 +721,7 @@ true - + stoptest @@ -717,8 +737,17 @@ - - props.remove("category_url_key"); + + +// Init and save random object for get random values with/without seed +import java.util.Random; +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom}); +} +props.put("RandomObject", random); + +props.remove("category_url_key"); props.remove("category_url_keys_list"); props.remove("category_name"); props.remove("category_names_list"); @@ -960,56 +989,159 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr Refresh all cache types - - - - - - - - - - - ${base_path} - GET - true - false - true - false - false - - Site - Get Category 1 - + - - - <span>Category ([0-9]+)</span> + + + + Content-Type + application/json + + + Accept + */* + - Assertion.response_data - false - 2 - + - - false - category_url_keys - <a href="http://${host}${base_path}(index.php/)?([^'"]+)${url_suffix}" class="level-top" > - $2$ - - -1 - simple_product_1_url_key - - - - false - category_names - <a href="http://${host}${base_path}(index.php/)?category-([0-9]+)${url_suffix}" class="level-top" ><span>([^'"]+)</span> - $3$ - - -1 - simple_product_1_url_key - + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + true + path + = + true + searchCriteria[filterGroups][0][filters][0][field] + + + true + 1/2/% + = + true + searchCriteria[filterGroups][0][filters][0][value] + + + true + like + = + true + searchCriteria[filterGroups][0][filters][0][conditionType] + + + true + level + = + true + searchCriteria[filterGroups][1][filters][0][field] + + + true + 2 + = + true + searchCriteria[filterGroups][1][filters][0][value] + + + true + ${categories_count} + = + true + searchCriteria[pageSize] + + + + + + + + + + ${base_path}rest/V1/categories/list + GET + true + false + false + false + false + + + + + false + category_url_keys + url_key\",\"value\":\"(.*?)\" + $1$ + + -1 + + + + false + category_names + name\":\"(.*?)\" + $1$ + + -1 + + + category_url_keys @@ -1086,54 +1218,31 @@ props.put("category_name", vars.get("category_name")); false - - - - - - - - - - - ${base_path}catalogsearch/result/?limit=30&q=Simple - GET - true - false - true - false - false - - + - - - (?i)Search results for: (.+?)Simple(.+?) + + + + Content-Type + application/json + + + Accept + */* + - Assertion.response_data - false - 2 - - - - false - simple_products_url_keys - <a class="product-item-link"(?s).+?href="http://${host}${base_path}(index.php/)?([^'"]+)${url_suffix}">(?s).+?Simple - $2$ - - -1 - + - - - simple_products_url_keys - simple_products_url_key - true - - - - - + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + @@ -1141,8 +1250,8 @@ props.put("category_name", vars.get("category_name")); - ${base_path}${simple_products_url_key}${url_suffix} - GET + ${base_path}rest/V1/integration/admin/token + POST true false true @@ -1151,79 +1260,112 @@ props.put("category_name", vars.get("category_name")); - - - simple_product_id - .//input[@type="hidden" and @name="product"]/@value - false - true - false - - - - - simple_product_title - .//*[@data-ui-id='page-title-wrapper']/text() - false - true - false - - - - false - simple_product_uenc - "uenc":"([^"]+)" - $1$ - - 1 - simple_product_1_url_key - + + admin_token + $ + + + BODY + - + - ^\d+$ + ^[a-z0-9-]+$ Assertion.response_data false 1 variable - simple_product_id + admin_token - - - ^.+$ + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + true + type_id + = + true + searchCriteria[filterGroups][0][filters][0][field] + + + true + simple + = + true + searchCriteria[filterGroups][0][filters][0][value] + + + true + ${simple_products_count} + = + true + searchCriteria[pageSize] + - Assertion.response_data - false - 1 - variable - simple_product_title - + + + + + + + + ${base_path}rest/V1/products + GET + true + false + true + false + false + + + + + false + simple_products_url_keys + url_key\",\"value\":\"(.*?)\" + $1$ + + -1 + - - - ^[a-z0-9-]+$ - - Assertion.response_data - false - 1 - variable - simple_products_url_key - + + false + simple_product_ids + \"id\":(\d+), + $1$ + + -1 + - - - ^.+$ - - Assertion.response_data - false - 1 - variable - simple_product_uenc - + + false + simple_product_names + name\":\"(.*?)\" + $1$ + + -1 + + + + simple_product_ids + simple_product_id + true + + 1 @@ -1236,6 +1378,7 @@ props.put("category_name", vars.get("category_name")); import java.util.ArrayList; import java.util.HashMap; +import org.apache.commons.codec.binary.Base64; // If it is first iteration of cycle then recreate productList if (1 == Integer.parseInt(vars.get("simple_products_counter"))) { @@ -1244,13 +1387,14 @@ if (1 == Integer.parseInt(vars.get("simple_products_counter"))) { } else { productList = props.get("simple_products_list"); } - +String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); +encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map Map productMap = new HashMap(); productMap.put("id", vars.get("simple_product_id")); -productMap.put("title", vars.get("simple_product_title")); -productMap.put("url_key", vars.get("simple_products_url_key")); -productMap.put("uenc", vars.get("simple_product_uenc")); +productMap.put("title", vars.get("simple_product_names_" + vars.get("simple_products_counter"))); +productMap.put("url_key", vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))); +productMap.put("uenc", new String(encodedUrl)); // Collect products map in products list productList.add(productMap); @@ -1260,55 +1404,31 @@ productList.add(productMap); - - - - - - - - - - - ${base_path}catalogsearch/result/?limit=30&q=Configurable - GET - true - false - true - false - false - - + - - - Search results for: (.+?)Configurable(.+?) - <div class="search results"> + + + + Content-Type + application/json + + + Accept + */* + - Assertion.response_data - false - 2 - - - - false - configurable_products_url_keys - <a class="product-item-link"(?s).+?href="http://${host}${base_path}(index.php/)?([^'"]+)${url_suffix}">(?s).+?Configurable - $2$ - - -1 - + - - - configurable_products_url_keys - configurable_products_url_key - true - - - - - + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + @@ -1316,8 +1436,8 @@ productList.add(productMap); - ${base_path}${configurable_products_url_key}${url_suffix} - GET + ${base_path}rest/V1/integration/admin/token + POST true false true @@ -1326,119 +1446,121 @@ productList.add(productMap); - - - configurable_product_id - .//input[@type="hidden" and @name="product"]/@value - false - true - false - + + admin_token + $ + + + BODY + - - - configurable_product_title - .//*[@data-ui-id='page-title-wrapper']/text() - false - true - false - + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + - + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + true + type_id + = + true + searchCriteria[filterGroups][0][filters][0][field] + + + true + configurable + = + true + searchCriteria[filterGroups][0][filters][0][value] + + + true + ${configurable_products_count} + = + true + searchCriteria[pageSize] + + + + + + + + + + ${base_path}rest/V1/products + GET + true + false + true + false + false + + + + false - configurable_product_uenc - "uenc":"([^"]+)" + configurable_products_url_keys + url_key\",\"value\":\"(.*?)\" $1$ - 1 - simple_product_1_url_key + -1 - + false - configurable_product_attribute_id - "[sp|json]+Config": \{"attributes":\{"(\d+)" + configurable_product_ids + \"id\":(\d+), $1$ - 1 + -1 - + false - configurable_product_attribute_option_id - "options":\[\{"id":"(\d+)" + configurable_product_names + name\":\"(.*?)\" $1$ - 1 + -1 - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - configurable_product_id - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - configurable_product_title - - - - - ^[a-z0-9-]+$ - - Assertion.response_data - false - 1 - variable - configurable_products_url_key - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - configurable_product_attribute_id - - - - - ^\d+$ - - Assertion.response_data - false - 1 - variable - configurable_product_attribute_option_id - - - - - ^.+$ - - Assertion.response_data - false - 1 - variable - configurable_product_uenc - + + false + configurable_product_skus + sku\":\"(.*?)\" + $1$ + + -1 + + + + configurable_product_ids + configurable_product_id + true + + 1 @@ -1451,6 +1573,7 @@ productList.add(productMap); import java.util.ArrayList; import java.util.HashMap; +import org.apache.commons.codec.binary.Base64; // If it is first iteration of cycle then recreate productList if (1 == Integer.parseInt(vars.get("configurable_products_counter"))) { @@ -1460,17 +1583,18 @@ if (1 == Integer.parseInt(vars.get("configurable_products_counter"))) { productList = props.get("configurable_products_list"); } +String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); +encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map Map productMap = new HashMap(); productMap.put("id", vars.get("configurable_product_id")); -productMap.put("title", vars.get("configurable_product_title")); -productMap.put("url_key", vars.get("configurable_products_url_key")); -productMap.put("uenc", vars.get("configurable_product_uenc")); -productMap.put("attribute_id", vars.get("configurable_product_attribute_id")); -productMap.put("attribute_option_id", vars.get("configurable_product_attribute_option_id")); +productMap.put("title", vars.get("configurable_product_names_" + vars.get("configurable_products_counter"))); +productMap.put("sku", vars.get("configurable_product_skus_" + vars.get("configurable_products_counter"))); +productMap.put("url_key", vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))); +productMap.put("uenc", new String(encodedUrl)); // Collect products map in products list -productList.add(productMap); +productList.add(productMap); false @@ -1519,7 +1643,7 @@ manager.add(cookie); - + @@ -2104,7 +2228,7 @@ if ("${cache_indicator}" == "1") { - + continue @@ -2120,57 +2244,28 @@ if ("${cache_indicator}" == "1") { - - rv1 - '.' - 1 - 999999 - 1 - true - - - - - rv2 - '.' - 1 - 999999 - 2 - true - - - - - rv3 - '.' - 1 - 999999 - 3 - true - - - Passing arguments between threads - number = (int)(${rv1} * props.get("simple_products_list").size()); + +number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); -number1 = (int)(${rv2} * props.get("simple_products_list").size()); +number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); -number = (int)(${rv3} * props.get("configurable_products_list").size()); +number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); vars.put("configurable_product_1_id", configurableList.get("id")); -number = (int)(Math.random() * props.get("category_url_keys_list").size()); +number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); vars.put("testLabel", "CatProdBrows"); @@ -2179,7 +2274,7 @@ vars.put("testLabel", "CatProdBrows"); true - + @@ -2210,13 +2305,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2268,13 +2363,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2305,14 +2400,64 @@ vars.put("testLabel", "CatProdBrows"); 2 + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + + + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2343,14 +2488,64 @@ vars.put("testLabel", "CatProdBrows"); 2 + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + - + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + + + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2383,7 +2578,7 @@ vars.put("testLabel", "CatProdBrows"); - + continue @@ -2399,53 +2594,23 @@ vars.put("testLabel", "CatProdBrows"); - - rv1 - '.' - 1 - 999999 - 1 - true - - - - - rv2 - '.' - 1 - 999999 - 2 - true - - - - - rv3 - '.' - 1 - 999999 - 3 - true - - - Passing arguments between threads - number = (int)(${rv1} * props.get("simple_products_list").size()); + number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number1 = (int)(${rv2} * props.get("simple_products_list").size()); +number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_uenc", simpleList.get("uenc")); -number = (int)(${rv3} * props.get("configurable_products_list").size()); +number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); @@ -2454,7 +2619,7 @@ vars.put("configurable_attribute_id", configurableList.get("attribute_id")); vars.put("configurable_option_id", configurableList.get("attribute_option_id")); vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = (int)(Math.random() * props.get("category_url_keys_list").size()); +number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); vars.put("testLabel", "BrowsAddToCart"); @@ -2464,7 +2629,7 @@ vars.put("loadType", "Guest"); true - + @@ -2495,7 +2660,7 @@ vars.put("loadType", "Guest"); - + @@ -2584,13 +2749,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2642,13 +2807,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2679,14 +2844,64 @@ vars.put("loadType", "Guest"); 2 + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + + + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2747,7 +2962,7 @@ vars.put("loadType", "Guest"); - + @@ -2799,7 +3014,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_1_name} to your shopping cart. @@ -2828,13 +3043,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2865,14 +3080,64 @@ vars.put("loadType", "Guest"); 2 + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + - + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + + + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2932,7 +3197,7 @@ vars.put("loadType", "Guest"); - + @@ -2987,7 +3252,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_2_name} to your shopping cart. @@ -3016,13 +3281,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3048,19 +3313,142 @@ vars.put("loadType", "Guest"); <title>${configurable_product_1_name} <span>In stock</span> - Assertion.response_data - false - 2 - + Assertion.response_data + false + 2 + + + + + false + configurable_product_sku + itemprop="sku">([^<]*)<\/ + $1$ + NOT_FOUND + 1 + + + + + + ${think_time_delay_offset} + ${think_time_deviation} + + + + + true + 1 + + + + + + Content-Type + application/json + + + Accept + */* + + + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + + + + + + ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all + GET + true + false + true + false + false + + + + + attribute_ids + $.[*].attribute_id + NO_VALUE + + BODY + + + + option_values + $.[*].values[0].value_index + NO_VALUE + + BODY + + + - - - ${think_time_delay_offset} - ${think_time_deviation} - - - + @@ -3126,8 +3514,38 @@ vars.put("loadType", "Guest"); - - + + + false + + + + try { + attribute_ids = vars.get("attribute_ids"); + option_values = vars.get("option_values"); + attribute_ids = attribute_ids.replace("[","").replace("]","").replace("\"", ""); + option_values = option_values.replace("[","").replace("]","").replace("\"", ""); + attribute_ids_array = attribute_ids.split(","); + option_values_array = option_values.split(","); + args = ctx.getCurrentSampler().getArguments(); + it = args.iterator(); + while (it.hasNext()) { + argument = it.next(); + if (argument.getStringValue().contains("${")) { + args.removeArgument(argument.getName()); + } + } + for (int i = 0; i < attribute_ids_array.length; i++) { + ctx.getCurrentSampler().addArgument("super_attribute[" + attribute_ids_array[i] + "]", option_values_array[i]); + } + } catch (Exception e) { + log.error("eror…", e); + } + + + + + @@ -3182,7 +3600,7 @@ vars.put("loadType", "Guest"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -3212,7 +3630,7 @@ vars.put("loadType", "Guest"); - + continue @@ -3228,53 +3646,24 @@ vars.put("loadType", "Guest"); - - rv1 - '.' - 1 - 999999 - 1 - true - - - - - rv2 - '.' - 1 - 999999 - 2 - true - - - - - rv3 - '.' - 1 - 999999 - 3 - true - - - Passing arguments between threads - number = (int)(${rv1} * props.get("simple_products_list").size()); + +number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number1 = (int)(${rv2} * props.get("simple_products_list").size()); +number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_uenc", simpleList.get("uenc")); -number = (int)(${rv3} * props.get("configurable_products_list").size()); +number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); @@ -3283,7 +3672,7 @@ vars.put("configurable_attribute_id", configurableList.get("attribute_id")); vars.put("configurable_option_id", configurableList.get("attribute_option_id")); vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = (int)(Math.random() * props.get("category_url_keys_list").size()); +number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); vars.put("testLabel", "GuestChkt"); @@ -3293,7 +3682,7 @@ vars.put("loadType", "Guest"); true - + @@ -3324,7 +3713,7 @@ vars.put("loadType", "Guest"); - + @@ -3413,13 +3802,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3471,13 +3860,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3508,14 +3897,64 @@ vars.put("loadType", "Guest"); 2 + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + + + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3576,7 +4015,7 @@ vars.put("loadType", "Guest"); - + @@ -3628,7 +4067,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_1_name} to your shopping cart. @@ -3657,13 +4096,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3694,14 +4133,64 @@ vars.put("loadType", "Guest"); 2 + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + - + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + + + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3761,7 +4250,7 @@ vars.put("loadType", "Guest"); - + @@ -3816,7 +4305,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_2_name} to your shopping cart. @@ -3845,13 +4334,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3882,14 +4371,137 @@ vars.put("loadType", "Guest"); 2 + + + false + configurable_product_sku + itemprop="sku">([^<]*)<\/ + $1$ + NOT_FOUND + 1 + + + + + + ${think_time_delay_offset} + ${think_time_deviation} + + + + + true + 1 + + + + + + Content-Type + application/json + + + Accept + */* + + + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + + + + + + + ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all + GET + true + false + true + false + false + + + + + attribute_ids + $.[*].attribute_id + NO_VALUE + + BODY + + + + option_values + $.[*].values[0].value_index + NO_VALUE + + BODY + + + - - - ${think_time_delay_offset} - ${think_time_deviation} - - - + @@ -3955,8 +4567,38 @@ vars.put("loadType", "Guest"); - - + + + false + + + + try { + attribute_ids = vars.get("attribute_ids"); + option_values = vars.get("option_values"); + attribute_ids = attribute_ids.replace("[","").replace("]","").replace("\"", ""); + option_values = option_values.replace("[","").replace("]","").replace("\"", ""); + attribute_ids_array = attribute_ids.split(","); + option_values_array = option_values.split(","); + args = ctx.getCurrentSampler().getArguments(); + it = args.iterator(); + while (it.hasNext()) { + argument = it.next(); + if (argument.getStringValue().contains("${")) { + args.removeArgument(argument.getName()); + } + } + for (int i = 0; i < attribute_ids_array.length; i++) { + ctx.getCurrentSampler().addArgument("super_attribute[" + attribute_ids_array[i] + "]", option_values_array[i]); + } + } catch (Exception e) { + log.error("eror…", e); + } + + + + + @@ -4011,7 +4653,7 @@ vars.put("loadType", "Guest"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -4040,13 +4682,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4126,13 +4768,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4191,13 +4833,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4256,13 +4898,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4321,13 +4963,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4405,7 +5047,7 @@ vars.put("loadType", "Guest"); - + @@ -4438,7 +5080,7 @@ vars.put("loadType", "Guest"); - + continue @@ -4454,55 +5096,25 @@ vars.put("loadType", "Guest"); - - rv1 - '.' - 1 - 999999 - 1 - true - - - - - rv2 - '.' - 1 - 999999 - 2 - true - - - - - rv3 - '.' - 1 - 999999 - 3 - true - - - Passing arguments between threads import org.apache.jmeter.samplers.SampleResult; -number = (int)(${rv1} * props.get("simple_products_list").size()); +number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number1 = (int)(${rv2} * props.get("simple_products_list").size()); +number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_uenc", simpleList.get("uenc")); -number = (int)(${rv3} * props.get("configurable_products_list").size()); +number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); @@ -4511,7 +5123,7 @@ vars.put("configurable_attribute_id", configurableList.get("attribute_id")); vars.put("configurable_option_id", configurableList.get("attribute_option_id")); vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = (int)(Math.random() * props.get("category_url_keys_list").size()); +number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); @@ -4541,7 +5153,7 @@ vars.put("loadType", "Customer"); true - + @@ -4572,13 +5184,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4609,7 +5221,7 @@ vars.put("loadType", "Customer"); - + @@ -4698,13 +5310,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4784,13 +5396,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4842,13 +5454,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4879,14 +5491,64 @@ vars.put("loadType", "Customer"); 2 + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + - + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + + + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4947,7 +5609,7 @@ vars.put("loadType", "Customer"); - + @@ -4999,7 +5661,7 @@ vars.put("loadType", "Customer"); - + You added ${simple_product_1_name} to your shopping cart. @@ -5028,13 +5690,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5065,14 +5727,64 @@ vars.put("loadType", "Customer"); 2 + + + product_id + .//input[@type="hidden" and @name="product"]/@value + false + true + false + + + + + ^\d+$ + + Assertion.response_data + false + 1 + variable + product_id + + + + + + + + + + + + + + ${base_path}review/product/listAjax/id/${product_id}/ + GET + true + false + true + false + false + + + + + + 200 + + Assertion.response_code + false + 2 + + - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5132,7 +5844,7 @@ vars.put("loadType", "Customer"); - + @@ -5187,7 +5899,7 @@ vars.put("loadType", "Customer"); - + You added ${simple_product_2_name} to your shopping cart. @@ -5216,13 +5928,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5253,14 +5965,137 @@ vars.put("loadType", "Customer"); 2 - - + + + false + configurable_product_sku + itemprop="sku">([^<]*)<\/ + $1$ + NOT_FOUND + 1 + + + + ${think_time_delay_offset} ${think_time_deviation} - + + + true + 1 + + + + + + Content-Type + application/json + + + Accept + */* + + + + + + true + + + + false + {"username":"${admin_user}","password":"${admin_password}"} + = + + + + + + + + + + ${base_path}rest/V1/integration/admin/token + POST + true + false + true + false + false + + + + + admin_token + $ + + + BODY + + + + + ^[a-z0-9-]+$ + + Assertion.response_data + false + 1 + variable + admin_token + + + + + + + Authorization + Bearer ${admin_token} + + + + + + + + + + + + + + + ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all + GET + true + false + true + false + false + + + + + attribute_ids + $.[*].attribute_id + NO_VALUE + + BODY + + + + option_values + $.[*].values[0].value_index + NO_VALUE + + BODY + + + + + @@ -5326,7 +6161,37 @@ vars.put("loadType", "Customer"); - + + + false + + + + try { + attribute_ids = vars.get("attribute_ids"); + option_values = vars.get("option_values"); + attribute_ids = attribute_ids.replace("[","").replace("]","").replace("\"", ""); + option_values = option_values.replace("[","").replace("]","").replace("\"", ""); + attribute_ids_array = attribute_ids.split(","); + option_values_array = option_values.split(","); + args = ctx.getCurrentSampler().getArguments(); + it = args.iterator(); + while (it.hasNext()) { + argument = it.next(); + if (argument.getStringValue().contains("${")) { + args.removeArgument(argument.getName()); + } + } + for (int i = 0; i < attribute_ids_array.length; i++) { + ctx.getCurrentSampler().addArgument("super_attribute[" + attribute_ids_array[i] + "]", option_values_array[i]); + } + } catch (Exception e) { + log.error("eror…", e); + } + + + + From 2fc146e9fbc3eb2a66fb0a37d485487cc5d64a5f Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Fri, 1 Sep 2017 10:37:07 +0300 Subject: [PATCH 063/151] MAGETWO-70819: Widget with condition "special date to" --- .../Magento/CatalogWidget/Block/Product/ProductsList.php | 8 ++++++++ .../Test/Unit/Block/Product/ProductsListTest.php | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php index 8d0da9b67c194..373b88049c7b5 100644 --- a/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php +++ b/app/code/Magento/CatalogWidget/Block/Product/ProductsList.php @@ -259,6 +259,14 @@ protected function getConditions() $conditions = $this->conditionsHelper->decode($conditions); } + foreach ($conditions as $key => $condition) { + if (!empty($condition['attribute']) + && in_array($condition['attribute'], ['special_from_date', 'special_to_date']) + ) { + $conditions[$key]['value'] = date('Y-m-d H:i:s', strtotime($condition['value'])); + } + } + $this->rule->loadPost(['conditions' => $conditions]); return $this->rule->getConditions(); } diff --git a/app/code/Magento/CatalogWidget/Test/Unit/Block/Product/ProductsListTest.php b/app/code/Magento/CatalogWidget/Test/Unit/Block/Product/ProductsListTest.php index a6cb8f3527986..e871ed4359d5c 100644 --- a/app/code/Magento/CatalogWidget/Test/Unit/Block/Product/ProductsListTest.php +++ b/app/code/Magento/CatalogWidget/Test/Unit/Block/Product/ProductsListTest.php @@ -288,6 +288,11 @@ public function testCreateCollection($pagerEnable, $productsCount, $productsPerP $this->collectionFactory->expects($this->once())->method('create')->willReturn($collection); $this->productsList->setData('conditions_encoded', 'some_serialized_conditions'); + $this->widgetConditionsHelper->expects($this->once()) + ->method('decode') + ->with('some_serialized_conditions') + ->willReturn([]); + $this->builder->expects($this->once())->method('attachConditionToCollection') ->with($collection, $this->getConditionsForCollection($collection)) ->willReturnSelf(); From f54e868f5e17fe6a050882c82b127c4aa3c40071 Mon Sep 17 00:00:00 2001 From: Andrei Malets Date: Fri, 1 Sep 2017 11:22:18 +0300 Subject: [PATCH 064/151] MAGETWO-72076: Update benchmark.jmx and README files in Performance Toolkit, add performance analytics script - Added setup/performance-toolkit/aggregate-report folder to blacklist for phpcpd --- .../Magento/Test/Php/_files/phpcpd/blacklist/common.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt index ebe8501337eff..8587abefba576 100644 --- a/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt +++ b/dev/tests/static/testsuite/Magento/Test/Php/_files/phpcpd/blacklist/common.txt @@ -199,3 +199,4 @@ Magento/Framework/MessageQueue/Publisher/Config/PublisherConfigItem Magento/Framework/MessageQueue/Topology/Config/ExchangeConfigItem IntegrationConfig.php *Test.php +setup/performance-toolkit/aggregate-report From 16ec817f371b82e8c5dca701e3c7cd79ca7d5e48 Mon Sep 17 00:00:00 2001 From: Andrei Malets Date: Fri, 1 Sep 2017 11:32:15 +0300 Subject: [PATCH 065/151] MAGETWO-72076: Update benchmark.jmx and README files in Performance Toolkit, add performance analytics script - Synchronize benchmark_2015.jmx and scenario compiled from fragments --- setup/performance-toolkit/benchmark_2015.jmx | 6 ------ 1 file changed, 6 deletions(-) diff --git a/setup/performance-toolkit/benchmark_2015.jmx b/setup/performance-toolkit/benchmark_2015.jmx index 55220815fee2c..625a93c62db86 100644 --- a/setup/performance-toolkit/benchmark_2015.jmx +++ b/setup/performance-toolkit/benchmark_2015.jmx @@ -1,10 +1,4 @@ - From 71e7238728698472743334048bf6740f24aa8e28 Mon Sep 17 00:00:00 2001 From: Sergii Kovalenko Date: Fri, 1 Sep 2017 11:48:40 +0300 Subject: [PATCH 066/151] MAGETWO-71613: [AP: New Order] Tier-prices are not applied on add complex product by SKU --- .../Magento/Sales/Controller/Adminhtml/Order/Create.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php index 21ccf52078b01..1343b77bcd0ae 100644 --- a/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php +++ b/app/code/Magento/Sales/Controller/Adminhtml/Order/Create.php @@ -151,6 +151,8 @@ protected function _processActionData($action = null) 'session' => $this->_getSession(), ]; + $this->_eventManager->dispatch('adminhtml_sales_order_create_process_data_before', $eventData); + /** * Import post data, in order to make order quote valid */ @@ -158,8 +160,6 @@ protected function _processActionData($action = null) $this->_getOrderCreateModel()->importPostData($data); } - $this->_eventManager->dispatch('adminhtml_sales_order_create_process_data_before', $eventData); - /** * Initialize catalog rule data */ @@ -210,6 +210,8 @@ protected function _processActionData($action = null) $this->_getOrderCreateModel()->applySidebarData($data); } + $this->_eventManager->dispatch('adminhtml_sales_order_create_process_item_before', $eventData); + /** * Adding product to quote from shopping cart, wishlist etc. */ @@ -256,6 +258,8 @@ protected function _processActionData($action = null) $this->_getOrderCreateModel()->moveQuoteItem($moveItemId, $moveTo, $moveQty); } + $this->_eventManager->dispatch('adminhtml_sales_order_create_process_item_after', $eventData); + if ($paymentData = $this->getRequest()->getPost('payment')) { $this->_getOrderCreateModel()->getQuote()->getPayment()->addData($paymentData); } From 32a19b4ea0be23c763a0a9cea465cacdbb90ae60 Mon Sep 17 00:00:00 2001 From: Andrei Malets Date: Fri, 1 Sep 2017 12:07:09 +0300 Subject: [PATCH 067/151] MAGETWO-72076: Update benchmark.jmx and README files in Performance Toolkit, add performance analytics script - Synchronize benchmark_2015.jmx and scenario compiled from fragments --- setup/performance-toolkit/benchmark_2015.jmx | 32 ++++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/setup/performance-toolkit/benchmark_2015.jmx b/setup/performance-toolkit/benchmark_2015.jmx index 625a93c62db86..f25ec8f09a6d9 100644 --- a/setup/performance-toolkit/benchmark_2015.jmx +++ b/setup/performance-toolkit/benchmark_2015.jmx @@ -6186,7 +6186,7 @@ vars.put("loadType", "Customer"); - + @@ -6241,7 +6241,7 @@ vars.put("loadType", "Customer"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -6270,13 +6270,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -6396,13 +6396,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6461,13 +6461,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6526,13 +6526,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6591,13 +6591,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -6630,7 +6630,7 @@ vars.put("loadType", "Customer"); - + stoptest @@ -6738,7 +6738,7 @@ props.remove("customer_emails_list"); - + false @@ -6802,7 +6802,7 @@ props.remove("customer_emails_list"); - + false @@ -6838,7 +6838,7 @@ props.remove("customer_emails_list"); ${report_save_path}/detailed-urls-report.log - + false From 38fff10398b550d3a826e63f626ea2f811243685 Mon Sep 17 00:00:00 2001 From: Andrei Malets Date: Fri, 1 Sep 2017 12:43:13 +0300 Subject: [PATCH 068/151] MAGETWO-72076: Update benchmark.jmx and README files in Performance Toolkit, add performance analytics script - Synchronize benchmark_2015.jmx and scenario compiled from fragments --- setup/performance-toolkit/benchmark_2015.jmx | 248 ++++++++++--------- 1 file changed, 127 insertions(+), 121 deletions(-) diff --git a/setup/performance-toolkit/benchmark_2015.jmx b/setup/performance-toolkit/benchmark_2015.jmx index f25ec8f09a6d9..844b5d127a014 100644 --- a/setup/performance-toolkit/benchmark_2015.jmx +++ b/setup/performance-toolkit/benchmark_2015.jmx @@ -1,4 +1,10 @@ + @@ -677,7 +683,7 @@ 4 - + @@ -699,7 +705,7 @@ - + @@ -715,7 +721,7 @@ true - + stoptest @@ -1637,7 +1643,7 @@ manager.add(cookie); - + @@ -2222,7 +2228,7 @@ if ("${cache_indicator}" == "1") { - + continue @@ -2268,7 +2274,7 @@ vars.put("testLabel", "CatProdBrows"); true - + @@ -2299,13 +2305,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2357,13 +2363,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2445,13 +2451,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2533,13 +2539,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2572,7 +2578,7 @@ vars.put("testLabel", "CatProdBrows"); - + continue @@ -2623,7 +2629,7 @@ vars.put("loadType", "Guest"); true - + @@ -2654,7 +2660,7 @@ vars.put("loadType", "Guest"); - + @@ -2743,13 +2749,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2801,13 +2807,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2889,13 +2895,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2956,7 +2962,7 @@ vars.put("loadType", "Guest"); - + @@ -3008,7 +3014,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_1_name} to your shopping cart. @@ -3037,13 +3043,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3125,13 +3131,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3191,7 +3197,7 @@ vars.put("loadType", "Guest"); - + @@ -3246,7 +3252,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_2_name} to your shopping cart. @@ -3275,13 +3281,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3312,7 +3318,7 @@ vars.put("loadType", "Guest"); 2 - + false configurable_product_sku @@ -3323,13 +3329,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true 1 @@ -3442,7 +3448,7 @@ vars.put("loadType", "Guest"); - + @@ -3508,7 +3514,7 @@ vars.put("loadType", "Guest"); - + false @@ -3539,7 +3545,7 @@ vars.put("loadType", "Guest"); - + @@ -3594,7 +3600,7 @@ vars.put("loadType", "Guest"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -3624,7 +3630,7 @@ vars.put("loadType", "Guest"); - + continue @@ -3676,7 +3682,7 @@ vars.put("loadType", "Guest"); true - + @@ -3707,7 +3713,7 @@ vars.put("loadType", "Guest"); - + @@ -3796,13 +3802,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3854,13 +3860,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3942,13 +3948,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4009,7 +4015,7 @@ vars.put("loadType", "Guest"); - + @@ -4061,7 +4067,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_1_name} to your shopping cart. @@ -4090,13 +4096,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4178,13 +4184,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4244,7 +4250,7 @@ vars.put("loadType", "Guest"); - + @@ -4299,7 +4305,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_2_name} to your shopping cart. @@ -4328,13 +4334,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4365,7 +4371,7 @@ vars.put("loadType", "Guest"); 2 - + false configurable_product_sku @@ -4376,13 +4382,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true 1 @@ -4495,7 +4501,7 @@ vars.put("loadType", "Guest"); - + @@ -4561,7 +4567,7 @@ vars.put("loadType", "Guest"); - + false @@ -4592,7 +4598,7 @@ vars.put("loadType", "Guest"); - + @@ -4647,7 +4653,7 @@ vars.put("loadType", "Guest"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -4676,13 +4682,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4762,13 +4768,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4827,13 +4833,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4892,13 +4898,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4957,13 +4963,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -5041,7 +5047,7 @@ vars.put("loadType", "Guest"); - + @@ -5074,7 +5080,7 @@ vars.put("loadType", "Guest"); - + continue @@ -5147,7 +5153,7 @@ vars.put("loadType", "Customer"); true - + @@ -5178,13 +5184,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5215,7 +5221,7 @@ vars.put("loadType", "Customer"); - + @@ -5304,13 +5310,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5390,13 +5396,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5448,13 +5454,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5536,13 +5542,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5603,7 +5609,7 @@ vars.put("loadType", "Customer"); - + @@ -5655,7 +5661,7 @@ vars.put("loadType", "Customer"); - + You added ${simple_product_1_name} to your shopping cart. @@ -5684,13 +5690,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5772,13 +5778,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5838,7 +5844,7 @@ vars.put("loadType", "Customer"); - + @@ -5893,7 +5899,7 @@ vars.put("loadType", "Customer"); - + You added ${simple_product_2_name} to your shopping cart. @@ -5922,13 +5928,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5959,7 +5965,7 @@ vars.put("loadType", "Customer"); 2 - + false configurable_product_sku @@ -5970,13 +5976,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true 1 @@ -6089,7 +6095,7 @@ vars.put("loadType", "Customer"); - + @@ -6155,7 +6161,7 @@ vars.put("loadType", "Customer"); - + false @@ -6186,7 +6192,7 @@ vars.put("loadType", "Customer"); - + @@ -6241,7 +6247,7 @@ vars.put("loadType", "Customer"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -6270,13 +6276,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -6396,13 +6402,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6461,13 +6467,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6526,13 +6532,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6591,13 +6597,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -6630,7 +6636,7 @@ vars.put("loadType", "Customer"); - + stoptest @@ -6738,7 +6744,7 @@ props.remove("customer_emails_list"); - + false @@ -6802,7 +6808,7 @@ props.remove("customer_emails_list"); - + false @@ -6838,7 +6844,7 @@ props.remove("customer_emails_list"); ${report_save_path}/detailed-urls-report.log - + false From f3122175a77c1241c24db2513533ffb548e514f9 Mon Sep 17 00:00:00 2001 From: Iryna Lagno Date: Fri, 1 Sep 2017 12:50:42 +0300 Subject: [PATCH 069/151] MAGETWO-72046: Error processing your request when placing reorder for simple product of configurable if attribute is changed - for 2.2 --- .../ConfigurableProductSales/LICENSE.txt | 48 +++ .../ConfigurableProductSales/LICENSE_AFL.txt | 48 +++ .../OrderedProductAvailabilityChecker.php | 115 +++++++ .../ConfigurableProductSales/README.md | 4 + .../ConfigurableProductSales/composer.json | 28 ++ .../ConfigurableProductSales/etc/di.xml | 16 + .../ConfigurableProductSales/etc/module.xml | 15 + .../ConfigurableProductSales/registration.php | 9 + .../Adminhtml/Order/Create/Reorder.php | 78 ++++- .../OrderedProductAvailabilityChecker.php | 53 +++ ...redProductAvailabilityCheckerInterface.php | 25 ++ .../Reorder/UnavailableProductsProvider.php | 54 +++ .../Adminhtml/Order/Create/ReorderTest.php | 307 ++++++++++++++++++ .../OrderProductAvailabilityCheckerTest.php | 131 ++++++++ .../UnavailableProductsProviderTest.php | 100 ++++++ composer.json | 1 + composer.lock | 2 +- .../UnavailableProductsProviderTest.php | 34 ++ ...der_item_with_configurable_for_reorder.php | 94 ++++++ ...with_configurable_for_reorder_rollback.php | 8 + 20 files changed, 1163 insertions(+), 7 deletions(-) create mode 100644 app/code/Magento/ConfigurableProductSales/LICENSE.txt create mode 100644 app/code/Magento/ConfigurableProductSales/LICENSE_AFL.txt create mode 100644 app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php create mode 100644 app/code/Magento/ConfigurableProductSales/README.md create mode 100644 app/code/Magento/ConfigurableProductSales/composer.json create mode 100644 app/code/Magento/ConfigurableProductSales/etc/di.xml create mode 100644 app/code/Magento/ConfigurableProductSales/etc/module.xml create mode 100644 app/code/Magento/ConfigurableProductSales/registration.php create mode 100644 app/code/Magento/Sales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php create mode 100644 app/code/Magento/Sales/Model/Order/Reorder/OrderedProductAvailabilityCheckerInterface.php create mode 100644 app/code/Magento/Sales/Model/Order/Reorder/UnavailableProductsProvider.php create mode 100644 app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Create/ReorderTest.php create mode 100644 app/code/Magento/Sales/Test/Unit/Model/Order/Reorder/OrderProductAvailabilityCheckerTest.php create mode 100644 app/code/Magento/Sales/Test/Unit/Model/Order/Reorder/UnavailableProductsProviderTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/Model/Order/Reorder/UnavailableProductsProviderTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_item_with_configurable_for_reorder.php create mode 100644 dev/tests/integration/testsuite/Magento/Sales/_files/order_item_with_configurable_for_reorder_rollback.php diff --git a/app/code/Magento/ConfigurableProductSales/LICENSE.txt b/app/code/Magento/ConfigurableProductSales/LICENSE.txt new file mode 100644 index 0000000000000..49525fd99da9c --- /dev/null +++ b/app/code/Magento/ConfigurableProductSales/LICENSE.txt @@ -0,0 +1,48 @@ + +Open Software License ("OSL") v. 3.0 + +This Open Software License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Open Software License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, with the proviso that copies of Original Work or Derivative Works that You distribute or communicate shall be licensed under this Open Software License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including 'fair use' or 'fair dealing'). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright (C) 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Open Software License" or "OSL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. \ No newline at end of file diff --git a/app/code/Magento/ConfigurableProductSales/LICENSE_AFL.txt b/app/code/Magento/ConfigurableProductSales/LICENSE_AFL.txt new file mode 100644 index 0000000000000..f39d641b18a19 --- /dev/null +++ b/app/code/Magento/ConfigurableProductSales/LICENSE_AFL.txt @@ -0,0 +1,48 @@ + +Academic Free License ("AFL") v. 3.0 + +This Academic Free License (the "License") applies to any original work of authorship (the "Original Work") whose owner (the "Licensor") has placed the following licensing notice adjacent to the copyright notice for the Original Work: + +Licensed under the Academic Free License version 3.0 + + 1. Grant of Copyright License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, for the duration of the copyright, to do the following: + + 1. to reproduce the Original Work in copies, either alone or as part of a collective work; + + 2. to translate, adapt, alter, transform, modify, or arrange the Original Work, thereby creating derivative works ("Derivative Works") based upon the Original Work; + + 3. to distribute or communicate copies of the Original Work and Derivative Works to the public, under any license of your choice that does not contradict the terms and conditions, including Licensor's reserved rights and remedies, in this Academic Free License; + + 4. to perform the Original Work publicly; and + + 5. to display the Original Work publicly. + + 2. Grant of Patent License. Licensor grants You a worldwide, royalty-free, non-exclusive, sublicensable license, under patent claims owned or controlled by the Licensor that are embodied in the Original Work as furnished by the Licensor, for the duration of the patents, to make, use, sell, offer for sale, have made, and import the Original Work and Derivative Works. + + 3. Grant of Source Code License. The term "Source Code" means the preferred form of the Original Work for making modifications to it and all available documentation describing how to modify the Original Work. Licensor agrees to provide a machine-readable copy of the Source Code of the Original Work along with each copy of the Original Work that Licensor distributes. Licensor reserves the right to satisfy this obligation by placing a machine-readable copy of the Source Code in an information repository reasonably calculated to permit inexpensive and convenient access by You for as long as Licensor continues to distribute the Original Work. + + 4. Exclusions From License Grant. Neither the names of Licensor, nor the names of any contributors to the Original Work, nor any of their trademarks or service marks, may be used to endorse or promote products derived from this Original Work without express prior permission of the Licensor. Except as expressly stated herein, nothing in this License grants any license to Licensor's trademarks, copyrights, patents, trade secrets or any other intellectual property. No patent license is granted to make, use, sell, offer for sale, have made, or import embodiments of any patent claims other than the licensed claims defined in Section 2. No license is granted to the trademarks of Licensor even if such marks are included in the Original Work. Nothing in this License shall be interpreted to prohibit Licensor from licensing under terms different from this License any Original Work that Licensor otherwise would have a right to license. + + 5. External Deployment. The term "External Deployment" means the use, distribution, or communication of the Original Work or Derivative Works in any way such that the Original Work or Derivative Works may be used by anyone other than You, whether those works are distributed or communicated to those persons or made available as an application intended for use over a network. As an express condition for the grants of license hereunder, You must treat any External Deployment by You of the Original Work or a Derivative Work as a distribution under section 1(c). + + 6. Attribution Rights. You must retain, in the Source Code of any Derivative Works that You create, all copyright, patent, or trademark notices from the Source Code of the Original Work, as well as any notices of licensing and any descriptive text identified therein as an "Attribution Notice." You must cause the Source Code for any Derivative Works that You create to carry a prominent Attribution Notice reasonably calculated to inform recipients that You have modified the Original Work. + + 7. Warranty of Provenance and Disclaimer of Warranty. Licensor warrants that the copyright in and to the Original Work and the patent rights granted herein by Licensor are owned by the Licensor or are sublicensed to You under the terms of this License with the permission of the contributor(s) of those copyrights and patent rights. Except as expressly stated in the immediately preceding sentence, the Original Work is provided under this License on an "AS IS" BASIS and WITHOUT WARRANTY, either express or implied, including, without limitation, the warranties of non-infringement, merchantability or fitness for a particular purpose. THE ENTIRE RISK AS TO THE QUALITY OF THE ORIGINAL WORK IS WITH YOU. This DISCLAIMER OF WARRANTY constitutes an essential part of this License. No license to the Original Work is granted by this License except under this disclaimer. + + 8. Limitation of Liability. Under no circumstances and under no legal theory, whether in tort (including negligence), contract, or otherwise, shall the Licensor be liable to anyone for any indirect, special, incidental, or consequential damages of any character arising as a result of this License or the use of the Original Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses. This limitation of liability shall not apply to the extent applicable law prohibits such limitation. + + 9. Acceptance and Termination. If, at any time, You expressly assented to this License, that assent indicates your clear and irrevocable acceptance of this License and all of its terms and conditions. If You distribute or communicate copies of the Original Work or a Derivative Work, You must make a reasonable effort under the circumstances to obtain the express assent of recipients to the terms of this License. This License conditions your rights to undertake the activities listed in Section 1, including your right to create Derivative Works based upon the Original Work, and doing so without honoring these terms and conditions is prohibited by copyright law and international treaty. Nothing in this License is intended to affect copyright exceptions and limitations (including "fair use" or "fair dealing"). This License shall terminate immediately and You may no longer exercise any of the rights granted to You by this License upon your failure to honor the conditions in Section 1(c). + + 10. Termination for Patent Action. This License shall terminate automatically and You may no longer exercise any of the rights granted to You by this License as of the date You commence an action, including a cross-claim or counterclaim, against Licensor or any licensee alleging that the Original Work infringes a patent. This termination provision shall not apply for an action alleging patent infringement by combinations of the Original Work with other software or hardware. + + 11. Jurisdiction, Venue and Governing Law. Any action or suit relating to this License may be brought only in the courts of a jurisdiction wherein the Licensor resides or in which Licensor conducts its primary business, and under the laws of that jurisdiction excluding its conflict-of-law provisions. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any use of the Original Work outside the scope of this License or after its termination shall be subject to the requirements and penalties of copyright or patent law in the appropriate jurisdiction. This section shall survive the termination of this License. + + 12. Attorneys' Fees. In any action to enforce the terms of this License or seeking damages relating thereto, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. This section shall survive the termination of this License. + + 13. Miscellaneous. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. + + 14. Definition of "You" in This License. "You" throughout this License, whether in upper or lower case, means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with you. For purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + + 15. Right to Use. You may use the Original Work in all ways not otherwise restricted or conditioned by this License or by law, and Licensor promises not to interfere with or be responsible for such uses by You. + + 16. Modification of This License. This License is Copyright © 2005 Lawrence Rosen. Permission is granted to copy, distribute, or communicate this License without modification. Nothing in this License permits You to modify this License as applied to the Original Work or to Derivative Works. However, You may modify the text of this License and copy, distribute or communicate your modified version (the "Modified License") and apply it to other original works of authorship subject to the following conditions: (i) You may not indicate in any way that your Modified License is the "Academic Free License" or "AFL" and you may not use those names in the name of your Modified License; (ii) You must replace the notice specified in the first paragraph above with the notice "Licensed under " or with a notice of your own that is not confusingly similar to the notice in this License; and (iii) You may not claim that your original works are open source software unless your Modified License has been approved by Open Source Initiative (OSI) and You comply with its license review and certification process. diff --git a/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php b/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php new file mode 100644 index 0000000000000..dceb5767edae9 --- /dev/null +++ b/app/code/Magento/ConfigurableProductSales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php @@ -0,0 +1,115 @@ +resourceConnection = $resourceConnection; + $this->metadataPool = $metadataPool; + } + + /** + * @inheritdoc + */ + public function isAvailable(Item $item) + { + $buyRequest = $item->getBuyRequest(); + $superAttribute = $buyRequest->getData()['super_attribute']; + $connection = $this->getConnection(); + $select = $connection->select(); + $orderItemParentId = $item->getParentItem()->getProductId(); + $select->from( + ['cpe' => $this->resourceConnection->getTableName('catalog_product_entity')], + ['cpe.entity_id'] + ) + ->where('cpe.entity_id = ?', $item->getProductId()); + $select->join( + ['cpsl' => $this->resourceConnection->getTableName('catalog_product_super_link')], + sprintf( + 'cpe.entity_id = cpsl.product_id AND cpsl.parent_id = %d', + $orderItemParentId + ), + [] + ); + foreach ($superAttribute as $attributeId => $attributeValue) { + $select->join( + ['cpid' . $attributeId => $this->resourceConnection->getTableName('catalog_product_entity_int')], + sprintf( + 'cpe.%1$s = cpid%2$d.%1$s AND cpid%2$d.attribute_id = %2$d AND cpid%2$d.store_id = %3$d', + $this->getMetadata()->getLinkField(), + $attributeId, + Store::DEFAULT_STORE_ID + ), + [] + ) + ->joinLeft( + ['cpis' . $attributeId => $this->resourceConnection->getTableName('catalog_product_entity_int')], + sprintf( + 'cpe.%1$s = cpis%2$d.%1$s AND cpis%2$d.attribute_id = %2$d AND cpis%2$d.store_id = %3$d', + $this->getMetadata()->getLinkField(), + $attributeId, + $item->getStoreId() + ), + [] + ) + ->where( + sprintf( + '%s = ?', + $connection->getIfNullSql( + 'cpis' . $attributeId . '.value', + 'cpid' . $attributeId . '.value' + ) + ), + $attributeValue + ); + } + return (bool)$connection->fetchCol($select); + } + + /** + * @return \Magento\Framework\DB\Adapter\AdapterInterface + */ + private function getConnection() + { + return $this->resourceConnection->getConnection(); + } + + /** + * @return \Magento\Framework\EntityManager\EntityMetadataInterface + */ + private function getMetadata() + { + return $this->metadataPool->getMetadata(ProductInterface::class); + } +} diff --git a/app/code/Magento/ConfigurableProductSales/README.md b/app/code/Magento/ConfigurableProductSales/README.md new file mode 100644 index 0000000000000..af915a8265827 --- /dev/null +++ b/app/code/Magento/ConfigurableProductSales/README.md @@ -0,0 +1,4 @@ +# Magento_ConfigurableProductSales module + +The Magento_ConfigurableProductSales module checks that the selected options of order item are still presented in +Catalog. Returns true if the previously ordered item configuration is still available. \ No newline at end of file diff --git a/app/code/Magento/ConfigurableProductSales/composer.json b/app/code/Magento/ConfigurableProductSales/composer.json new file mode 100644 index 0000000000000..acf7b5c191f8a --- /dev/null +++ b/app/code/Magento/ConfigurableProductSales/composer.json @@ -0,0 +1,28 @@ +{ + "name": "magento/module-configurable-product-sales", + "description": "N/A", + "require": { + "php": "7.0.2|7.0.4|~7.0.6|~7.1.0", + "magento/module-catalog": "101.1.*", + "magento/module-sales": "100.2.*", + "magento/module-store": "100.2.*", + "magento/framework": "100.2.*" + }, + "suggest": { + "magento/module-configurable-product": "100.2.*" + }, + "type": "magento2-module", + "version": "100.2.0-dev", + "license": [ + "OSL-3.0", + "AFL-3.0" + ], + "autoload": { + "files": [ + "registration.php" + ], + "psr-4": { + "Magento\\ConfigurableProductSales\\": "" + } + } +} diff --git a/app/code/Magento/ConfigurableProductSales/etc/di.xml b/app/code/Magento/ConfigurableProductSales/etc/di.xml new file mode 100644 index 0000000000000..b53faf74ffa1d --- /dev/null +++ b/app/code/Magento/ConfigurableProductSales/etc/di.xml @@ -0,0 +1,16 @@ + + + + + + + Magento\ConfigurableProductSales\Model\Order\Reorder\OrderedProductAvailabilityChecker + + + + diff --git a/app/code/Magento/ConfigurableProductSales/etc/module.xml b/app/code/Magento/ConfigurableProductSales/etc/module.xml new file mode 100644 index 0000000000000..4da83c9c0269b --- /dev/null +++ b/app/code/Magento/ConfigurableProductSales/etc/module.xml @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/app/code/Magento/ConfigurableProductSales/registration.php b/app/code/Magento/ConfigurableProductSales/registration.php new file mode 100644 index 0000000000000..99affe39c15c1 --- /dev/null +++ b/app/code/Magento/ConfigurableProductSales/registration.php @@ -0,0 +1,9 @@ +unavailableProductsProvider = $unavailableProductsProvider; + $this->orderRepository = $orderRepository; + $this->reorderHelper = $reorderHelper; + parent::__construct( + $context, + $productHelper, + $escaper, + $resultPageFactory, + $resultForwardFactory + ); + } + /** * @return \Magento\Backend\Model\View\Result\Forward|\Magento\Backend\Model\View\Result\Redirect */ @@ -14,22 +68,34 @@ public function execute() { $this->_getSession()->clearStorage(); $orderId = $this->getRequest()->getParam('order_id'); - $order = $this->_objectManager->create(\Magento\Sales\Model\Order::class)->load($orderId); - if (!$this->_objectManager->get(\Magento\Sales\Helper\Reorder::class)->canReorder($order->getEntityId())) { + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->orderRepository->get($orderId); + if (!$this->reorderHelper->canReorder($order->getEntityId())) { return $this->resultForwardFactory->create()->forward('noroute'); } /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ $resultRedirect = $this->resultRedirectFactory->create(); - if ($order->getId()) { + if (!$order->getId()) { + $resultRedirect->setPath('sales/order/'); + return $resultRedirect; + } + + $unavailableProducts = $this->unavailableProductsProvider->getForOrder($order); + if (count($unavailableProducts) > 0) { + foreach ($unavailableProducts as $sku) { + $this->messageManager->addErrorMessage( + sprintf('Product "%s" not found. This product is no longer available.', $sku) + ); + } + $resultRedirect->setPath('sales/order/view', ['order_id' => $orderId]); + } else { $order->setReordered(true); $this->_getSession()->setUseOldShippingMethod(true); $this->_getOrderCreateModel()->initFromOrder($order); - $resultRedirect->setPath('sales/*'); - } else { - $resultRedirect->setPath('sales/order/'); } + return $resultRedirect; } } diff --git a/app/code/Magento/Sales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php b/app/code/Magento/Sales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php new file mode 100644 index 0000000000000..d7f50e737fa5d --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Reorder/OrderedProductAvailabilityChecker.php @@ -0,0 +1,53 @@ +productAvailabilityChecks = $productAvailabilityChecks; + } + + /** + * @inheritdoc + */ + public function isAvailable(Item $item) + { + if ($item->getParentItem() + && isset($this->productAvailabilityChecks[$item->getParentItem()->getProductType()]) + ) { + $checkForType = $this->productAvailabilityChecks[$item->getParentItem()->getProductType()]; + if (!$checkForType instanceof OrderedProductAvailabilityCheckerInterface) { + throw new ConfigurationMismatchException(__('Received check doesn\'t match interface')); + } + return $checkForType->isAvailable($item); + } else { + return true; + } + } +} diff --git a/app/code/Magento/Sales/Model/Order/Reorder/OrderedProductAvailabilityCheckerInterface.php b/app/code/Magento/Sales/Model/Order/Reorder/OrderedProductAvailabilityCheckerInterface.php new file mode 100644 index 0000000000000..556d6f9d870ef --- /dev/null +++ b/app/code/Magento/Sales/Model/Order/Reorder/OrderedProductAvailabilityCheckerInterface.php @@ -0,0 +1,25 @@ +salesConfig = $salesConfig; + $this->orderedProductAvailabilityChecker = $orderedProductAvailabilityChecker; + } + + /** + * Gets products that are unavailable for the order. + * + * @param \Magento\Sales\Model\Order $order + * @return array + */ + public function getForOrder($order) + { + $unavailableProducts = []; + foreach ($order->getItemsCollection($this->salesConfig->getAvailableProductTypes(), false) as $orderItem) { + /** @var \Magento\Sales\Model\Order\Item $orderItem */ + if (!$this->orderedProductAvailabilityChecker->isAvailable($orderItem)) { + $unavailableProducts[] = $orderItem->getSku(); + } + } + return $unavailableProducts; + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Create/ReorderTest.php b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Create/ReorderTest.php new file mode 100644 index 0000000000000..1fdd9759f5045 --- /dev/null +++ b/app/code/Magento/Sales/Test/Unit/Controller/Adminhtml/Order/Create/ReorderTest.php @@ -0,0 +1,307 @@ +orderId = 111; + $this->orderRepositoryMock = $this->getMockBuilder(OrderRepositoryInterface::class)->getMockForAbstractClass(); + $this->orderMock = $this->getMockBuilder(Order::class) + ->disableOriginalConstructor() + ->setMethods(['getEntityId', 'getId', 'setReordered']) + ->getMock(); + $this->requestMock = $this->getMockBuilder(RequestInterface::class)->getMockForAbstractClass(); + $this->objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class)->getMockForAbstractClass(); + $this->resultForwardFactoryMock = $this->getMockBuilder(ForwardFactory::class)->getMock(); + $this->resultRedirectFactoryMock = $this->getMockBuilder(RedirectFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $this->resultRedirectMock = $this->getMockBuilder(Redirect::class)->disableOriginalConstructor()->getMock(); + $this->resultForwardMock = $this->getMockBuilder(Forward::class)->disableOriginalConstructor()->getMock(); + $this->quoteSessionMock = $this->getMockBuilder(Quote::class) + ->disableOriginalConstructor() + ->setMethods(['clearStorage', 'setUseOldShippingMethod']) + ->getMock(); + $this->reorderHelperMock = $this->getMockBuilder(ReorderHelper::class) + ->disableOriginalConstructor() + ->getMock(); + $this->messageManagerMock = $this->getMockBuilder(ManagerInterface::class)->getMockForAbstractClass(); + $this->unavailableProductsProviderMock = $this->getMockBuilder(UnavailableProductsProvider::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderCreateMock = $this->getMockBuilder(Create::class)->disableOriginalConstructor()->getMock(); + $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->context = $objectManager->getObject( + Context::class, + [ + 'request' => $this->requestMock, + 'objectManager' => $this->objectManagerMock, + 'messageManager' => $this->messageManagerMock, + 'resultRedirectFactory' => $this->resultRedirectFactoryMock + ] + ); + + $this->reorder = $objectManager->getObject( + Reorder::class, + [ + 'unavailableProductsProvider' => $this->unavailableProductsProviderMock, + 'orderRepository' => $this->orderRepositoryMock, + 'reorderHelper' => $this->reorderHelperMock, + 'context' => $this->context, + 'resultForwardFactory' => $this->resultForwardFactoryMock, + ] + ); + } + + public function testExecuteForward() + { + $this->clearStorage(); + $this->getOrder(); + $this->canReorder(false); + $this->prepareForward(); + + $this->assertInstanceOf(Forward::class, $this->reorder->execute()); + } + + public function testExecuteRedirectOrderGrid() + { + $this->clearStorage(); + $this->getOrder(); + $this->canReorder(true); + $this->createRedirect(); + $this->getOrderId(null); + $this->setPath('sales/order/'); + + $this->assertInstanceOf(Redirect::class, $this->reorder->execute()); + } + + public function testExecuteRedirectBack() + { + $this->clearStorage(); + $this->getOrder(); + $this->canReorder(true); + $this->createRedirect(); + $this->getOrderId($this->orderId); + $this->getUnavailableProducts([1, 3]); + $this->messageManagerMock->expects($this->any())->method('addErrorMessage'); + $this->setPath('sales/order/view', ['order_id' => $this->orderId]); + + $this->assertInstanceOf(Redirect::class, $this->reorder->execute()); + } + + public function testExecuteRedirectNewOrder() + { + $this->clearStorage(); + $this->getOrder(); + $this->canReorder(true); + $this->createRedirect(); + $this->getOrderId($this->orderId); + $this->getUnavailableProducts([]); + $this->initFromOrder(); + $this->setPath('sales/*'); + + $this->assertInstanceOf(Redirect::class, $this->reorder->execute()); + } + + private function clearStorage() + { + $this->objectManagerMock->expects($this->at(0)) + ->method('get') + ->with(Quote::class) + ->willReturn($this->quoteSessionMock); + $this->quoteSessionMock->expects($this->once())->method('clearStorage')->will($this->returnSelf()); + } + + private function getOrder() + { + $this->requestMock->expects($this->once()) + ->method('getParam') + ->with('order_id') + ->willReturn($this->orderId); + $this->orderRepositoryMock->expects($this->once()) + ->method('get') + ->with($this->orderId) + ->willReturn($this->orderMock); + } + + /** + * @param bool $result + */ + private function canReorder($result) + { + $entity_id = 1; + $this->orderMock->expects($this->once())->method('getEntityId')->willReturn($entity_id); + $this->reorderHelperMock->expects($this->once()) + ->method('canReorder') + ->with($entity_id) + ->willReturn($result); + } + + private function prepareForward() + { + $this->resultForwardFactoryMock->expects($this->once())->method('create')->willReturn($this->resultForwardMock); + $this->resultForwardMock->expects($this->once())->method('forward')->with('noroute')->willReturnSelf(); + } + + private function createRedirect() + { + $this->resultRedirectFactoryMock->expects($this->once()) + ->method('create') + ->willReturn($this->resultRedirectMock); + } + + /** + * @param null|int $orderId + */ + private function getOrderId($orderId) + { + $this->orderMock->expects($this->once())->method('getId')->willReturn($orderId); + } + + /** + * @param string $path + * @param null|array $params + */ + private function setPath($path, $params = []) + { + $this->resultRedirectMock->expects($this->once())->method('setPath')->with($path, $params); + } + + /** + * @param array $unavailableProducts + */ + private function getUnavailableProducts(array $unavailableProducts) + { + $this->unavailableProductsProviderMock->expects($this->any()) + ->method('getForOrder') + ->with($this->orderMock) + ->willReturn($unavailableProducts); + } + + private function initFromOrder() + { + $this->orderMock->expects($this->once())->method('setReordered')->with(true)->willReturnSelf(); + $this->objectManagerMock->expects($this->at(1)) + ->method('get') + ->with(Quote::class) + ->willReturn($this->quoteSessionMock); + $this->quoteSessionMock->expects($this->once()) + ->method('setUseOldShippingMethod') + ->with(true) + ->will($this->returnSelf()); + $this->objectManagerMock->expects($this->at(2)) + ->method('get') + ->with(Create::class) + ->willReturn($this->orderCreateMock); + $this->orderCreateMock->expects($this->once()) + ->method('initFromOrder') + ->with($this->orderMock) + ->willReturnSelf(); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Reorder/OrderProductAvailabilityCheckerTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Reorder/OrderProductAvailabilityCheckerTest.php new file mode 100644 index 0000000000000..45b8b82bf8ae8 --- /dev/null +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Reorder/OrderProductAvailabilityCheckerTest.php @@ -0,0 +1,131 @@ +orderItemMock = $this->getMockBuilder(Item::class)->disableOriginalConstructor()->getMock(); + $this->orderItemInterfaceMock = $this->getMockBuilder(OrderItemInterface::class) + ->disableOriginalConstructor() + ->getMockForAbstractClass(); + + $this->productTypeConfigurable = 'configurable'; + $this->productTypeSimple = 'simple'; + $this->configurableCheckerMock = $this->getMockBuilder(ConfigurableChecker::class) + ->disableOriginalConstructor() + ->getMock(); + $fakeClass = new \stdClass(); + $this->productAvailabilityChecks[$this->productTypeConfigurable] = $this->configurableCheckerMock; + $this->productAvailabilityChecks[$this->productTypeSimple] = $fakeClass; + + $this->checker = $objectManager->getObject( + OrderedProductAvailabilityChecker::class, + [ + 'productAvailabilityChecks' => $this->productAvailabilityChecks + ] + ); + } + + public function testIsAvailableTrue() + { + $this->getProductType($this->productTypeConfigurable); + $this->isAvailable(true); + $this->assertTrue($this->checker->isAvailable($this->orderItemMock)); + } + + public function testIsAvailableFalse() + { + $this->getProductType($this->productTypeConfigurable); + $this->isAvailable(false); + $this->assertFalse($this->checker->isAvailable($this->orderItemMock)); + } + + /** + * @expectedException \Magento\Framework\Exception\ConfigurationMismatchException + */ + public function testIsAvailableException() + { + $this->getProductType($this->productTypeSimple); + $this->checker->isAvailable($this->orderItemMock); + } + + public function testIsAvailableTypeNotChecks() + { + $this->getProductType('test_type'); + $this->assertTrue($this->checker->isAvailable($this->orderItemMock)); + } + + /** + * @param string $productType + */ + private function getProductType($productType) + { + $this->orderItemMock->expects($this->any()) + ->method('getParentItem') + ->willReturn($this->orderItemInterfaceMock); + $this->orderItemInterfaceMock->expects($this->any()) + ->method('getProductType') + ->willReturn($productType); + } + + /** + * @param bool $result + */ + private function isAvailable($result) + { + $this->configurableCheckerMock->expects($this->once()) + ->method('isAvailable') + ->with($this->orderItemMock) + ->willReturn($result); + } +} diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Reorder/UnavailableProductsProviderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Reorder/UnavailableProductsProviderTest.php new file mode 100644 index 0000000000000..8949309646d3b --- /dev/null +++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Reorder/UnavailableProductsProviderTest.php @@ -0,0 +1,100 @@ +salesConfigMock = $this->getMockBuilder(Config::class)->disableOriginalConstructor()->getMock(); + $this->checkerMock = $this->getMockBuilder(OrderedProductAvailabilityChecker::class) + ->disableOriginalConstructor() + ->getMock(); + $this->orderMock = $this->getMockBuilder(Order::class)->disableOriginalConstructor()->getMock(); + $this->orderItemMock = $this->getMockBuilder(Item::class)->disableOriginalConstructor()->getMock(); + $this->unavailableProductsProvider = $objectManager->getObject( + UnavailableProductsProvider::class, + [ + 'salesConfig' => $this->salesConfigMock, + 'orderedProductAvailabilityChecker' => $this->checkerMock + ] + ); + } + + public function testGetForOrder() + { + $sku = 'sku'; + $this->isAvailable(false); + $this->orderItemMock->expects($this->any())->method('getSku')->willReturn($sku); + $unavailableProducts[] = $sku; + + $this->assertEquals( + $unavailableProducts, + $this->unavailableProductsProvider->getForOrder($this->orderMock) + ); + } + + public function testGetForOrderEmpty() + { + $this->isAvailable(true); + + $this->assertEquals([], $this->unavailableProductsProvider->getForOrder($this->orderMock)); + } + + /** + * @param bool $result + */ + private function isAvailable($result) + { + $productTypes = ['configurable']; + $this->salesConfigMock->expects($this->any()) + ->method('getAvailableProductTypes') + ->willReturn($productTypes); + $this->orderMock->expects($this->any()) + ->method('getItemsCollection') + ->with($productTypes, false) + ->willReturn([$this->orderItemMock]); + $this->checkerMock->expects($this->any()) + ->method('isAvailable') + ->with($this->orderItemMock) + ->willReturn($result); + } +} diff --git a/composer.json b/composer.json index 1f6d5f0ee1df9..335bf4f0cfdb2 100644 --- a/composer.json +++ b/composer.json @@ -109,6 +109,7 @@ "magento/module-config": "100.2.0-dev", "magento/module-configurable-import-export": "100.2.0-dev", "magento/module-configurable-product": "100.2.0-dev", + "magento/module-configurable-product-sales": "100.2.0-dev", "magento/module-contact": "100.2.0-dev", "magento/module-cookie": "100.2.0-dev", "magento/module-cron": "100.2.0-dev", diff --git a/composer.lock b/composer.lock index 25cdd4911539b..159ce2084040b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "d7201c87c0acb53f0b569b7055d04659", + "content-hash": "3e13b8fc4b511545915d1804ca7796ac", "packages": [ { "name": "braintree/braintree_php", diff --git a/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Reorder/UnavailableProductsProviderTest.php b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Reorder/UnavailableProductsProviderTest.php new file mode 100644 index 0000000000000..2df771d54ade1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/Model/Order/Reorder/UnavailableProductsProviderTest.php @@ -0,0 +1,34 @@ +get(OrderInterfaceFactory::class); + /** @var \Magento\Sales\Model\Order $order */ + $order = $orderFactory->create()->loadByIncrementId('100001001'); + $orderItems = $order->getItems(); + $orderItemSimple = array_pop($orderItems); + $orderItemSimple->getSku(); + /** @var UnavailableProductsProvider $unavailableProductsProvider */ + $unavailableProductsProvider = + $objectManager->create(UnavailableProductsProvider::class); + $unavailableProducts = $unavailableProductsProvider->getForOrder($order); + $this->assertEquals($orderItemSimple->getSku(), $unavailableProducts[0]); + } +} diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_item_with_configurable_for_reorder.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_item_with_configurable_for_reorder.php new file mode 100644 index 0000000000000..67f80ca9b2d09 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_item_with_configurable_for_reorder.php @@ -0,0 +1,94 @@ +create(\Magento\Sales\Model\Order\Address::class, ['data' => $addressData]); +$billingAddress->setAddressType('billing'); + +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType('shipping'); + +$payment = $objectManager->create(\Magento\Sales\Model\Order\Payment::class); +$payment->setMethod('checkmo'); + +/** @var ProductRepository $productRepository */ +$productRepository = $objectManager->get(ProductRepositoryInterface::class); +$product = $productRepository->getById(1); +/** @var \Magento\Catalog\Model\Product $productSimple */ +$simpleProduct = $productRepository->getById(20); + + +/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */ +$eavConfig = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(\Magento\Eav\Model\Config::class); +$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable'); + +/** @var $options \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection */ +$options = $objectManager->create(\Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection::class); +$option = $options->setAttributeFilter($attribute->getId()) + ->getFirstItem(); + +$requestInfo = [ + 'qty' => 1, + 'super_attribute' => [ + $attribute->getId() => $option->getId(), + ], +]; +/** @var \Magento\Sales\Model\Order $order */ +$order = $objectManager->create(\Magento\Sales\Model\Order::class); +$order->setIncrementId('100000001'); +$order->loadByIncrementId('100000001'); +if ($order->getId()) { + $order->delete(); +} +/** @var \Magento\Sales\Model\Order\Item $orderItem */ +$orderItem = $objectManager->create(\Magento\Sales\Model\Order\Item::class); +$orderItemSimple = clone $orderItem; +$orderItem->setProductId($product->getId()); +$orderItem->setQtyOrdered(1); +$orderItem->setBasePrice($product->getPrice()); +$orderItem->setPrice($product->getPrice()); +$orderItem->setRowTotal($product->getPrice()); +$orderItem->setProductType($product->getTypeId()); +$orderItem->setProductOptions(['info_buyRequest' => $requestInfo]); +$orderItemSimple->setProductId($simpleProduct->getId()); +$orderItemSimple->setParentItem($orderItem); +$orderItemSimple->setStoreId(0); +$orderItemSimple->setProductType($simpleProduct->getTypeId()); +$orderItemSimple->setProductOptions(['info_buyRequest' => $requestInfo]); +$orderItemSimple->setSku($simpleProduct->getSku()); + +/** @var \Magento\Sales\Model\Order $order */ +$order = $objectManager->create(\Magento\Sales\Model\Order::class); +$order->setIncrementId('100001001'); +$order->setState(\Magento\Sales\Model\Order::STATE_NEW); +$order->setStatus($order->getConfig()->getStateDefaultStatus(\Magento\Sales\Model\Order::STATE_NEW)); +$order->setCustomerIsGuest(true); +$order->setCustomerEmail('customer@null.com'); +$order->setCustomerFirstname('firstname'); +$order->setCustomerLastname('lastname'); +$order->setBillingAddress($billingAddress); +$order->setShippingAddress($shippingAddress); +$order->setAddresses([$billingAddress, $shippingAddress]); +$order->setPayment($payment); +$order->addItem($orderItem); +$order->addItem($orderItemSimple); +$order->setStoreId($objectManager->get(\Magento\Store\Model\StoreManagerInterface::class)->getStore()->getId()); +$order->setSubtotal(100); +$order->setBaseSubtotal(100); +$order->setBaseGrandTotal(100); +$order->save(); +// Change attribute value for simple of configurable +$simpleProduct->setData('test_configurable', 100); +$simpleProduct->save(); +$simpleProduct->isAvailable(); diff --git a/dev/tests/integration/testsuite/Magento/Sales/_files/order_item_with_configurable_for_reorder_rollback.php b/dev/tests/integration/testsuite/Magento/Sales/_files/order_item_with_configurable_for_reorder_rollback.php new file mode 100644 index 0000000000000..597ebbd72a40c --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Sales/_files/order_item_with_configurable_for_reorder_rollback.php @@ -0,0 +1,8 @@ + Date: Fri, 1 Sep 2017 15:45:21 +0300 Subject: [PATCH 070/151] MAGETWO-71890: Magento fails with deploymentConfig present on new install --- .../Magento/Deploy/Console/CommandList.php | 58 +++++++++++++++++ .../Test/Unit/Console/CommandListTest.php | 51 +++++++++++++++ app/code/Magento/Deploy/cli_commands.php | 8 +++ app/code/Magento/Deploy/composer.json | 1 + .../Setup/Console/Command/InstallCommand.php | 7 ++ .../Console/Command/InstallCommandTest.php | 65 ++++++++++++++++++- 6 files changed, 187 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/Deploy/Console/CommandList.php create mode 100644 app/code/Magento/Deploy/Test/Unit/Console/CommandListTest.php create mode 100644 app/code/Magento/Deploy/cli_commands.php diff --git a/app/code/Magento/Deploy/Console/CommandList.php b/app/code/Magento/Deploy/Console/CommandList.php new file mode 100644 index 0000000000000..2470737b19217 --- /dev/null +++ b/app/code/Magento/Deploy/Console/CommandList.php @@ -0,0 +1,58 @@ +objectManager = $objectManager; + } + + /** + * Gets list of command classes + * + * @return string[] + */ + private function getCommandsClasses() + { + return [ + \Magento\Deploy\Console\Command\App\ConfigImportCommand::class, + ]; + } + + /** + * @inheritdoc + */ + public function getCommands() + { + $commands = []; + foreach ($this->getCommandsClasses() as $class) { + if (class_exists($class)) { + $commands[] = $this->objectManager->get($class); + } else { + throw new \Exception('Class ' . $class . ' does not exist'); + } + } + + return $commands; + } +} diff --git a/app/code/Magento/Deploy/Test/Unit/Console/CommandListTest.php b/app/code/Magento/Deploy/Test/Unit/Console/CommandListTest.php new file mode 100644 index 0000000000000..41052b2760c78 --- /dev/null +++ b/app/code/Magento/Deploy/Test/Unit/Console/CommandListTest.php @@ -0,0 +1,51 @@ +objectManagerMock = $this->getMockBuilder(ObjectManagerInterface::class) + ->getMockForAbstractClass(); + + $this->model = new CommandList( + $this->objectManagerMock + ); + } + + public function testGetCommands() + { + $this->objectManagerMock->expects($this->once()) + ->method('get') + ->withConsecutive([ + ConfigImportCommand::class, + ]); + + $this->model->getCommands(); + } +} diff --git a/app/code/Magento/Deploy/cli_commands.php b/app/code/Magento/Deploy/cli_commands.php new file mode 100644 index 0000000000000..dd111b479e2ce --- /dev/null +++ b/app/code/Magento/Deploy/cli_commands.php @@ -0,0 +1,8 @@ +installerFactory->create($consoleLogger); $installer->install($input->getOptions()); + + $importConfigCommand = $this->getApplication()->find(ConfigImportCommand::COMMAND_NAME); + $arrayInput = new ArrayInput([]); + $arrayInput->setInteractive($input->isInteractive()); + $importConfigCommand->run($arrayInput, $output); } /** diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallCommandTest.php index 46e93486d6def..5b7b6c1626911 100644 --- a/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallCommandTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/InstallCommandTest.php @@ -6,7 +6,11 @@ namespace Magento\Setup\Test\Unit\Console\Command; +use Magento\Deploy\Console\Command\App\ConfigImportCommand; use Magento\Setup\Console\Command\InstallCommand; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Helper\HelperSet; +use Symfony\Component\Console\Input\InputDefinition; use Symfony\Component\Console\Tester\CommandTester; use Magento\Setup\Model\AdminAccount; use Magento\Backend\Setup\ConfigOptionsList as BackendConfigOptionsList; @@ -38,6 +42,26 @@ class InstallCommandTest extends \PHPUnit\Framework\TestCase */ private $installer; + /** + * @var Application|\PHPUnit_Framework_MockObject_MockObject + */ + private $applicationMock; + + /** + * @var HelperSet|\PHPUnit_Framework_MockObject_MockObject + */ + private $helperSetMock; + + /** + * @var InputDefinition|\PHPUnit_Framework_MockObject_MockObject + */ + private $definitionMock; + + /** + * @var ConfigImportCommand|\PHPUnit_Framework_MockObject_MockObject + */ + private $configImportMock; + public function setUp() { $this->input = [ @@ -88,12 +112,42 @@ public function setUp() $this->installerFactory = $this->createMock(\Magento\Setup\Model\InstallerFactory::class); $this->installer = $this->createMock(\Magento\Setup\Model\Installer::class); + $this->applicationMock = $this->getMockBuilder(Application::class) + ->disableOriginalConstructor() + ->getMock(); + $this->helperSetMock = $this->getMockBuilder(HelperSet::class) + ->disableOriginalConstructor() + ->getMock(); + $this->definitionMock = $this->getMockBuilder(InputDefinition::class) + ->disableOriginalConstructor() + ->getMock(); + $this->configImportMock = $this->getMockBuilder(ConfigImportCommand::class) + ->disableOriginalConstructor() + ->getMock(); + + $this->applicationMock->expects($this->any()) + ->method('getHelperSet') + ->willReturn($this->helperSetMock); + $this->applicationMock->expects($this->any()) + ->method('getDefinition') + ->willReturn($this->definitionMock); + $this->definitionMock->expects($this->any()) + ->method('getOptions') + ->willReturn([]); + $this->applicationMock->expects($this->any()) + ->method('find') + ->with(ConfigImportCommand::COMMAND_NAME) + ->willReturn($this->configImportMock); + $this->command = new InstallCommand( $this->installerFactory, $configModel, $userConfig, $adminUser ); + $this->command->setApplication( + $this->applicationMock + ); } public function testExecute() @@ -102,6 +156,8 @@ public function testExecute() ->method('create') ->will($this->returnValue($this->installer)); $this->installer->expects($this->once())->method('install'); + $this->configImportMock->expects($this->once()) + ->method('run'); $commandTester = new CommandTester($this->command); $commandTester->execute($this->input); @@ -134,6 +190,7 @@ private function getOptionsListDeployConfig() ->expects($this->any()) ->method('getName') ->will($this->returnValue(BackendConfigOptionsList::INPUT_KEY_BACKEND_FRONTNAME)); + return [$option1, $option2, $option3, $option4]; } @@ -164,6 +221,7 @@ private function getOptionsListUserConfig() ->expects($this->any()) ->method('getName') ->will($this->returnValue(StoreConfigurationDataMapper::KEY_CURRENCY)); + return [$option1, $option2, $option3, $option4]; } @@ -199,6 +257,7 @@ private function getOptionsListAdminUser() ->expects($this->any()) ->method('getName') ->will($this->returnValue(AdminAccount::KEY_LAST_NAME)); + return [$option1, $option2, $option3, $option4, $option5]; } @@ -246,8 +305,8 @@ public function validateDataProvider() { return [ 'without option' => ['', ''], - 'normal case' => ['abcde', ''], - '20 chars' => ['12345678901234567890', ''] + 'normal case' => ['abcde', ''], + '20 chars' => ['12345678901234567890', ''], ]; } @@ -258,7 +317,7 @@ public function validateWithExceptionDataProvider() { return [ ['123456789012345678901', 'InvalidArgumentException'], - ['abcdefghijk12345678fdgsdfgsdfgsdfsgsdfg90abcdefgdfddgsdfg', 'InvalidArgumentException'] + ['abcdefghijk12345678fdgsdfgsdfgsdfsgsdfg90abcdefgdfddgsdfg', 'InvalidArgumentException'], ]; } } From 127da1b7c01534d8fb5495ee0fb56000d2396f27 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Fri, 1 Sep 2017 16:14:09 +0300 Subject: [PATCH 071/151] MAGETWO-70819: Widget with condition "special date to" --- .../Rule/Model/Condition/Sql/Builder.php | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php index c3ffda059c951..fff4c08cc0c66 100644 --- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php +++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php @@ -116,24 +116,26 @@ protected function _joinTablesToCollection( protected function _getMappedSqlCondition(AbstractCondition $condition, $value = '') { $argument = $condition->getMappedSqlField(); - if ($argument) { - $conditionOperator = $condition->getOperatorForValidate(); - if (!isset($this->_conditionOperatorMap[$conditionOperator])) { - throw new \Magento\Framework\Exception\LocalizedException(__('Unknown condition operator')); - } + if (empty($argument)) { + return $this->_expressionFactory->create(['expression' => '1 = -1']); + } - $sql = str_replace( - ':field', - $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), 0), - $this->_conditionOperatorMap[$conditionOperator] - ); + $conditionOperator = $condition->getOperatorForValidate(); - return $this->_expressionFactory->create( - ['expression' => $value . $this->_connection->quoteInto($sql, $condition->getBindArgumentValue())] - ); + if (!isset($this->_conditionOperatorMap[$conditionOperator])) { + throw new \Magento\Framework\Exception\LocalizedException(__('Unknown condition operator')); } - return ''; + + $sql = str_replace( + ':field', + $this->_connection->getIfNullSql($this->_connection->quoteIdentifier($argument), 0), + $this->_conditionOperatorMap[$conditionOperator] + ); + + return $this->_expressionFactory->create( + ['expression' => $value . $this->_connection->quoteInto($sql, $condition->getBindArgumentValue())] + ); } /** From cf72a45ee53e20081365f9c98892035872439df4 Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Fri, 1 Sep 2017 09:54:30 -0500 Subject: [PATCH 072/151] MAGETWO-71765: Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Fixed code style. --- app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php index 1c622e6f2ff8e..975de6483b935 100644 --- a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php +++ b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php @@ -345,13 +345,12 @@ public function testCaptureAmountRounding($amount, $setAmount, $expectedResult) $this->gatewayMock->expects($this->once()) ->method('postRequest') ->with( - $this->callback(function($request) use ($expectedResult) - { + $this->callback(function ($request) use ($expectedResult) { return is_callable([$request, 'getAmt']) && $request->getAmt() == $expectedResult; } ), $this->isInstanceOf(PayflowConfig::class) - ) + ) ->willReturn($response); $this->payflowpro->capture($paymentMock, $amount); From 6b6e8236f06d217200fead08a22a51262554aaae Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Fri, 1 Sep 2017 10:09:52 -0500 Subject: [PATCH 073/151] MAGETWO-71765: Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Fixed code style. --- app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php index 975de6483b935..2998011a3db0d 100644 --- a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php +++ b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php @@ -346,11 +346,10 @@ public function testCaptureAmountRounding($amount, $setAmount, $expectedResult) ->method('postRequest') ->with( $this->callback(function ($request) use ($expectedResult) { - return is_callable([$request, 'getAmt']) && $request->getAmt() == $expectedResult; - } - ), + return is_callable([$request, 'getAmt']) && $request->getAmt() == $expectedResult;} + ), $this->isInstanceOf(PayflowConfig::class) - ) + ) ->willReturn($response); $this->payflowpro->capture($paymentMock, $amount); From 9b886a7fb46ca31e6e3fbeb28da6ca473e5cf092 Mon Sep 17 00:00:00 2001 From: Joan He Date: Fri, 1 Sep 2017 10:49:17 -0500 Subject: [PATCH 074/151] MAGETWO-72112: [Github] Child categories included in menu when parent category is disabled or hidden #10664 --- app/code/Magento/Catalog/Plugin/Block/Topmenu.php | 1 + app/code/Magento/Theme/Block/Html/Topmenu.php | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/app/code/Magento/Catalog/Plugin/Block/Topmenu.php b/app/code/Magento/Catalog/Plugin/Block/Topmenu.php index 7a95cac6a6ff1..28f9ee5b8b359 100644 --- a/app/code/Magento/Catalog/Plugin/Block/Topmenu.php +++ b/app/code/Magento/Catalog/Plugin/Block/Topmenu.php @@ -98,6 +98,7 @@ public function beforeGetHtml( $parentCategoryNode->getTree(), $parentCategoryNode ); + $categoryNode->setData('is_parent_active', $category->getParentId() == $categoryParentId); $parentCategoryNode->addChild($categoryNode); $mapping[$category->getId()] = $categoryNode; //add node in stack diff --git a/app/code/Magento/Theme/Block/Html/Topmenu.php b/app/code/Magento/Theme/Block/Html/Topmenu.php index cf2e347bbc024..b1b22e06d7172 100644 --- a/app/code/Magento/Theme/Block/Html/Topmenu.php +++ b/app/code/Magento/Theme/Block/Html/Topmenu.php @@ -220,7 +220,11 @@ protected function _getHtml( $parentPositionClass = $menuTree->getPositionClass(); $itemPositionClassPrefix = $parentPositionClass ? $parentPositionClass . '-' : 'nav-'; + /** @var \Magento\Framework\Data\Tree\Node $child */ foreach ($children as $child) { + if ($childLevel === 0 && $child->getData('is_parent_active') === false) { + continue; + } $child->setLevel($childLevel); $child->setIsFirst($counter == 1); $child->setIsLast($counter == $childrenCount); From 3521cb818de3bbfa26deacf8b73c83127bde95fe Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Fri, 1 Sep 2017 11:11:58 -0500 Subject: [PATCH 075/151] MAGETWO-71765: Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Fixed code style. --- app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php index 2998011a3db0d..c9689c8601a02 100644 --- a/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php +++ b/app/code/Magento/Paypal/Test/Unit/Model/PayflowproTest.php @@ -346,8 +346,8 @@ public function testCaptureAmountRounding($amount, $setAmount, $expectedResult) ->method('postRequest') ->with( $this->callback(function ($request) use ($expectedResult) { - return is_callable([$request, 'getAmt']) && $request->getAmt() == $expectedResult;} - ), + return is_callable([$request, 'getAmt']) && $request->getAmt() == $expectedResult; + }), $this->isInstanceOf(PayflowConfig::class) ) ->willReturn($response); From 8c93df2a9f731ef322712a0f8b592e957bd08b75 Mon Sep 17 00:00:00 2001 From: Andrii Voskoboinikov Date: Fri, 1 Sep 2017 19:13:49 +0300 Subject: [PATCH 076/151] MAGETWO-70392: benchmarks.jmx does not work with https --- setup/performance-toolkit/benchmark.jmx | 437 ++++++++++++------------ 1 file changed, 221 insertions(+), 216 deletions(-) diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index 844b5d127a014..a812626e51cbf 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -14,6 +14,11 @@ + + request_protocol + ${__P(request_protocol,http)} + = + abandonedCartByGuest ${__P(abandonedCartByGuest,0)} @@ -51,7 +56,7 @@ admin_path - ${__P(admin_path,admin)} + ${__P(admin_path,backend)} = @@ -421,7 +426,7 @@ customer_checkout_percent - ${__P(customer_checkout_percent,4)} + ${__P(customer_checkout_percent,100)} = @@ -451,7 +456,7 @@ guest_checkout_percent - ${__P(guest_checkout_percent,4)} + ${__P(guest_checkout_percent,100)} = @@ -636,12 +641,12 @@ view_catalog_percent - ${__P(view_catalog_percent,62)} + ${__P(view_catalog_percent,100)} = view_product_add_to_cart_percent - ${__P(view_product_add_to_cart_percent,30)} + ${__P(view_product_add_to_cart_percent,100)} = @@ -676,14 +681,14 @@ - http + ${request_protocol} utf-8 Java 4 - + @@ -705,7 +710,7 @@ - + @@ -721,7 +726,7 @@ true - + stoptest @@ -799,7 +804,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}${admin_path} GET @@ -879,7 +884,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}${admin_path}/admin/dashboard/ POST @@ -933,7 +938,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}${admin_path}/admin/cache/massEnable POST @@ -976,7 +981,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}${admin_path}/admin/cache/massRefresh POST @@ -1019,7 +1024,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -1111,7 +1116,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}rest/V1/categories/list GET @@ -1248,7 +1253,7 @@ props.put("category_name", vars.get("category_name")); - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -1319,7 +1324,7 @@ props.put("category_name", vars.get("category_name")); - + ${request_protocol} ${base_path}rest/V1/products GET @@ -1387,7 +1392,7 @@ if (1 == Integer.parseInt(vars.get("simple_products_counter"))) { } else { productList = props.get("simple_products_list"); } -String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); +String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map Map productMap = new HashMap(); @@ -1434,7 +1439,7 @@ productList.add(productMap); - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -1505,7 +1510,7 @@ productList.add(productMap); - + ${request_protocol} ${base_path}rest/V1/products GET @@ -1583,7 +1588,7 @@ if (1 == Integer.parseInt(vars.get("configurable_products_counter"))) { productList = props.get("configurable_products_list"); } -String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); +String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map Map productMap = new HashMap(); @@ -1609,7 +1614,7 @@ productList.add(productMap); - + ${request_protocol} ${base_path}${admin_path}/customer/index/ GET @@ -1643,7 +1648,7 @@ manager.add(cookie); - + @@ -1709,7 +1714,7 @@ manager.add(cookie); - + ${request_protocol} ${base_path}${admin_path}/mui/index/render/ GET @@ -1902,7 +1907,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}${admin_path}/admin/cache/massDisable POST @@ -1938,7 +1943,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}${admin_path}/admin/cache/ GET @@ -1996,7 +2001,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}${admin_path}/admin/cache/ GET @@ -2054,7 +2059,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}${admin_path}/admin/cache/ GET @@ -2134,7 +2139,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}page_cache/block/render/ GET @@ -2215,7 +2220,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}checkout/cart/add POST @@ -2228,7 +2233,7 @@ if ("${cache_indicator}" == "1") { - + continue @@ -2274,7 +2279,7 @@ vars.put("testLabel", "CatProdBrows"); true - + @@ -2283,7 +2288,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path} GET @@ -2305,13 +2310,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2320,7 +2325,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}${category_url_key}${url_suffix} GET @@ -2363,13 +2368,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2378,7 +2383,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -2429,7 +2434,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2451,13 +2456,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2466,7 +2471,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -2517,7 +2522,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2539,13 +2544,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2554,7 +2559,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -2578,7 +2583,7 @@ vars.put("testLabel", "CatProdBrows"); - + continue @@ -2629,7 +2634,7 @@ vars.put("loadType", "Guest"); true - + @@ -2638,7 +2643,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path} GET @@ -2660,7 +2665,7 @@ vars.put("loadType", "Guest"); - + @@ -2705,7 +2710,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}page_cache/block/render/ GET @@ -2749,13 +2754,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2764,7 +2769,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${category_url_key}${url_suffix} GET @@ -2807,13 +2812,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2822,7 +2827,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -2873,7 +2878,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2895,13 +2900,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2939,7 +2944,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -2962,7 +2967,7 @@ vars.put("loadType", "Guest"); - + @@ -2993,7 +2998,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -3014,7 +3019,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_1_name} to your shopping cart. @@ -3043,13 +3048,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3058,7 +3063,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -3109,7 +3114,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -3131,13 +3136,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3175,7 +3180,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -3197,7 +3202,7 @@ vars.put("loadType", "Guest"); - + @@ -3231,7 +3236,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -3252,7 +3257,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_2_name} to your shopping cart. @@ -3281,13 +3286,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3296,7 +3301,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -3318,7 +3323,7 @@ vars.put("loadType", "Guest"); 2 - + false configurable_product_sku @@ -3329,13 +3334,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true 1 @@ -3369,7 +3374,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -3418,7 +3423,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -3448,7 +3453,7 @@ vars.put("loadType", "Guest"); - + @@ -3493,7 +3498,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -3514,7 +3519,7 @@ vars.put("loadType", "Guest"); - + false @@ -3545,7 +3550,7 @@ vars.put("loadType", "Guest"); - + @@ -3579,7 +3584,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -3600,7 +3605,7 @@ vars.put("loadType", "Guest"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -3630,7 +3635,7 @@ vars.put("loadType", "Guest"); - + continue @@ -3682,7 +3687,7 @@ vars.put("loadType", "Guest"); true - + @@ -3691,7 +3696,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path} GET @@ -3713,7 +3718,7 @@ vars.put("loadType", "Guest"); - + @@ -3758,7 +3763,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}page_cache/block/render/ GET @@ -3802,13 +3807,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3817,7 +3822,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${category_url_key}${url_suffix} GET @@ -3860,13 +3865,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3875,7 +3880,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -3926,7 +3931,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -3948,13 +3953,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3992,7 +3997,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -4015,7 +4020,7 @@ vars.put("loadType", "Guest"); - + @@ -4046,7 +4051,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -4067,7 +4072,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_1_name} to your shopping cart. @@ -4096,13 +4101,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4111,7 +4116,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -4162,7 +4167,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -4184,13 +4189,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4228,7 +4233,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -4250,7 +4255,7 @@ vars.put("loadType", "Guest"); - + @@ -4284,7 +4289,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -4305,7 +4310,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_2_name} to your shopping cart. @@ -4334,13 +4339,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4349,7 +4354,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -4371,7 +4376,7 @@ vars.put("loadType", "Guest"); 2 - + false configurable_product_sku @@ -4382,13 +4387,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true 1 @@ -4422,7 +4427,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -4471,7 +4476,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -4501,7 +4506,7 @@ vars.put("loadType", "Guest"); - + @@ -4546,7 +4551,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -4567,7 +4572,7 @@ vars.put("loadType", "Guest"); - + false @@ -4598,7 +4603,7 @@ vars.put("loadType", "Guest"); - + @@ -4632,7 +4637,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -4653,7 +4658,7 @@ vars.put("loadType", "Guest"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -4682,13 +4687,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4697,7 +4702,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/ GET @@ -4768,13 +4773,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4790,7 +4795,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/default/V1/customers/isEmailAvailable POST @@ -4833,13 +4838,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4855,7 +4860,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/default/V1/guest-carts/${cart_id}/estimate-shipping-methods POST @@ -4898,13 +4903,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4920,7 +4925,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/default/V1/guest-carts/${cart_id}/shipping-information POST @@ -4963,13 +4968,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4985,7 +4990,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/default/V1/guest-carts/${cart_id}/payment-information POST @@ -5047,7 +5052,7 @@ vars.put("loadType", "Guest"); - + @@ -5056,7 +5061,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/onepage/success/ GET @@ -5080,7 +5085,7 @@ vars.put("loadType", "Guest"); - + continue @@ -5153,7 +5158,7 @@ vars.put("loadType", "Customer"); true - + @@ -5162,7 +5167,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path} GET @@ -5184,13 +5189,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5199,7 +5204,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}customer/account/login/ GET @@ -5221,7 +5226,7 @@ vars.put("loadType", "Customer"); - + @@ -5266,7 +5271,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}page_cache/block/render/ GET @@ -5310,13 +5315,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5354,7 +5359,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}customer/account/loginPost/ POST @@ -5396,13 +5401,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5411,7 +5416,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}${category_url_key}${url_suffix} GET @@ -5454,13 +5459,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5469,7 +5474,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -5520,7 +5525,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -5542,13 +5547,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5586,7 +5591,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -5609,7 +5614,7 @@ vars.put("loadType", "Customer"); - + @@ -5640,7 +5645,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -5661,7 +5666,7 @@ vars.put("loadType", "Customer"); - + You added ${simple_product_1_name} to your shopping cart. @@ -5690,13 +5695,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5705,7 +5710,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -5756,7 +5761,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -5778,13 +5783,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5822,7 +5827,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -5844,7 +5849,7 @@ vars.put("loadType", "Customer"); - + @@ -5878,7 +5883,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -5899,7 +5904,7 @@ vars.put("loadType", "Customer"); - + You added ${simple_product_2_name} to your shopping cart. @@ -5928,13 +5933,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5943,7 +5948,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -5965,7 +5970,7 @@ vars.put("loadType", "Customer"); 2 - + false configurable_product_sku @@ -5976,13 +5981,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true 1 @@ -6016,7 +6021,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -6065,7 +6070,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -6095,7 +6100,7 @@ vars.put("loadType", "Customer"); - + @@ -6140,7 +6145,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -6161,7 +6166,7 @@ vars.put("loadType", "Customer"); - + false @@ -6192,7 +6197,7 @@ vars.put("loadType", "Customer"); - + @@ -6226,7 +6231,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -6247,7 +6252,7 @@ vars.put("loadType", "Customer"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -6276,13 +6281,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -6291,7 +6296,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}checkout/ GET @@ -6402,13 +6407,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6424,7 +6429,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}rest/default/V1/carts/mine/estimate-shipping-methods-by-address-id POST @@ -6467,13 +6472,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6489,7 +6494,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}rest/default/V1/carts/mine/shipping-information POST @@ -6532,13 +6537,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6554,7 +6559,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}rest/default/V1/carts/mine/payment-information POST @@ -6597,13 +6602,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -6612,7 +6617,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}checkout/onepage/success/ GET @@ -6636,7 +6641,7 @@ vars.put("loadType", "Customer"); - + stoptest @@ -6694,7 +6699,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}DeploymentEvent.php POST @@ -6744,7 +6749,7 @@ props.remove("customer_emails_list"); - + false @@ -6808,7 +6813,7 @@ props.remove("customer_emails_list"); - + false @@ -6844,7 +6849,7 @@ props.remove("customer_emails_list"); ${report_save_path}/detailed-urls-report.log - + false From dda3e02790fa2e32ec28630df570a8426ad395a9 Mon Sep 17 00:00:00 2001 From: Oleh Posyniak Date: Mon, 4 Sep 2017 10:02:06 +0300 Subject: [PATCH 077/151] MAGETWO-71890: Magento fails with deploymentConfig present on new install --- .../Deploy/Test/Unit/Console/CommandListTest.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Deploy/Test/Unit/Console/CommandListTest.php b/app/code/Magento/Deploy/Test/Unit/Console/CommandListTest.php index 41052b2760c78..0d305551e0af2 100644 --- a/app/code/Magento/Deploy/Test/Unit/Console/CommandListTest.php +++ b/app/code/Magento/Deploy/Test/Unit/Console/CommandListTest.php @@ -40,12 +40,19 @@ protected function setUp() public function testGetCommands() { + $configImportCommand = $this->getMockBuilder(ConfigImportCommand::class) + ->disableOriginalConstructor() + ->getMock(); + $this->objectManagerMock->expects($this->once()) ->method('get') - ->withConsecutive([ - ConfigImportCommand::class, + ->willReturnMap([ + [ConfigImportCommand::class, $configImportCommand], ]); - $this->model->getCommands(); + $this->assertSame( + [$configImportCommand], + $this->model->getCommands() + ); } } From 74274a0cdbb6220c43e987d43cfbb53c3fac2a52 Mon Sep 17 00:00:00 2001 From: Michail Slabko Date: Mon, 4 Sep 2017 11:13:07 +0300 Subject: [PATCH 078/151] MAGETWO-70392: benchmarks.jmx does not work with https --- setup/performance-toolkit/benchmark.jmx | 242 ++++++++++++------------ 1 file changed, 121 insertions(+), 121 deletions(-) diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index a812626e51cbf..07aa48f8b4504 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -688,7 +688,7 @@ 4 - + @@ -710,7 +710,7 @@ - + @@ -726,7 +726,7 @@ true - + stoptest @@ -1648,7 +1648,7 @@ manager.add(cookie); - + @@ -2233,7 +2233,7 @@ if ("${cache_indicator}" == "1") { - + continue @@ -2279,7 +2279,7 @@ vars.put("testLabel", "CatProdBrows"); true - + @@ -2310,13 +2310,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2368,13 +2368,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2456,13 +2456,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2544,13 +2544,13 @@ vars.put("testLabel", "CatProdBrows"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2583,7 +2583,7 @@ vars.put("testLabel", "CatProdBrows"); - + continue @@ -2634,7 +2634,7 @@ vars.put("loadType", "Guest"); true - + @@ -2665,7 +2665,7 @@ vars.put("loadType", "Guest"); - + @@ -2754,13 +2754,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2812,13 +2812,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2900,13 +2900,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -2967,7 +2967,7 @@ vars.put("loadType", "Guest"); - + @@ -3019,7 +3019,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_1_name} to your shopping cart. @@ -3048,13 +3048,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3136,13 +3136,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3202,7 +3202,7 @@ vars.put("loadType", "Guest"); - + @@ -3257,7 +3257,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_2_name} to your shopping cart. @@ -3286,13 +3286,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3323,7 +3323,7 @@ vars.put("loadType", "Guest"); 2 - + false configurable_product_sku @@ -3334,13 +3334,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true 1 @@ -3453,7 +3453,7 @@ vars.put("loadType", "Guest"); - + @@ -3519,7 +3519,7 @@ vars.put("loadType", "Guest"); - + false @@ -3550,7 +3550,7 @@ vars.put("loadType", "Guest"); - + @@ -3605,7 +3605,7 @@ vars.put("loadType", "Guest"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -3635,7 +3635,7 @@ vars.put("loadType", "Guest"); - + continue @@ -3687,7 +3687,7 @@ vars.put("loadType", "Guest"); true - + @@ -3718,7 +3718,7 @@ vars.put("loadType", "Guest"); - + @@ -3807,13 +3807,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3865,13 +3865,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -3953,13 +3953,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4020,7 +4020,7 @@ vars.put("loadType", "Guest"); - + @@ -4072,7 +4072,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_1_name} to your shopping cart. @@ -4101,13 +4101,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4189,13 +4189,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4255,7 +4255,7 @@ vars.put("loadType", "Guest"); - + @@ -4310,7 +4310,7 @@ vars.put("loadType", "Guest"); - + You added ${simple_product_2_name} to your shopping cart. @@ -4339,13 +4339,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4376,7 +4376,7 @@ vars.put("loadType", "Guest"); 2 - + false configurable_product_sku @@ -4387,13 +4387,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true 1 @@ -4506,7 +4506,7 @@ vars.put("loadType", "Guest"); - + @@ -4572,7 +4572,7 @@ vars.put("loadType", "Guest"); - + false @@ -4603,7 +4603,7 @@ vars.put("loadType", "Guest"); - + @@ -4658,7 +4658,7 @@ vars.put("loadType", "Guest"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -4687,13 +4687,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -4773,13 +4773,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4838,13 +4838,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4903,13 +4903,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -4968,13 +4968,13 @@ vars.put("loadType", "Guest"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -5052,7 +5052,7 @@ vars.put("loadType", "Guest"); - + @@ -5085,7 +5085,7 @@ vars.put("loadType", "Guest"); - + continue @@ -5158,7 +5158,7 @@ vars.put("loadType", "Customer"); true - + @@ -5189,13 +5189,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5226,7 +5226,7 @@ vars.put("loadType", "Customer"); - + @@ -5315,13 +5315,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5401,13 +5401,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5459,13 +5459,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5547,13 +5547,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5614,7 +5614,7 @@ vars.put("loadType", "Customer"); - + @@ -5666,7 +5666,7 @@ vars.put("loadType", "Customer"); - + You added ${simple_product_1_name} to your shopping cart. @@ -5695,13 +5695,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5783,13 +5783,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5849,7 +5849,7 @@ vars.put("loadType", "Customer"); - + @@ -5904,7 +5904,7 @@ vars.put("loadType", "Customer"); - + You added ${simple_product_2_name} to your shopping cart. @@ -5933,13 +5933,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -5970,7 +5970,7 @@ vars.put("loadType", "Customer"); 2 - + false configurable_product_sku @@ -5981,13 +5981,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true 1 @@ -6100,7 +6100,7 @@ vars.put("loadType", "Customer"); - + @@ -6166,7 +6166,7 @@ vars.put("loadType", "Customer"); - + false @@ -6197,7 +6197,7 @@ vars.put("loadType", "Customer"); - + @@ -6252,7 +6252,7 @@ vars.put("loadType", "Customer"); - + You added ${configurable_product_1_name} to your shopping cart. @@ -6281,13 +6281,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -6407,13 +6407,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6472,13 +6472,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6537,13 +6537,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + true @@ -6602,13 +6602,13 @@ vars.put("loadType", "Customer"); - + ${think_time_delay_offset} ${think_time_deviation} - + @@ -6641,7 +6641,7 @@ vars.put("loadType", "Customer"); - + stoptest @@ -6749,7 +6749,7 @@ props.remove("customer_emails_list"); - + false @@ -6813,7 +6813,7 @@ props.remove("customer_emails_list"); - + false @@ -6849,7 +6849,7 @@ props.remove("customer_emails_list"); ${report_save_path}/detailed-urls-report.log - + false From 5ca7b75c20a4c114644197dd1e042a0441c4ab50 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Mon, 4 Sep 2017 13:03:16 +0300 Subject: [PATCH 079/151] MAGETWO-70819: Widget with condition "special date to" --- .../Rule/Model/Condition/Sql/BuilderTest.php | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php diff --git a/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php b/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php new file mode 100644 index 0000000000000..8e2d4ec4d369d --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php @@ -0,0 +1,67 @@ +model = Bootstrap::getObjectManager()->create(\Magento\Rule\Model\Condition\Sql\Builder::class); + } + + public function testAttachConditionToCollection() + { + /** @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory */ + $collectionFactory = Bootstrap::getObjectManager()->create( + \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class + ); + /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */ + $collection = $collectionFactory->create(); + + /** @var \Magento\CatalogWidget\Model\RuleFactory $ruleFactory */ + $ruleFactory = Bootstrap::getObjectManager()->create(\Magento\CatalogWidget\Model\RuleFactory::class); + /** @var \Magento\CatalogWidget\Model\Rule $rule */ + $rule = $ruleFactory->create(); + + $ruleConditionArray = [ + 'conditions' => [ + '1' => [ + 'type' => \Magento\CatalogWidget\Model\Rule\Condition\Combine::class, + 'aggregator' => 'all', + 'value' => '1', + 'new_child' => '' + ], + '1--1' => [ + 'type' => \Magento\CatalogWidget\Model\Rule\Condition\Product::class, + 'attribute' => 'category_ids', + 'operator' => '==', + 'value' => '3' + ], + '1--2' => [ + 'type' => \Magento\CatalogWidget\Model\Rule\Condition\Product::class, + 'attribute' => 'special_to_date', + 'operator' => '==', + 'value' => '2017-09-15' + ], + ] + ]; + + + $rule->loadPost($ruleConditionArray); + $this->model->attachConditionToCollection($collection, $rule->getConditions()); + + $whereString = 'WHERE (category_id IN (\'3\')))) AND(IFNULL(`e`.`entity_id`, 0) = \'2017-09-15\') ))'; + $this->assertNotFalse(strpos($collection->getSelectSql(true), $whereString)); + } +} From cebb3a334f3703d10d2d4091d5701d38fd40d7f4 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Mon, 4 Sep 2017 13:24:32 +0300 Subject: [PATCH 080/151] MAGETWO-49796: Catalog top nav, CSS class not set to active when using Varnish --- lib/web/mage/menu.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/web/mage/menu.js b/lib/web/mage/menu.js index 8a212b2bd445d..05d3217414883 100644 --- a/lib/web/mage/menu.js +++ b/lib/web/mage/menu.js @@ -206,8 +206,8 @@ define([ if (firstCategoryUrl) { lastUrlSection = firstCategoryUrl.substr(firstCategoryUrl.lastIndexOf('/')); - categoryUrlExtension = (lastUrlSection.lastIndexOf('.') !== -1) - ? lastUrlSection.substr(lastUrlSection.lastIndexOf('.')) : ''; + categoryUrlExtension = lastUrlSection.lastIndexOf('.') !== -1 ? + lastUrlSection.substr(lastUrlSection.lastIndexOf('.')) : ''; possibleCategoryUrl = currentUrl.substr(0, currentUrl.lastIndexOf('/')) + categoryUrlExtension; this._setActiveMenuForCategory(possibleCategoryUrl); From 1addf5360143797ca31feedb4bca0477b528a712 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Mon, 4 Sep 2017 14:20:12 +0300 Subject: [PATCH 081/151] MAGETWO-70819: Widget with condition "special date to" --- .../testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php b/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php index 8e2d4ec4d369d..c9640ceba87d2 100644 --- a/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php +++ b/dev/tests/integration/testsuite/Magento/Rule/Model/Condition/Sql/BuilderTest.php @@ -57,7 +57,6 @@ public function testAttachConditionToCollection() ] ]; - $rule->loadPost($ruleConditionArray); $this->model->attachConditionToCollection($collection, $rule->getConditions()); From c6d8494fea1dd7655de8fd6ed96993c00433624c Mon Sep 17 00:00:00 2001 From: kalexeyev Date: Mon, 4 Sep 2017 18:49:43 +0300 Subject: [PATCH 082/151] MAGETWO-71215: [EAV] Junk attribute values created when scheduling new staging update --- .../Product/Initialization/Helper.php | 19 +- .../Initialization/Helper/AttributeFilter.php | 41 ++++ .../Helper/AttributeFilterTest.php | 203 ++++++++++++++++++ .../Product/Initialization/HelperTest.php | 13 ++ 4 files changed, 273 insertions(+), 3 deletions(-) create mode 100644 app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper/AttributeFilter.php create mode 100644 app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/AttributeFilterTest.php diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php index 17a6bf6a189d1..beb6f2b13bcfe 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php @@ -12,6 +12,7 @@ use Magento\Catalog\Model\Product\Initialization\Helper\ProductLinks; use Magento\Catalog\Model\Product\Link\Resolver as LinkResolver; use Magento\Framework\App\ObjectManager; +use Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper\AttributeFilter; /** * @api @@ -84,6 +85,11 @@ class Helper */ private $linkTypeProvider; + /** + * @var AttributeFilter + */ + private $attributeFilter; + /** * Constructor * @@ -97,6 +103,7 @@ class Helper * @param \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory|null $productLinkFactory * @param \Magento\Catalog\Api\ProductRepositoryInterface|null $productRepository * @param \Magento\Catalog\Model\Product\LinkTypeProvider|null $linkTypeProvider + * @param AttributeFilter|null $attributeFilter * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ public function __construct( @@ -109,7 +116,8 @@ public function __construct( \Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory $customOptionFactory = null, \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory $productLinkFactory = null, \Magento\Catalog\Api\ProductRepositoryInterface $productRepository = null, - \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider = null + \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider = null, + AttributeFilter $attributeFilter = null ) { $this->request = $request; $this->storeManager = $storeManager; @@ -125,6 +133,8 @@ public function __construct( ->get(\Magento\Catalog\Api\ProductRepositoryInterface::class); $this->linkTypeProvider = $linkTypeProvider ?: \Magento\Framework\App\ObjectManager::getInstance() ->get(\Magento\Catalog\Model\Product\LinkTypeProvider::class); + $this->attributeFilter = $attributeFilter ?: \Magento\Framework\App\ObjectManager::getInstance() + ->get(AttributeFilter::class); } /** @@ -187,6 +197,11 @@ public function initializeFromData(\Magento\Catalog\Model\Product $product, arra $productOptions = []; } $productData['tier_price'] = isset($productData['tier_price']) ? $productData['tier_price'] : []; + + $useDefaults = (array)$this->request->getPost('use_default', []); + + $productData = $this->attributeFilter->prepareProductAttributes($product, $productData, $useDefaults); + $product->addData($productData); if ($wasLockedMedia) { @@ -196,8 +211,6 @@ public function initializeFromData(\Magento\Catalog\Model\Product $product, arra /** * Check "Use Default Value" checkboxes values */ - $useDefaults = (array)$this->request->getPost('use_default', []); - foreach ($useDefaults as $attributeCode => $useDefaultState) { if ($useDefaultState) { $product->setData($attributeCode, null); diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper/AttributeFilter.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper/AttributeFilter.php new file mode 100644 index 0000000000000..237168282afae --- /dev/null +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper/AttributeFilter.php @@ -0,0 +1,41 @@ + $value) { + $considerUseDefaultsAttribute = !isset($useDefaults[$attribute]) || $useDefaults[$attribute] === "1"; + if ($value === '' && $considerUseDefaultsAttribute) { + /** @var $product Product */ + if ((bool)$product->getData($attribute) === (bool)$value) { + unset($productData[$attribute]); + } + } + } + return $productData; + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/AttributeFilterTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/AttributeFilterTest.php new file mode 100644 index 0000000000000..28617addc6d27 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/Helper/AttributeFilterTest.php @@ -0,0 +1,203 @@ +model = $objectHelper->getObject(AttributeFilter::class); + } + + /** + * @param array $requestProductData + * @param array $useDefaults + * @param array $expectedProductData + * @param array $initialProductData + * @dataProvider setupInputDataProvider + */ + public function testPrepareProductAttributes( + $requestProductData, + $useDefaults, + $expectedProductData, + $initialProductData + ) { + $productMockMap = $this->getMockBuilder(Product::class) + ->disableOriginalConstructor() + ->setMethods(['getData']) + ->getMock(); + + if (!empty($initialProductData)) { + $productMockMap->expects($this->any())->method('getData')->willReturnMap($initialProductData); + } + + $actualProductData = $this->model->prepareProductAttributes($productMockMap, $requestProductData, $useDefaults); + $this->assertEquals($expectedProductData, $actualProductData); + } + + /** + * @return array + * @SuppressWarnings(PHPMD.ExcessiveMethodLength) + */ + public function setupInputDataProvider() + { + return [ + 'create_new_product' => [ + 'productData' => [ + 'name' => 'testName', + 'sku' => 'testSku', + 'price' => '100', + 'description' => '' + ], + 'useDefaults' => [], + 'expectedProductData' => [ + 'name' => 'testName', + 'sku' => 'testSku', + 'price' => '100' + ], + 'initialProductData' => [] + ], + 'update_product_without_use_defaults' => [ + 'productData' => [ + 'name' => 'testName2', + 'sku' => 'testSku2', + 'price' => '101', + 'description' => '', + 'special_price' => null + ], + 'useDefaults' => [], + 'expectedProductData' => [ + 'name' => 'testName2', + 'sku' => 'testSku2', + 'price' => '101', + 'special_price' => null + ], + 'initialProductData' => [ + ['name', 'testName2'], + ['sku', 'testSku2'], + ['price', '101'], + ['special_price', null] + ] + ], + 'update_product_without_use_defaults_2' => [ + 'productData' => [ + 'name' => 'testName2', + 'sku' => 'testSku2', + 'price' => '101', + 'description' => 'updated description', + 'special_price' => null + ], + 'useDefaults' => [], + 'expectedProductData' => [ + 'name' => 'testName2', + 'sku' => 'testSku2', + 'price' => '101', + 'description' => 'updated description', + 'special_price' => null + ], + 'initialProductData' => [ + ['name', 'testName2'], + ['sku', 'testSku2'], + ['price', '101'], + ['special_price', null] + ] + ], + 'update_product_with_use_defaults' => [ + 'productData' => [ + 'name' => 'testName2', + 'sku' => 'testSku2', + 'price' => '101', + 'description' => '', + 'special_price' => null + ], + 'useDefaults' => [ + 'description' => '0' + ], + 'expectedProductData' => [ + 'name' => 'testName2', + 'sku' => 'testSku2', + 'price' => '101', + 'special_price' => null, + 'description' => '' + ], + 'initialProductData' => [ + ['name', 'testName2'], + ['sku', 'testSku2'], + ['price', '101'], + ['special_price', null], + ['description', 'descr text'] + ] + ], + 'update_product_with_use_defaults_2' => [ + 'requestProductData' => [ + 'name' => 'testName3', + 'sku' => 'testSku3', + 'price' => '103', + 'description' => 'descr modified', + 'special_price' => '100' + ], + 'useDefaults' => [ + 'description' => '0' + ], + 'expectedProductData' => [ + 'name' => 'testName3', + 'sku' => 'testSku3', + 'price' => '103', + 'special_price' => '100', + 'description' => 'descr modified' + ], + 'initialProductData' => [ + ['name', null,'testName2'], + ['sku', null, 'testSku2'], + ['price', null, '101'], + ['description', null, 'descr text'] + ] + ], + 'update_product_with_use_defaults_3' => [ + 'requestProductData' => [ + 'name' => 'testName3', + 'sku' => 'testSku3', + 'price' => '103', + 'special_price' => '100' + ], + 'useDefaults' => [ + 'description' => '1' + ], + 'expectedProductData' => [ + 'name' => 'testName3', + 'sku' => 'testSku3', + 'price' => '103', + 'special_price' => '100', + ], + 'initialProductData' => [ + ['name', null,'testName2'], + ['sku', null, 'testSku2'], + ['price', null, '101'], + ['description', null, 'descr text'] + ] + ], + ]; + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php index c164c281a4e53..dce3f5886d1a8 100644 --- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php @@ -20,6 +20,7 @@ use Magento\Catalog\Model\Product\LinkTypeProvider; use Magento\Catalog\Api\Data\ProductLinkTypeInterface; use Magento\Catalog\Model\ProductLink\Link as ProductLink; +use Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper\AttributeFilter; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -89,6 +90,11 @@ class HelperTest extends \PHPUnit\Framework\TestCase */ protected $productLinksMock; + /** + * @var AttributeFilter|\PHPUnit_Framework_MockObject_MockObject + */ + protected $attributeFilterMock; + protected function setUp() { $this->objectManager = new ObjectManager($this); @@ -134,6 +140,10 @@ protected function setUp() $this->productLinksMock->expects($this->any()) ->method('initializeLinks') ->willReturn($this->productMock); + $this->attributeFilterMock = $this->getMockBuilder(AttributeFilter::class) + ->setMethods(['prepareProductAttributes']) + ->disableOriginalConstructor() + ->getMock(); $this->helper = $this->objectManager->getObject( Helper::class, @@ -146,6 +156,7 @@ protected function setUp() 'productLinkFactory' => $this->productLinkFactoryMock, 'productRepository' => $this->productRepositoryMock, 'linkTypeProvider' => $this->linkTypeProviderMock, + 'attributeFilter' => $this->attributeFilterMock ] ); @@ -269,6 +280,8 @@ public function testInitialize( ->getMock(); }); + $this->attributeFilterMock->expects($this->any())->method('prepareProductAttributes')->willReturnArgument(1); + $this->assertEquals($this->productMock, $this->helper->initialize($this->productMock)); $this->assertEquals($expWebsiteIds, $this->productMock->getDataByKey('website_ids')); From 43c542ee09301fb5104783248beea1fc509506e1 Mon Sep 17 00:00:00 2001 From: Stanislav Idolov Date: Tue, 5 Sep 2017 08:49:25 +0300 Subject: [PATCH 083/151] MAGETWO-70819: Widget with condition "special date to" --- app/code/Magento/Rule/Model/Condition/Sql/Builder.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php index fff4c08cc0c66..41a55f4c25166 100644 --- a/app/code/Magento/Rule/Model/Condition/Sql/Builder.php +++ b/app/code/Magento/Rule/Model/Condition/Sql/Builder.php @@ -108,6 +108,8 @@ protected function _joinTablesToCollection( } /** + * Returns sql expression based on rule condition. + * * @param AbstractCondition $condition * @param string $value * @return string @@ -117,6 +119,7 @@ protected function _getMappedSqlCondition(AbstractCondition $condition, $value = { $argument = $condition->getMappedSqlField(); + // If rule hasn't valid argument - create negative expression to prevent incorrect rule behavior. if (empty($argument)) { return $this->_expressionFactory->create(['expression' => '1 = -1']); } From 000a7a7b2175bb2c58a45edc2de5a1137db9c74c Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Tue, 5 Sep 2017 09:59:53 +0300 Subject: [PATCH 084/151] MAGETWO-71931: Product export doesn`t work. Error 503 Service Unavailable --- app/code/Magento/CatalogImportExport/Model/Export/Product.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/CatalogImportExport/Model/Export/Product.php b/app/code/Magento/CatalogImportExport/Model/Export/Product.php index 34bd8d9600410..07dea303e1584 100644 --- a/app/code/Magento/CatalogImportExport/Model/Export/Product.php +++ b/app/code/Magento/CatalogImportExport/Model/Export/Product.php @@ -782,7 +782,7 @@ protected function getItemsPerPage() } // Tested one product to have up to such size - $memoryPerProduct = 100000; + $memoryPerProduct = 500000; // Decrease memory limit to have supply $memoryUsagePercent = 0.8; // Minimum Products limit From 12c124421bf2b035512f5bfcff0a63fd06291671 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Tue, 5 Sep 2017 12:19:24 +0300 Subject: [PATCH 085/151] MAGETWO-62464: Travis CI: GD2 imagettfbbox creates image with invalid size --- .../Magento/Framework/Image/Adapter/InterfaceTest.php | 6 +----- lib/internal/Magento/Framework/Image/Adapter/Gd2.php | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php b/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php index 9c89b906318ed..a76b56b13bc08 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php @@ -5,8 +5,6 @@ */ namespace Magento\Framework\Image\Adapter; -use Magento\Framework\App\Filesystem\DirectoryList; - /** * @magentoAppIsolation enabled */ @@ -547,9 +545,7 @@ public function cropDataProvider() */ public function testCreatePngFromString($pixel1, $expectedColor1, $pixel2, $expectedColor2, $adapterType) { - if (!function_exists('imagettfbbox') - || (getenv('TRAVIS') && getenv('TRAVIS_PHP_VERSION') == '7.1') - ) { + if (!function_exists('imagettfbbox')) { $this->markTestSkipped('Workaround for problem with imagettfbbox() function on Travis'); } $adapter = $this->_getAdapter($adapterType); diff --git a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php index f0807cb6d1cd3..9500cf99eafc7 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php +++ b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php @@ -737,8 +737,8 @@ protected function _createImageFromText($text) protected function _createImageFromTtfText($text, $font) { $boundingBox = imagettfbbox($this->_fontSize, 0, $font, $text); - $width = abs($boundingBox[4]) + abs($boundingBox[0]); - $height = abs($boundingBox[5]) + abs($boundingBox[1]); + $width = abs($boundingBox[4] - $boundingBox[0]); + $height = abs($boundingBox[5] - $boundingBox[1]); $this->_createEmptyImage($width, $height); From 129592c675408e3012ace1bcaca5eff27e48da70 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi Date: Tue, 5 Sep 2017 12:57:28 +0300 Subject: [PATCH 086/151] MAGETWO-72184: PHP precision causes issues with float and rounded digits - Set precision and serialize_precision equal to avoid issues with rounding --- app/bootstrap.php | 6 +- .../DB/DataConverter/SerializedToJson.php | 27 ++++++++- .../DataConverter/SerializedToJsonTest.php | 58 ++++++++----------- 3 files changed, 54 insertions(+), 37 deletions(-) diff --git a/app/bootstrap.php b/app/bootstrap.php index 94142dcf0c225..6701a9f4dd51e 100644 --- a/app/bootstrap.php +++ b/app/bootstrap.php @@ -62,6 +62,6 @@ date_default_timezone_set('UTC'); -/* Adjustment of precision value for several versions of PHP */ -ini_set('precision', 17); -ini_set('serialize_precision', 17); +/* For data consistency between displaying (printing) and serialization a float number */ +ini_set('precision', 14); +ini_set('serialize_precision', 14); diff --git a/lib/internal/Magento/Framework/DB/DataConverter/SerializedToJson.php b/lib/internal/Magento/Framework/DB/DataConverter/SerializedToJson.php index 7f6f072a8a1d7..bc31cb91ecede 100644 --- a/lib/internal/Magento/Framework/DB/DataConverter/SerializedToJson.php +++ b/lib/internal/Magento/Framework/DB/DataConverter/SerializedToJson.php @@ -93,7 +93,17 @@ protected function unserializeValue($value) } /** - * Encode value with json encoder + * Encode value with json encoder. + * + * In PHP version < 7.1.0 serialize() uses PG(serialize_precision) which set to 17 be default. + * Since json_encode() uses EG(precision) which set to 14 be default, json_encode() removes lower digits of + * fraction parts and destroys original value even if PHP's float could hold more precise float value. + * To prevent this issue EG(precision) is set to 17 to be equal with PG(serialize_precision) during + * data converting from serialized format to JSON. + * + * In PHP version >= 7.1.0 serialize() and json_encode() use PG(serialize_precision) which set to -1 be default. + * Setting -1 uses better algorithm for rounding float numbers. + * But for data consistency during converting process PG(serialize_precision) is set to 17. * * @param string $value * @return string @@ -101,7 +111,22 @@ protected function unserializeValue($value) */ protected function encodeJson($value) { + $storedPrecision = ini_get('precision'); + $storedSerializePrecision = ini_get('serialize_precision'); + + if (PHP_VERSION_ID < 70100) { + // In PHP version < 7.1.0 json_encode() uses EG(precision). + ini_set('precision', 17); + } else { + // In PHP version >= 7.1.0 json_encode() uses PG(serialize_precision). + ini_set('serialize_precision', 17); + } + $value = $this->json->serialize($value); + + ini_set('precision', $storedPrecision); + ini_set('serialize_precision', $storedSerializePrecision); + if (json_last_error()) { throw new DataConversionException(json_last_error_msg()); } diff --git a/lib/internal/Magento/Framework/DB/Test/Unit/DataConverter/SerializedToJsonTest.php b/lib/internal/Magento/Framework/DB/Test/Unit/DataConverter/SerializedToJsonTest.php index 452e49d414b71..23143e635fb24 100644 --- a/lib/internal/Magento/Framework/DB/Test/Unit/DataConverter/SerializedToJsonTest.php +++ b/lib/internal/Magento/Framework/DB/Test/Unit/DataConverter/SerializedToJsonTest.php @@ -8,20 +8,9 @@ use Magento\Framework\Serialize\Serializer\Serialize; use Magento\Framework\Serialize\Serializer\Json; use Magento\Framework\DB\DataConverter\SerializedToJson; -use Magento\Framework\TestFramework\Unit\Helper\ObjectManager; class SerializedToJsonTest extends \PHPUnit\Framework\TestCase { - /** - * @var Serialize|\PHPUnit_Framework_MockObject_MockObject - */ - private $serializeMock; - - /** - * @var Json|\PHPUnit_Framework_MockObject_MockObject - */ - private $jsonMock; - /** * @var SerializedToJson */ @@ -29,31 +18,34 @@ class SerializedToJsonTest extends \PHPUnit\Framework\TestCase protected function setUp() { - $objectManager = new ObjectManager($this); - $this->serializeMock = $this->createMock(Serialize::class); - $this->jsonMock = $this->createMock(Json::class); - $this->serializedToJson = $objectManager->getObject( - SerializedToJson::class, - [ - 'serialize' => $this->serializeMock, - 'json' => $this->jsonMock - ] + $this->serializedToJson = new SerializedToJson( + new Serialize(), + new Json() ); } - public function testConvert() + /** + * Tests converting from serialized to JSON format with different precision settings. + * + * @param $serializedData + * @param $expectedJson + * @dataProvider convertDataProvider + */ + public function testConvert($serializedData, $expectedJson) + { + $this->assertEquals($expectedJson, $this->serializedToJson->convert($serializedData)); + } + + /** + * @case #1 - Serialized 0.1234567890123456789 with serialize_precision = 17 (default for PHP version < 7.1.0) + * @case #2 - Serialized 2.203 with serialize_precision = 17 (default for PHP version < 7.1.0 ) + * @return array + */ + public function convertDataProvider() { - $serializedData = 'serialized data'; - $jsonData = 'json data'; - $unserializedData = 'unserialized data'; - $this->serializeMock->expects($this->once()) - ->method('unserialize') - ->with($serializedData) - ->willReturn($unserializedData); - $this->jsonMock->expects($this->once()) - ->method('serialize') - ->with($unserializedData) - ->willReturn($jsonData); - $this->assertEquals($jsonData, $this->serializedToJson->convert($serializedData)); + return [ + 1 => ['serializedData' => 'a:1:{i:0;d:0.12345678901234568;}', 'expectedJson' => '[0.12345678901234568]'], + 2 => ['serializedData' => 'a:1:{i:0;d:2.2029999999999998;}', 'expectedJson' => '[2.2029999999999998]'] + ]; } } From 504febb02c08b40228c198bc8c9233407d63dbf6 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Tue, 5 Sep 2017 13:58:39 +0300 Subject: [PATCH 087/151] MAGETWO-62464: Travis CI: GD2 imagettfbbox creates image with invalid size --- lib/internal/Magento/Framework/Image/Adapter/Gd2.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php index 9500cf99eafc7..f1bedaceef09f 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php +++ b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php @@ -748,7 +748,7 @@ protected function _createImageFromTtfText($text, $font) $this->_fontSize, 0, 0, - $height - abs($boundingBox[1]), + $height, $black, $font, $text From d8d13884b852adb1af48c82a82c95bf9b5a3795f Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Tue, 5 Sep 2017 14:53:28 -0500 Subject: [PATCH 088/151] MAGETWO-71765: Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Fixed return type for _getCaptureAmount. - Swapped out round($amount, 2) for formatPrice. --- app/code/Magento/Paypal/Model/Payflowpro.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Paypal/Model/Payflowpro.php b/app/code/Magento/Paypal/Model/Payflowpro.php index 8d59a9578a17d..4fcfc3e3b121f 100644 --- a/app/code/Magento/Paypal/Model/Payflowpro.php +++ b/app/code/Magento/Paypal/Model/Payflowpro.php @@ -392,7 +392,7 @@ public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount * Get capture amount * * @param float $amount - * @return float + * @return string|int */ protected function _getCaptureAmount($amount) { @@ -512,7 +512,7 @@ public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount) $request = $this->buildBasicRequest(); $request->setTrxtype(self::TRXTYPE_CREDIT); $request->setOrigid($payment->getParentTransactionId()); - $request->setAmt(round($amount, 2)); + $request->setAmt($this->formatPrice($amount)); $response = $this->postRequest($request, $this->getConfig()); $this->processErrors($response); @@ -607,7 +607,7 @@ public function postRequest(DataObject $request, ConfigInterface $config) protected function _buildPlaceRequest(DataObject $payment, $amount) { $request = $this->buildBasicRequest(); - $request->setAmt(round($amount, 2)); + $request->setAmt($this->formatPrice($amount)); $request->setAcct($payment->getCcNumber()); $request->setExpdate(sprintf('%02d', $payment->getCcExpMonth()) . substr($payment->getCcExpYear(), -2, 2)); $request->setCvv2($payment->getCcCid()); From 42dfd059dbbc698617869794b56c32a0306f7cdc Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Tue, 5 Sep 2017 15:59:45 -0500 Subject: [PATCH 089/151] MAGETWO-71765: Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Refactored _getCaptureAmount($amount) to remove floating point equality comparison in case of precision issue. --- app/code/Magento/Paypal/Model/Payflowpro.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Paypal/Model/Payflowpro.php b/app/code/Magento/Paypal/Model/Payflowpro.php index 4fcfc3e3b121f..d5b07f3236bdd 100644 --- a/app/code/Magento/Paypal/Model/Payflowpro.php +++ b/app/code/Magento/Paypal/Model/Payflowpro.php @@ -391,15 +391,15 @@ public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount /** * Get capture amount * - * @param float $amount + * @param string $amount * @return string|int */ protected function _getCaptureAmount($amount) { $infoInstance = $this->getInfoInstance(); - $amountToPay = $this->formatPrice($amount); - $authorizedAmount = $this->formatPrice($infoInstance->getAmountAuthorized()); - return $amountToPay != $authorizedAmount ? $amountToPay : 0; + $amountToPay = $amount; + $authorizedAmount = $infoInstance->getAmountAuthorized(); + return abs($amountToPay - $authorizedAmount) < 0.00001 ? 0 : $amountToPay; } /** @@ -424,7 +424,7 @@ public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount) $request->setOrigid($payment->getParentTransactionId()); $captureAmount = $this->_getCaptureAmount($amount); if ($captureAmount) { - $request->setAmt($captureAmount); + $request->setAmt($this->formatPrice($captureAmount)); } $trxType = $this->getInfoInstance()->hasAmountPaid() ? self::TRXTYPE_SALE : self::TRXTYPE_DELAYED_CAPTURE; $request->setTrxtype($trxType); From e6bbe78b03eab00f63bba53a65319d1a3c7aeb01 Mon Sep 17 00:00:00 2001 From: Eric Bohanon Date: Tue, 5 Sep 2017 17:05:56 -0500 Subject: [PATCH 090/151] MAGETWO-70346: Configurable product shows on frontend after deleting child products - Add plugin around delete to update all indexers for child products - Add class to update all indexers related to product - Unit Tests - Functional test --- .../Adminhtml/Product/MassDelete.php | 16 ++- .../Catalog/Model/Indexer/Product/Full.php | 101 ++++++++++++++ .../Unit/Model/Indexer/Product/FullTest.php | 132 ++++++++++++++++++ app/code/Magento/Catalog/etc/di.xml | 10 ++ app/code/Magento/CatalogInventory/etc/di.xml | 7 + app/code/Magento/CatalogSearch/etc/di.xml | 7 + .../Plugin/Model/ResourceModel/Product.php | 46 ++++++ .../Model/ResourceModel/ProductTest.php | 81 ++++++++++- .../Magento/ConfigurableProduct/etc/di.xml | 5 + .../DeleteChildConfigurableProductTest.php | 104 ++++++++++++++ .../DeleteChildConfigurableProductTest.xml | 22 +++ 11 files changed, 524 insertions(+), 7 deletions(-) create mode 100644 app/code/Magento/Catalog/Model/Indexer/Product/Full.php create mode 100644 app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/FullTest.php create mode 100644 dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteChildConfigurableProductTest.php create mode 100644 dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteChildConfigurableProductTest.xml diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php index a27783ab3f3fe..2402fb213cda0 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/MassDelete.php @@ -7,10 +7,10 @@ namespace Magento\Catalog\Controller\Adminhtml\Product; use Magento\Framework\Controller\ResultFactory; -use Magento\Catalog\Controller\Adminhtml\Product\Builder; use Magento\Backend\App\Action\Context; use Magento\Ui\Component\MassAction\Filter; use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; +use Magento\Catalog\Api\ProductRepositoryInterface; class MassDelete extends \Magento\Catalog\Controller\Adminhtml\Product { @@ -26,20 +26,29 @@ class MassDelete extends \Magento\Catalog\Controller\Adminhtml\Product */ protected $collectionFactory; + /** + * @var ProductRepositoryInterface + */ + private $productRepository; + /** * @param Context $context * @param Builder $productBuilder * @param Filter $filter * @param CollectionFactory $collectionFactory + * @param ProductRepositoryInterface $productRepository */ public function __construct( Context $context, Builder $productBuilder, Filter $filter, - CollectionFactory $collectionFactory + CollectionFactory $collectionFactory, + ProductRepositoryInterface $productRepository = null ) { $this->filter = $filter; $this->collectionFactory = $collectionFactory; + $this->productRepository = $productRepository + ?: \Magento\Framework\App\ObjectManager::getInstance()->create(ProductRepositoryInterface::class); parent::__construct($context, $productBuilder); } @@ -50,8 +59,9 @@ public function execute() { $collection = $this->filter->getCollection($this->collectionFactory->create()); $productDeleted = 0; + /** @var \Magento\Catalog\Model\Product $product */ foreach ($collection->getItems() as $product) { - $product->delete(); + $this->productRepository->delete($product); $productDeleted++; } $this->messageManager->addSuccess( diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Full.php b/app/code/Magento/Catalog/Model/Indexer/Product/Full.php new file mode 100644 index 0000000000000..ed5596f3726ec --- /dev/null +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Full.php @@ -0,0 +1,101 @@ +indexerRegistry = $indexerRegistry; + $this->pageCacheConfig = $pageCacheConfig; + $this->cacheTypeList = $cacheTypeList; + $this->indexerList = $indexerList; + } + + /** + * {@inheritdoc} + */ + public function executeFull() + { + foreach ($this->indexerList as $indexerName) { + $indexer = $this->indexerRegistry->get($indexerName); + if (!$indexer->isScheduled()) { + $indexer->reindexAll(); + } + } + } + + /** + * {@inheritdoc} + */ + public function executeList(array $ids) + { + if (!empty($ids)) { + foreach ($this->indexerList as $indexerName) { + $indexer = $this->indexerRegistry->get($indexerName); + if (!$indexer->isScheduled()) { + $indexer->reindexList($ids); + } + } + } + } + + /** + * {@inheritDoc} + */ + public function executeRow($id) + { + if (!empty($id)) { + foreach ($this->indexerList as $indexerName) { + $indexer = $this->indexerRegistry->get($indexerName); + if (!$indexer->isScheduled()) { + $indexer->reindexRow($id); + } + } + } + } +} diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/FullTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/FullTest.php new file mode 100644 index 0000000000000..cb3f017cb67f9 --- /dev/null +++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/FullTest.php @@ -0,0 +1,132 @@ +objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->indexerRegistryMock = $this->createMock(IndexerRegistry::class); + $this->configMock = $this->createMock(Config::class); + $this->typeListMock = $this->getMockForAbstractClass(TypeListInterface::class, [], "", false); + + $this->full = $this->objectManager->getObject( + Full::class, + [ + 'indexerRegistry' => $this->indexerRegistryMock, + 'pageCacheConfig' => $this->configMock, + 'cacheTypeList' => $this->typeListMock, + 'indexerList' => ['catalog_indexer', 'product_indexer', 'stock_indexer', 'search_indexer'] + ] + ); + } + + public function testExecuteFull() + { + $indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false); + $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); + $indexerMock->expects($this->exactly(4))->method('reindexAll'); + $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); + $this->configMock->expects($this->once())->method('isEnabled')->willReturn(true); + $this->typeListMock->expects($this->once())->method('invalidate')->with('full_page'); + + $this->full->executeFull(); + } + + public function testExecuteFullPageCacheDisabled() + { + $indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false); + $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); + $indexerMock->expects($this->exactly(4))->method('reindexAll'); + $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); + $this->configMock->expects($this->once())->method('isEnabled')->willReturn(false); + $this->typeListMock->expects($this->never())->method('invalidate'); + + $this->full->executeFull(); + } + + public function testExecuteList() + { + $indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false); + $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); + $indexerMock->expects($this->exactly(4))->method('reindexList')->with([1, 2]); + $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); + $this->configMock->expects($this->once())->method('isEnabled')->willReturn(true); + $this->typeListMock->expects($this->once())->method('invalidate')->with('full_page'); + + $this->full->executeList([1, 2]); + } + + public function testExecuteListPageCacheDisabled() + { + $indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false); + $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); + $indexerMock->expects($this->exactly(4))->method('reindexList')->with([1, 2]); + $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); + $this->configMock->expects($this->once())->method('isEnabled')->willReturn(false); + $this->typeListMock->expects($this->never())->method('invalidate'); + + $this->full->executeList([1, 2]); + } + + public function testExecuteRow() + { + $indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false); + $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); + $indexerMock->expects($this->exactly(4))->method('reindexRow')->with(1); + $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); + $this->configMock->expects($this->once())->method('isEnabled')->willReturn(true); + $this->typeListMock->expects($this->once())->method('invalidate')->with('full_page'); + + $this->full->executeRow(1); + } + + public function testExecuteRowPageCacheDisabled() + { + $indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false); + $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); + $indexerMock->expects($this->exactly(4))->method('reindexRow')->with(1); + $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); + $this->configMock->expects($this->once())->method('isEnabled')->willReturn(false); + $this->typeListMock->expects($this->never())->method('invalidate'); + + $this->full->executeRow(1); + } +} diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml index 6a976aa0cca94..c0d5adf1e3c29 100644 --- a/app/code/Magento/Catalog/etc/di.xml +++ b/app/code/Magento/Catalog/etc/di.xml @@ -84,6 +84,16 @@ Magento\Framework\Mview\View\ChangelogInterface + + + + Magento\Catalog\Model\Indexer\Category\Product::INDEXER_ID + Magento\Catalog\Model\Indexer\Product\Category::INDEXER_ID + Magento\Catalog\Model\Indexer\Product\Price\Processor::INDEXER_ID + Magento\Catalog\Model\Indexer\Product\Eav\Processor::INDEXER_ID + + + diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml index 2f64d71595c86..04935b11ce02b 100644 --- a/app/code/Magento/CatalogInventory/etc/di.xml +++ b/app/code/Magento/CatalogInventory/etc/di.xml @@ -60,6 +60,13 @@ + + + + Magento\CatalogInventory\Model\Indexer\Stock\Processor::INDEXER_ID + + + diff --git a/app/code/Magento/CatalogSearch/etc/di.xml b/app/code/Magento/CatalogSearch/etc/di.xml index 212f62c2a1d35..546f4a80e53a4 100644 --- a/app/code/Magento/CatalogSearch/etc/di.xml +++ b/app/code/Magento/CatalogSearch/etc/di.xml @@ -39,6 +39,13 @@ + + + + Magento\CatalogSearch\Model\Indexer\Fulltext::INDEXER_ID + + + diff --git a/app/code/Magento/ConfigurableProduct/Plugin/Model/ResourceModel/Product.php b/app/code/Magento/ConfigurableProduct/Plugin/Model/ResourceModel/Product.php index 79c08b8502b0d..1555e88700a45 100644 --- a/app/code/Magento/ConfigurableProduct/Plugin/Model/ResourceModel/Product.php +++ b/app/code/Magento/ConfigurableProduct/Plugin/Model/ResourceModel/Product.php @@ -7,9 +7,34 @@ namespace Magento\ConfigurableProduct\Plugin\Model\ResourceModel; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; +use Magento\Framework\Indexer\ActionInterface; class Product { + /** + * @var Configurable + */ + private $configurable; + + /** + * @var ActionInterface + */ + private $productIndexer; + + /** + * Initialize Product dependencies. + * + * @param Configurable $configurable + * @param ActionInterface $productIndexer + */ + public function __construct( + Configurable $configurable, + ActionInterface $productIndexer + ) { + $this->configurable = $configurable; + $this->productIndexer = $productIndexer; + } + /** * We need reset attribute set id to attribute after related simple product was saved * @@ -28,4 +53,25 @@ public function beforeSave( $object->getTypeInstance()->getSetAttributes($object); } } + + /** + * Gather configurable parent ids of product being deleted and reindex after delete is complete. + * + * @param \Magento\Catalog\Model\ResourceModel\Product $subject + * @param \Closure $proceed + * @param \Magento\Catalog\Model\Product $product + * @return \Magento\Catalog\Model\ResourceModel\Product + * @SuppressWarnings(PHPMD.UnusedFormalParameter) + */ + public function aroundDelete( + \Magento\Catalog\Model\ResourceModel\Product $subject, + \Closure $proceed, + \Magento\Catalog\Model\Product $product + ) { + $configurableProductIds = $this->configurable->getParentIdsByChild($product->getId()); + $result = $proceed($product); + $this->productIndexer->executeList($configurableProductIds); + + return $result; + } } diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/Model/ResourceModel/ProductTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/Model/ResourceModel/ProductTest.php index a7af9c9159916..454b38c9c76d6 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/Model/ResourceModel/ProductTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/Model/ResourceModel/ProductTest.php @@ -8,12 +8,53 @@ use Magento\Catalog\Model\Product\Type; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; +use Magento\Framework\Indexer\ActionInterface; +use Magento\Framework\Indexer\IndexerInterface; +use Magento\PageCache\Model\Config; +use Magento\Framework\App\Cache\TypeListInterface; class ProductTest extends \PHPUnit\Framework\TestCase { + /** + * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager + */ + private $objectManager; + + /** + * @var Configurable|\PHPUnit_Framework_MockObject_MockObject + */ + private $configurableMock; + + /** + * @var ActionInterface|\PHPUnit_Framework_MockObject_MockObject + */ + private $actionMock; + + /** + * @var \Magento\ConfigurableProduct\Plugin\Model\ResourceModel\Product + */ + private $model; + + public function setUp() + { + $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); + $this->configurableMock = $this->createMock(Configurable::class); + $this->actionMock = $this->createMock(ActionInterface::class); + + $this->model = $this->objectManager->getObject( + \Magento\ConfigurableProduct\Plugin\Model\ResourceModel\Product::class, + [ + 'configurable' => $this->configurableMock, + 'indexerAction' => $this->actionMock, + ] + ); + } + public function testBeforeSaveConfigurable() { + /** @var \Magento\Catalog\Model\ResourceModel\Product|\PHPUnit_Framework_MockObject_MockObject $subject */ $subject = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class); + /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $object */ $object = $this->createPartialMock(\Magento\Catalog\Model\Product::class, ['getTypeId', 'getTypeInstance']); $type = $this->createPartialMock( \Magento\ConfigurableProduct\Model\Product\Type\Configurable::class, @@ -24,8 +65,7 @@ public function testBeforeSaveConfigurable() $object->expects($this->once())->method('getTypeId')->will($this->returnValue(Configurable::TYPE_CODE)); $object->expects($this->once())->method('getTypeInstance')->will($this->returnValue($type)); - $product = new \Magento\ConfigurableProduct\Plugin\Model\ResourceModel\Product(); - $product->beforeSave( + $this->model->beforeSave( $subject, $object ); @@ -33,15 +73,48 @@ public function testBeforeSaveConfigurable() public function testBeforeSaveSimple() { + /** @var \Magento\Catalog\Model\ResourceModel\Product|\PHPUnit_Framework_MockObject_MockObject $subject */ $subject = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class); + /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $object */ $object = $this->createPartialMock(\Magento\Catalog\Model\Product::class, ['getTypeId', 'getTypeInstance']); $object->expects($this->once())->method('getTypeId')->will($this->returnValue(Type::TYPE_SIMPLE)); $object->expects($this->never())->method('getTypeInstance'); - $product = new \Magento\ConfigurableProduct\Plugin\Model\ResourceModel\Product(); - $product->beforeSave( + $this->model->beforeSave( $subject, $object ); } + + public function testAroundDelete() + { + $productId = '1'; + $parentConfigId = ['2']; + /** @var \Magento\Catalog\Model\ResourceModel\Product|\PHPUnit_Framework_MockObject_MockObject $subject */ + $subject = $this->createMock(\Magento\Catalog\Model\ResourceModel\Product::class); + /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */ + $product = $this->createPartialMock( + \Magento\Catalog\Model\Product::class, + ['getId', 'delete'] + ); + $product->expects($this->once())->method('getId')->willReturn($productId); + $product->expects($this->once())->method('delete')->willReturn(true); + $this->configurableMock->expects($this->once()) + ->method('getParentIdsByChild') + ->with($productId) + ->willReturn($parentConfigId); + $this->actionMock->expects($this->once())->method('executeList')->with($parentConfigId); + + $return = $this->model->aroundDelete( + $subject, + /** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $prod */ + function (\Magento\Catalog\Model\Product $prod) use ($subject) { + $prod->delete(); + return $subject; + }, + $product + ); + + $this->assertEquals($subject->getTypeId(), $return->getTypeId()); + } } diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml index 30fd8737c3820..379b5ee94cabd 100644 --- a/app/code/Magento/ConfigurableProduct/etc/di.xml +++ b/app/code/Magento/ConfigurableProduct/etc/di.xml @@ -191,4 +191,9 @@ indexer + + + Magento\Catalog\Model\Indexer\Product\Full + + diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteChildConfigurableProductTest.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteChildConfigurableProductTest.php new file mode 100644 index 0000000000000..a0761057c958b --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteChildConfigurableProductTest.php @@ -0,0 +1,104 @@ + Catalog + * 3. Click on narrow near "Add Product" button + * 4. Select Configurable Product + * 5. Fill in data according to data sets + * 6. Save the product. + * 7. From the product grid, select the child products and mass delete them. + * 6. Navigate to the frontend + * 7. Verify that the product is not available on the category page. + * 8. Verify that product is displayed on frontend through direct url + */ +class DeleteChildConfigurableProductTest extends Injectable +{ + /** + * Product page with a grid. + * + * @var CatalogProductIndex + */ + protected $productGrid; + + /** + * Page to create a product. + * + * @var CatalogProductNew + */ + protected $productNew; + + /** + * Assert Invalid Date error message. + * + * @var AssertProductSaveMessage + */ + private $assertProductSaveMessage; + + /** + * Page to update a product. + * + * @var CatalogProductEdit + */ + private $editProductPage; + + /** + * @param CatalogProductNew $productNew + * @param CatalogProductIndex $productGrid + * @param CatalogProductEdit $editProductPage + * @param assertProductSaveMessage $assertProductSaveMessage + */ + public function __inject( + CatalogProductNew $productNew, + CatalogProductIndex $productGrid, + CatalogProductEdit $editProductPage, + AssertProductSaveMessage $assertProductSaveMessage + ) { + $this->productGrid = $productGrid; + $this->productNew = $productNew; + $this->editProductPage = $editProductPage; + $this->assertProductSaveMessage = $assertProductSaveMessage; + } + + /** + * @param ConfigurableProduct $product + * @return array + */ + public function test(ConfigurableProduct $product) + { + $deleteProducts = []; + $this->productGrid->open(); + $this->productGrid->getGridPageActionBlock()->addProduct('configurable'); + $this->productNew->getProductForm()->fill($product); + $this->productNew->getFormPageActions()->save($product); + $this->assertProductSaveMessage->processAssert($this->editProductPage); + + $configurableAttributesData = $product->getConfigurableAttributesData(); + $this->productGrid->open(); + foreach ($configurableAttributesData['matrix'] as $variation) { + $filter = ['name' => $variation['name']]; + $this->productGrid->getProductGrid()->search($filter); + $itemId = $this->productGrid->getProductGrid()->getFirstItemId(); + $deleteProducts[] = [$this->productGrid->getProductGrid()->getColumnValue($itemId, 'SKU')]; + } + $this->productGrid->open(); + + $this->productGrid->getProductGrid()->massaction($deleteProducts, 'Delete', true); + return ['product'=> $product]; + } +} diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteChildConfigurableProductTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteChildConfigurableProductTest.xml new file mode 100644 index 0000000000000..435d5aad4635d --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/DeleteChildConfigurableProductTest.xml @@ -0,0 +1,22 @@ + + + + + + configurable-product-%isolation% + two_new_options_with_empty_sku + Configurable Product %isolation% + configurable_sku_%isolation% + 100 + no + default_subcategory + + + + + From 254da57f4cf5fdc559f9b2b1cc795363bb6d33dd Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Wed, 6 Sep 2017 15:05:11 +0300 Subject: [PATCH 091/151] MAGETWO-71969: Unable to finish checkout in Safari (private mode) --- .../frontend/layout/default_head_blocks.xml | 1 + .../view/frontend/templates/js/polyfill.phtml | 125 ++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml diff --git a/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml b/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml index 2c86c3259a690..38ab9c29402e9 100644 --- a/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml +++ b/app/code/Magento/Theme/view/frontend/layout/default_head_blocks.xml @@ -13,6 +13,7 @@ + diff --git a/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml b/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml new file mode 100644 index 0000000000000..74a5357b1016c --- /dev/null +++ b/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml @@ -0,0 +1,125 @@ + + + From b31765a972601b8add83ed969e6d428503c0a291 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Wed, 6 Sep 2017 16:13:29 +0300 Subject: [PATCH 092/151] MAGETWO-71922: Error in Import Customers Main File with custom attribute. --- .../Model/Export/Address.php | 14 +++- .../Model/Export/Customer.php | 2 +- .../Model/Import/AbstractCustomer.php | 14 ++++ .../Model/Import/Address.php | 18 +++-- .../Model/Import/Customer.php | 22 ++++-- .../Model/Export/Entity/AbstractEav.php | 71 ++++++++++++++++--- .../Model/Import/AbstractEntity.php | 3 +- .../Model/Import/Entity/AbstractEav.php | 7 +- 8 files changed, 118 insertions(+), 33 deletions(-) diff --git a/app/code/Magento/CustomerImportExport/Model/Export/Address.php b/app/code/Magento/CustomerImportExport/Model/Export/Address.php index efb3279c2bee4..194d44c974848 100644 --- a/app/code/Magento/CustomerImportExport/Model/Export/Address.php +++ b/app/code/Magento/CustomerImportExport/Model/Export/Address.php @@ -29,6 +29,11 @@ class Address extends \Magento\ImportExport\Model\Export\Entity\AbstractEav /**#@-*/ + /** + * Country column name for index value + */ + const COLUMN_COUNTRY_ID = 'country_id'; + /**#@+ * Particular columns that contains of customer default addresses */ @@ -55,6 +60,13 @@ class Address extends \Magento\ImportExport\Model\Export\Entity\AbstractEav /**#@-*/ protected $_permanentAttributes = [self::COLUMN_WEBSITE, self::COLUMN_EMAIL, self::COLUMN_ADDRESS_ID]; + /** + * Attributes with index (not label) value + * + * @var string[] + */ + protected $_indexValueAttributes = [self::COLUMN_COUNTRY_ID]; + /** * Default addresses column names to appropriate customer attribute code * @@ -149,7 +161,7 @@ public function __construct( $data['address_collection'] ) ? $data['address_collection'] : $addressColFactory->create(); - $this->_initWebsites(true); + $this->_initAttributeValues()->_initAttributeTypes()->_initWebsites(true); $this->setFileName($this->getEntityTypeCode()); } diff --git a/app/code/Magento/CustomerImportExport/Model/Export/Customer.php b/app/code/Magento/CustomerImportExport/Model/Export/Customer.php index 46e8cc0b3e515..14f0ae324e0a4 100644 --- a/app/code/Magento/CustomerImportExport/Model/Export/Customer.php +++ b/app/code/Magento/CustomerImportExport/Model/Export/Customer.php @@ -112,7 +112,7 @@ public function __construct( $data['customer_collection'] ) ? $data['customer_collection'] : $customerColFactory->create(); - $this->_initAttributeValues()->_initStores()->_initWebsites(true); + $this->_initAttributeValues()->_initAttributeTypes()->_initStores()->_initWebsites(true); } /** diff --git a/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php b/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php index 2d69ad00ac910..ade8b07c79cc0 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php @@ -248,4 +248,18 @@ public function getCustomerStorage() { return $this->_customerStorage; } + + /** + * Returns id of option by value for select and multiselect attributes + * + * @param array $attributeParameters Parameters of an attribute + * @param int|string $value A value of an attribute + * @return int An option id of attribute + */ + protected function getSelectAttrIdByValue(array $attributeParameters, $value) + { + return isset($attributeParameters['options'][strtolower($value)]) + ? $attributeParameters['options'][strtolower($value)] + : 0; + } } diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Address.php b/app/code/Magento/CustomerImportExport/Model/Import/Address.php index ed27a2e3867e8..fcdf9f94d2f0f 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/Address.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/Address.php @@ -486,6 +486,7 @@ protected function _mergeEntityAttributes(array $newAttributes, array $attribute */ protected function _prepareDataForUpdate(array $rowData) { + $multiSeparator = $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]; $email = strtolower($rowData[self::COLUMN_EMAIL]); $customerId = $this->_getCustomerId($email, $rowData[self::COLUMN_WEBSITE]); // entity table data @@ -523,20 +524,17 @@ protected function _prepareDataForUpdate(array $rowData) continue; } } elseif ($newAddress && !strlen($rowData[$attributeAlias])) { - } elseif ('select' == $attributeParams['type']) { - $value = $attributeParams['options'][strtolower($rowData[$attributeAlias])]; + } elseif (in_array($attributeParams['type'], ['select', 'boolean'])) { + $value = $this->getSelectAttrIdByValue($attributeParams, mb_strtolower($rowData[$attributeAlias])); } elseif ('datetime' == $attributeParams['type']) { $value = (new \DateTime())->setTimestamp(strtotime($rowData[$attributeAlias])); $value = $value->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT); } elseif ('multiselect' == $attributeParams['type']) { - $separator = isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]) ? - $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] : - Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR; - $value = str_replace( - $separator, - Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, - $rowData[$attributeAlias] - ); + $ids = []; + foreach (explode($multiSeparator, mb_strtolower($rowData[$attributeAlias])) as $subValue) { + $ids[] = $this->getSelectAttrIdByValue($attributeParams, $subValue); + } + $value = implode(',', $ids); } else { $value = $rowData[$attributeAlias]; } diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php index badfe06bd58de..fd14ce8f7e9a2 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php @@ -6,6 +6,7 @@ namespace Magento\CustomerImportExport\Model\Import; use Magento\Customer\Api\Data\CustomerInterface; +use Magento\ImportExport\Model\Import; use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface; /** @@ -338,6 +339,7 @@ protected function _getNextEntityId() */ protected function _prepareDataForUpdate(array $rowData) { + $multiSeparator = $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]; $entitiesToCreate = []; $entitiesToUpdate = []; $attributesToSave = []; @@ -376,10 +378,14 @@ protected function _prepareDataForUpdate(array $rowData) // attribute values foreach (array_intersect_key($rowData, $this->_attributes) as $attributeCode => $value) { $attributeParameters = $this->_attributes[$attributeCode]; - if ('select' == $attributeParameters['type']) { - $value = isset($attributeParameters['options'][strtolower($value)]) - ? $attributeParameters['options'][strtolower($value)] - : 0; + if (in_array($attributeParameters['type'], ['select', 'boolean'])) { + $value = $this->getSelectAttrIdByValue($attributeParameters, $value); + } elseif ('multiselect' == $attributeParameters['type']) { + $ids = []; + foreach (explode($multiSeparator, mb_strtolower($value)) as $subValue) { + $ids[] = $this->getSelectAttrIdByValue($attributeParameters, $subValue); + } + $value = implode(',', $ids); } elseif ('datetime' == $attributeParameters['type'] && !empty($value)) { $value = (new \DateTime())->setTimestamp(strtotime($value)); $value = $value->format(\Magento\Framework\Stdlib\DateTime::DATETIME_PHP_FORMAT); @@ -535,7 +541,13 @@ protected function _validateRowForUpdate(array $rowData, $rowNumber) continue; } if (isset($rowData[$attributeCode]) && strlen($rowData[$attributeCode])) { - $this->isAttributeValid($attributeCode, $attributeParams, $rowData, $rowNumber); + $this->isAttributeValid( + $attributeCode, + $attributeParams, + $rowData, + $rowNumber, + $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] + ); } elseif ($attributeParams['is_required'] && !$this->_getCustomerId($email, $website)) { $this->addRowError(self::ERROR_VALUE_IS_REQUIRED, $rowNumber, $attributeCode); } diff --git a/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php b/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php index 1bc78a836ab98..4e6b146536239 100644 --- a/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php +++ b/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php @@ -8,6 +8,7 @@ use Magento\Eav\Model\Entity\Attribute\AbstractAttribute; use Magento\Eav\Model\Entity\Collection\AbstractCollection; use Magento\ImportExport\Model\Export; +use Magento\ImportExport\Model\Import; use Magento\Store\Model\Store; /** @@ -27,6 +28,13 @@ abstract class AbstractEav extends \Magento\ImportExport\Model\Export\AbstractEn */ protected $_attributeValues = []; + /** + * Attribute code to its types. Only attributes with options + * + * @var array + */ + protected $_attributeTypes = []; + /** * Entity type id. * @@ -88,6 +96,20 @@ protected function _initAttributeValues() return $this; } + /** + * Initializes attribute types + * + * @return $this + */ + protected function _initAttributeTypes() + { + /** @var $attribute AbstractAttribute */ + foreach ($this->getAttributeCollection() as $attribute) { + $this->_attributeTypes[$attribute->getAttributeCode()] = $attribute->getFrontendInput(); + } + return $this; + } + /** * Apply filter to collection and add not skipped attributes to select * @@ -246,19 +268,50 @@ protected function _addAttributeValuesToRow(\Magento\Framework\Model\AbstractMod foreach ($validAttributeCodes as $attributeCode) { $attributeValue = $item->getData($attributeCode); - if (isset( + if ($this->isMultiselect($attributeCode)) { + $values = []; + $attributeValue = explode(Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, $attributeValue); + foreach ($attributeValue as $value) { + $values[] = $this->getAttributeValueById($attributeCode, $value); + } + $row[$attributeCode] = implode(Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR, $values); + } else { + $row[$attributeCode] = $this->getAttributeValueById($attributeCode, $attributeValue); + } + } + + return $row; + } + + /** + * Checks that attribute is multiselect type by attribute code + * + * @param string $attributeCode An attribute code + * @return bool Returns true if attribute is multiselect type + */ + private function isMultiselect($attributeCode) { + return isset($this->_attributeTypes[$attributeCode]) + && $this->_attributeTypes[$attributeCode] === 'multiselect'; + } + + /** + * Returns attribute value by id + * + * @param string $attributeCode An attribute code + * @param int|string $valueId + * @return mixed + */ + private function getAttributeValueById($attributeCode, $valueId) + { + if (isset( $this->_attributeValues[$attributeCode] ) && isset( - $this->_attributeValues[$attributeCode][$attributeValue] + $this->_attributeValues[$attributeCode][$valueId] ) - ) { - $attributeValue = $this->_attributeValues[$attributeCode][$attributeValue]; - } - if (null !== $attributeValue) { - $row[$attributeCode] = $attributeValue; - } + ) { + return $this->_attributeValues[$attributeCode][$valueId]; } - return $row; + return $valueId; } } diff --git a/app/code/Magento/ImportExport/Model/Import/AbstractEntity.php b/app/code/Magento/ImportExport/Model/Import/AbstractEntity.php index 641b033e364c4..5bd956c1bc322 100644 --- a/app/code/Magento/ImportExport/Model/Import/AbstractEntity.php +++ b/app/code/Magento/ImportExport/Model/Import/AbstractEntity.php @@ -691,8 +691,9 @@ public function isAttributeValid( break; case 'select': case 'multiselect': + case 'boolean': $valid = true; - foreach (explode($multiSeparator, strtolower($rowData[$attributeCode])) as $value) { + foreach (explode($multiSeparator, mb_strtolower($rowData[$attributeCode])) as $value) { $valid = isset($attributeParams['options'][$value]); if (!$valid) { break; diff --git a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEav.php b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEav.php index 9a92f7fdd8894..82c4478874844 100644 --- a/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEav.php +++ b/app/code/Magento/ImportExport/Model/Import/Entity/AbstractEav.php @@ -228,12 +228,7 @@ public function getAttributeOptions( foreach ($value as $innerOption) { // skip ' -- Please Select -- ' option if (strlen($innerOption['value'])) { - if ($attribute->isStatic()) { - $options[strtolower($innerOption[$index])] = $innerOption['value']; - } else { - // Non-static attributes flip keys an values - $options[$innerOption['value']] = $innerOption[$index]; - } + $options[mb_strtolower($innerOption[$index])] = $innerOption['value']; } } } From 240e2cc9107015b790a93807ee75f89427766469 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Wed, 6 Sep 2017 16:15:32 +0300 Subject: [PATCH 093/151] MAGETWO-72305: USPS First-Class Mail Parcel method no longer displaying checkout - Renamed "First-Class Mail Parcel" to "First-Class Package Service - Retail" according to USPS API changes --- app/code/Magento/Usps/Model/Carrier.php | 4 ++-- app/code/Magento/Usps/Setup/InstallData.php | 1 + app/code/Magento/Usps/i18n/en_US.csv | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Usps/Model/Carrier.php b/app/code/Magento/Usps/Model/Carrier.php index e7ffe5970ecdd..1233c6ede491d 100644 --- a/app/code/Magento/Usps/Model/Carrier.php +++ b/app/code/Magento/Usps/Model/Carrier.php @@ -643,7 +643,7 @@ public function getCode($type, $code = '') 'method' => [ '0_FCLE' => __('First-Class Mail Large Envelope'), '0_FCL' => __('First-Class Mail Letter'), - '0_FCP' => __('First-Class Mail Parcel'), + '0_FCP' => __('First-Class Package Service - Retail'), '0_FCPC' => __('First-Class Mail Postcards'), '1' => __('Priority Mail'), '2' => __('Priority Mail Express Hold For Pickup'), @@ -795,7 +795,7 @@ public function getCode($type, $code = '') 'method_to_code' => [ 'First-Class Mail Large Envelope' => '0_FCLE', 'First-Class Mail Letter' => '0_FCL', - 'First-Class Mail Parcel' => '0_FCP', + 'First-Class Package Service - Retail' => '0_FCP', ], 'first_class_mail_type' => ['LETTER' => __('Letter'), 'FLAT' => __('Flat'), 'PARCEL' => __('Parcel')], 'container' => [ diff --git a/app/code/Magento/Usps/Setup/InstallData.php b/app/code/Magento/Usps/Setup/InstallData.php index bea1aa665c1ba..6ed70588f65ac 100644 --- a/app/code/Magento/Usps/Setup/InstallData.php +++ b/app/code/Magento/Usps/Setup/InstallData.php @@ -39,6 +39,7 @@ public function install(ModuleDataSetupInterface $setup, ModuleContextInterface 'First-Class Mail Letter' => '0_FCL', 'First-Class Mail Parcel' => '0_FCP', 'First-Class Mail Package' => '0_FCP', + 'First-Class Package Service - Retail' => '0_FCP', 'Parcel Post' => '4', 'Retail Ground' => '4', 'Media Mail' => '6', diff --git a/app/code/Magento/Usps/i18n/en_US.csv b/app/code/Magento/Usps/i18n/en_US.csv index 97c558d45d8cc..ab1a11155fe04 100644 --- a/app/code/Magento/Usps/i18n/en_US.csv +++ b/app/code/Magento/Usps/i18n/en_US.csv @@ -1,6 +1,6 @@ "First-Class Mail Large Envelope","First-Class Mail Large Envelope" "First-Class Mail Letter","First-Class Mail Letter" -"First-Class Mail Parcel","First-Class Mail Parcel" +"First-Class Package Service - Retail","First-Class Package Service - Retail" "First-Class Mail Postcards","First-Class Mail Postcards" "Priority Mail","Priority Mail" "Priority Mail Express Hold For Pickup","Priority Mail Express Hold For Pickup" From be772d30692f3bc0afb9a508bf53ebcad8ea2d87 Mon Sep 17 00:00:00 2001 From: Andrii Lugovyi Date: Wed, 6 Sep 2017 16:41:28 +0300 Subject: [PATCH 094/151] MAGETWO-72076: Update benchmark.jmx and README files in Performance Toolkit, add performance analytics script --- setup/performance-toolkit/benchmark_2015.jmx | 185 ++++++++++--------- 1 file changed, 95 insertions(+), 90 deletions(-) diff --git a/setup/performance-toolkit/benchmark_2015.jmx b/setup/performance-toolkit/benchmark_2015.jmx index 844b5d127a014..0197f144cd39e 100644 --- a/setup/performance-toolkit/benchmark_2015.jmx +++ b/setup/performance-toolkit/benchmark_2015.jmx @@ -14,6 +14,11 @@ + + request_protocol + ${__P(request_protocol,http)} + = + abandonedCartByGuest ${__P(abandonedCartByGuest,0)} @@ -676,7 +681,7 @@ - http + ${request_protocol} utf-8 Java @@ -799,7 +804,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}${admin_path} GET @@ -879,7 +884,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}${admin_path}/admin/dashboard/ POST @@ -933,7 +938,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}${admin_path}/admin/cache/massEnable POST @@ -976,7 +981,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}${admin_path}/admin/cache/massRefresh POST @@ -1019,7 +1024,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -1111,7 +1116,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - + ${request_protocol} ${base_path}rest/V1/categories/list GET @@ -1248,7 +1253,7 @@ props.put("category_name", vars.get("category_name")); - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -1319,7 +1324,7 @@ props.put("category_name", vars.get("category_name")); - + ${request_protocol} ${base_path}rest/V1/products GET @@ -1387,7 +1392,7 @@ if (1 == Integer.parseInt(vars.get("simple_products_counter"))) { } else { productList = props.get("simple_products_list"); } -String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); +String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map Map productMap = new HashMap(); @@ -1434,7 +1439,7 @@ productList.add(productMap); - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -1505,7 +1510,7 @@ productList.add(productMap); - + ${request_protocol} ${base_path}rest/V1/products GET @@ -1583,7 +1588,7 @@ if (1 == Integer.parseInt(vars.get("configurable_products_counter"))) { productList = props.get("configurable_products_list"); } -String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); +String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map Map productMap = new HashMap(); @@ -1609,7 +1614,7 @@ productList.add(productMap); - + ${request_protocol} ${base_path}${admin_path}/customer/index/ GET @@ -1709,7 +1714,7 @@ manager.add(cookie); - + ${request_protocol} ${base_path}${admin_path}/mui/index/render/ GET @@ -1902,7 +1907,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}${admin_path}/admin/cache/massDisable POST @@ -1938,7 +1943,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}${admin_path}/admin/cache/ GET @@ -1996,7 +2001,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}${admin_path}/admin/cache/ GET @@ -2054,7 +2059,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}${admin_path}/admin/cache/ GET @@ -2134,7 +2139,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}page_cache/block/render/ GET @@ -2215,7 +2220,7 @@ if ("${cache_indicator}" == "1") { - + ${request_protocol} ${base_path}checkout/cart/add POST @@ -2283,7 +2288,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path} GET @@ -2320,7 +2325,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}${category_url_key}${url_suffix} GET @@ -2378,7 +2383,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -2429,7 +2434,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2466,7 +2471,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -2517,7 +2522,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2554,7 +2559,7 @@ vars.put("testLabel", "CatProdBrows"); - + ${request_protocol} ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -2638,7 +2643,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path} GET @@ -2705,7 +2710,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}page_cache/block/render/ GET @@ -2764,7 +2769,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${category_url_key}${url_suffix} GET @@ -2822,7 +2827,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -2873,7 +2878,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2939,7 +2944,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -2993,7 +2998,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -3058,7 +3063,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -3109,7 +3114,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -3175,7 +3180,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -3231,7 +3236,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -3296,7 +3301,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -3369,7 +3374,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -3418,7 +3423,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -3493,7 +3498,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -3579,7 +3584,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -3691,7 +3696,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path} GET @@ -3758,7 +3763,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}page_cache/block/render/ GET @@ -3817,7 +3822,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${category_url_key}${url_suffix} GET @@ -3875,7 +3880,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -3926,7 +3931,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -3992,7 +3997,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -4046,7 +4051,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -4111,7 +4116,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -4162,7 +4167,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -4228,7 +4233,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -4284,7 +4289,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -4349,7 +4354,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -4422,7 +4427,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -4471,7 +4476,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -4546,7 +4551,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -4632,7 +4637,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -4697,7 +4702,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/ GET @@ -4790,7 +4795,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/default/V1/customers/isEmailAvailable POST @@ -4855,7 +4860,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/default/V1/guest-carts/${cart_id}/estimate-shipping-methods POST @@ -4920,7 +4925,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/default/V1/guest-carts/${cart_id}/shipping-information POST @@ -4985,7 +4990,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}rest/default/V1/guest-carts/${cart_id}/payment-information POST @@ -5056,7 +5061,7 @@ vars.put("loadType", "Guest"); - + ${request_protocol} ${base_path}checkout/onepage/success/ GET @@ -5162,7 +5167,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path} GET @@ -5199,7 +5204,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}customer/account/login/ GET @@ -5266,7 +5271,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}page_cache/block/render/ GET @@ -5354,7 +5359,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}customer/account/loginPost/ POST @@ -5411,7 +5416,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}${category_url_key}${url_suffix} GET @@ -5469,7 +5474,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -5520,7 +5525,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -5586,7 +5591,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -5640,7 +5645,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -5705,7 +5710,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -5756,7 +5761,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -5822,7 +5827,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -5878,7 +5883,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -5943,7 +5948,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -6016,7 +6021,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}rest/V1/integration/admin/token POST @@ -6065,7 +6070,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -6140,7 +6145,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}checkout/cart/add/ POST @@ -6226,7 +6231,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}customer/section/load/ GET @@ -6291,7 +6296,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}checkout/ GET @@ -6424,7 +6429,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}rest/default/V1/carts/mine/estimate-shipping-methods-by-address-id POST @@ -6489,7 +6494,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}rest/default/V1/carts/mine/shipping-information POST @@ -6554,7 +6559,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}rest/default/V1/carts/mine/payment-information POST @@ -6612,7 +6617,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}checkout/onepage/success/ GET @@ -6694,7 +6699,7 @@ vars.put("loadType", "Customer"); - + ${request_protocol} ${base_path}DeploymentEvent.php POST From 1ae2acfe2b56135681c1bb11c0666d344f45a723 Mon Sep 17 00:00:00 2001 From: Viktor Tymchynskyi Date: Wed, 6 Sep 2017 17:45:35 +0300 Subject: [PATCH 095/151] MAGETWO-71831: Unable to create a shipping label for a shipment with USPS - Add formatting decimal values according USPS API --- app/code/Magento/Usps/Model/Carrier.php | 6 +-- .../Usps/Test/Unit/Model/CarrierTest.php | 44 +++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Usps/Model/Carrier.php b/app/code/Magento/Usps/Model/Carrier.php index e7ffe5970ecdd..553f1e79ea4f3 100644 --- a/app/code/Magento/Usps/Model/Carrier.php +++ b/app/code/Magento/Usps/Model/Carrier.php @@ -1795,10 +1795,10 @@ protected function _formIntlShipmentRequest(\Magento\Framework\DataObject $reque } $individualItemWeight = $itemWeight / $ceiledQty; $itemDetail->addChild('Quantity', $ceiledQty); - $itemDetail->addChild('Value', $item->getCustomsValue() * $item->getQty()); + $itemDetail->addChild('Value', sprintf('%.2F', $item->getCustomsValue() * $item->getQty())); list($individualPoundsWeight, $individualOuncesWeight) = $this->_convertPoundOunces($individualItemWeight); $itemDetail->addChild('NetPounds', $individualPoundsWeight); - $itemDetail->addChild('NetOunces', $individualOuncesWeight); + $itemDetail->addChild('NetOunces', sprintf('%.2F', $individualOuncesWeight)); $itemDetail->addChild('HSTariffNumber', 0); $itemDetail->addChild('CountryOfOrigin', $countryOfManufacture); @@ -1814,7 +1814,7 @@ protected function _formIntlShipmentRequest(\Magento\Framework\DataObject $reque } $xml->addChild('GrossPounds', $packagePoundsWeight); - $xml->addChild('GrossOunces', $packageOuncesWeight); + $xml->addChild('GrossOunces', sprintf('%.2F', $packageOuncesWeight)); if ($packageParams->getContentType() == 'OTHER' && $packageParams->getContentTypeOther() != null) { $xml->addChild('ContentType', $packageParams->getContentType()); $xml->addChild('ContentTypeOther ', $packageParams->getContentTypeOther()); diff --git a/app/code/Magento/Usps/Test/Unit/Model/CarrierTest.php b/app/code/Magento/Usps/Test/Unit/Model/CarrierTest.php index d6e8e34962f28..751bd4c97b182 100644 --- a/app/code/Magento/Usps/Test/Unit/Model/CarrierTest.php +++ b/app/code/Magento/Usps/Test/Unit/Model/CarrierTest.php @@ -5,6 +5,7 @@ */ namespace Magento\Usps\Test\Unit\Model; +use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory; use Magento\Framework\HTTP\ZendClient; use Magento\Framework\HTTP\ZendClientFactory; use Magento\Quote\Model\Quote\Address\RateRequest; @@ -162,6 +163,22 @@ function ($data) { ] ); + $productCollection = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Collection::class) + ->disableOriginalConstructor() + ->getMock(); + $productCollection->method('addStoreFilter') + ->willReturnSelf(); + $productCollection->method('addFieldToFilter') + ->willReturnSelf(); + $productCollection->method('addAttributeToSelect') + ->willReturn([]); + + $productCollectionFactory = $this->getMockBuilder(CollectionFactory::class) + ->disableOriginalConstructor() + ->getMock(); + $productCollectionFactory->method('create') + ->willReturn($productCollection); + $arguments = [ 'scopeConfig' => $this->scope, 'xmlSecurity' => new \Magento\Framework\Xml\Security(), @@ -172,6 +189,7 @@ function ($data) { 'data' => $data, 'rateErrorFactory' => $this->errorFactory, 'carrierHelper' => $carrierHelper, + 'productCollectionFactory' => $productCollectionFactory, ]; $this->dataHelper = $this->getMockBuilder(DataHelper::class) @@ -265,6 +283,32 @@ public function testReturnOfShipment() $this->assertNotEmpty($this->carrier->returnOfShipment($request)->getInfo()[0]['tracking_number']); } + public function testFormattingFloatValuesForIntlShipmentRequest() + { + $this->httpResponse->method('getBody') + ->willReturn( + file_get_contents(__DIR__ . '/_files/success_usps_response_return_shipment.xml') + ); + $request = $this->objectManager->getObject( + \Magento\Shipping\Model\Shipment\ReturnShipment::class, + require __DIR__ . '/_files/return_shipment_request_data.php' + ); + + $request->setRecipientAddressCountryCode('UK'); + $formattedValuesRegex = '(5.00<\/Value>).*'; + $formattedValuesRegex .= '(0.00<\/NetOunces>).*'; + $formattedValuesRegex .= '(0.00<\/GrossOunces>)'; + + $this->httpClient->expects($this->exactly(2)) + ->method('setParameterGet') + ->withConsecutive( + ['API', 'ExpressMailIntl'], + ['XML', $this->matchesRegularExpression('/' . $formattedValuesRegex . '/')] + ); + + $this->carrier->returnOfShipment($request); + } + /** * Emulates the config's `getValue` method. * From 1758590782cf5b6abba33c8dc7552c08a0643501 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Wed, 6 Sep 2017 17:51:02 +0300 Subject: [PATCH 096/151] MAGETWO-62464: Travis CI: GD2 imagettfbbox creates image with invalid size --- .../Framework/Image/Adapter/InterfaceTest.php | 31 +++++++++---------- .../Magento/Framework/Image/Adapter/Gd2.php | 2 +- .../Framework/Image/Adapter/ImageMagick.php | 2 +- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php b/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php index a76b56b13bc08..420803d9530bd 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Image/Adapter/InterfaceTest.php @@ -545,9 +545,6 @@ public function cropDataProvider() */ public function testCreatePngFromString($pixel1, $expectedColor1, $pixel2, $expectedColor2, $adapterType) { - if (!function_exists('imagettfbbox')) { - $this->markTestSkipped('Workaround for problem with imagettfbbox() function on Travis'); - } $adapter = $this->_getAdapter($adapterType); /** @var \Magento\Framework\Filesystem\Directory\ReadFactory readFactory */ @@ -560,9 +557,11 @@ public function testCreatePngFromString($pixel1, $expectedColor1, $pixel2, $expe $adapter->refreshImageDimensions(); $color1 = $adapter->getColorAt($pixel1['x'], $pixel1['y']); + unset($color1['alpha']); $this->assertEquals($expectedColor1, $color1); $color2 = $adapter->getColorAt($pixel2['x'], $pixel2['y']); + unset($color2['alpha']); $this->assertEquals($expectedColor2, $color2); } @@ -576,30 +575,30 @@ public function createPngFromStringDataProvider() return [ [ ['x' => 5, 'y' => 8], - 'expectedColor1' => ['red' => 0, 'green' => 0, 'blue' => 0, 'alpha' => 0], - ['x' => 0, 'y' => 15], - 'expectedColor2' => ['red' => 255, 'green' => 255, 'blue' => 255, 'alpha' => 127], + 'expectedColor1' => ['red' => 0, 'green' => 0, 'blue' => 0], + ['x' => 0, 'y' => 14], + 'expectedColor2' => ['red' => 255, 'green' => 255, 'blue' => 255], \Magento\Framework\Image\Adapter\AdapterInterface::ADAPTER_GD2, ], [ - ['x' => 4, 'y' => 7], - 'expectedColor1' => ['red' => 0, 'green' => 0, 'blue' => 0, 'alpha' => 0], - ['x' => 0, 'y' => 15], - 'expectedColor2' => ['red' => 255, 'green' => 255, 'blue' => 255, 'alpha' => 127], + ['x' => 5, 'y' => 12], + 'expectedColor1' => ['red' => 0, 'green' => 0, 'blue' => 0], + ['x' => 0, 'y' => 20], + 'expectedColor2' => ['red' => 255, 'green' => 255, 'blue' => 255], \Magento\Framework\Image\Adapter\AdapterInterface::ADAPTER_IM ], [ ['x' => 1, 'y' => 14], - 'expectedColor1' => ['red' => 255, 'green' => 255, 'blue' => 255, 'alpha' => 127], + 'expectedColor1' => ['red' => 255, 'green' => 255, 'blue' => 255], ['x' => 5, 'y' => 12], - 'expectedColor2' => ['red' => 0, 'green' => 0, 'blue' => 0, 'alpha' => 0], + 'expectedColor2' => ['red' => 0, 'green' => 0, 'blue' => 0], \Magento\Framework\Image\Adapter\AdapterInterface::ADAPTER_GD2 ], [ - ['x' => 1, 'y' => 14], - 'expectedColor1' => ['red' => 255, 'green' => 255, 'blue' => 255, 'alpha' => 127], - ['x' => 4, 'y' => 10], - 'expectedColor2' => ['red' => 0, 'green' => 0, 'blue' => 0, 'alpha' => 0], + ['x' => 1, 'y' => 20], + 'expectedColor1' => ['red' => 255, 'green' => 255, 'blue' => 255], + ['x' => 5, 'y' => 16], + 'expectedColor2' => ['red' => 0, 'green' => 0, 'blue' => 0], \Magento\Framework\Image\Adapter\AdapterInterface::ADAPTER_IM ] ]; diff --git a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php index f1bedaceef09f..444ab7113d429 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/Gd2.php +++ b/lib/internal/Magento/Framework/Image/Adapter/Gd2.php @@ -748,7 +748,7 @@ protected function _createImageFromTtfText($text, $font) $this->_fontSize, 0, 0, - $height, + $height - $boundingBox[1], $black, $font, $text diff --git a/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php b/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php index 5da9b46e458c7..02d3c86d01b79 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php +++ b/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php @@ -434,7 +434,7 @@ public function createPngFromString($text, $font = '') } } - $draw->setFontSize($this->_fontSize); + $draw->setFontSize($this->_fontSize * 4 / 3); $draw->setFillColor($color); $draw->setStrokeAntialias(true); $draw->setTextAntialias(true); From 3494fbb0cfb4a952308bc775027017b064911865 Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Wed, 6 Sep 2017 18:11:01 +0300 Subject: [PATCH 097/151] MAGETWO-69210: [Google Tag Manager] Ajax "Add to Cart" / "Remove from Cart" do not fire any events --- .../view/frontend/templates/product/list.phtml | 6 ++++-- .../view/frontend/templates/product/view/form.phtml | 3 ++- .../view/frontend/web/js/catalog-add-to-cart.js | 2 ++ .../Magento/Checkout/view/frontend/web/js/sidebar.js | 12 ++++++++++-- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml index bdcfce204b185..6d6739d3ffd6d 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml @@ -78,7 +78,7 @@ $_helper = $this->helper('Magento\Catalog\Helper\Output');
    > isSaleable()): ?> getAddToCartPostParams($_product); ?> -
    + getBlockHtml('formkey') ?> @@ -121,7 +121,9 @@ $_helper = $this->helper('Magento\Catalog\Helper\Output'); diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml index bfc90bd8ca0ea..881f23181cfd2 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml @@ -16,7 +16,8 @@ getProduct(); ?>
    - getOptions()): ?> enctype="multipart/form-data"> diff --git a/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js b/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js index c6021e860c6c2..7686de1d45c5d 100644 --- a/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js +++ b/app/code/Magento/Catalog/view/frontend/web/js/catalog-add-to-cart.js @@ -97,6 +97,8 @@ define([ success: function (res) { var eventData, parameters; + $(document).trigger('ajax:addToCart', form.data().productSku); + if (self.isLoaderEnabled()) { $('body').trigger(self.options.processStop); } diff --git a/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js b/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js index 3bc624e5dfdb6..0632b39b4927f 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js @@ -228,10 +228,18 @@ define([ }, /** - * Update content after item remove. + * Update content after item remove + * + * @param elem + * @param response * @private */ - _removeItemAfter: function () { + _removeItemAfter: function (elem, response) { + var productData = customerData.get('cart')().items.find(function (item) { + return Number(elem.data('cart-item')) === Number(item['item_id']); + }); + + $(document).trigger('ajax:removeFromCart', productData['product_sku']); }, /** From c387ff42d3c1afce40237b81eb697364be070ae4 Mon Sep 17 00:00:00 2001 From: Eric Bohanon Date: Wed, 6 Sep 2017 10:27:20 -0500 Subject: [PATCH 098/151] MAGETWO-70346: Configurable product shows on frontend after deleting child products --- app/code/Magento/ConfigurableProduct/etc/di.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml index 379b5ee94cabd..b9ea0c7e27011 100644 --- a/app/code/Magento/ConfigurableProduct/etc/di.xml +++ b/app/code/Magento/ConfigurableProduct/etc/di.xml @@ -193,7 +193,7 @@ - Magento\Catalog\Model\Indexer\Product\Full + Magento\Catalog\Model\Indexer\Product\Full From 48526495907b5962f9cd9932751d18d6392a1fc3 Mon Sep 17 00:00:00 2001 From: Sviatoslav Mankivskyi Date: Wed, 6 Sep 2017 19:17:36 +0300 Subject: [PATCH 099/151] MAGETWO-62464: Travis CI: GD2 imagettfbbox creates image with invalid size --- lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php b/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php index 02d3c86d01b79..50b9a5a013273 100644 --- a/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php +++ b/lib/internal/Magento/Framework/Image/Adapter/ImageMagick.php @@ -434,6 +434,7 @@ public function createPngFromString($text, $font = '') } } + // Font size for ImageMagick is set in pixels, while the for GD2 it is in points. 3/4 is ratio between them $draw->setFontSize($this->_fontSize * 4 / 3); $draw->setFillColor($color); $draw->setStrokeAntialias(true); From 7b119d5cbd70ca72f8c9945d8abc7a893fb34edc Mon Sep 17 00:00:00 2001 From: Daniel Renaud Date: Wed, 6 Sep 2017 11:27:50 -0500 Subject: [PATCH 100/151] MAGETWO-71771: imposible perform full refund for Order Paid with PayPal Payments Standard -Add integration test for Nvp::callRefundTransaction --- .../Magento/Paypal/Model/Api/NvpTest.php | 43 +++++++++ .../order_standard_with_tax_and_invoice.php | 93 +++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Paypal/_files/order_standard_with_tax_and_invoice.php diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Api/NvpTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Model/Api/NvpTest.php index b007ed54f4203..c6a168c04d6ae 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Api/NvpTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/Api/NvpTest.php @@ -118,6 +118,49 @@ public function testRequestTotalsAndLineItemsWithFPT() $this->nvpApi->callSetExpressCheckout(); } + /** + * Test that the refund request to Paypal sends the correct data + * + * @magentoDataFixture Magento/Paypal/_files/order_standard_with_tax_and_invoice.php + */ + public function testCallRefundTransaction() + { + $this->assertTrue(true); + /** @var \Magento\Sales\Model\Order $order */ + $order = $this->objectManager->create(\Magento\Sales\Model\Order::class); + $order->loadByIncrementId('100000001'); + + /** @var \Magento\Sales\Model\Order\Payment $payment */ + $payment = $order->getPayment(); + + $this->nvpApi->setPayment( + $payment + )->setTransactionId( + 'fooTransactionId' + )->setAmount( + $payment->formatAmount($order->getBaseGrandTotal()) + )->setCurrencyCode( + $order->getBaseCurrencyCode() + )->setRefundType( + Config::REFUND_TYPE_PARTIAL + ); + + $httpQuery = 'TRANSACTIONID=fooTransactionId&REFUNDTYPE=Partial' + .'&CURRENCYCODE=USD&AMT=145.98&METHOD=RefundTransaction' + .'&VERSION=72.0&BUTTONSOURCE=Magento_Cart_'; + + $this->httpClient->expects($this->once())->method('write') + ->with( + 'POST', + 'https://api-3t.paypal.com/nvp', + '1.1', + [], + $httpQuery + ); + + $this->nvpApi->callRefundTransaction(); + } + /** * Gets quote by reserved order id. * diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/order_standard_with_tax_and_invoice.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/order_standard_with_tax_and_invoice.php new file mode 100644 index 0000000000000..4d6b40d0b12a7 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Paypal/_files/order_standard_with_tax_and_invoice.php @@ -0,0 +1,93 @@ +setPrice(121); + +$objectManager = Bootstrap::getObjectManager(); + +$addressData = include __DIR__ . '/address_data.php'; +$billingAddress = $objectManager->create( + Address::class, + ['data' => $addressData] +); +$billingAddress->setAddressType('billing'); +$shippingAddress = clone $billingAddress; +$shippingAddress->setId(null)->setAddressType('shipping'); + +$payment = $objectManager->create(Payment::class); +$payment->setMethod(Config::METHOD_WPS_EXPRESS); + +$taxRate = .0825; +$taxAmount = $product->getPrice() * $taxRate; + +/** @var Item $orderItem */ +$orderItem = $objectManager->create(Item::class); +$orderItem->setProductId($product->getId())->setQtyOrdered(1); +$orderItem->setBasePrice($product->getPrice()); +$orderItem->setPrice($product->getPrice()); +$orderItem->setRowTotal($product->getPrice()); +$orderItem->setRowTotalInclTax($product->getPrice() + $taxAmount); +$orderItem->setBaseRowTotal($product->getPrice()); +$orderItem->setBaseRowTotalInclTax($product->getPrice() + $taxAmount); +$orderItem->setBaseRowInvoiced($product->getPrice() + $taxAmount); +$orderItem->setProductType('simple'); + +$itemsAmount = $product->getPrice(); +$shippingAmount = 15; +$itemsAmountInclTax = $itemsAmount + $taxAmount; +$totalAmount = $itemsAmountInclTax + $shippingAmount; + +/** @var Order $order */ +$order = $objectManager->create(Order::class); +$order->setCustomerEmail('co@co.co') + ->setIncrementId('100000001') + ->addItem($orderItem) + ->setSubtotal($itemsAmount) + ->setBaseSubtotal($itemsAmount) + ->setBaseGrandTotal($totalAmount) + ->setGrandTotal($totalAmount) + ->setTaxAmount($taxAmount) + ->setBaseCurrencyCode('USD') + ->setCustomerIsGuest(true) + ->setStoreId(1) + ->setEmailSent(true) + ->setState(Order::STATE_PROCESSING) + ->setBillingAddress($billingAddress) + ->setShippingAddress($shippingAddress) + ->setBaseTotalPaid($totalAmount) + ->setTotalPaid($totalAmount) + ->setData('base_to_global_rate', 1) + ->setData('base_to_order_rate', 1) + ->setData('shipping_amount', $shippingAmount) + ->setData('base_shipping_amount', $shippingAmount) + ->setPayment($payment); + +/** @var OrderRepositoryInterface $orderRepository */ +$orderRepository = $objectManager->get(OrderRepositoryInterface::class); +$orderRepository->save($order); + +/** @var InvoiceService $invoiceService */ +$invoiceService = $objectManager->create(InvoiceManagementInterface::class); + +/** @var Transaction $transaction */ +$transaction = $objectManager->create(Transaction::class); + +$invoice = $invoiceService->prepareInvoice($order, [$orderItem->getId() => 1]); +$invoice->register(); + +$transaction->addObject($invoice)->addObject($order)->save(); From 20c25a5e8399c3d5e48a498b1dd99c93e4485c4d Mon Sep 17 00:00:00 2001 From: Michael Yu Date: Wed, 6 Sep 2017 12:13:33 -0500 Subject: [PATCH 101/151] MAGETWO-71765: Impossible perform partial invoice for order placed with taxes and PayPal Payflow Pro - Fix _getCaptureAmount($amount) documentation. --- app/code/Magento/Paypal/Model/Payflowpro.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Paypal/Model/Payflowpro.php b/app/code/Magento/Paypal/Model/Payflowpro.php index d5b07f3236bdd..0e8d6db5e9a28 100644 --- a/app/code/Magento/Paypal/Model/Payflowpro.php +++ b/app/code/Magento/Paypal/Model/Payflowpro.php @@ -391,8 +391,8 @@ public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount /** * Get capture amount * - * @param string $amount - * @return string|int + * @param float $amount + * @return float|int */ protected function _getCaptureAmount($amount) { From 9245b7b025956c4c46d88dc567df9003ce3c015f Mon Sep 17 00:00:00 2001 From: Eric Bohanon Date: Wed, 6 Sep 2017 13:05:16 -0500 Subject: [PATCH 102/151] MAGETWO-71656: Configurable with disabled children are still shown on category page --- .../Test/Unit/Plugin/Model/ResourceModel/ProductTest.php | 5 +---- .../TestCase/VerifyConfigurableProductEntityPriceTest.xml | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/Model/ResourceModel/ProductTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/Model/ResourceModel/ProductTest.php index 454b38c9c76d6..73eb8734b6063 100644 --- a/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/Model/ResourceModel/ProductTest.php +++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Plugin/Model/ResourceModel/ProductTest.php @@ -9,9 +9,6 @@ use Magento\Catalog\Model\Product\Type; use Magento\ConfigurableProduct\Model\Product\Type\Configurable; use Magento\Framework\Indexer\ActionInterface; -use Magento\Framework\Indexer\IndexerInterface; -use Magento\PageCache\Model\Config; -use Magento\Framework\App\Cache\TypeListInterface; class ProductTest extends \PHPUnit\Framework\TestCase { @@ -45,7 +42,7 @@ public function setUp() \Magento\ConfigurableProduct\Plugin\Model\ResourceModel\Product::class, [ 'configurable' => $this->configurableMock, - 'indexerAction' => $this->actionMock, + 'productIndexer' => $this->actionMock, ] ); } diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/VerifyConfigurableProductEntityPriceTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/VerifyConfigurableProductEntityPriceTest.xml index 7aa4a6e14066c..6d22cea4689a8 100644 --- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/VerifyConfigurableProductEntityPriceTest.xml +++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/VerifyConfigurableProductEntityPriceTest.xml @@ -32,7 +32,6 @@ - MAGETWO-66699: Configurable product when all child products are disabled configurableProduct::product_with_color From d34a47108f75ade43874a89313991ebb5377c054 Mon Sep 17 00:00:00 2001 From: Eric Bohanon Date: Wed, 6 Sep 2017 13:46:27 -0500 Subject: [PATCH 103/151] MAGETWO-70346: Configurable product shows on frontend after deleting child --- .../Catalog/Model/Indexer/Product/Full.php | 18 ------ .../Unit/Model/Indexer/Product/FullTest.php | 58 ------------------- 2 files changed, 76 deletions(-) diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Full.php b/app/code/Magento/Catalog/Model/Indexer/Product/Full.php index ed5596f3726ec..bb696c5cab4ce 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Full.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Full.php @@ -8,8 +8,6 @@ use Magento\Framework\Indexer\ActionInterface; use Magento\Framework\Indexer\IndexerRegistry; -use Magento\PageCache\Model\Config; -use Magento\Framework\App\Cache\TypeListInterface; /** * Reindex all relevant product indexers @@ -21,16 +19,6 @@ class Full implements ActionInterface */ private $indexerRegistry; - /** - * @var Config - */ - private $pageCacheConfig; - - /** - * @var TypeListInterface - */ - private $cacheTypeList; - /** * @var string[] */ @@ -40,19 +28,13 @@ class Full implements ActionInterface * Initialize dependencies * * @param IndexerRegistry $indexerRegistry - * @param Config $pageCacheConfig - * @param TypeListInterface $cacheTypeList * @param string[] $indexerList */ public function __construct( IndexerRegistry $indexerRegistry, - Config $pageCacheConfig, - TypeListInterface $cacheTypeList, array $indexerList ) { $this->indexerRegistry = $indexerRegistry; - $this->pageCacheConfig = $pageCacheConfig; - $this->cacheTypeList = $cacheTypeList; $this->indexerList = $indexerList; } diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/FullTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/FullTest.php index cb3f017cb67f9..de2c4eaf7dc67 100644 --- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/FullTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/FullTest.php @@ -10,8 +10,6 @@ use Magento\Framework\Indexer\IndexerInterface; use PHPUnit\Framework\TestCase; use Magento\Framework\Indexer\IndexerRegistry; -use Magento\PageCache\Model\Config; -use Magento\Framework\App\Cache\TypeListInterface; class FullTest extends TestCase { @@ -25,16 +23,6 @@ class FullTest extends TestCase */ private $indexerRegistryMock; - /** - * @var Config|\PHPUnit_Framework_MockObject_MockObject - */ - private $configMock; - - /** - * @var TypeListInterface|\PHPUnit_Framework_MockObject_MockObject - */ - private $typeListMock; - /** * @var Full */ @@ -44,15 +32,11 @@ public function setUp() { $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this); $this->indexerRegistryMock = $this->createMock(IndexerRegistry::class); - $this->configMock = $this->createMock(Config::class); - $this->typeListMock = $this->getMockForAbstractClass(TypeListInterface::class, [], "", false); $this->full = $this->objectManager->getObject( Full::class, [ 'indexerRegistry' => $this->indexerRegistryMock, - 'pageCacheConfig' => $this->configMock, - 'cacheTypeList' => $this->typeListMock, 'indexerList' => ['catalog_indexer', 'product_indexer', 'stock_indexer', 'search_indexer'] ] ); @@ -64,20 +48,6 @@ public function testExecuteFull() $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); $indexerMock->expects($this->exactly(4))->method('reindexAll'); $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); - $this->configMock->expects($this->once())->method('isEnabled')->willReturn(true); - $this->typeListMock->expects($this->once())->method('invalidate')->with('full_page'); - - $this->full->executeFull(); - } - - public function testExecuteFullPageCacheDisabled() - { - $indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false); - $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); - $indexerMock->expects($this->exactly(4))->method('reindexAll'); - $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); - $this->configMock->expects($this->once())->method('isEnabled')->willReturn(false); - $this->typeListMock->expects($this->never())->method('invalidate'); $this->full->executeFull(); } @@ -88,20 +58,6 @@ public function testExecuteList() $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); $indexerMock->expects($this->exactly(4))->method('reindexList')->with([1, 2]); $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); - $this->configMock->expects($this->once())->method('isEnabled')->willReturn(true); - $this->typeListMock->expects($this->once())->method('invalidate')->with('full_page'); - - $this->full->executeList([1, 2]); - } - - public function testExecuteListPageCacheDisabled() - { - $indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false); - $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); - $indexerMock->expects($this->exactly(4))->method('reindexList')->with([1, 2]); - $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); - $this->configMock->expects($this->once())->method('isEnabled')->willReturn(false); - $this->typeListMock->expects($this->never())->method('invalidate'); $this->full->executeList([1, 2]); } @@ -112,20 +68,6 @@ public function testExecuteRow() $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); $indexerMock->expects($this->exactly(4))->method('reindexRow')->with(1); $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); - $this->configMock->expects($this->once())->method('isEnabled')->willReturn(true); - $this->typeListMock->expects($this->once())->method('invalidate')->with('full_page'); - - $this->full->executeRow(1); - } - - public function testExecuteRowPageCacheDisabled() - { - $indexerMock = $this->getMockForAbstractClass(IndexerInterface::class, [], "", false); - $indexerMock->expects($this->exactly(4))->method('isScheduled')->willReturn(false); - $indexerMock->expects($this->exactly(4))->method('reindexRow')->with(1); - $this->indexerRegistryMock->expects($this->exactly(4))->method('get')->willReturn($indexerMock); - $this->configMock->expects($this->once())->method('isEnabled')->willReturn(false); - $this->typeListMock->expects($this->never())->method('invalidate'); $this->full->executeRow(1); } From cbcb78ae23cf9210317a0174cb9e43282c035f6e Mon Sep 17 00:00:00 2001 From: Krissy Hiserote Date: Wed, 6 Sep 2017 13:49:12 -0500 Subject: [PATCH 104/151] MAGETWO-69470: Coupon with type 'Auto' can't be generated. - move coupon type auto functional test to EE --- .../Promo/Quote/Edit/PromoQuoteForm.xml | 2 +- .../CreateSalesRuleEntityPartTwoTest.xml | 29 ------------------- 2 files changed, 1 insertion(+), 30 deletions(-) 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 6e078d455c68d..89b2dd9045e39 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 @@ -82,7 +82,7 @@ \Magento\SalesRule\Test\Block\Adminhtml\Promo\Quote\Edit\Section\ManageCouponCode - [id="sales-rule-form-tab-coupons"] + [data-index="manage_coupon_codes"] css selector diff --git a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityPartTwoTest.xml b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityPartTwoTest.xml index af2c7fa67966b..5968ff11d245c 100644 --- a/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityPartTwoTest.xml +++ b/dev/tests/functional/tests/app/Magento/SalesRule/Test/TestCase/CreateSalesRuleEntityPartTwoTest.xml @@ -132,34 +132,5 @@ - - 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 - to_maintain:yes - MAGETWO-65554: [FT] Magento\SalesRule\Test\TestCase\CreateSalesRuleEntityTest fails on CI - - - - From 7e0b68933665cdc97069837c35c8948a6c876bd5 Mon Sep 17 00:00:00 2001 From: Daniel Renaud Date: Wed, 6 Sep 2017 14:08:05 -0500 Subject: [PATCH 105/151] MAGETWO-71771: imposible perform full refund for Order Paid with PayPal Payments Standard - Reuse test fixture for integration test --- .../Magento/Paypal/Model/Api/NvpTest.php | 2 +- .../Paypal/_files/order_express_with_tax.php | 21 +++++ .../order_standard_with_tax_and_invoice.php | 93 ------------------- 3 files changed, 22 insertions(+), 94 deletions(-) create mode 100644 dev/tests/integration/testsuite/Magento/Paypal/_files/order_express_with_tax.php delete mode 100644 dev/tests/integration/testsuite/Magento/Paypal/_files/order_standard_with_tax_and_invoice.php diff --git a/dev/tests/integration/testsuite/Magento/Paypal/Model/Api/NvpTest.php b/dev/tests/integration/testsuite/Magento/Paypal/Model/Api/NvpTest.php index c6a168c04d6ae..58136d45f5883 100644 --- a/dev/tests/integration/testsuite/Magento/Paypal/Model/Api/NvpTest.php +++ b/dev/tests/integration/testsuite/Magento/Paypal/Model/Api/NvpTest.php @@ -121,7 +121,7 @@ public function testRequestTotalsAndLineItemsWithFPT() /** * Test that the refund request to Paypal sends the correct data * - * @magentoDataFixture Magento/Paypal/_files/order_standard_with_tax_and_invoice.php + * @magentoDataFixture Magento/Paypal/_files/order_express_with_tax.php */ public function testCallRefundTransaction() { diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/order_express_with_tax.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/order_express_with_tax.php new file mode 100644 index 0000000000000..40c002d45adb1 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Paypal/_files/order_express_with_tax.php @@ -0,0 +1,21 @@ +setSubtotal($subTotal); +$order->setBaseSubtotal($subTotal); +$order->setGrandTotal($totalAmount); +$order->setBaseGrandTotal($totalAmount); +$order->setTaxAmount($taxAmount); + +$order->save(); diff --git a/dev/tests/integration/testsuite/Magento/Paypal/_files/order_standard_with_tax_and_invoice.php b/dev/tests/integration/testsuite/Magento/Paypal/_files/order_standard_with_tax_and_invoice.php deleted file mode 100644 index 4d6b40d0b12a7..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Paypal/_files/order_standard_with_tax_and_invoice.php +++ /dev/null @@ -1,93 +0,0 @@ -setPrice(121); - -$objectManager = Bootstrap::getObjectManager(); - -$addressData = include __DIR__ . '/address_data.php'; -$billingAddress = $objectManager->create( - Address::class, - ['data' => $addressData] -); -$billingAddress->setAddressType('billing'); -$shippingAddress = clone $billingAddress; -$shippingAddress->setId(null)->setAddressType('shipping'); - -$payment = $objectManager->create(Payment::class); -$payment->setMethod(Config::METHOD_WPS_EXPRESS); - -$taxRate = .0825; -$taxAmount = $product->getPrice() * $taxRate; - -/** @var Item $orderItem */ -$orderItem = $objectManager->create(Item::class); -$orderItem->setProductId($product->getId())->setQtyOrdered(1); -$orderItem->setBasePrice($product->getPrice()); -$orderItem->setPrice($product->getPrice()); -$orderItem->setRowTotal($product->getPrice()); -$orderItem->setRowTotalInclTax($product->getPrice() + $taxAmount); -$orderItem->setBaseRowTotal($product->getPrice()); -$orderItem->setBaseRowTotalInclTax($product->getPrice() + $taxAmount); -$orderItem->setBaseRowInvoiced($product->getPrice() + $taxAmount); -$orderItem->setProductType('simple'); - -$itemsAmount = $product->getPrice(); -$shippingAmount = 15; -$itemsAmountInclTax = $itemsAmount + $taxAmount; -$totalAmount = $itemsAmountInclTax + $shippingAmount; - -/** @var Order $order */ -$order = $objectManager->create(Order::class); -$order->setCustomerEmail('co@co.co') - ->setIncrementId('100000001') - ->addItem($orderItem) - ->setSubtotal($itemsAmount) - ->setBaseSubtotal($itemsAmount) - ->setBaseGrandTotal($totalAmount) - ->setGrandTotal($totalAmount) - ->setTaxAmount($taxAmount) - ->setBaseCurrencyCode('USD') - ->setCustomerIsGuest(true) - ->setStoreId(1) - ->setEmailSent(true) - ->setState(Order::STATE_PROCESSING) - ->setBillingAddress($billingAddress) - ->setShippingAddress($shippingAddress) - ->setBaseTotalPaid($totalAmount) - ->setTotalPaid($totalAmount) - ->setData('base_to_global_rate', 1) - ->setData('base_to_order_rate', 1) - ->setData('shipping_amount', $shippingAmount) - ->setData('base_shipping_amount', $shippingAmount) - ->setPayment($payment); - -/** @var OrderRepositoryInterface $orderRepository */ -$orderRepository = $objectManager->get(OrderRepositoryInterface::class); -$orderRepository->save($order); - -/** @var InvoiceService $invoiceService */ -$invoiceService = $objectManager->create(InvoiceManagementInterface::class); - -/** @var Transaction $transaction */ -$transaction = $objectManager->create(Transaction::class); - -$invoice = $invoiceService->prepareInvoice($order, [$orderItem->getId() => 1]); -$invoice->register(); - -$transaction->addObject($invoice)->addObject($order)->save(); From c03addfd598349f5089b777410f16cc1178cf1cc Mon Sep 17 00:00:00 2001 From: Krissy Hiserote Date: Wed, 6 Sep 2017 14:40:32 -0500 Subject: [PATCH 106/151] MAGETWO-69470: Coupon with type 'Auto' can't be generated. - fix static test errors --- .../SalesRule/Model/Service/CouponManagementService.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php b/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php index 27673a717f7a2..3d99c5a9a9a22 100644 --- a/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php +++ b/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php @@ -8,6 +8,7 @@ /** * Coupon management service class * + * @SuppressWarnings(PHPMD.CouplingBetweenObjects) */ class CouponManagementService implements \Magento\SalesRule\Api\CouponManagementInterface { @@ -88,7 +89,10 @@ public function generate(\Magento\SalesRule\Api\Data\CouponGenerationSpecInterfa $couponSpec->getRuleId() ); } - if (!$rule->getUseAutoGeneration() && $rule->getCouponType() != \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO) { + if ( + !$rule->getUseAutoGeneration() + && $rule->getCouponType() != \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO + ) { throw new \Magento\Framework\Exception\LocalizedException( __('Specified rule does not allow automatic coupon generation') ); From 868fc1fd20c8ac690e04151106f1610c30469d84 Mon Sep 17 00:00:00 2001 From: Krissy Hiserote Date: Wed, 6 Sep 2017 15:15:10 -0500 Subject: [PATCH 107/151] MAGETWO-69470: Coupon with type 'Auto' can't be generated. - fix static test errors --- .../SalesRule/Model/Service/CouponManagementService.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php b/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php index 3d99c5a9a9a22..bff74740aa241 100644 --- a/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php +++ b/app/code/Magento/SalesRule/Model/Service/CouponManagementService.php @@ -89,8 +89,7 @@ public function generate(\Magento\SalesRule\Api\Data\CouponGenerationSpecInterfa $couponSpec->getRuleId() ); } - if ( - !$rule->getUseAutoGeneration() + if (!$rule->getUseAutoGeneration() && $rule->getCouponType() != \Magento\SalesRule\Model\Rule::COUPON_TYPE_AUTO ) { throw new \Magento\Framework\Exception\LocalizedException( From f4620b744d9bfc208b1f58dcd9848500fcabea94 Mon Sep 17 00:00:00 2001 From: Joan He Date: Wed, 6 Sep 2017 16:10:30 -0500 Subject: [PATCH 108/151] MAGETWO-72112: [Github] Child categories included in menu when parent category is disabled or hidden #10664 - add function tests --- .../AssertCategoryIncludeInNavigationMenu.php | 48 ++++++ .../AssertCategoryNotInNavigationMenu.php | 48 ++++++ .../AssertSubCategoryNotInNavigationMenu.php | 48 ++++++ ...categoryNotIncludeInNavigationMenuTest.php | 149 ++++++++++++++++++ ...categoryNotIncludeInNavigationMenuTest.xml | 43 +++++ 5 files changed, 336 insertions(+) create mode 100644 dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIncludeInNavigationMenu.php create mode 100644 dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNotInNavigationMenu.php create mode 100644 dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertSubCategoryNotInNavigationMenu.php create mode 100644 dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.php create mode 100644 dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.xml diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIncludeInNavigationMenu.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIncludeInNavigationMenu.php new file mode 100644 index 0000000000000..44200a286f8fb --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryIncludeInNavigationMenu.php @@ -0,0 +1,48 @@ +open(); + \PHPUnit_Framework_Assert::assertTrue( + $catalogCategoryView->getTopmenu()->isCategoryVisible($category->getName()), + 'Expected that ' . $category->getName() . ' is visible in navigation menu.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Category is visible in navigation menu"; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNotInNavigationMenu.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNotInNavigationMenu.php new file mode 100644 index 0000000000000..fd05c289560f1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertCategoryNotInNavigationMenu.php @@ -0,0 +1,48 @@ +open(); + \PHPUnit_Framework_Assert::assertFalse( + $catalogCategoryView->getTopmenu()->isCategoryVisible($category->getName()), + 'Expected that ' . $category->getName() . ' is not visible in navigation menu.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Category is not visible in navigation menu"; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertSubCategoryNotInNavigationMenu.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertSubCategoryNotInNavigationMenu.php new file mode 100644 index 0000000000000..b4876c395dee1 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertSubCategoryNotInNavigationMenu.php @@ -0,0 +1,48 @@ +open(); + \PHPUnit_Framework_Assert::assertFalse( + $catalogCategoryView->getTopmenu()->isCategoryVisible($subcategory->getName()), + 'Expected that ' . $subcategory->getName() . ' is not visible in navigation menu.' + ); + } + + /** + * Returns a string representation of the object. + * + * @return string + */ + public function toString() + { + return "Subcategory is not visible in navigation menu"; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.php new file mode 100644 index 0000000000000..4e12d60312c75 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.php @@ -0,0 +1,149 @@ +Categories. + * 2. Open category created in preconditions. + * 3. Update data according to data set. + * 4. Save category. + * 5. Perform assertions. + * + * @group Category_Management + * @ZephyrId MAGETWO-72238 + */ +class SubcategoryNotIncludeInNavigationMenuTest extends Injectable +{ + /* tags */ + const MVP = 'yes'; + /* end tags */ + + /** + * Catalog category index page. + * + * @var CatalogCategoryIndex + */ + protected $catalogCategoryIndex; + + /** + * Catalog category edit page. + * + * @var CatalogCategoryEdit + */ + protected $catalogCategoryEdit; + + /** + * Fixture Factory. + * + * @var FixtureFactory + */ + protected $fixtureFactory; + + /** + * Inject pages. + * + * @param CatalogCategoryIndex $catalogCategoryIndex + * @param CatalogCategoryEdit $catalogCategoryEdit + * @param FixtureFactory $fixtureFactory + * @return void + */ + public function __inject( + CatalogCategoryIndex $catalogCategoryIndex, + CatalogCategoryEdit $catalogCategoryEdit, + FixtureFactory $fixtureFactory + ) { + $this->fixtureFactory = $fixtureFactory; + $this->catalogCategoryIndex = $catalogCategoryIndex; + $this->catalogCategoryEdit = $catalogCategoryEdit; + } + + /** + * Top parent category update test. + * + * @param Category $category + * @param Category $initialCategory + * @param int $nestingLevel + * @return array + */ + public function test( + Category $category, + Category $initialCategory, + $nestingLevel + ) { + $initialCategory->persist(); + $topCategory = $this->getParentCategoryByNestingLevel($initialCategory, $nestingLevel); + $this->catalogCategoryIndex->open(); + $this->catalogCategoryIndex->getTreeCategories()->selectCategory($topCategory); + $this->catalogCategoryEdit->getEditForm()->fill($category); + $this->catalogCategoryEdit->getFormPageActions()->save(); + + $categories = []; + $this->getCategoryFixture($categories, $initialCategory, $category->getData(), $nestingLevel); + return [ + 'category' => $categories[1], + 'subcategory' => $categories[2], + ]; + } + + /** + * Get category fixture after saving in the admin panel. + * + * @param array $categories + * @param Category $currentCategory + * @param array $data + * @param int $nestingLevel + * @return Category + */ + private function getCategoryFixture(array &$categories, Category $currentCategory, array $data, int $nestingLevel) + { + if (--$nestingLevel) { + $parentCategory = $this->getCategoryFixture( + $categories, + $currentCategory->getDataFieldConfig('parent_id')['source']->getParentCategory(), + $data, + $nestingLevel + ); + $category = $this->fixtureFactory->createByCode( + 'category', + ['data' => array_merge($currentCategory->getData(), ['parent_id' => ['source' => $parentCategory]])] + ); + } else { + $category = $this->fixtureFactory->createByCode( + 'category', + ['data' => array_merge($currentCategory->getData(), $data)] + ); + } + $categories[$nestingLevel + 1] = $category; + return $category; + } + + /** + * Get parent category by category nesting level. + * + * @param Category $category + * @param int $nestingLevel + * @return Category + */ + private function getParentCategoryByNestingLevel(Category $category, $nestingLevel) + { + for ($nestingIterator = 1; $nestingIterator < $nestingLevel; $nestingIterator++) { + $category = $category->getDataFieldConfig('parent_id')['source']->getParentCategory(); + } + + return $category; + } +} diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.xml new file mode 100644 index 0000000000000..94d99dd6b7b24 --- /dev/null +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.xml @@ -0,0 +1,43 @@ + + + + + + two_nested_categories + 2 + Yes + Yes + + + + + two_nested_categories + 2 + Yes + No + + + + + two_nested_categories + 2 + No + Yes + + + + + two_nested_categories + 2 + No + No + + + + + From 46d9434e2d3d828ae327bb5fe781a2b1067712e0 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 7 Sep 2017 10:08:52 +0300 Subject: [PATCH 109/151] MAGETWO-71922: Error in Import Customers Main File with custom attribute. --- .../CustomerImportExport/Model/Export/Address.php | 6 ++++++ .../CustomerImportExport/Model/Import/Address.php | 10 ++++++---- .../CustomerImportExport/Model/Import/Customer.php | 8 ++++++-- .../ImportExport/Model/Export/Entity/AbstractEav.php | 10 ++++------ 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/app/code/Magento/CustomerImportExport/Model/Export/Address.php b/app/code/Magento/CustomerImportExport/Model/Export/Address.php index 194d44c974848..ec1c894ae4851 100644 --- a/app/code/Magento/CustomerImportExport/Model/Export/Address.php +++ b/app/code/Magento/CustomerImportExport/Model/Export/Address.php @@ -34,6 +34,11 @@ class Address extends \Magento\ImportExport\Model\Export\Entity\AbstractEav */ const COLUMN_COUNTRY_ID = 'country_id'; + /** + * Name of region id column + */ + const COLUMN_REGION_ID = 'region_id'; + /**#@+ * Particular columns that contains of customer default addresses */ @@ -255,6 +260,7 @@ public function exportItem($item) $row[self::COLUMN_ADDRESS_ID] = $item['entity_id']; $row[self::COLUMN_EMAIL] = $customer['email']; $row[self::COLUMN_WEBSITE] = $this->_websiteIdToCode[$customer['website_id']]; + $row[self::COLUMN_REGION_ID] = $item->getRegionId(); $this->getWriter()->writeRow($row); } diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Address.php b/app/code/Magento/CustomerImportExport/Model/Import/Address.php index fcdf9f94d2f0f..ea5828d5f58b3 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/Address.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/Address.php @@ -486,7 +486,9 @@ protected function _mergeEntityAttributes(array $newAttributes, array $attribute */ protected function _prepareDataForUpdate(array $rowData) { - $multiSeparator = $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]; + $multiSeparator = isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]) + ? $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] + : Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR; $email = strtolower($rowData[self::COLUMN_EMAIL]); $customerId = $this->_getCustomerId($email, $rowData[self::COLUMN_WEBSITE]); // entity table data @@ -738,9 +740,9 @@ protected function _validateRowForUpdate(array $rowData, $rowNumber) continue; } if (isset($rowData[$attributeCode]) && strlen($rowData[$attributeCode])) { - $multiSeparator = isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]) ? - $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] : - Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR; + $multiSeparator = isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]) + ? $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] + : Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR; $this->isAttributeValid( $attributeCode, $attributeParams, diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php index fd14ce8f7e9a2..bd538bb1a1ac0 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php @@ -339,7 +339,9 @@ protected function _getNextEntityId() */ protected function _prepareDataForUpdate(array $rowData) { - $multiSeparator = $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]; + $multiSeparator = isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]) + ? $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] + : Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR; $entitiesToCreate = []; $entitiesToUpdate = []; $attributesToSave = []; @@ -546,7 +548,9 @@ protected function _validateRowForUpdate(array $rowData, $rowNumber) $attributeParams, $rowData, $rowNumber, - $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] + isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]) + ? $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] + : Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR ); } elseif ($attributeParams['is_required'] && !$this->_getCustomerId($email, $website)) { $this->addRowError(self::ERROR_VALUE_IS_REQUIRED, $rowNumber, $attributeCode); diff --git a/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php b/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php index 4e6b146536239..266501208aef6 100644 --- a/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php +++ b/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php @@ -289,7 +289,8 @@ protected function _addAttributeValuesToRow(\Magento\Framework\Model\AbstractMod * @param string $attributeCode An attribute code * @return bool Returns true if attribute is multiselect type */ - private function isMultiselect($attributeCode) { + private function isMultiselect($attributeCode) + { return isset($this->_attributeTypes[$attributeCode]) && $this->_attributeTypes[$attributeCode] === 'multiselect'; } @@ -303,11 +304,8 @@ private function isMultiselect($attributeCode) { */ private function getAttributeValueById($attributeCode, $valueId) { - if (isset( - $this->_attributeValues[$attributeCode] - ) && isset( - $this->_attributeValues[$attributeCode][$valueId] - ) + if (isset($this->_attributeValues[$attributeCode]) + && isset($this->_attributeValues[$attributeCode][$valueId]) ) { return $this->_attributeValues[$attributeCode][$valueId]; } From 70e82c3639bc038a4ebe0e12c6b8b296fa5d1d3b Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Thu, 7 Sep 2017 11:01:52 +0300 Subject: [PATCH 110/151] MAGETWO-69210: [Google Tag Manager] Ajax "Add to Cart" / "Remove from Cart" do not fire any events --- app/code/Magento/Checkout/view/frontend/web/js/sidebar.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js b/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js index 0632b39b4927f..13a2b524e5186 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/sidebar.js @@ -230,11 +230,10 @@ define([ /** * Update content after item remove * - * @param elem - * @param response + * @param {Object} elem * @private */ - _removeItemAfter: function (elem, response) { + _removeItemAfter: function (elem) { var productData = customerData.get('cart')().items.find(function (item) { return Number(elem.data('cart-item')) === Number(item['item_id']); }); From 6f59c554abfaf115032878159d7f0216c51c8147 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 7 Sep 2017 11:06:14 +0300 Subject: [PATCH 111/151] MAGETWO-71922: Error in Import Customers Main File with custom attribute. --- .../Model/Import/AbstractCustomer.php | 13 +++++++++++++ .../CustomerImportExport/Model/Import/Address.php | 9 ++------- .../CustomerImportExport/Model/Import/Customer.php | 4 +--- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php b/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php index ade8b07c79cc0..38854b1836869 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/AbstractCustomer.php @@ -5,6 +5,7 @@ */ namespace Magento\CustomerImportExport\Model\Import; +use Magento\ImportExport\Model\Import; use Magento\CustomerImportExport\Model\ResourceModel\Import\Customer\Storage; use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface; @@ -262,4 +263,16 @@ protected function getSelectAttrIdByValue(array $attributeParameters, $value) ? $attributeParameters['options'][strtolower($value)] : 0; } + + /** + * Returns multiple value separator + * + * @return string + */ + protected function getMultipleValueSeparator() + { + return isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]) + ? $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] + : Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR; + } } diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Address.php b/app/code/Magento/CustomerImportExport/Model/Import/Address.php index ea5828d5f58b3..7d44ef079d152 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/Address.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/Address.php @@ -5,7 +5,6 @@ */ namespace Magento\CustomerImportExport\Model\Import; -use Magento\ImportExport\Model\Import; use Magento\ImportExport\Model\Import\ErrorProcessing\ProcessingErrorAggregatorInterface; /** @@ -486,9 +485,7 @@ protected function _mergeEntityAttributes(array $newAttributes, array $attribute */ protected function _prepareDataForUpdate(array $rowData) { - $multiSeparator = isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]) - ? $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] - : Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR; + $multiSeparator = $this->getMultipleValueSeparator(); $email = strtolower($rowData[self::COLUMN_EMAIL]); $customerId = $this->_getCustomerId($email, $rowData[self::COLUMN_WEBSITE]); // entity table data @@ -722,6 +719,7 @@ protected function _isOptionalAddressEmpty(array $rowData) */ protected function _validateRowForUpdate(array $rowData, $rowNumber) { + $multiSeparator = $this->getMultipleValueSeparator(); if ($this->_checkUniqueKey($rowData, $rowNumber)) { $email = strtolower($rowData[self::COLUMN_EMAIL]); $website = $rowData[self::COLUMN_WEBSITE]; @@ -740,9 +738,6 @@ protected function _validateRowForUpdate(array $rowData, $rowNumber) continue; } if (isset($rowData[$attributeCode]) && strlen($rowData[$attributeCode])) { - $multiSeparator = isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]) - ? $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] - : Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR; $this->isAttributeValid( $attributeCode, $attributeParams, diff --git a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php index bd538bb1a1ac0..bee4479526037 100644 --- a/app/code/Magento/CustomerImportExport/Model/Import/Customer.php +++ b/app/code/Magento/CustomerImportExport/Model/Import/Customer.php @@ -339,9 +339,7 @@ protected function _getNextEntityId() */ protected function _prepareDataForUpdate(array $rowData) { - $multiSeparator = isset($this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR]) - ? $this->_parameters[Import::FIELD_FIELD_MULTIPLE_VALUE_SEPARATOR] - : Import::DEFAULT_GLOBAL_MULTI_VALUE_SEPARATOR; + $multiSeparator = $this->getMultipleValueSeparator(); $entitiesToCreate = []; $entitiesToUpdate = []; $attributesToSave = []; From 558fccb65005133b0f7e430f68bd28c5f6b7a0b5 Mon Sep 17 00:00:00 2001 From: Bohdan Korablov Date: Thu, 7 Sep 2017 11:09:15 +0300 Subject: [PATCH 112/151] MAGETWO-71922: Error in Import Customers Main File with custom attribute. --- .../ImportExport/Model/Export/Entity/AbstractEav.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php b/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php index 266501208aef6..f15a79c21c322 100644 --- a/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php +++ b/app/code/Magento/ImportExport/Model/Export/Entity/AbstractEav.php @@ -33,7 +33,7 @@ abstract class AbstractEav extends \Magento\ImportExport\Model\Export\AbstractEn * * @var array */ - protected $_attributeTypes = []; + protected $attributeTypes = []; /** * Entity type id. @@ -105,7 +105,7 @@ protected function _initAttributeTypes() { /** @var $attribute AbstractAttribute */ foreach ($this->getAttributeCollection() as $attribute) { - $this->_attributeTypes[$attribute->getAttributeCode()] = $attribute->getFrontendInput(); + $this->attributeTypes[$attribute->getAttributeCode()] = $attribute->getFrontendInput(); } return $this; } @@ -291,8 +291,8 @@ protected function _addAttributeValuesToRow(\Magento\Framework\Model\AbstractMod */ private function isMultiselect($attributeCode) { - return isset($this->_attributeTypes[$attributeCode]) - && $this->_attributeTypes[$attributeCode] === 'multiselect'; + return isset($this->attributeTypes[$attributeCode]) + && $this->attributeTypes[$attributeCode] === 'multiselect'; } /** From ab18b6cc27bed16be132993bf8c50af4d37593f7 Mon Sep 17 00:00:00 2001 From: Ievgen Sentiabov Date: Thu, 7 Sep 2017 15:26:50 +0300 Subject: [PATCH 113/151] MAGETWO-72305: USPS First-Class Mail Parcel method no longer displaying checkout - Moved update for shipping methods with outdated format to upgrade data script --- .../{InstallData.php => UpgradeData.php} | 36 ++++++++++++------- app/code/Magento/Usps/etc/module.xml | 2 +- 2 files changed, 24 insertions(+), 14 deletions(-) rename app/code/Magento/Usps/Setup/{InstallData.php => UpgradeData.php} (83%) diff --git a/app/code/Magento/Usps/Setup/InstallData.php b/app/code/Magento/Usps/Setup/UpgradeData.php similarity index 83% rename from app/code/Magento/Usps/Setup/InstallData.php rename to app/code/Magento/Usps/Setup/UpgradeData.php index 6ed70588f65ac..f8a15d170b3f5 100644 --- a/app/code/Magento/Usps/Setup/InstallData.php +++ b/app/code/Magento/Usps/Setup/UpgradeData.php @@ -6,19 +6,29 @@ namespace Magento\Usps\Setup; -use Magento\Framework\Setup\InstallDataInterface; use Magento\Framework\Setup\ModuleContextInterface; use Magento\Framework\Setup\ModuleDataSetupInterface; +use Magento\Framework\Setup\UpgradeDataInterface; -/** - * @codeCoverageIgnore - */ -class InstallData implements InstallDataInterface +class UpgradeData implements UpgradeDataInterface { /** - * {@inheritdoc} + * @inheritdoc + */ + public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + { + if (version_compare($context->getVersion(), '2.0.1', '<')) { + $this->updateAllowedMethods($setup); + } + } + + /** + * Replaces titles of allowed shipping methods to their codes. + * + * @param ModuleDataSetupInterface $setup + * @return void */ - public function install(ModuleDataSetupInterface $setup, ModuleContextInterface $context) + private function updateAllowedMethods(ModuleDataSetupInterface $setup) { $installer = $setup; $configDataTable = $installer->getTable('core_config_data'); @@ -69,12 +79,12 @@ public function install(ModuleDataSetupInterface $setup, ModuleContextInterface 'Priority Mail International Large Flat Rate Box' => 'INT_11', ]; - $select = $connection->select()->from( - $configDataTable - )->where( - 'path IN (?)', - ['carriers/usps/free_method', 'carriers/usps/allowed_methods'] - ); + $select = $connection->select() + ->from($configDataTable) + ->where( + 'path IN (?)', + ['carriers/usps/free_method', 'carriers/usps/allowed_methods'] + ); $oldConfigValues = $connection->fetchAll($select); foreach ($oldConfigValues as $oldValue) { diff --git a/app/code/Magento/Usps/etc/module.xml b/app/code/Magento/Usps/etc/module.xml index 8283e9149face..8a1ec284c6333 100644 --- a/app/code/Magento/Usps/etc/module.xml +++ b/app/code/Magento/Usps/etc/module.xml @@ -6,6 +6,6 @@ */ --> - + From 499e95175933ee5d954591475024fd784f74d984 Mon Sep 17 00:00:00 2001 From: Dmytro Voskoboinikov Date: Thu, 7 Sep 2017 15:27:41 +0300 Subject: [PATCH 114/151] MAGETWO-70377: [GitHub] Tier price saving percentage wrong when VAT is included in price #8833 --- .../Catalog/Pricing/Price/TierPrice.php | 11 ++++- .../Test/Unit/Pricing/Price/TierPriceTest.php | 40 ++++++++++++------- 2 files changed, 35 insertions(+), 16 deletions(-) diff --git a/app/code/Magento/Catalog/Pricing/Price/TierPrice.php b/app/code/Magento/Catalog/Pricing/Price/TierPrice.php index d86302181b26b..fd8e29ed5a02b 100644 --- a/app/code/Magento/Catalog/Pricing/Price/TierPrice.php +++ b/app/code/Magento/Catalog/Pricing/Price/TierPrice.php @@ -215,14 +215,21 @@ protected function getBasePrice() } /** + * Calculates savings percentage according to the given tier price amount + * and related product price amount. + * * @param AmountInterface $amount + * * @return float */ public function getSavePercent(AmountInterface $amount) { + $productPriceAmount = $this->priceInfo->getPrice( + FinalPrice::PRICE_CODE + )->getAmount(); + return round( - 100 - ((100 / $this->priceInfo->getPrice(FinalPrice::PRICE_CODE)->getValue()) - * $amount->getBaseAmount()) + 100 - ((100 / $productPriceAmount->getValue()) * $amount->getValue()) ); } diff --git a/app/code/Magento/Catalog/Test/Unit/Pricing/Price/TierPriceTest.php b/app/code/Magento/Catalog/Test/Unit/Pricing/Price/TierPriceTest.php index 152133ef903f0..12fe4e2bdae97 100644 --- a/app/code/Magento/Catalog/Test/Unit/Pricing/Price/TierPriceTest.php +++ b/app/code/Magento/Catalog/Test/Unit/Pricing/Price/TierPriceTest.php @@ -10,6 +10,8 @@ use Magento\Catalog\Pricing\Price\TierPrice; use Magento\Catalog\Pricing\Price\FinalPrice; +use Magento\Framework\Pricing\Amount\AmountInterface; +use Magento\Framework\Pricing\Price\PriceInterface; use Magento\Customer\Model\Group; use Magento\Customer\Model\GroupManagement; @@ -250,7 +252,7 @@ public function testGetterTierPriceList($tierPrices, $basePrice, $expectedResult { $this->product->setData(TierPrice::PRICE_CODE, $tierPrices); - $price = $this->createMock(\Magento\Framework\Pricing\Price\PriceInterface::class); + $price = $this->createMock(PriceInterface::class); $price->expects($this->any())->method('getValue')->will($this->returnValue($basePrice)); $this->calculator->expects($this->atLeastOnce())->method('getAmount') @@ -341,27 +343,37 @@ public function providerForGetterTierPriceList() } /** - * @covers \Magento\Catalog\Pricing\Price\TierPrice::__construct - * @covers \Magento\Catalog\Pricing\Price\TierPrice::getSavePercent - * @covers \Magento\Catalog\Pricing\Price\TierPrice::getBasePrice + * @param float $basePrice + * @param float $tierPrice + * @param float $savedPercent + * * @dataProvider dataProviderGetSavePercent */ public function testGetSavePercent($basePrice, $tierPrice, $savedPercent) { - $price = $this->createMock(\Magento\Framework\Pricing\Price\PriceInterface::class); + /** @var AmountInterface|\PHPUnit_Framework_MockObject_MockObject $amount */ + $amount = $this->getMockForAbstractClass(AmountInterface::class); - $this->priceInfo->expects(static::atLeastOnce()) - ->method('getPrice') - ->with(FinalPrice::PRICE_CODE) - ->willReturn($price); - $price->expects(static::atLeastOnce()) + $amount->expects($this->any()) + ->method('getValue') + ->willReturn($tierPrice); + + $basePriceAmount = $this->getMockForAbstractClass(AmountInterface::class); + + $basePriceAmount->expects($this->any()) ->method('getValue') ->willReturn($basePrice); - $amount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class); - $amount->expects($this->atLeastOnce()) - ->method('getBaseAmount') - ->will($this->returnValue($tierPrice)); + $price = $this->getMockForAbstractClass(PriceInterface::class); + + $price->expects($this->any()) + ->method('getAmount') + ->willReturn($basePriceAmount); + + $this->priceInfo->expects($this->any()) + ->method('getPrice') + ->with(FinalPrice::PRICE_CODE) + ->willReturn($price); $this->assertEquals($savedPercent, $this->model->getSavePercent($amount)); } From 9f746f6f05d23d0fa15a4ffcb2f272446937f472 Mon Sep 17 00:00:00 2001 From: Joan He Date: Wed, 6 Sep 2017 10:26:15 -0500 Subject: [PATCH 115/151] MAGETWO-70837: Pricing discrepancy in shopping cart - fix javascript test failures --- .../Checkout/view/frontend/web/js/model/cart/cache.js | 5 +++-- .../web/js/model/cart/totals-processor/default.js | 2 +- .../Magento/Checkout/view/frontend/web/js/model/totals.js | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/cache.js b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/cache.js index 9b13a579447ed..ac3a43af39ba8 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/cache.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/cache.js @@ -198,8 +198,9 @@ define([ * @returns {Boolean} */ _isSubtotalChanged: function (subtotal) { - var cached = this.get('totals').subtotal; - return subtotal != cached; + var cached = parseFloat(this.get('totals').subtotal); + + return subtotal !== cached; } }; }); diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js index 276fed5a294f9..e269462047748 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/cart/totals-processor/default.js @@ -92,7 +92,7 @@ define([ !cartCache.isChanged('shippingCarrierCode', data.shippingCarrierCode) && !cartCache.isChanged('address', address) && cartCache.get('totals') && - !cartCache.isChanged('subtotal', quote.totals()['subtotal']) + !cartCache.isChanged('subtotal', parseFloat(quote.totals().subtotal)) ) { quote.setTotals(cartCache.get('totals')); } else { diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js b/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js index 01d0786d81038..aba0c31b998d1 100644 --- a/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js +++ b/app/code/Magento/Checkout/view/frontend/web/js/model/totals.js @@ -14,15 +14,15 @@ define([ 'use strict'; var quoteItems = ko.observable(quote.totals().items), - cartData = customerData.get('cart'); + cartData = customerData.get('cart'), + quoteSubtotal = parseFloat(quote.totals().subtotal), + subtotalAmount = parseFloat(cartData().subtotalAmount); quote.totals.subscribe(function (newValue) { quoteItems(newValue.items); }); - var quoteSubtotal = quote.totals().subtotal, - subtotalAmount = cartData()['subtotalAmount']; - if (quoteSubtotal != subtotalAmount) { + if (quoteSubtotal !== subtotalAmount) { customerData.reload(['cart'], false); } From 5c39791df8110249e9893c747a2225fc9b4791cc Mon Sep 17 00:00:00 2001 From: Joan He Date: Wed, 6 Sep 2017 08:52:53 -0500 Subject: [PATCH 116/151] MAGETWO-71706: PayPal Express Checkout payment method doesn't appear after enabling PayPal Payments Advanced on website level - fix javascript test failure --- .../Paypal/view/adminhtml/web/js/rules.js | 298 +++++++++--------- 1 file changed, 149 insertions(+), 149 deletions(-) diff --git a/app/code/Magento/Paypal/view/adminhtml/web/js/rules.js b/app/code/Magento/Paypal/view/adminhtml/web/js/rules.js index 102e05048e29a..4a5248cb87587 100644 --- a/app/code/Magento/Paypal/view/adminhtml/web/js/rules.js +++ b/app/code/Magento/Paypal/view/adminhtml/web/js/rules.js @@ -16,179 +16,179 @@ define([ * @returns {Boolean} */ var isSolutionEnabled = function (solution, enabler) { - return solution.find(enabler).val() === '1'; - }, + return solution.find(enabler).val() === '1'; + }, - /** - * Check is solution has related solutions enabled - * - * @param {Object} data - * @returns {Boolean} - */ - hasRelationsEnabled = function (data) { - var name; + /** + * Check is solution has related solutions enabled + * + * @param {Object} data + * @returns {Boolean} + */ + hasRelationsEnabled = function (data) { + var name; - for (name in data.argument) { - if ( - data.solutionsElements[name] && - isSolutionEnabled(data.solutionsElements[name], data.enableButton) - ) { - return true; + for (name in data.argument) { + if ( + data.solutionsElements[name] && + isSolutionEnabled(data.solutionsElements[name], data.enableButton) + ) { + return true; + } } - } - return false; - }, + return false; + }, - /** - * Set solution select-enabler to certain option - * - * @param {*} solution - * @param {String} enabler - * @param {Boolean} enabled - */ - setSolutionSelectEnabled = function (solution, enabler, enabled) { - enabled = !(enabled || typeof enabled === 'undefined') ? '0' : '1'; + /** + * Set solution select-enabler to certain option + * + * @param {*} solution + * @param {String} enabler + * @param {Boolean} enabled + */ + setSolutionSelectEnabled = function (solution, enabler, enabled) { + enabled = !(enabled || typeof enabled === 'undefined') ? '0' : '1'; - solution.find(enabler + ' option[value=' + enabled + ']') + solution.find(enabler + ' option[value=' + enabled + ']') .prop('selected', true); - }, + }, - /** - * Set solution property 'disabled' value - * - * @param {*} solution - * @param {String} enabler - * @param {Boolean} enabled - */ - setSolutionPropEnabled = function (solution, enabler, enabled) { - enabled = !(enabled || typeof enabled === 'undefined'); + /** + * Set solution property 'disabled' value + * + * @param {*} solution + * @param {String} enabler + * @param {Boolean} enabled + */ + setSolutionPropEnabled = function (solution, enabler, enabled) { + enabled = !(enabled || typeof enabled === 'undefined'); - solution.find(enabler).prop('disabled', enabled); - }, + solution.find(enabler).prop('disabled', enabled); + }, - /** - * Set/unset solution select-enabler label - * - * @param {*} solution - * @param {String} enabler - * @param {Boolean} enabled - */ - setSolutionMarkEnabled = function (solution, enabler, enabled) { - var solutionEnabler = solution.find('label[for="' + solution.find(enabler).attr('id') + '"]'); + /** + * Set/unset solution select-enabler label + * + * @param {*} solution + * @param {String} enabler + * @param {Boolean} enabled + */ + setSolutionMarkEnabled = function (solution, enabler, enabled) { + var solutionEnabler = solution.find('label[for="' + solution.find(enabler).attr('id') + '"]'); - enabled || typeof enabled === 'undefined' ? - solutionEnabler.addClass('enabled') : - solutionEnabler.removeClass('enabled'); - }, + enabled || typeof enabled === 'undefined' ? + solutionEnabler.addClass('enabled') : + solutionEnabler.removeClass('enabled'); + }, - /** - * Set/unset solution section label - * - * @param {*} solution - * @param {Boolean} enabled - */ - setSolutionSectionMarkEnabled = function (solution, enabled) { - var solutionSection = solution.find('.section-config'); + /** + * Set/unset solution section label + * + * @param {*} solution + * @param {Boolean} enabled + */ + setSolutionSectionMarkEnabled = function (solution, enabled) { + var solutionSection = solution.find('.section-config'); - enabled || typeof enabled === 'undefined' ? - solutionSection.addClass('enabled') : - solutionSection.removeClass('enabled'); - }, + enabled || typeof enabled === 'undefined' ? + solutionSection.addClass('enabled') : + solutionSection.removeClass('enabled'); + }, - /** - * Set/unset solution section inner labels - * - * @param {*} solution - * @param {Boolean} enabled - */ - setSolutionLabelsMarkEnabled = function (solution, enabled) { - var solutionLabels = solution.find('label.enabled'); + /** + * Set/unset solution section inner labels + * + * @param {*} solution + * @param {Boolean} enabled + */ + setSolutionLabelsMarkEnabled = function (solution, enabled) { + var solutionLabels = solution.find('label.enabled'); - enabled || typeof enabled === 'undefined' ? - solutionLabels.addClass('enabled') : - solutionLabels.removeClass('enabled'); - }, + enabled || typeof enabled === 'undefined' ? + solutionLabels.addClass('enabled') : + solutionLabels.removeClass('enabled'); + }, - /** - * Set solution as disabled - * - * @param {*} solution - * @param {String} enabler - */ - disableSolution = function (solution, enabler) { - setSolutionUsedefaultEnabled(solution, enabler); - setSolutionMarkEnabled(solution, enabler, false); - setSolutionSelectEnabled(solution, enabler, false); - setSolutionPropEnabled(solution, enabler, false); - }, + /** + * Set/unset solution usedefault checkbox + * + * @param {*} solution + * @param {String} enabler + * @param {Boolean} checked + */ + setSolutionUsedefaultEnabled = function (solution, enabler, checked) { + checked = !(checked || typeof checked === 'undefined'); - /** - * Set solution as enabled - * - * @param {*} solution - * @param {String} enabler - */ - enableSolution = function (solution, enabler) { - setSolutionUsedefaultEnabled(solution, enabler); - setSolutionPropEnabled(solution, enabler); - setSolutionSelectEnabled(solution, enabler); - setSolutionMarkEnabled(solution, enabler); - }, + solution.find('input[id="' + solution.find(enabler).attr('id') + '_inherit"]') + .prop('checked', checked); + }, - /** - * Lock/unlock solution configuration button - * - * @param {*} solution - * @param {String} buttonConfiguration - * @param {Boolean} unlock - */ - setSolutionConfigurationUnlock = function (solution, buttonConfiguration, unlock) { - var solutionConfiguration = solution.find(buttonConfiguration); + /** + * Set solution as disabled + * + * @param {*} solution + * @param {String} enabler + */ + disableSolution = function (solution, enabler) { + setSolutionUsedefaultEnabled(solution, enabler); + setSolutionMarkEnabled(solution, enabler, false); + setSolutionSelectEnabled(solution, enabler, false); + setSolutionPropEnabled(solution, enabler, false); + }, - unlock || typeof unlock === 'undefined' ? - solutionConfiguration.removeClass('disabled').removeAttr('disabled') : - solutionConfiguration.addClass('disabled').attr('disabled', 'disabled'); - }, + /** + * Set solution as enabled + * + * @param {*} solution + * @param {String} enabler + */ + enableSolution = function (solution, enabler) { + setSolutionUsedefaultEnabled(solution, enabler); + setSolutionPropEnabled(solution, enabler); + setSolutionSelectEnabled(solution, enabler); + setSolutionMarkEnabled(solution, enabler); + }, - /** - * Set/unset solution usedefault checkbox - * - * @param {*} solution - * @param {String} enabler - * @param {Boolean} checked - */ - setSolutionUsedefaultEnabled = function (solution, enabler, checked) { - checked = !(checked || typeof checked === 'undefined'); + /** + * Lock/unlock solution configuration button + * + * @param {*} solution + * @param {String} buttonConfiguration + * @param {Boolean} unlock + */ + setSolutionConfigurationUnlock = function (solution, buttonConfiguration, unlock) { + var solutionConfiguration = solution.find(buttonConfiguration); - solution.find('input[id="' + solution.find(enabler).attr('id') + '_inherit"]') - .prop('checked', checked); - }, + unlock || typeof unlock === 'undefined' ? + solutionConfiguration.removeClass('disabled').removeAttr('disabled') : + solutionConfiguration.addClass('disabled').attr('disabled', 'disabled'); + }, - /** - * Forward solution select-enabler changes - * - * @param {*} solution - * @param {String} enabler - */ - forwardSolutionChange = function (solution, enabler) { - solution.find(enabler).change(); - }, + /** + * Forward solution select-enabler changes + * + * @param {*} solution + * @param {String} enabler + */ + forwardSolutionChange = function (solution, enabler) { + solution.find(enabler).change(); + }, - /** - * Show/hide dependent fields - * - * @param {*} solution - * @param {String} identifier - * @param {Boolean} show - */ - showDependsField = function (solution, identifier, show) { - show = show || typeof show === 'undefined'; + /** + * Show/hide dependent fields + * + * @param {*} solution + * @param {String} identifier + * @param {Boolean} show + */ + showDependsField = function (solution, identifier, show) { + show = show || typeof show === 'undefined'; - solution.find(identifier).toggle(show); - solution.find(identifier).closest('tr').toggle(show); - solution.find(identifier).attr('disabled', !show); - }; + solution.find(identifier).toggle(show); + solution.find(identifier).closest('tr').toggle(show); + solution.find(identifier).attr('disabled', !show); + }; return Class.extend({ defaults: { From fa930276f6835bc196ea20d5955c7beb32f15c3a Mon Sep 17 00:00:00 2001 From: Iurii Ivashchenko Date: Thu, 7 Sep 2017 16:14:57 +0300 Subject: [PATCH 117/151] MAGETWO-71759: Impossible place order from admin using saved PayPal Pro credit card --- .../order/create/billing/method/form.phtml | 6 ++- .../Order/Create/Billing/Method/FormTest.php | 50 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 dev/tests/integration/testsuite/Magento/Sales/Block/Adminhtml/Order/Create/Billing/Method/FormTest.php diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml index ddf292867ccce..e03cbf1b2187f 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml @@ -39,7 +39,11 @@
    -
    +
    escapeHtml(__('No Payment Methods')); ?>
    From d08bed8dbdb3752fe7f943a66ba46801c10c9f98 Mon Sep 17 00:00:00 2001 From: Dan Mooney Date: Fri, 1 Sep 2017 15:32:40 -0500 Subject: [PATCH 122/151] MAGETWO-59810: Enforce use of IntlDateFormatter for creating timestamps --- .../Catalog/Controller/Adminhtml/Category.php | 42 -------- .../Controller/Adminhtml/Category/Save.php | 31 ++++++ .../Stdlib/DateTime/Filter/DataTest.php | 44 --------- .../Stdlib/DateTime/Filter/DateTest.php | 98 +++++++++++++++++++ .../Framework/Stdlib/DateTime/Filter/Date.php | 2 +- .../Framework/Stdlib/DateTime/Timezone.php | 3 +- .../Test/Unit/DateTime/TimezoneTest.php | 18 +++- 7 files changed, 146 insertions(+), 92 deletions(-) delete mode 100644 dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DataTest.php create mode 100644 dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTest.php diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php index 5da3cba49bf9e..bfdec73547e1a 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php @@ -17,11 +17,6 @@ abstract class Category extends \Magento\Backend\App\Action */ const ADMIN_RESOURCE = 'Magento_Catalog::categories'; - /** - * @var \Magento\Framework\Stdlib\DateTime\Filter\DateTime - */ - private $dateTimeFilter; - /** * Initialize requested category and put it into registry. * Root category can be returned, if inappropriate store/category is specified @@ -124,41 +119,4 @@ protected function ajaxRequestResponse($category, $resultPage) $resultJson->setData($eventResponse->getData()); return $resultJson; } - - /** - * @return \Magento\Framework\Stdlib\DateTime\Filter\DateTime - * - * @deprecated 101.0.0 - */ - private function getDateTimeFilter() - { - if ($this->dateTimeFilter === null) { - $this->dateTimeFilter = \Magento\Framework\App\ObjectManager::getInstance() - ->get(\Magento\Framework\Stdlib\DateTime\Filter\DateTime::class); - } - return $this->dateTimeFilter; - } - - /** - * Datetime data preprocessing - * - * @param \Magento\Catalog\Model\Category $category - * @param array $postData - * - * @return array - */ - protected function dateTimePreprocessing($category, $postData) - { - $dateFieldFilters = []; - $attributes = $category->getAttributes(); - foreach ($attributes as $attrKey => $attribute) { - if ($attribute->getBackend()->getType() == 'datetime') { - if (array_key_exists($attrKey, $postData) && $postData[$attrKey] != '') { - $dateFieldFilters[$attrKey] = $this->getDateTimeFilter(); - } - } - } - $inputFilter = new \Zend_Filter_Input($dateFieldFilters, [], $postData); - return $inputFilter->getUnescaped(); - } } diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php index 412ca927e1bae..0db6ceb2fcee7 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php @@ -54,6 +54,11 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category */ private $eavConfig; + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date + */ + private $dateFilter; + /** * Constructor * @@ -61,6 +66,7 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category * @param \Magento\Framework\Controller\Result\RawFactory $resultRawFactory * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory * @param \Magento\Framework\View\LayoutFactory $layoutFactory + * @param \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter * @param StoreManagerInterface $storeManager * @param \Magento\Eav\Model\Config $eavConfig */ @@ -69,6 +75,7 @@ public function __construct( \Magento\Framework\Controller\Result\RawFactory $resultRawFactory, \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory, \Magento\Framework\View\LayoutFactory $layoutFactory, + \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter, StoreManagerInterface $storeManager, \Magento\Eav\Model\Config $eavConfig = null ) { @@ -76,6 +83,7 @@ public function __construct( $this->resultRawFactory = $resultRawFactory; $this->resultJsonFactory = $resultJsonFactory; $this->layoutFactory = $layoutFactory; + $this->dateFilter = $dateFilter; $this->storeManager = $storeManager; $this->eavConfig = $eavConfig ?: \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Eav\Model\Config::class); @@ -363,4 +371,27 @@ protected function getRedirectParams($isNewCategory, $hasError, $categoryId, $pa } return ['path' => $path, 'params' => $params]; } + + /** + * Datetime data preprocessing + * + * @param \Magento\Catalog\Model\Category $category + * @param array $postData + * + * @return array + */ + private function dateTimePreprocessing($category, $postData) + { + $dateFieldFilters = []; + $attributes = $category->getAttributes(); + foreach ($attributes as $attrKey => $attribute) { + if ($attribute->getBackend()->getType() == 'datetime') { + if (array_key_exists($attrKey, $postData) && $postData[$attrKey] != '') { + $dateFieldFilters[$attrKey] = $this->dateFilter; + } + } + } + $inputFilter = new \Zend_Filter_Input($dateFieldFilters, [], $postData); + return $inputFilter->getUnescaped(); + } } diff --git a/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DataTest.php b/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DataTest.php deleted file mode 100644 index a742c2e87efbc..0000000000000 --- a/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DataTest.php +++ /dev/null @@ -1,44 +0,0 @@ -dataFilter = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get( - \Magento\Framework\Stdlib\DateTime\Filter\Date::class - ); - } - - /** - * @param string $inputData - * @param string $expectedDate - * - * @dataProvider filterDataProvider - */ - public function testFilter($inputData, $expectedDate) - { - $this->assertEquals($expectedDate, $this->dataFilter->filter($inputData)); - } - - /** - * @return array - */ - public function filterDataProvider() - { - return [ - ['2000-01-01', '2000-01-01'], - ['2014-03-30T02:30:00', '2014-03-30'], - ['12/31/2000', '2000-12-31'] - ]; - } -} diff --git a/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTest.php b/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTest.php new file mode 100644 index 0000000000000..314db1e28b468 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTest.php @@ -0,0 +1,98 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $this->localeResolver = $this->objectManager->get(\Magento\Framework\Locale\ResolverInterface::class); + + $this->localeDate = $this->objectManager->get(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class, [ + 'localeResolver' => $this->localeResolver + ]); + + $this->dateFilter = $this->objectManager->get(\Magento\Framework\Stdlib\DateTime\Filter\Date::class, [ + 'localeDate' => $this->localeDate + ]); + } + + /** + * @param string $inputData + * @param string $expectedDate + * + * @dataProvider filterDataProvider + */ + public function testFilter($inputData, $expectedDate) + { + $this->markTestSkipped( + 'Input data not realistic with actual request payload from admin UI. See MAGETWO-59810' + ); + $this->assertEquals($expectedDate, $this->dateFilter->filter($inputData)); + } + + /** + * @return array + */ + public function filterDataProvider() + { + return [ + ['2000-01-01', '2000-01-01'], + ['2014-03-30T02:30:00', '2014-03-30'], + ['12/31/2000', '2000-12-31'] + ]; + } + + /** + * @param string $locale + * @param string $inputData + * @param string $expectedDate + * + * @dataProvider localeDateFilterProvider + * @return void + */ + public function testLocaleDateFilter($locale, $inputData, $expectedDate) + { + $this->localeResolver->setLocale($locale); + $this->assertEquals($expectedDate, $this->dateFilter->filter($inputData)); + } + + /** + * @return array + */ + public function localeDateFilterProvider() + { + return [ + ['en_US', '01/02/2010', '2010-01-02'], + ['fr_FR', '01/02/2010', '2010-02-01'], + ['de_DE', '01/02/2010', '2010-02-01'], + ]; + } +} diff --git a/lib/internal/Magento/Framework/Stdlib/DateTime/Filter/Date.php b/lib/internal/Magento/Framework/Stdlib/DateTime/Filter/Date.php index 38cdeb8d02991..1138dc2e60887 100644 --- a/lib/internal/Magento/Framework/Stdlib/DateTime/Filter/Date.php +++ b/lib/internal/Magento/Framework/Stdlib/DateTime/Filter/Date.php @@ -63,7 +63,7 @@ public function __construct(TimezoneInterface $localeDate) public function filter($value) { try { - $value = $this->_localeDate->date($value, null, false); + $value = $this->_localeDate->date($value, null, false, false); return $value->format('Y-m-d'); } catch (\Exception $e) { throw new \Exception("Invalid input date format '$value'"); diff --git a/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php b/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php index ba9c8c8c098fe..d5e37bb67e58b 100644 --- a/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php +++ b/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php @@ -151,7 +151,6 @@ public function getDateTimeFormat($type) /** * {@inheritdoc} - * @SuppressWarnings(PHPMD.NPathComplexity) */ public function date($date = null, $locale = null, $useTimezone = true, $includeTime = true) { @@ -175,7 +174,7 @@ public function date($date = null, $locale = null, $useTimezone = true, $include $timeType, new \DateTimeZone($timezone) ); - $date = $formatter->parse($date) ?: (new \DateTime($date))->getTimestamp(); + $date = $formatter->parse($date); break; } diff --git a/lib/internal/Magento/Framework/Stdlib/Test/Unit/DateTime/TimezoneTest.php b/lib/internal/Magento/Framework/Stdlib/Test/Unit/DateTime/TimezoneTest.php index b4f482847f1c0..d57525590b9e8 100644 --- a/lib/internal/Magento/Framework/Stdlib/Test/Unit/DateTime/TimezoneTest.php +++ b/lib/internal/Magento/Framework/Stdlib/Test/Unit/DateTime/TimezoneTest.php @@ -91,14 +91,26 @@ public function testDateIncludeTime($date, $locale, $includeTime, $expectedTimes public function dateIncludeTimeDataProvider() { return [ - 'Parse date without time' => [ + 'Parse d/m/y date without time' => [ '19/05/2017', // date 'ar_KW', // locale false, // include time 1495170000 // expected timestamp ], - 'Parse date with time' => [ - '05/19/2017 00:01 am', // date + 'Parse d/m/y date with time' => [ + '19/05/2017 00:01 صباحاً', // datetime (00:01 am) + 'ar_KW', // locale + true, // include time + 1495170060 // expected timestamp + ], + 'Parse m/d/y date without time' => [ + '05/19/2017', // date + 'en_US', // locale + false, // include time + 1495170000 // expected timestamp + ], + 'Parse m/d/y date with time' => [ + '05/19/2017 00:01 am', // datetime 'en_US', // locale true, // include time 1495170060 // expected timestamp From 26f6aac69461cfde4ff17e0f28bae4edb35e14d4 Mon Sep 17 00:00:00 2001 From: Dan Mooney Date: Tue, 5 Sep 2017 12:57:43 -0500 Subject: [PATCH 123/151] MAGETWO-59810: Move dateTimeProcessing back to Adminhtml\Category --- .../Catalog/Controller/Adminhtml/Category.php | 40 +++++++++++++++++++ .../Controller/Adminhtml/Category/Save.php | 31 +------------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php index bfdec73547e1a..13c4353e65204 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category.php @@ -17,6 +17,23 @@ abstract class Category extends \Magento\Backend\App\Action */ const ADMIN_RESOURCE = 'Magento_Catalog::categories'; + /** + * @var \Magento\Framework\Stdlib\DateTime\Filter\Date + */ + protected $dateFilter; + + /** + * @param \Magento\Backend\App\Action\Context $context + * @param \Magento\Framework\Stdlib\DateTime\Filter\Date|null $dateFilter + */ + public function __construct( + \Magento\Backend\App\Action\Context $context, + \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter = null + ) { + $this->dateFilter = $dateFilter; + parent::__construct($context); + } + /** * Initialize requested category and put it into registry. * Root category can be returned, if inappropriate store/category is specified @@ -119,4 +136,27 @@ protected function ajaxRequestResponse($category, $resultPage) $resultJson->setData($eventResponse->getData()); return $resultJson; } + + /** + * Datetime data preprocessing + * + * @param \Magento\Catalog\Model\Category $category + * @param array $postData + * + * @return array + */ + protected function dateTimePreprocessing($category, $postData) + { + $dateFieldFilters = []; + $attributes = $category->getAttributes(); + foreach ($attributes as $attrKey => $attribute) { + if ($attribute->getBackend()->getType() == 'datetime') { + if (array_key_exists($attrKey, $postData) && $postData[$attrKey] != '') { + $dateFieldFilters[$attrKey] = $this->dateFilter; + } + } + } + $inputFilter = new \Zend_Filter_Input($dateFieldFilters, [], $postData); + return $inputFilter->getUnescaped(); + } } diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php index 0db6ceb2fcee7..d1ec3be1a8895 100644 --- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php +++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php @@ -54,11 +54,6 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category */ private $eavConfig; - /** - * @var \Magento\Framework\Stdlib\DateTime\Filter\Date - */ - private $dateFilter; - /** * Constructor * @@ -79,11 +74,10 @@ public function __construct( StoreManagerInterface $storeManager, \Magento\Eav\Model\Config $eavConfig = null ) { - parent::__construct($context); + parent::__construct($context, $dateFilter); $this->resultRawFactory = $resultRawFactory; $this->resultJsonFactory = $resultJsonFactory; $this->layoutFactory = $layoutFactory; - $this->dateFilter = $dateFilter; $this->storeManager = $storeManager; $this->eavConfig = $eavConfig ?: \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Eav\Model\Config::class); @@ -371,27 +365,4 @@ protected function getRedirectParams($isNewCategory, $hasError, $categoryId, $pa } return ['path' => $path, 'params' => $params]; } - - /** - * Datetime data preprocessing - * - * @param \Magento\Catalog\Model\Category $category - * @param array $postData - * - * @return array - */ - private function dateTimePreprocessing($category, $postData) - { - $dateFieldFilters = []; - $attributes = $category->getAttributes(); - foreach ($attributes as $attrKey => $attribute) { - if ($attribute->getBackend()->getType() == 'datetime') { - if (array_key_exists($attrKey, $postData) && $postData[$attrKey] != '') { - $dateFieldFilters[$attrKey] = $this->dateFilter; - } - } - } - $inputFilter = new \Zend_Filter_Input($dateFieldFilters, [], $postData); - return $inputFilter->getUnescaped(); - } } From 316b52a36c1c28de538b840a6909f2722ec30b45 Mon Sep 17 00:00:00 2001 From: Dan Mooney Date: Tue, 5 Sep 2017 14:05:43 -0500 Subject: [PATCH 124/151] MAGETWO-59810: Add DateTimeTest to cover Filter\DateTime --- .../Stdlib/DateTime/Filter/DateTimeTest.php | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTimeTest.php diff --git a/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTimeTest.php b/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTimeTest.php new file mode 100644 index 0000000000000..e8a736e926e69 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTimeTest.php @@ -0,0 +1,76 @@ +objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager(); + + $this->localeResolver = $this->objectManager->get(\Magento\Framework\Locale\ResolverInterface::class); + + $this->localeDate = $this->objectManager->get(\Magento\Framework\Stdlib\DateTime\TimezoneInterface::class, [ + 'localeResolver' => $this->localeResolver + ]); + + $this->dateTimeFilter = $this->objectManager->get(\Magento\Framework\Stdlib\DateTime\Filter\DateTime::class, [ + 'localeDate' => $this->localeDate + ]); + } + + /** + * @param string $locale + * @param string $inputData + * @param string $expectedDate + * + * @dataProvider localeDatetimeFilterProvider + * @return void + */ + public function testLocaleDatetimeFilter($locale, $inputData, $expectedDate) + { + $this->localeResolver->setLocale($locale); + $this->assertEquals($expectedDate, $this->dateTimeFilter->filter($inputData)); + } + + /** + * @return array + */ + public function localeDatetimeFilterProvider() + { + return [ + ['en_US', '01/02/2010 3:30pm', '2010-01-02 15:30:00'], + ['en_US', '01/02/2010 1:00am', '2010-01-02 01:00:00'], + ['en_US', '01/02/2010 01:00am', '2010-01-02 01:00:00'], + ['fr_FR', '01/02/2010 15:30', '2010-02-01 15:30:00'], + ['fr_FR', '01/02/2010 1:00', '2010-02-01 01:00:00'], + ['fr_FR', '01/02/2010 01:00', '2010-02-01 01:00:00'], + ['de_DE', '01/02/2010 15:30', '2010-02-01 15:30:00'], + ]; + } +} From 181bc32b304820d4eb9a342139f7dd08bc0b293b Mon Sep 17 00:00:00 2001 From: Dan Mooney Date: Wed, 6 Sep 2017 12:17:23 -0500 Subject: [PATCH 125/151] MAGETWO-59810: Reinstate DateTime instantiation fallback --- .../Magento/Framework/Stdlib/DateTime/Filter/DateTimeTest.php | 2 ++ lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTimeTest.php b/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTimeTest.php index e8a736e926e69..69c63c84388ef 100644 --- a/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTimeTest.php +++ b/dev/tests/integration/testsuite/Magento/Framework/Stdlib/DateTime/Filter/DateTimeTest.php @@ -71,6 +71,8 @@ public function localeDatetimeFilterProvider() ['fr_FR', '01/02/2010 1:00', '2010-02-01 01:00:00'], ['fr_FR', '01/02/2010 01:00', '2010-02-01 01:00:00'], ['de_DE', '01/02/2010 15:30', '2010-02-01 15:30:00'], + ['en_US', '2017-09-01T15:30:00.000Z', '2017-09-01 15:30:00'], + ['fr_FR', '2017-09-01T15:30:00.000Z', '2017-09-01 15:30:00'], ]; } } diff --git a/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php b/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php index d5e37bb67e58b..90aec6024fe12 100644 --- a/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php +++ b/lib/internal/Magento/Framework/Stdlib/DateTime/Timezone.php @@ -174,7 +174,7 @@ public function date($date = null, $locale = null, $useTimezone = true, $include $timeType, new \DateTimeZone($timezone) ); - $date = $formatter->parse($date); + $date = $formatter->parse($date) ?: (new \DateTime($date))->getTimestamp(); break; } From 3ac248a3e132c888dcff4e28a42a64e7dd2325d4 Mon Sep 17 00:00:00 2001 From: Joan He Date: Thu, 7 Sep 2017 11:47:48 -0500 Subject: [PATCH 126/151] MAGETWO-70837: Pricing discrepancy in shopping cart - fix function test \Magento\NegotiableQuote\Test\TestCase\CheckQuoteAfterDisablingProductTest failure --- app/code/Magento/Quote/Model/Quote.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php index ae7701ede9da3..480bcb477a2b3 100644 --- a/app/code/Magento/Quote/Model/Quote.php +++ b/app/code/Magento/Quote/Model/Quote.php @@ -2375,8 +2375,8 @@ protected function _afterLoad() { // collect totals and save me, if required if (1 == $this->getTriggerRecollect()) { - $this->setTriggerRecollect(0); $this->collectTotals()->save(); + $this->setTriggerRecollect(0); } return parent::_afterLoad(); } From c30e9c6085def040f01f20a6e9b29985a658ac3f Mon Sep 17 00:00:00 2001 From: Joan He Date: Thu, 7 Sep 2017 12:27:45 -0500 Subject: [PATCH 127/151] MAGETWO-72112: [Github] Child categories included in menu when parent category is disabled or hidden #10664 - address code review comments --- app/code/Magento/Catalog/Plugin/Block/Topmenu.php | 13 +++++++++---- .../SubcategoryNotIncludeInNavigationMenuTest.php | 6 +++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/app/code/Magento/Catalog/Plugin/Block/Topmenu.php b/app/code/Magento/Catalog/Plugin/Block/Topmenu.php index 28f9ee5b8b359..5119a32d921de 100644 --- a/app/code/Magento/Catalog/Plugin/Block/Topmenu.php +++ b/app/code/Magento/Catalog/Plugin/Block/Topmenu.php @@ -93,12 +93,15 @@ public function beforeGetHtml( $parentCategoryNode = $mapping[$categoryParentId]; $categoryNode = new Node( - $this->getCategoryAsArray($category, $currentCategory), + $this->getCategoryAsArray( + $category, + $currentCategory, + $category->getParentId() == $categoryParentId + ), 'id', $parentCategoryNode->getTree(), $parentCategoryNode ); - $categoryNode->setData('is_parent_active', $category->getParentId() == $categoryParentId); $parentCategoryNode->addChild($categoryNode); $mapping[$category->getId()] = $categoryNode; //add node in stack @@ -148,16 +151,18 @@ private function getCurrentCategory() * * @param \Magento\Catalog\Model\Category $category * @param \Magento\Catalog\Model\Category $currentCategory + * @param bool $isParentActive * @return array */ - private function getCategoryAsArray($category, $currentCategory) + private function getCategoryAsArray($category, $currentCategory, $isParentActive) { return [ 'name' => $category->getName(), 'id' => 'category-node-' . $category->getId(), 'url' => $this->catalogCategory->getCategoryUrl($category), 'has_active' => in_array((string)$category->getId(), explode('/', $currentCategory->getPath()), true), - 'is_active' => $category->getId() == $currentCategory->getId() + 'is_active' => $category->getId() == $currentCategory->getId(), + 'is_parent_active' => $isParentActive ]; } diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.php index 4e12d60312c75..cf309c2e5c980 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Category/SubcategoryNotIncludeInNavigationMenuTest.php @@ -37,21 +37,21 @@ class SubcategoryNotIncludeInNavigationMenuTest extends Injectable * * @var CatalogCategoryIndex */ - protected $catalogCategoryIndex; + private $catalogCategoryIndex; /** * Catalog category edit page. * * @var CatalogCategoryEdit */ - protected $catalogCategoryEdit; + private $catalogCategoryEdit; /** * Fixture Factory. * * @var FixtureFactory */ - protected $fixtureFactory; + private $fixtureFactory; /** * Inject pages. From 46d54c4c43a420ab1ba47165517f4486cedc86c1 Mon Sep 17 00:00:00 2001 From: Iurii Ivashchenko Date: Thu, 7 Sep 2017 17:47:35 +0300 Subject: [PATCH 128/151] MAGETWO-71759: Impossible place order from admin using saved PayPal Pro credit card - static fixes for template --- .../order/create/billing/method/form.phtml | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml index e03cbf1b2187f..9dda4e7e067ed 100644 --- a/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml +++ b/app/code/Magento/Sales/view/adminhtml/templates/order/create/billing/method/form.phtml @@ -4,36 +4,47 @@ * See COPYING.txt for license details. */ -// @codingStandardsIgnoreFile - ?> -hasMethods()): ?> +hasMethods()) : ?>
    getMethods(); - $_methodsCount = count($_methods); + $_methods = $block->getMethods(); + $_methodsCount = count($_methods); $_counter = 0; ?> - getCode(); $_counter++; ?> + getCode(); + $_counter++; + ?>
    - 1): ?> - getSelectedMethodCode() == $_code): ?> checked="checked" - class="admin__control-radio validate-one-required-by-name"/> + 1) : ?> + getSelectedMethodCode() == $_code) : ?> + checked="checked" + + + class="admin__control-radioescapeHtml($className); ?>"/> - - +
    - getChildHtml('payment.method.' . $_code) ?> + getChildHtml('payment.method.' . $_code) ?>
    @@ -44,11 +55,11 @@ 'Magento_Sales/order/create/form' ], function(mage) { mage.apply(); - - order.setPaymentMethod('getSelectedMethodCode() ?>'); + + order.setPaymentMethod('escapeHtml($block->getSelectedMethodCode()); ?>'); }); - -
    + +
    escapeHtml(__('No Payment Methods')); ?>
    From 1c026616b031be5c7630411a0ce450525a6ca25a Mon Sep 17 00:00:00 2001 From: Robert He Date: Thu, 7 Sep 2017 14:30:49 -0500 Subject: [PATCH 129/151] MAGETWO-71445: Out of stock options for configurable products still show up in search and layered navigation - fixed processing relations of products using the wrong productIds --- .../Catalog/Model/Indexer/Product/Eav/AbstractAction.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php index cd40cddebea15..6a2642a8568f4 100644 --- a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php +++ b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/AbstractAction.php @@ -143,7 +143,7 @@ protected function syncData($indexer, $destinationTable, $ids) protected function processRelations($indexer, $ids, $onlyParents = false) { $parentIds = $indexer->getRelationsByChild($ids); - $childIds = $onlyParents ? [] : $indexer->getRelationsByParent($ids); + $childIds = $onlyParents ? [] : $indexer->getRelationsByParent($parentIds); return array_unique(array_merge($ids, $childIds, $parentIds)); } } From 8ba70c8bf6ac335763d2bc59f1a1000e38f8be24 Mon Sep 17 00:00:00 2001 From: Robert He Date: Thu, 7 Sep 2017 15:10:07 -0500 Subject: [PATCH 130/151] MAGETWO-71666: Unable to save product after failed attempt - fixed static failures --- .../TestCase/Product/ReSavingProductAfterInitialSaveTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php index 01a71ce07fcac..5ca7f06effc24 100644 --- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php +++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestCase/Product/ReSavingProductAfterInitialSaveTest.php @@ -92,8 +92,7 @@ public function test( $this->productGrid->open(); $this->productGrid->getGridPageActionBlock()->addProduct('simple'); - if(!($this->newProductPage->getProductForm()->isProductNewFromDateVisible('product-details'))) - { + if (!($this->newProductPage->getProductForm()->isProductNewFromDateVisible('product-details'))) { $this->markTestSkipped('This is a CE only test.'); } $this->newProductPage->getProductForm()->fill($originalProduct); From ad7dc6f019243dfaa565480e11b069e46b4f8374 Mon Sep 17 00:00:00 2001 From: Andrii Lugovyi Date: Mon, 4 Sep 2017 18:41:59 +0300 Subject: [PATCH 131/151] MAGETWO-66914: PAT with custom profile --- setup/performance-toolkit/benchmark.jmx | 257 ++++++++++++------------ 1 file changed, 132 insertions(+), 125 deletions(-) diff --git a/setup/performance-toolkit/benchmark.jmx b/setup/performance-toolkit/benchmark.jmx index 07aa48f8b4504..41d9d5be25416 100644 --- a/setup/performance-toolkit/benchmark.jmx +++ b/setup/performance-toolkit/benchmark.jmx @@ -14,11 +14,6 @@ - - request_protocol - ${__P(request_protocol,http)} - = - abandonedCartByGuest ${__P(abandonedCartByGuest,0)} @@ -56,7 +51,7 @@ admin_path - ${__P(admin_path,backend)} + ${__P(admin_path,admin)} = @@ -426,7 +421,7 @@ customer_checkout_percent - ${__P(customer_checkout_percent,100)} + ${__P(customer_checkout_percent,4)} = @@ -456,7 +451,7 @@ guest_checkout_percent - ${__P(guest_checkout_percent,100)} + ${__P(guest_checkout_percent,4)} = @@ -641,12 +636,12 @@ view_catalog_percent - ${__P(view_catalog_percent,100)} + ${__P(view_catalog_percent,62)} = view_product_add_to_cart_percent - ${__P(view_product_add_to_cart_percent,100)} + ${__P(view_product_add_to_cart_percent,30)} = @@ -681,7 +676,7 @@ - ${request_protocol} + http utf-8 Java @@ -744,14 +739,6 @@ -// Init and save random object for get random values with/without seed -import java.util.Random; -Random random = new Random(); -if (${seedForRandom} > 0) { - random.setSeed(${seedForRandom}); -} -props.put("RandomObject", random); - props.remove("category_url_key"); props.remove("category_url_keys_list"); props.remove("category_name"); @@ -804,7 +791,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}${admin_path} GET @@ -884,7 +871,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}${admin_path}/admin/dashboard/ POST @@ -938,7 +925,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}${admin_path}/admin/cache/massEnable POST @@ -981,7 +968,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}${admin_path}/admin/cache/massRefresh POST @@ -1024,7 +1011,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -1116,7 +1103,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}rest/V1/categories/list GET @@ -1253,7 +1240,7 @@ props.put("category_name", vars.get("category_name")); - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -1324,7 +1311,7 @@ props.put("category_name", vars.get("category_name")); - ${request_protocol} + ${base_path}rest/V1/products GET @@ -1392,7 +1379,7 @@ if (1 == Integer.parseInt(vars.get("simple_products_counter"))) { } else { productList = props.get("simple_products_list"); } -String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); +String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map Map productMap = new HashMap(); @@ -1439,7 +1426,7 @@ productList.add(productMap); - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -1510,7 +1497,7 @@ productList.add(productMap); - ${request_protocol} + ${base_path}rest/V1/products GET @@ -1588,7 +1575,7 @@ if (1 == Integer.parseInt(vars.get("configurable_products_counter"))) { productList = props.get("configurable_products_list"); } -String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); +String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map Map productMap = new HashMap(); @@ -1614,7 +1601,7 @@ productList.add(productMap); - ${request_protocol} + ${base_path}${admin_path}/customer/index/ GET @@ -1714,7 +1701,7 @@ manager.add(cookie); - ${request_protocol} + ${base_path}${admin_path}/mui/index/render/ GET @@ -1907,7 +1894,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}${admin_path}/admin/cache/massDisable POST @@ -1943,7 +1930,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}${admin_path}/admin/cache/ GET @@ -2001,7 +1988,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}${admin_path}/admin/cache/ GET @@ -2059,7 +2046,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}${admin_path}/admin/cache/ GET @@ -2139,7 +2126,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}page_cache/block/render/ GET @@ -2220,7 +2207,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}checkout/cart/add POST @@ -2252,25 +2239,30 @@ if ("${cache_indicator}" == "1") { Passing arguments between threads -number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +import java.util.Random; +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom}); +} +number = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +number1 = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); +number = random.nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); vars.put("configurable_product_1_id", configurableList.get("id")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); +number = random.nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); vars.put("testLabel", "CatProdBrows"); @@ -2288,7 +2280,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path} GET @@ -2325,7 +2317,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}${category_url_key}${url_suffix} GET @@ -2383,7 +2375,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -2434,7 +2426,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2471,7 +2463,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -2522,7 +2514,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2559,7 +2551,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -2601,21 +2593,27 @@ vars.put("testLabel", "CatProdBrows"); Passing arguments between threads - number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); + +import java.util.Random; +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom}); +} +number = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +number1 = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); +number = random.nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); @@ -2624,7 +2622,7 @@ vars.put("configurable_attribute_id", configurableList.get("attribute_id")); vars.put("configurable_option_id", configurableList.get("attribute_option_id")); vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); +number = random.nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); vars.put("testLabel", "BrowsAddToCart"); @@ -2643,7 +2641,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path} GET @@ -2710,7 +2708,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}page_cache/block/render/ GET @@ -2769,7 +2767,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${category_url_key}${url_suffix} GET @@ -2827,7 +2825,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -2878,7 +2876,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2944,7 +2942,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -2998,7 +2996,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -3063,7 +3061,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -3114,7 +3112,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -3180,7 +3178,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -3236,7 +3234,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -3301,7 +3299,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -3374,7 +3372,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -3423,7 +3421,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -3498,7 +3496,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -3584,7 +3582,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -3654,21 +3652,26 @@ vars.put("loadType", "Guest"); Passing arguments between threads -number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +import java.util.Random; +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom}); +} +number = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +number1 = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); +number = random.nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); @@ -3677,7 +3680,7 @@ vars.put("configurable_attribute_id", configurableList.get("attribute_id")); vars.put("configurable_option_id", configurableList.get("attribute_option_id")); vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); +number = random.nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); vars.put("testLabel", "GuestChkt"); @@ -3696,7 +3699,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path} GET @@ -3763,7 +3766,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}page_cache/block/render/ GET @@ -3822,7 +3825,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${category_url_key}${url_suffix} GET @@ -3880,7 +3883,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -3931,7 +3934,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -3997,7 +4000,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -4051,7 +4054,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -4116,7 +4119,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -4167,7 +4170,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -4233,7 +4236,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -4289,7 +4292,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -4354,7 +4357,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -4427,7 +4430,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -4476,7 +4479,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -4551,7 +4554,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -4637,7 +4640,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -4702,7 +4705,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/ GET @@ -4795,7 +4798,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/default/V1/customers/isEmailAvailable POST @@ -4860,7 +4863,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/default/V1/guest-carts/${cart_id}/estimate-shipping-methods POST @@ -4925,7 +4928,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/default/V1/guest-carts/${cart_id}/shipping-information POST @@ -4990,7 +4993,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/default/V1/guest-carts/${cart_id}/payment-information POST @@ -5061,7 +5064,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/onepage/success/ GET @@ -5104,22 +5107,26 @@ vars.put("loadType", "Guest"); Passing arguments between threads import org.apache.jmeter.samplers.SampleResult; - -number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +import java.util.Random; +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom}); +} +number = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +number1 = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); +number = random.nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); @@ -5128,7 +5135,7 @@ vars.put("configurable_attribute_id", configurableList.get("attribute_id")); vars.put("configurable_option_id", configurableList.get("attribute_option_id")); vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); +number = random.nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); @@ -5167,7 +5174,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path} GET @@ -5204,7 +5211,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}customer/account/login/ GET @@ -5271,7 +5278,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}page_cache/block/render/ GET @@ -5359,7 +5366,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}customer/account/loginPost/ POST @@ -5416,7 +5423,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}${category_url_key}${url_suffix} GET @@ -5474,7 +5481,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -5525,7 +5532,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -5591,7 +5598,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -5645,7 +5652,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -5710,7 +5717,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -5761,7 +5768,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -5827,7 +5834,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -5883,7 +5890,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -5948,7 +5955,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -6021,7 +6028,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -6070,7 +6077,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -6145,7 +6152,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -6231,7 +6238,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -6296,7 +6303,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}checkout/ GET @@ -6429,7 +6436,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}rest/default/V1/carts/mine/estimate-shipping-methods-by-address-id POST @@ -6494,7 +6501,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}rest/default/V1/carts/mine/shipping-information POST @@ -6559,7 +6566,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}rest/default/V1/carts/mine/payment-information POST @@ -6617,7 +6624,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}checkout/onepage/success/ GET @@ -6699,7 +6706,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}DeploymentEvent.php POST From 835db5195795e3bf6c4c408ba1bc335882d78c96 Mon Sep 17 00:00:00 2001 From: Andrii Lugovyi Date: Thu, 7 Sep 2017 23:34:54 +0300 Subject: [PATCH 132/151] MAGETWO-66914: PAT with custom profile --- setup/performance-toolkit/benchmark_2015.jmx | 247 ++++++++++--------- 1 file changed, 127 insertions(+), 120 deletions(-) diff --git a/setup/performance-toolkit/benchmark_2015.jmx b/setup/performance-toolkit/benchmark_2015.jmx index 0197f144cd39e..41d9d5be25416 100644 --- a/setup/performance-toolkit/benchmark_2015.jmx +++ b/setup/performance-toolkit/benchmark_2015.jmx @@ -14,11 +14,6 @@ - - request_protocol - ${__P(request_protocol,http)} - = - abandonedCartByGuest ${__P(abandonedCartByGuest,0)} @@ -681,7 +676,7 @@ - ${request_protocol} + http utf-8 Java @@ -744,14 +739,6 @@ -// Init and save random object for get random values with/without seed -import java.util.Random; -Random random = new Random(); -if (${seedForRandom} > 0) { - random.setSeed(${seedForRandom}); -} -props.put("RandomObject", random); - props.remove("category_url_key"); props.remove("category_url_keys_list"); props.remove("category_name"); @@ -804,7 +791,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}${admin_path} GET @@ -884,7 +871,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}${admin_path}/admin/dashboard/ POST @@ -938,7 +925,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}${admin_path}/admin/cache/massEnable POST @@ -981,7 +968,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}${admin_path}/admin/cache/massRefresh POST @@ -1024,7 +1011,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -1116,7 +1103,7 @@ if (!slash.equals(path.substring(path.length() -1)) || !slash.equals(path.substr - ${request_protocol} + ${base_path}rest/V1/categories/list GET @@ -1253,7 +1240,7 @@ props.put("category_name", vars.get("category_name")); - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -1324,7 +1311,7 @@ props.put("category_name", vars.get("category_name")); - ${request_protocol} + ${base_path}rest/V1/products GET @@ -1392,7 +1379,7 @@ if (1 == Integer.parseInt(vars.get("simple_products_counter"))) { } else { productList = props.get("simple_products_list"); } -String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); +String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("simple_products_url_keys_" + vars.get("simple_products_counter"))+ vars.get("url_suffix"); encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map Map productMap = new HashMap(); @@ -1439,7 +1426,7 @@ productList.add(productMap); - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -1510,7 +1497,7 @@ productList.add(productMap); - ${request_protocol} + ${base_path}rest/V1/products GET @@ -1588,7 +1575,7 @@ if (1 == Integer.parseInt(vars.get("configurable_products_counter"))) { productList = props.get("configurable_products_list"); } -String productUrl = vars.get("request_protocol") + "://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); +String productUrl = "http://" + vars.get("host") + vars.get("base_path") + vars.get("configurable_products_url_keys_" + vars.get("configurable_products_counter"))+ vars.get("url_suffix"); encodedUrl = Base64.encodeBase64(productUrl.getBytes()); // Create product map Map productMap = new HashMap(); @@ -1614,7 +1601,7 @@ productList.add(productMap); - ${request_protocol} + ${base_path}${admin_path}/customer/index/ GET @@ -1714,7 +1701,7 @@ manager.add(cookie); - ${request_protocol} + ${base_path}${admin_path}/mui/index/render/ GET @@ -1907,7 +1894,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}${admin_path}/admin/cache/massDisable POST @@ -1943,7 +1930,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}${admin_path}/admin/cache/ GET @@ -2001,7 +1988,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}${admin_path}/admin/cache/ GET @@ -2059,7 +2046,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}${admin_path}/admin/cache/ GET @@ -2139,7 +2126,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}page_cache/block/render/ GET @@ -2220,7 +2207,7 @@ if ("${cache_indicator}" == "1") { - ${request_protocol} + ${base_path}checkout/cart/add POST @@ -2252,25 +2239,30 @@ if ("${cache_indicator}" == "1") { Passing arguments between threads -number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +import java.util.Random; +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom}); +} +number = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +number1 = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); +number = random.nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); vars.put("configurable_product_1_id", configurableList.get("id")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); +number = random.nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); vars.put("testLabel", "CatProdBrows"); @@ -2288,7 +2280,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path} GET @@ -2325,7 +2317,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}${category_url_key}${url_suffix} GET @@ -2383,7 +2375,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -2434,7 +2426,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2471,7 +2463,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -2522,7 +2514,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2559,7 +2551,7 @@ vars.put("testLabel", "CatProdBrows"); - ${request_protocol} + ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -2601,21 +2593,27 @@ vars.put("testLabel", "CatProdBrows"); Passing arguments between threads - number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); + +import java.util.Random; +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom}); +} +number = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +number1 = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); +number = random.nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); @@ -2624,7 +2622,7 @@ vars.put("configurable_attribute_id", configurableList.get("attribute_id")); vars.put("configurable_option_id", configurableList.get("attribute_option_id")); vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); +number = random.nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); vars.put("testLabel", "BrowsAddToCart"); @@ -2643,7 +2641,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path} GET @@ -2710,7 +2708,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}page_cache/block/render/ GET @@ -2769,7 +2767,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${category_url_key}${url_suffix} GET @@ -2827,7 +2825,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -2878,7 +2876,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -2944,7 +2942,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -2998,7 +2996,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -3063,7 +3061,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -3114,7 +3112,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -3180,7 +3178,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -3236,7 +3234,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -3301,7 +3299,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -3374,7 +3372,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -3423,7 +3421,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -3498,7 +3496,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -3584,7 +3582,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -3654,21 +3652,26 @@ vars.put("loadType", "Guest"); Passing arguments between threads -number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +import java.util.Random; +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom}); +} +number = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +number1 = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); +number = random.nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); @@ -3677,7 +3680,7 @@ vars.put("configurable_attribute_id", configurableList.get("attribute_id")); vars.put("configurable_option_id", configurableList.get("attribute_option_id")); vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); +number = random.nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); vars.put("testLabel", "GuestChkt"); @@ -3696,7 +3699,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path} GET @@ -3763,7 +3766,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}page_cache/block/render/ GET @@ -3822,7 +3825,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${category_url_key}${url_suffix} GET @@ -3880,7 +3883,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -3931,7 +3934,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -3997,7 +4000,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -4051,7 +4054,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -4116,7 +4119,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -4167,7 +4170,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -4233,7 +4236,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -4289,7 +4292,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -4354,7 +4357,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -4427,7 +4430,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -4476,7 +4479,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -4551,7 +4554,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -4637,7 +4640,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -4702,7 +4705,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/ GET @@ -4795,7 +4798,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/default/V1/customers/isEmailAvailable POST @@ -4860,7 +4863,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/default/V1/guest-carts/${cart_id}/estimate-shipping-methods POST @@ -4925,7 +4928,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/default/V1/guest-carts/${cart_id}/shipping-information POST @@ -4990,7 +4993,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}rest/default/V1/guest-carts/${cart_id}/payment-information POST @@ -5061,7 +5064,7 @@ vars.put("loadType", "Guest"); - ${request_protocol} + ${base_path}checkout/onepage/success/ GET @@ -5104,22 +5107,26 @@ vars.put("loadType", "Guest"); Passing arguments between threads import org.apache.jmeter.samplers.SampleResult; - -number = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +import java.util.Random; +Random random = new Random(); +if (${seedForRandom} > 0) { + random.setSeed(${seedForRandom}); +} +number = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number); vars.put("simple_product_1_url_key", simpleList.get("url_key")); vars.put("simple_product_1_name", simpleList.get("title")); vars.put("simple_product_1_id", simpleList.get("id")); vars.put("simple_product_1_uenc", simpleList.get("uenc")); -number1 = props.get("RandomObject").nextInt(props.get("simple_products_list").size()); +number1 = random.nextInt(props.get("simple_products_list").size()); simpleList = props.get("simple_products_list").get(number1); vars.put("simple_product_2_url_key", simpleList.get("url_key")); vars.put("simple_product_2_name", simpleList.get("title")); vars.put("simple_product_2_id", simpleList.get("id")); vars.put("simple_product_2_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("configurable_products_list").size()); +number = random.nextInt(props.get("configurable_products_list").size()); configurableList = props.get("configurable_products_list").get(number); vars.put("configurable_product_1_url_key", configurableList.get("url_key")); vars.put("configurable_product_1_name", configurableList.get("title")); @@ -5128,7 +5135,7 @@ vars.put("configurable_attribute_id", configurableList.get("attribute_id")); vars.put("configurable_option_id", configurableList.get("attribute_option_id")); vars.put("configurable_product_1_uenc", simpleList.get("uenc")); -number = props.get("RandomObject").nextInt(props.get("category_url_keys_list").size()); +number = random.nextInt(props.get("category_url_keys_list").size()); vars.put("category_url_key", props.get("category_url_keys_list").get(number)); vars.put("category_name", props.get("category_names_list").get(number)); @@ -5167,7 +5174,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path} GET @@ -5204,7 +5211,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}customer/account/login/ GET @@ -5271,7 +5278,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}page_cache/block/render/ GET @@ -5359,7 +5366,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}customer/account/loginPost/ POST @@ -5416,7 +5423,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}${category_url_key}${url_suffix} GET @@ -5474,7 +5481,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}${simple_product_1_url_key}${url_suffix} GET @@ -5525,7 +5532,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -5591,7 +5598,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -5645,7 +5652,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -5710,7 +5717,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}${simple_product_2_url_key}${url_suffix} GET @@ -5761,7 +5768,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}review/product/listAjax/id/${product_id}/ GET @@ -5827,7 +5834,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -5883,7 +5890,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -5948,7 +5955,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}${configurable_product_1_url_key}${url_suffix} GET @@ -6021,7 +6028,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}rest/V1/integration/admin/token POST @@ -6070,7 +6077,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}rest/V1/configurable-products/${configurable_product_sku}/options/all GET @@ -6145,7 +6152,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}checkout/cart/add/ POST @@ -6231,7 +6238,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}customer/section/load/ GET @@ -6296,7 +6303,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}checkout/ GET @@ -6429,7 +6436,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}rest/default/V1/carts/mine/estimate-shipping-methods-by-address-id POST @@ -6494,7 +6501,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}rest/default/V1/carts/mine/shipping-information POST @@ -6559,7 +6566,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}rest/default/V1/carts/mine/payment-information POST @@ -6617,7 +6624,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}checkout/onepage/success/ GET @@ -6699,7 +6706,7 @@ vars.put("loadType", "Customer"); - ${request_protocol} + ${base_path}DeploymentEvent.php POST From e8c717a651500fd0eb7a2a8943f18fd62ae95554 Mon Sep 17 00:00:00 2001 From: Andrii Lugovyi Date: Fri, 8 Sep 2017 13:28:18 +0300 Subject: [PATCH 133/151] MAGETWO-72401: fix jenkins unittest --- dev/tests/unit/phpunit.xml.dist | 2 -- 1 file changed, 2 deletions(-) diff --git a/dev/tests/unit/phpunit.xml.dist b/dev/tests/unit/phpunit.xml.dist index 1078c65b89f6a..9ad64a80a923d 100644 --- a/dev/tests/unit/phpunit.xml.dist +++ b/dev/tests/unit/phpunit.xml.dist @@ -13,8 +13,6 @@ > ../../../app/code/*/*/Test/Unit - ../../../dev/tools/*/*/Test/Unit - ../../../dev/tools/*/*/*/Test/Unit ../../../lib/internal/*/*/Test/Unit ../../../lib/internal/*/*/*/Test/Unit ../../../setup/src/*/*/Test/Unit From 5e9de4b4a8cee69693eb71a9ddec696b1d62b6c6 Mon Sep 17 00:00:00 2001 From: Volodymyr Zaets Date: Fri, 8 Sep 2017 14:10:55 +0300 Subject: [PATCH 134/151] MAGETWO-69210: [Google Tag Manager] Ajax "Add to Cart" / "Remove from Cart" do not fire any events --- .../Catalog/view/frontend/templates/product/list.phtml | 2 +- .../view/frontend/templates/product/view/form.phtml | 4 ++-- .../Theme/view/frontend/templates/js/polyfill.phtml | 7 +++++++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml index 6d6739d3ffd6d..d15c80e84efea 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/list.phtml @@ -122,7 +122,7 @@ $_helper = $this->helper('Magento\Catalog\Helper\Output'); { "[data-role=tocart-form], .form.map.checkout": { "catalogAddToCart": { - "product_sku": "getSku() ?>" + "product_sku": "getSku() ?>" } } } diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml index 881f23181cfd2..3f9e961fbcadc 100644 --- a/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml +++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/form.phtml @@ -16,8 +16,8 @@ getProduct(); ?>
    - getOptions()): ?> enctype="multipart/form-data"> diff --git a/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml b/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml index 74a5357b1016c..7e8854b914261 100644 --- a/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml +++ b/app/code/Magento/Theme/view/frontend/templates/js/polyfill.phtml @@ -3,6 +3,13 @@ * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ + +/** + * Polyfill for local storage and session storage for old browsers and with enabled private mode. + * + * Emulates behavior of the native local storage and session storage. Adds ability to use "getItem", "setItem", + * "removeItem" methods. + */ ?>