Skip to content

Commit 516acb2

Browse files
authored
Merge pull request #6638 from magento-tsg/2.4-develop-sidecar-pr16
[Sidecar] Fixes for 2.4 (pr16)
2 parents 9d39246 + e1d322f commit 516acb2

File tree

5 files changed

+571
-0
lines changed

5 files changed

+571
-0
lines changed
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\CatalogImportExport\Model\Import;
9+
10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\Catalog\Model\Product;
12+
use Magento\CatalogImportExport\Model\Import\Product\RowValidatorInterface;
13+
use Magento\CatalogImportExport\Model\Import\ProductImport;
14+
use Magento\Framework\App\Filesystem\DirectoryList;
15+
use Magento\Framework\File\Csv;
16+
use Magento\Framework\Filesystem;
17+
use Magento\Framework\Filesystem\Directory\Write;
18+
use Magento\Framework\MessageQueue\MessageEncoder;
19+
use Magento\Framework\ObjectManagerInterface;
20+
use Magento\ImportExport\Model\Export\Consumer;
21+
use Magento\ImportExport\Model\Import as ImportModel;
22+
use Magento\ImportExport\Model\Import\Source\Csv as CsvSource;
23+
use Magento\ImportExport\Model\Import\Source\CsvFactory;
24+
use Magento\MysqlMq\Model\Driver\Queue;
25+
use Magento\TestFramework\Helper\Bootstrap;
26+
use Magento\TestFramework\MysqlMq\DeleteTopicRelatedMessages;
27+
use PHPUnit\Framework\TestCase;
28+
29+
/**
30+
* Checks import behaviour if specified images do not exist
31+
*
32+
* @see \Magento\CatalogImportExport\Model\Import\Product
33+
*
34+
* @magentoAppArea adminhtml
35+
*/
36+
class ImportWithNotExistImagesTest extends TestCase
37+
{
38+
/** @var string */
39+
private const TOPIC = 'import_export.export';
40+
41+
/** @var ObjectManagerInterface */
42+
private $objectManager;
43+
44+
/** @var MessageEncoder */
45+
private $messageEncoder;
46+
47+
/** @var Consumer */
48+
private $consumer;
49+
50+
/** @var Queue */
51+
private $queue;
52+
53+
/** @var Csv */
54+
private $csvReader;
55+
56+
/** @var Write */
57+
private $directory;
58+
59+
/** @var string */
60+
private $filePath;
61+
62+
/** @var ProductImport */
63+
private $import;
64+
65+
/** @var CsvFactory */
66+
private $csvFactory;
67+
68+
/** @var Filesystem */
69+
private $fileSystem;
70+
71+
/** @var ProductRepositoryInterface */
72+
private $productRepository;
73+
74+
/**
75+
* @inheritdoc
76+
*/
77+
public static function setUpBeforeClass(): void
78+
{
79+
parent::setUpBeforeClass();
80+
81+
$objectManager = Bootstrap::getObjectManager();
82+
/** @var DeleteTopicRelatedMessages $deleteMessages */
83+
$deleteMessages = $objectManager->get(DeleteTopicRelatedMessages::class);
84+
$deleteMessages->execute(self::TOPIC);
85+
}
86+
87+
/**
88+
* @inheritdoc
89+
*/
90+
protected function setUp(): void
91+
{
92+
parent::setUp();
93+
94+
$this->objectManager = Bootstrap::getObjectManager();
95+
$this->queue = $this->objectManager->create(Queue::class, ['queueName' => 'export']);
96+
$this->messageEncoder = $this->objectManager->get(MessageEncoder::class);
97+
$this->consumer = $this->objectManager->get(Consumer::class);
98+
$this->directory = $this->objectManager->get(Filesystem::class)->getDirectoryWrite(DirectoryList::VAR_DIR);
99+
$this->csvReader = $this->objectManager->get(Csv::class);
100+
$this->import = $this->objectManager->get(ProductFactory::class)->create();
101+
$this->csvFactory = $this->objectManager->get(CsvFactory::class);
102+
$this->fileSystem = $this->objectManager->get(Filesystem::class);
103+
$this->productRepository = $this->objectManager->get(ProductRepositoryInterface::class);
104+
$this->productRepository->cleanCache();
105+
}
106+
107+
/**
108+
* @inheritdoc
109+
*/
110+
protected function tearDown(): void
111+
{
112+
if ($this->filePath && $this->directory->isExist($this->filePath)) {
113+
$this->directory->delete($this->filePath);
114+
}
115+
116+
parent::tearDown();
117+
}
118+
119+
/**
120+
* @magentoDataFixture Magento/CatalogImportExport/_files/export_queue_product_with_images.php
121+
*
122+
* @return void
123+
*/
124+
public function testImportWithUnexistingImages(): void
125+
{
126+
$this->exportProducts();
127+
$this->assertTrue($this->directory->isExist($this->filePath), 'Products were not imported to file');
128+
$fileContent = $this->csvReader->getData($this->directory->getAbsolutePath($this->filePath));
129+
$this->assertCount(2, $fileContent);
130+
$this->updateFileImagesToInvalidValues();
131+
$this->import->setParameters([
132+
'entity' => Product::ENTITY,
133+
'behavior' => ImportModel::BEHAVIOR_ADD_UPDATE,
134+
]);
135+
$this->assertImportErrors();
136+
$this->assertProductImages('/m/a/magento_image.jpg', 'simple');
137+
}
138+
139+
/**
140+
* Export products from queue to csv file
141+
*
142+
* @return void
143+
*/
144+
private function exportProducts(): void
145+
{
146+
$envelope = $this->queue->dequeue();
147+
$decodedMessage = $this->messageEncoder->decode(self::TOPIC, $envelope->getBody());
148+
$this->consumer->process($decodedMessage);
149+
$this->filePath = 'export/' . $decodedMessage->getFileName();
150+
}
151+
152+
/**
153+
* Change image names in an export file
154+
*
155+
* @return void
156+
*/
157+
private function updateFileImagesToInvalidValues(): void
158+
{
159+
$absolutePath = $this->directory->getAbsolutePath($this->filePath);
160+
$csv = $this->csvReader->getData($absolutePath);
161+
$imagesKeys = ['base_image', 'small_image', 'thumbnail_image'];
162+
$imagesPositions = [];
163+
foreach ($imagesKeys as $key) {
164+
$imagesPositions[] = array_search($key, $csv[0]);
165+
}
166+
167+
foreach ($imagesPositions as $imagesPosition) {
168+
$csv[1][$imagesPosition] = '/m/a/invalid_image.jpg';
169+
}
170+
171+
$this->csvReader->appendData($absolutePath, $csv);
172+
}
173+
174+
/**
175+
* Get export csv file
176+
*
177+
* @param string $file
178+
* @return CsvSource
179+
*/
180+
private function prepareFile(string $file): CsvSource
181+
{
182+
return $this->csvFactory->create([
183+
'file' => $file,
184+
'directory' => $this->fileSystem->getDirectoryWrite(DirectoryList::VAR_DIR),
185+
]);
186+
}
187+
188+
/**
189+
* Assert import errors
190+
*
191+
* @return void
192+
*/
193+
private function assertImportErrors(): void
194+
{
195+
$validationErrors = $this->import->setSource($this->prepareFile($this->filePath))->validateData();
196+
$this->assertEmpty($validationErrors->getAllErrors());
197+
$this->import->getErrorAggregator()->clear();
198+
$this->import->importData();
199+
$importErrors = $this->import->getErrorAggregator()->getAllErrors();
200+
$this->assertCount(1, $importErrors);
201+
$importError = reset($importErrors);
202+
$this->assertEquals(
203+
RowValidatorInterface::ERROR_MEDIA_URL_NOT_ACCESSIBLE,
204+
$importError->getErrorCode()
205+
);
206+
$errorMsg = (string)__('Imported resource (image) could not be downloaded ' .
207+
'from external resource due to timeout or access permissions');
208+
$this->assertEquals($errorMsg, $importError->getErrorMessage());
209+
}
210+
211+
/**
212+
* Assert product images were not changed after import
213+
*
214+
* @param string $imageName
215+
* @param string $productSku
216+
* @return void
217+
*/
218+
private function assertProductImages(string $imageName, string $productSku): void
219+
{
220+
$product = $this->productRepository->get($productSku);
221+
$this->assertEquals($imageName, $product->getImage());
222+
$this->assertEquals($imageName, $product->getSmallImage());
223+
$this->assertEquals($imageName, $product->getThumbnail());
224+
}
225+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\Catalog\Api\Data\ProductAttributeInterface;
9+
use Magento\Catalog\Api\Data\ProductInterface;
10+
use Magento\Framework\MessageQueue\PublisherInterface;
11+
use Magento\ImportExport\Model\Export\Entity\ExportInfoFactory;
12+
use Magento\TestFramework\Helper\Bootstrap;
13+
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
14+
15+
Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_with_image.php');
16+
17+
$objectManager = Bootstrap::getObjectManager();
18+
/** @var ExportInfoFactory $exportInfoFactory */
19+
$exportInfoFactory = $objectManager->get(ExportInfoFactory::class);
20+
/** @var PublisherInterface $messagePublisher */
21+
$messagePublisher = $objectManager->get(PublisherInterface::class);
22+
$dataObject = $exportInfoFactory->create(
23+
'csv',
24+
ProductAttributeInterface::ENTITY_TYPE_CODE,
25+
[ProductInterface::SKU => 'simple'],
26+
[]
27+
);
28+
$messagePublisher->publish('import_export.export', $dataObject);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
use Magento\TestFramework\MysqlMq\DeleteTopicRelatedMessages;
9+
use Magento\TestFramework\Helper\Bootstrap;
10+
use Magento\TestFramework\Workaround\Override\Fixture\Resolver;
11+
12+
$objectManager = Bootstrap::getObjectManager();
13+
/** @var DeleteTopicRelatedMessages $deleteTopicRelatedMessages */
14+
$deleteTopicRelatedMessages = $objectManager->get(DeleteTopicRelatedMessages::class);
15+
$deleteTopicRelatedMessages->execute('import_export.export');
16+
17+
Resolver::getInstance()->requireDataFixture('Magento/Catalog/_files/product_with_image_rollback.php');

0 commit comments

Comments
 (0)