Skip to content

Commit 956075d

Browse files
committed
MC-20425: [Integration Test] Check behavior when attribute set was changed to a new set with deleted attribute from the previous set
1 parent 68c48d5 commit 956075d

5 files changed

+425
-3
lines changed

dev/tests/integration/testsuite/Magento/Catalog/Controller/Product/ViewTest.php

Lines changed: 228 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,71 @@
33
* Copyright © Magento, Inc. All rights reserved.
44
* See COPYING.txt for license details.
55
*/
6+
declare(strict_types=1);
7+
68
namespace Magento\Catalog\Controller\Product;
79

10+
use Magento\Catalog\Api\ProductRepositoryInterface;
11+
use Magento\Catalog\Model\Product;
12+
use Magento\Eav\Model\AttributeSetSearchResults;
13+
use Magento\Eav\Model\Entity\Attribute\Set;
14+
use Magento\Framework\Api\SearchCriteriaBuilder;
15+
use Magento\Framework\Api\SortOrderBuilder;
16+
use Magento\Framework\App\Filesystem\DirectoryList;
17+
use Magento\Framework\Data\Collection;
18+
use Magento\Catalog\Api\AttributeSetRepositoryInterface;
19+
use Magento\Eav\Model\Entity\Type;
20+
use Magento\Framework\Filesystem;
21+
use Magento\Framework\Filesystem\Directory\WriteInterface;
22+
use Magento\TestFramework\Helper\Bootstrap;
23+
824
/**
9-
* @magentoDataFixture Magento/Catalog/controllers/_files/products.php
10-
* @magentoDbIsolation disabled
25+
* Integration test for product view front action.
26+
*
27+
* @magentoAppArea frontend
1128
*/
1229
class ViewTest extends \Magento\TestFramework\TestCase\AbstractController
1330
{
1431
/**
32+
* @var string
33+
*/
34+
private $systemLogFileName = 'system.log';
35+
36+
/**
37+
* @var ProductRepositoryInterface $productRepository
38+
*/
39+
private $productRepository;
40+
41+
/**
42+
* @var AttributeSetRepositoryInterface $attributeSetRepository
43+
*/
44+
private $attributeSetRepository;
45+
46+
/**
47+
* @var Type $productEntityType
48+
*/
49+
private $productEntityType;
50+
51+
/**
52+
* @inheritdoc
53+
*/
54+
protected function setUp()
55+
{
56+
parent::setUp();
57+
58+
$this->productRepository = $this->_objectManager->create(ProductRepositoryInterface::class);
59+
$this->attributeSetRepository = $this->_objectManager->create(AttributeSetRepositoryInterface::class);
60+
$this->productEntityType = $this->_objectManager->create(Type::class)
61+
->loadByCode(Product::ENTITY);
62+
}
63+
64+
/**
65+
* @magentoDbIsolation disabled
66+
* @magentoDataFixture Magento/Catalog/controllers/_files/products.php
1567
* @magentoConfigFixture current_store catalog/seo/product_canonical_tag 1
68+
* @return void
1669
*/
17-
public function testViewActionWithCanonicalTag()
70+
public function testViewActionWithCanonicalTag(): void
1871
{
1972
$this->markTestSkipped(
2073
'MAGETWO-40724: Canonical url from tests sometimes does not equal canonical url from action'
@@ -26,4 +79,176 @@ public function testViewActionWithCanonicalTag()
2679
$this->getResponse()->getBody()
2780
);
2881
}
82+
83+
/**
84+
* View product with custom attribute when attribute removed from it.
85+
*
86+
* It tests that after changing product attribute set from Default to Custom
87+
* there are no waring messages in log in case Custom not contains attribute from Default.
88+
*
89+
* @magentoDataFixture Magento/Catalog/_files/product_simple_with_country_of_manufacture.php
90+
* @magentoDataFixture Magento/Catalog/_files/attribute_set_based_on_default_without_country_of_manufacture.php
91+
* @magentoDbIsolation disabled
92+
* @return void
93+
*/
94+
public function testViewActionCustomAttributeSetWithoutCountryOfManufacture(): void
95+
{
96+
$product = $this->getProductBySku('simple_with_com');
97+
$attributeSetCustom = $this->getProductAttributeSetByName('custom_attribute_set_wout_com');
98+
99+
$product->setAttributeSetId($attributeSetCustom->getAttributeSetId());
100+
$this->productRepository->save($product);
101+
102+
$this->dispatch(sprintf('catalog/product/view/id/%s/', $product->getId()));
103+
$message = 'Attempt to load value of nonexistent EAV attribute';
104+
$this->assertFalse(
105+
$this->checkSystemLogForMessage($message),
106+
sprintf("Warning message found in %s: %s", $this->systemLogFileName, $message)
107+
);
108+
}
109+
110+
/**
111+
* Check system log file for error message.
112+
*
113+
* @param string $message
114+
* @return bool
115+
*/
116+
private function checkSystemLogForMessage(string $message): bool
117+
{
118+
$content = $this->getSystemLogContent();
119+
$pos = strpos($content, $message);
120+
121+
return $pos !== false;
122+
}
123+
124+
/**
125+
* Get product instance by sku.
126+
*
127+
* @param string $sku
128+
* @return Product
129+
*/
130+
private function getProductBySku(string $sku): Product
131+
{
132+
$product = $this->productRepository->get($sku);
133+
134+
return $product;
135+
}
136+
137+
/**
138+
* Get product attribute set by name.
139+
*
140+
* @param string $attributeSetName
141+
* @return Set|null
142+
*/
143+
private function getProductAttributeSetByName(string $attributeSetName): ?Set
144+
{
145+
/** @var SortOrderBuilder $sortOrderBuilder */
146+
$sortOrderBuilder = $this->_objectManager->create(SortOrderBuilder::class);
147+
/** @var SearchCriteriaBuilder $searchCriteriaBuilder */
148+
$searchCriteriaBuilder = $this->_objectManager->get(SearchCriteriaBuilder::class);
149+
$searchCriteriaBuilder->addFilter('attribute_set_name', $attributeSetName);
150+
$searchCriteriaBuilder->addFilter('entity_type_id', $this->productEntityType->getId());
151+
$attributeSetIdSortOrder = $sortOrderBuilder
152+
->setField('attribute_set_id')
153+
->setDirection(Collection::SORT_ORDER_DESC)
154+
->create();
155+
$searchCriteriaBuilder->addSortOrder($attributeSetIdSortOrder);
156+
$searchCriteriaBuilder->setPageSize(1);
157+
$searchCriteriaBuilder->setCurrentPage(1);
158+
159+
/** @var AttributeSetSearchResults $searchResult */
160+
$searchResult = $this->attributeSetRepository->getList($searchCriteriaBuilder->create());
161+
$items = $searchResult->getItems();
162+
163+
if (count($items) > 0) {
164+
return reset($items);
165+
}
166+
167+
return null;
168+
}
169+
170+
/**
171+
* Get system log content.
172+
*
173+
* @return string
174+
*/
175+
private function getSystemLogContent(): string
176+
{
177+
$logDir = $this->getLogDirectoryWrite();
178+
$logFullFileName = $logDir->getAbsolutePath($this->systemLogFileName);
179+
$content = $this->tail($logFullFileName, 10);
180+
181+
return $content;
182+
}
183+
184+
/**
185+
* Get file tail.
186+
*
187+
* @param string $filename
188+
* @param int $lines
189+
* @param int $buffer
190+
* @return false|string
191+
*/
192+
private function tail(string $filename, int $lines = 10, int $buffer = 4096)
193+
{
194+
// Open the file
195+
$f = fopen($filename, "rb");
196+
197+
// Jump to last character
198+
fseek($f, -1, SEEK_END);
199+
200+
// Read it and adjust line number if necessary
201+
// (Otherwise the result would be wrong if file doesn't end with a blank line)
202+
if (fread($f, 1) != "\n") {
203+
$lines--;
204+
}
205+
206+
// Start reading
207+
$output = '';
208+
$chunk = '';
209+
210+
// While we would like more
211+
while (ftell($f) > 0 && $lines >= 0) {
212+
// Figure out how far back we should jump
213+
$seek = min(ftell($f), $buffer);
214+
215+
// Do the jump (backwards, relative to where we are)
216+
fseek($f, -$seek, SEEK_CUR);
217+
218+
// Read a chunk and prepend it to our output
219+
$output = ($chunk = fread($f, $seek)) . $output;
220+
221+
// Jump back to where we started reading
222+
fseek($f, -mb_strlen($chunk, '8bit'), SEEK_CUR);
223+
224+
// Decrease our line counter
225+
$lines -= substr_count($chunk, "\n");
226+
}
227+
228+
// While we have too many lines
229+
// (Because of buffer size we might have read too many)
230+
while ($lines++ < 0) {
231+
// Find first newline and remove all text before that
232+
$output = substr($output, strpos($output, "\n") + 1);
233+
}
234+
235+
// Close file and return
236+
fclose($f);
237+
238+
return $output;
239+
}
240+
241+
/**
242+
* Get current LOG directory write.
243+
*
244+
* @return WriteInterface
245+
*/
246+
private function getLogDirectoryWrite()
247+
{
248+
/** @var Filesystem $filesystem */
249+
$filesystem = $this->_objectManager->create(Filesystem::class);
250+
$logDirectory = $filesystem->getDirectoryWrite(DirectoryList::LOG);
251+
252+
return $logDirectory;
253+
}
29254
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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\ProductAttributeRepositoryInterface;
10+
use Magento\Catalog\Model\Product;
11+
use Magento\Catalog\Model\Product\Attribute\Group;
12+
use Magento\Eav\Model\Entity\Attribute\Set;
13+
use Magento\Eav\Model\Entity\Type;
14+
use Magento\TestFramework\Helper\Bootstrap;
15+
16+
$objectManager = Bootstrap::getObjectManager();
17+
18+
/** @var ProductAttributeRepositoryInterface $attributeRepository */
19+
$attributeRepository = $objectManager->get(ProductAttributeRepositoryInterface::class);
20+
/** @var ProductAttributeInterface $attributeCountryOfManufacture */
21+
$attributeCountryOfManufacture = $attributeRepository->get('country_of_manufacture');
22+
23+
/** @var Magento\Eav\Model\Entity\Attribute\Set $attributeSet */
24+
$attributeSet = $objectManager->create(Set::class);
25+
$entityType = $objectManager->create(Type::class)
26+
->loadByCode(Magento\Catalog\Model\Product::ENTITY);
27+
$defaultSetId = $objectManager->create(Product::class)
28+
->getDefaultAttributeSetid();
29+
$data = [
30+
'attribute_set_name' => 'custom_attribute_set_wout_com',
31+
'entity_type_id' => $entityType->getId(),
32+
'sort_order' => 300,
33+
];
34+
35+
$attributeSet->setData($data);
36+
$attributeSet->validate();
37+
$attributeSet->save();
38+
$attributeSet->initFromSkeleton($defaultSetId);
39+
/** @var Group $group */
40+
foreach ($attributeSet->getGroups() as $group) {
41+
$groupAttributes = $group->getAttributes();
42+
$newAttributes = array_filter(
43+
$groupAttributes,
44+
function ($attribute) use ($attributeCountryOfManufacture) {
45+
/** @var ProductAttributeInterface $attribute */
46+
return $attribute->getAttributeId() != $attributeCountryOfManufacture->getAttributeId();
47+
}
48+
);
49+
if (count($newAttributes) < count($groupAttributes)) {
50+
$group->setAttributes($newAttributes);
51+
break;
52+
}
53+
}
54+
$attributeSet->save();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
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\Eav\Model\AttributeSetSearchResults;
9+
use Magento\Eav\Model\Entity\Attribute\Set;
10+
use Magento\Framework\Api\SearchCriteriaBuilder;
11+
use Magento\Framework\Api\SortOrderBuilder;
12+
use Magento\Framework\Data\Collection;
13+
use Magento\Framework\Registry;
14+
use Magento\TestFramework\Helper\Bootstrap;
15+
use Magento\Catalog\Api\AttributeSetRepositoryInterface;
16+
use Magento\Eav\Model\Entity\Type;
17+
18+
$objectManager = Bootstrap::getObjectManager();
19+
20+
/** @var AttributeSetRepositoryInterface $attributeSetRepository */
21+
$attributeSetRepository = $objectManager->create(AttributeSetRepositoryInterface::class);
22+
/** @var Type $entityType */
23+
$entityType = $objectManager->create(Type::class)
24+
->loadByCode(Magento\Catalog\Model\Product::ENTITY);
25+
$sortOrderBuilder = $objectManager->create(SortOrderBuilder::class);
26+
/** @var SearchCriteriaBuilder $searchCriteriaBuilder */
27+
$searchCriteriaBuilder = $objectManager->get(SearchCriteriaBuilder::class);
28+
$searchCriteriaBuilder->addFilter('attribute_set_name', 'custom_attribute_set_wout_com');
29+
$searchCriteriaBuilder->addFilter('entity_type_id', $entityType->getId());
30+
$attributeSetIdSortOrder = $sortOrderBuilder
31+
->setField('attribute_set_id')
32+
->setDirection(Collection::SORT_ORDER_DESC)
33+
->create();
34+
$searchCriteriaBuilder->addSortOrder($attributeSetIdSortOrder);
35+
$searchCriteriaBuilder->setPageSize(1);
36+
$searchCriteriaBuilder->setCurrentPage(1);
37+
38+
/** @var AttributeSetSearchResults $searchResult */
39+
$searchResult = $attributeSetRepository->getList($searchCriteriaBuilder->create());
40+
$items = $searchResult->getItems();
41+
42+
$registry = $objectManager->get(Registry::class);
43+
$registry->unregister('isSecureArea');
44+
$registry->register('isSecureArea', true);
45+
46+
try {
47+
if (count($items) > 0) {
48+
/** @var Set $attributeSet */
49+
$attributeSet = reset($items);
50+
$attributeSetRepository->deleteById($attributeSet->getId());
51+
}
52+
} catch (\Exception $e) {
53+
// In case of test run with DB isolation there is already no object in database
54+
// since rollback fixtures called after transaction rollback.
55+
}
56+
57+
$registry->unregister('isSecureArea');
58+
$registry->register('isSecureArea', false);

0 commit comments

Comments
 (0)