359 lines
12 KiB
PHP
359 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* Test services for name collisions.
|
|
*
|
|
* Let we have two service interfaces called Foo\Bar\Service\SomeBazV1Interface and Foo\Bar\Service\Some\BazV1Interface.
|
|
* Given current name generation logic both are going to be translated to BarSomeBazV1. This test checks such things
|
|
* are not going to happen.
|
|
*
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
namespace Magento\AsynchronousOperations\Model;
|
|
|
|
use Magento\AsynchronousOperations\Model\ResourceModel\Bulk\Collection as BulkCollection;
|
|
use Magento\Framework\MessageQueue\BulkPublisherInterface;
|
|
use Magento\Framework\Exception\BulkException;
|
|
use Magento\Framework\Phrase;
|
|
use Magento\Framework\Registry;
|
|
use Magento\Framework\Webapi\Exception;
|
|
use Magento\TestFramework\Helper\Bootstrap;
|
|
use Magento\Catalog\Api\Data\ProductInterface;
|
|
use Magento\TestFramework\MessageQueue\PublisherConsumerController;
|
|
use Magento\TestFramework\MessageQueue\EnvironmentPreconditionException;
|
|
use Magento\TestFramework\MessageQueue\PreconditionFailedException;
|
|
use Magento\Catalog\Model\ResourceModel\Product\Collection;
|
|
use Magento\Catalog\Api\ProductRepositoryInterface;
|
|
use Magento\Framework\ObjectManagerInterface;
|
|
|
|
/**
|
|
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
|
*
|
|
* @magentoDbIsolation disabled
|
|
*/
|
|
class MassScheduleTest extends \PHPUnit\Framework\TestCase
|
|
{
|
|
/**
|
|
* @var string[]
|
|
*/
|
|
protected $consumers = ['async.operations.all'];
|
|
|
|
/**
|
|
* @var ObjectManagerInterface
|
|
*/
|
|
protected $objectManager;
|
|
|
|
/**
|
|
* @var MassSchedule
|
|
*/
|
|
private $massSchedule;
|
|
|
|
/**
|
|
* @var Collection
|
|
*/
|
|
private $collection;
|
|
|
|
/**
|
|
* @var ProductRepositoryInterface
|
|
*/
|
|
private $productRepository;
|
|
|
|
/**
|
|
* @var PublisherConsumerController
|
|
*/
|
|
private $publisherConsumerController;
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
private $skus = [];
|
|
|
|
/** @var string */
|
|
private $logFilePath;
|
|
|
|
/**
|
|
* @var Registry
|
|
*/
|
|
private $registry;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->objectManager = Bootstrap::getObjectManager();
|
|
$this->registry = $this->objectManager->get(Registry::class);
|
|
$this->massSchedule = $this->objectManager->create(MassSchedule::class);
|
|
$this->logFilePath = TESTS_TEMP_DIR . "/MessageQueueTestLog.txt";
|
|
$this->collection = $this->objectManager->create(Collection::class);
|
|
$this->productRepository = $this->objectManager->create(ProductRepositoryInterface::class);
|
|
/** @var PublisherConsumerController publisherConsumerController */
|
|
$this->publisherConsumerController = $this->objectManager->create(PublisherConsumerController::class, [
|
|
'consumers' => $this->consumers,
|
|
'logFilePath' => $this->logFilePath,
|
|
'appInitParams' => \Magento\TestFramework\Helper\Bootstrap::getInstance()->getAppInitParams()
|
|
]);
|
|
|
|
try {
|
|
$this->publisherConsumerController->initialize();
|
|
} catch (EnvironmentPreconditionException $e) {
|
|
$this->markTestSkipped($e->getMessage());
|
|
} catch (PreconditionFailedException $e) {
|
|
$this->fail($e->getMessage());
|
|
}
|
|
|
|
parent::setUp();
|
|
}
|
|
|
|
/**
|
|
* @dataProvider productDataProvider
|
|
* @param ProductInterface[] $products
|
|
*/
|
|
public function testScheduleMass($products)
|
|
{
|
|
try {
|
|
$this->sendBulk($products);
|
|
} catch (BulkException $bulkException) {
|
|
$this->fail('Bulk was not accepted in full');
|
|
}
|
|
|
|
//assert all products are created
|
|
try {
|
|
$this->publisherConsumerController->waitForAsynchronousResult(
|
|
[$this, 'assertProductExists'],
|
|
[$this->skus, count($this->skus)]
|
|
);
|
|
} catch (PreconditionFailedException $e) {
|
|
$this->fail("Not all products were created");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @dataProvider publisherExceptionDataProvider
|
|
* @param \Exception $exception
|
|
*/
|
|
public function testScheduleMassWithExceptionDuringPublishing(\Exception $exception)
|
|
{
|
|
$products = [
|
|
['product' => $this->getProduct()],
|
|
];
|
|
|
|
$publisher = $this->createMock(BulkPublisherInterface::class);
|
|
$publisher->expects($this->atLeastOnce())
|
|
->method('publish')
|
|
->willThrowException($exception);
|
|
$bulkManagement = $this->objectManager->create(
|
|
BulkManagement::class,
|
|
['publisher' => $publisher]
|
|
);
|
|
$this->massSchedule = $this->objectManager->create(
|
|
MassSchedule::class,
|
|
['bulkManagement' => $bulkManagement]
|
|
);
|
|
|
|
$bulkCollection = $this->objectManager->create(BulkCollection::class);
|
|
$bulksCount = $bulkCollection->getSize();
|
|
try {
|
|
$this->massSchedule->publishMass(
|
|
'async.magento.catalog.api.productrepositoryinterface.save.post',
|
|
$products
|
|
);
|
|
$this->fail('Publish is not failed when operations are not published.');
|
|
} catch (\Exception $e) {
|
|
$bulkCollection = $this->objectManager->create(BulkCollection::class);
|
|
$this->assertEquals($bulksCount, $bulkCollection->getSize());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function publisherExceptionDataProvider(): array
|
|
{
|
|
return [
|
|
[new \InvalidArgumentException('Unknown publisher type async')],
|
|
[new \LogicException('Could not find an implementation type for type "async" and connection "amqp".')],
|
|
];
|
|
}
|
|
|
|
public function sendBulk($products)
|
|
{
|
|
$this->skus = [];
|
|
foreach ($products as $data) {
|
|
if (isset($data['product'])) {
|
|
$this->skus[] = $data['product']->getSku();
|
|
}
|
|
}
|
|
$this->clearProducts();
|
|
|
|
$result = $this->massSchedule->publishMass(
|
|
'async.magento.catalog.api.productrepositoryinterface.save.post',
|
|
$products
|
|
);
|
|
|
|
//assert bulk accepted with no errors
|
|
$this->assertFalse($result->isErrors());
|
|
|
|
//assert number of products sent to queue
|
|
$this->assertCount(count($this->skus), $result->getRequestItems());
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
$this->publisherConsumerController->stopConsumers();
|
|
$this->clearProducts();
|
|
|
|
parent::tearDown();
|
|
}
|
|
|
|
private function clearProducts()
|
|
{
|
|
$size = $this->objectManager->create(Collection::class)
|
|
->addAttributeToFilter('sku', ['in' => $this->skus])
|
|
->load()
|
|
->getSize();
|
|
|
|
if ($size == 0) {
|
|
return;
|
|
}
|
|
|
|
$this->registry->unregister('isSecureArea');
|
|
$this->registry->register('isSecureArea', true);
|
|
try {
|
|
foreach ($this->skus as $sku) {
|
|
$this->productRepository->deleteById($sku);
|
|
}
|
|
} catch (\Exception $e) {
|
|
//nothing to delete
|
|
}
|
|
$this->registry->unregister('isSecureArea');
|
|
|
|
$size = $this->objectManager->create(Collection::class)
|
|
->addAttributeToFilter('sku', ['in' => $this->skus])
|
|
->load()
|
|
->getSize();
|
|
|
|
if ($size > 0) {
|
|
throw new Exception(new Phrase("Collection size after clearing the products: %size", ['size' => $size]));
|
|
}
|
|
}
|
|
|
|
public function assertProductExists($productsSkus, $count)
|
|
{
|
|
$collection = $this->objectManager->create(Collection::class)
|
|
->addAttributeToFilter('sku', ['in' => $productsSkus])
|
|
->load();
|
|
$size = $collection->getSize();
|
|
return $size == $count;
|
|
}
|
|
|
|
/**
|
|
* @dataProvider productExceptionDataProvider
|
|
* @param ProductInterface[] $products
|
|
*/
|
|
public function testScheduleMassOneEntityFailure($products)
|
|
{
|
|
try {
|
|
$this->sendBulk($products);
|
|
} catch (BulkException $e) {
|
|
$this->assertCount(1, $e->getErrors());
|
|
|
|
$errors = $e->getErrors();
|
|
$this->assertInstanceOf(\Magento\Framework\Exception\LocalizedException::class, $errors[0]);
|
|
|
|
$this->assertEquals("Error processing 1 element of input data", $errors[0]->getMessage());
|
|
|
|
$reasonException = $errors[0]->getPrevious();
|
|
|
|
$expectedErrorMessage = "Data item corresponding to \"product\" " .
|
|
"must be specified in the message with topic " .
|
|
"\"async.magento.catalog.api.productrepositoryinterface.save.post\".";
|
|
$this->assertEquals(
|
|
$expectedErrorMessage,
|
|
$reasonException->getMessage()
|
|
);
|
|
|
|
/** @var \Magento\WebapiAsync\Model\AsyncResponse $bulkStatus */
|
|
$bulkStatus = $e->getData();
|
|
$this->assertTrue($bulkStatus->isErrors());
|
|
|
|
/** @var ItemStatus[] $items */
|
|
$items = $bulkStatus->getRequestItems();
|
|
$this->assertCount(2, $items);
|
|
|
|
$this->assertEquals(ItemStatus::STATUS_ACCEPTED, $items[0]->getStatus());
|
|
$this->assertEquals(0, $items[0]->getId());
|
|
|
|
$this->assertEquals(ItemStatus::STATUS_REJECTED, $items[1]->getStatus());
|
|
$this->assertEquals(1, $items[1]->getId());
|
|
$this->assertEquals($expectedErrorMessage, $items[1]->getErrorMessage());
|
|
}
|
|
|
|
//assert one products is created
|
|
try {
|
|
$this->publisherConsumerController->waitForAsynchronousResult(
|
|
[$this, 'assertProductExists'],
|
|
[$this->skus, count($this->skus)]
|
|
);
|
|
} catch (PreconditionFailedException $e) {
|
|
$this->fail("Not all products were created");
|
|
}
|
|
}
|
|
|
|
private function getProduct()
|
|
{
|
|
/** @var $product \Magento\Catalog\Model\Product */
|
|
$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
|
|
->create(ProductInterface::class);
|
|
$product
|
|
->setTypeId('simple')
|
|
->setAttributeSetId(4)
|
|
->setWebsiteIds([1])
|
|
->setName('Simple Product 1')
|
|
->setSku('unique-simple-product1')
|
|
->setPrice(10)
|
|
->setMetaTitle('meta title')
|
|
->setMetaKeyword('meta keyword')
|
|
->setMetaDescription('meta description')
|
|
->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
|
|
->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
|
|
->setStockData(['use_config_manage_stock' => 0]);
|
|
return $product;
|
|
}
|
|
|
|
public function productDataProvider()
|
|
{
|
|
return [
|
|
'single_product' => [
|
|
[['product' => $this->getProduct()]],
|
|
],
|
|
'multiple_products' => [
|
|
[
|
|
['product' => $this->getProduct()
|
|
->setName('Simple Product 3')
|
|
->setSku('unique-simple-product3')
|
|
->setMetaTitle('meta title 3')
|
|
],
|
|
['product' => $this->getProduct()
|
|
->setName('Simple Product 2')
|
|
->setSku('unique-simple-product2')
|
|
->setMetaTitle('meta title 2')
|
|
]
|
|
]
|
|
],
|
|
];
|
|
}
|
|
|
|
public function productExceptionDataProvider()
|
|
{
|
|
return [
|
|
'single_product' => [
|
|
[['product' => $this->getProduct()]],
|
|
],
|
|
'multiple_products' => [
|
|
[
|
|
['product' => $this->getProduct()],
|
|
['customer' => $this->getProduct()]
|
|
]
|
|
],
|
|
];
|
|
}
|
|
}
|