diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php
index 946f530655daa..6cfa90a7c4c0c 100644
--- a/app/code/Magento/Catalog/Model/Product.php
+++ b/app/code/Magento/Catalog/Model/Product.php
@@ -1613,6 +1613,17 @@ public function setIsDuplicable($value)
*/
public function isSalable()
{
+ if ($this->_catalogProduct->getSkipSaleableCheck()) {
+ return true;
+ }
+ if (($this->getOrigData('status') != $this->getData('status'))
+ || $this->isStockStatusChanged()) {
+ $this->unsetData('salable');
+ }
+
+ if ($this->hasData('salable')) {
+ return $this->getData('salable');
+ }
$this->_eventManager->dispatch('catalog_product_is_salable_before', ['product' => $this]);
$salable = $this->isAvailable();
@@ -1622,7 +1633,8 @@ public function isSalable()
'catalog_product_is_salable_after',
['product' => $this, 'salable' => $object]
);
- return $object->getIsSalable();
+ $this->setData('salable', $object->getIsSalable());
+ return $this->getData('salable');
}
/**
@@ -1632,7 +1644,7 @@ public function isSalable()
*/
public function isAvailable()
{
- return $this->getTypeInstance()->isSalable($this) || $this->_catalogProduct->getSkipSaleableCheck();
+ return $this->_catalogProduct->getSkipSaleableCheck() || $this->getTypeInstance()->isSalable($this);
}
/**
diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php
index 783507a0994f7..43a9549c46293 100644
--- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php
+++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/Full.php
@@ -156,6 +156,11 @@ class Full
*/
private $iteratorFactory;
+ /**
+ * @var \Magento\Framework\EntityManager\MetadataPool
+ */
+ private $metadataPool;
+
/**
* @param ResourceConnection $resource
* @param \Magento\Catalog\Model\Product\Type $catalogProductType
@@ -175,6 +180,7 @@ class Full
* @param \Magento\Framework\Search\Request\DimensionFactory $dimensionFactory
* @param \Magento\Framework\Indexer\ConfigInterface $indexerConfig
* @param \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\IndexIteratorFactory $indexIteratorFactory
+ * @param \Magento\Framework\EntityManager\MetadataPool $metadataPool
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -195,7 +201,8 @@ public function __construct(
\Magento\CatalogSearch\Model\ResourceModel\Fulltext $fulltextResource,
\Magento\Framework\Search\Request\DimensionFactory $dimensionFactory,
\Magento\Framework\Indexer\ConfigInterface $indexerConfig,
- \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\IndexIteratorFactory $indexIteratorFactory
+ \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\IndexIteratorFactory $indexIteratorFactory,
+ \Magento\Framework\EntityManager\MetadataPool $metadataPool = null
) {
$this->resource = $resource;
$this->connection = $resource->getConnection();
@@ -216,6 +223,8 @@ public function __construct(
$this->fulltextResource = $fulltextResource;
$this->dimensionFactory = $dimensionFactory;
$this->iteratorFactory = $indexIteratorFactory;
+ $this->metadataPool = $metadataPool ?: \Magento\Framework\App\ObjectManager::getInstance()
+ ->get(\Magento\Framework\EntityManager\MetadataPool::class);
}
/**
@@ -252,14 +261,22 @@ protected function getTable($table)
*/
protected function getProductIdsFromParents(array $entityIds)
{
- return $this->connection
+ /** @var \Magento\Framework\EntityManager\EntityMetadataInterface $metadata */
+ $metadata = $this->metadataPool->getMetadata(\Magento\Catalog\Api\Data\ProductInterface::class);
+ $fieldForParent = $metadata->getLinkField();
+
+ $select = $this->connection
->select()
- ->from($this->getTable('catalog_product_relation'), 'parent_id')
+ ->from(['relation' => $this->getTable('catalog_product_relation')], [])
->distinct(true)
->where('child_id IN (?)', $entityIds)
->where('parent_id NOT IN (?)', $entityIds)
- ->query()
- ->fetchAll(\Zend_Db::FETCH_COLUMN);
+ ->join(
+ ['cpe' => $this->getTable('catalog_product_entity')],
+ 'relation.parent_id = cpe.' . $fieldForParent,
+ ['cpe.entity_id']
+ );
+ return $this->connection->fetchCol($select);
}
/**
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Collection/SalableProcessor.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Collection/SalableProcessor.php
new file mode 100644
index 0000000000000..1fc4f6d4337bb
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Collection/SalableProcessor.php
@@ -0,0 +1,59 @@
+stockStatusFactory = $stockStatusFactory;
+ }
+
+ /**
+ * Adds filters to the collection to help determine if product is available for sale.
+ *
+ * This method adds several additional checks for a children products availability.
+ * Children products should be enabled and available in stock to be sold.
+ * It also adds the specific flag to the collection to prevent the case
+ * when filter already added and therefore may break the collection.
+ *
+ * @param Collection $collection
+ * @return Collection
+ */
+ public function process(Collection $collection)
+ {
+ $collection->addAttributeToFilter(
+ ProductInterface::STATUS,
+ Status::STATUS_ENABLED
+ );
+
+ $stockFlag = 'has_stock_status_filter';
+ if (!$collection->hasFlag($stockFlag)) {
+ $stockStatusResource = $this->stockStatusFactory->create();
+ $stockStatusResource->addStockDataToCollection($collection, true);
+ $collection->setFlag($stockFlag, true);
+ }
+
+ return $collection;
+ }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
index 93438b0fde3c7..e98f546943ff8 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
@@ -12,6 +12,10 @@
use Magento\Catalog\Model\Product;
use Magento\CatalogInventory\Api\StockRegistryInterface;
use Magento\CatalogInventory\Model\Stock\Status;
+use Magento\ConfigurableProduct\Model\Product\Type\Collection\SalableProcessor;
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable\AttributeFactory;
+use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable as ProductTypeConfigurable;
+use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Catalog\Model\Product\Gallery\ReadHandler as GalleryReadHandler;
@@ -96,29 +100,28 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
/**
* Catalog product type configurable
*
- * @var \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable
+ * @var ProductTypeConfigurable
*/
protected $_catalogProductTypeConfigurable;
/**
* Attribute collection factory
*
- * @var
- * \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\CollectionFactory
+ * @var ProductTypeConfigurable\Attribute\CollectionFactory
*/
protected $_attributeCollectionFactory;
/**
* Product collection factory
*
- * @var \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\CollectionFactory
+ * @var ProductTypeConfigurable\Product\CollectionFactory
*/
protected $_productCollectionFactory;
/**
* Configurable attribute factory
*
- * @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable\AttributeFactory
+ * @var AttributeFactory
*/
protected $configurableAttributeFactory;
@@ -177,7 +180,11 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
private $productFactory;
/**
- * @codingStandardsIgnoreStart/End
+ * @var SalableProcessor
+ */
+ private $salableProcessor;
+
+ /**
*
* @param \Magento\Catalog\Model\Product\Option $catalogProductOption
* @param \Magento\Eav\Model\Config $eavConfig
@@ -190,17 +197,21 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
* @param ProductRepositoryInterface $productRepository
* @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\ConfigurableFactory $typeConfigurableFactory
* @param \Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory $eavAttributeFactory
- * @param \Magento\ConfigurableProduct\Model\Product\Type\Configurable\AttributeFactory $configurableAttributeFactory
- * @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\CollectionFactory $productCollectionFactory
- * @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\CollectionFactory $attributeCollectionFactory
- * @param \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $catalogProductTypeConfigurable
+ * @param AttributeFactory $configurableAttributeFactory
+ * @param ProductTypeConfigurable\Product\CollectionFactory $productCollectionFactory
+ * @param ProductTypeConfigurable\Attribute\CollectionFactory $attributeCollectionFactory
+ * @param ProductTypeConfigurable $catalogProductTypeConfigurable
* @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
* @param \Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor
* @param \Magento\Framework\Cache\FrontendInterface $cache,
* @param \Magento\Customer\Model\Session $customerSession,
* @param StockRegistryInterface $stockRegistry,
* @param ProductInterfaceFactory $productFactory
- *
+ * @param \Magento\Framework\Cache\FrontendInterface $cache
+ * @param \Magento\Customer\Model\Session $customerSession
+ * @param StockRegistryInterface $stockRegistry
+ * @param ProductInterfaceFactory $productFactory
+ * @param SalableProcessor $salableProcessor
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
@@ -215,16 +226,17 @@ public function __construct(
ProductRepositoryInterface $productRepository,
\Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\ConfigurableFactory $typeConfigurableFactory,
\Magento\Catalog\Model\ResourceModel\Eav\AttributeFactory $eavAttributeFactory,
- \Magento\ConfigurableProduct\Model\Product\Type\Configurable\AttributeFactory $configurableAttributeFactory,
- \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\CollectionFactory $productCollectionFactory,
- \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\CollectionFactory $attributeCollectionFactory,
- \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable $catalogProductTypeConfigurable,
+ AttributeFactory $configurableAttributeFactory,
+ ProductTypeConfigurable\Product\CollectionFactory $productCollectionFactory,
+ ProductTypeConfigurable\Attribute\CollectionFactory $attributeCollectionFactory,
+ ProductTypeConfigurable $catalogProductTypeConfigurable,
\Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
\Magento\Framework\Api\ExtensionAttribute\JoinProcessorInterface $extensionAttributesJoinProcessor,
\Magento\Framework\Cache\FrontendInterface $cache = null,
\Magento\Customer\Model\Session $customerSession = null,
StockRegistryInterface $stockRegistry = null,
- ProductInterfaceFactory $productFactory = null
+ ProductInterfaceFactory $productFactory = null,
+ SalableProcessor $salableProcessor = null
) {
$this->typeConfigurableFactory = $typeConfigurableFactory;
$this->_eavAttributeFactory = $eavAttributeFactory;
@@ -251,6 +263,7 @@ public function __construct(
);
$this->stockRegistry = $stockRegistry ?: ObjectManager::getInstance()
->get(StockRegistryInterface::class);
+ $this->salableProcessor = $salableProcessor ?: ObjectManager::getInstance()->get(SalableProcessor::class);
}
/**
@@ -262,6 +275,7 @@ private function getCache()
if (null === $this->cache) {
$this->cache = ObjectManager::getInstance()->get(\Magento\Framework\Cache\FrontendInterface::class);
}
+
return $this->cache;
}
@@ -274,6 +288,7 @@ private function getCustomerSession()
if (null === $this->customerSession) {
$this->customerSession = ObjectManager::getInstance()->get(\Magento\Customer\Model\Session::class);
}
+
return $this->customerSession;
}
@@ -292,6 +307,7 @@ public function getRelationInfo()
)->setChildFieldName(
'product_id'
);
+
return $info;
}
@@ -329,10 +345,10 @@ public function getParentIdsByChild($childId)
*/
public function canUseAttribute(\Magento\Catalog\Model\ResourceModel\Eav\Attribute $attribute)
{
- return $attribute->getIsGlobal() == \Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface::SCOPE_GLOBAL &&
- $attribute->getIsVisible() &&
- $attribute->usesSource() &&
- $attribute->getIsUserDefined();
+ return $attribute->getIsGlobal() == ScopedAttributeInterface::SCOPE_GLOBAL &&
+ $attribute->getIsVisible() &&
+ $attribute->usesSource() &&
+ $attribute->getIsUserDefined();
}
/**
@@ -396,6 +412,7 @@ public function getUsedProductAttributeIds($product)
}
$product->setData($this->usedProductAttributeIds, $usedProductAttributeIds);
}
+
return $product->getData($this->usedProductAttributeIds);
}
@@ -411,7 +428,7 @@ public function getUsedProductAttributes($product)
$usedProductAttributes = [];
$usedAttributes = [];
foreach ($this->getConfigurableAttributes($product) as $attribute) {
- if (!is_null($attribute->getProductAttribute())) {
+ if ($attribute->getProductAttribute() !== null) {
$id = $attribute->getProductAttribute()->getId();
$usedProductAttributes[$id] = $attribute->getProductAttribute();
$usedAttributes[$id] = $attribute;
@@ -420,6 +437,7 @@ public function getUsedProductAttributes($product)
$product->setData($this->_usedAttributes, $usedAttributes);
$product->setData($this->usedProductAttributes, $usedProductAttributes);
}
+
return $product->getData($this->usedProductAttributes);
}
@@ -438,7 +456,7 @@ public function getConfigurableAttributes($product)
if (!$product->hasData($this->_configurableAttributes)) {
$metadata = $this->getMetadataPool()->getMetadata(ProductInterface::class);
$productId = $product->getData($metadata->getLinkField());
- $cacheId = __CLASS__ . $productId . '_' . $product->getStoreId();
+ $cacheId = __CLASS__ . $productId . '_' . $product->getStoreId();
$configurableAttributes = $this->getCache()->load($cacheId);
$configurableAttributes = $this->hasCacheData($configurableAttributes);
if ($configurableAttributes) {
@@ -456,6 +474,7 @@ public function getConfigurableAttributes($product)
$product->setData($this->_configurableAttributes, $configurableAttributes);
}
\Magento\Framework\Profiler::stop('CONFIGURABLE:' . __METHOD__);
+
return $product->getData($this->_configurableAttributes);
}
@@ -474,6 +493,7 @@ protected function hasCacheData($configurableAttributes)
}
}
}
+
return false;
}
@@ -488,7 +508,7 @@ public function resetConfigurableAttributes($product)
$metadata = $this->getMetadataPool()->getMetadata(ProductInterface::class);
$productId = $product->getData($metadata->getLinkField());
$product->unsetData($this->_configurableAttributes);
- $cacheId = __CLASS__ . $productId . '_' . $product->getStoreId();
+ $cacheId = __CLASS__ . $productId . '_' . $product->getStoreId();
$this->getCache()->remove($cacheId);
$this->getCache()->clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [self::TYPE_CODE . '_' . $productId]);
@@ -525,6 +545,7 @@ public function getConfigurableAttributesAsArray($product)
'options' => $eavAttribute->getSource()->getAllOptions(false),
];
}
+
return $res;
}
@@ -532,7 +553,7 @@ public function getConfigurableAttributesAsArray($product)
* Retrieve configurable attribute collection
*
* @param \Magento\Catalog\Model\Product $product
- * @return \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection
+ * @return ProductTypeConfigurable\Attribute\Collection
*/
public function getConfigurableAttributeCollection(\Magento\Catalog\Model\Product $product)
{
@@ -555,6 +576,7 @@ public function getUsedProductIds($product)
}
$product->setData($this->_usedProductIds, $usedProductIds);
}
+
return $product->getData($this->_usedProductIds);
}
@@ -637,7 +659,8 @@ function ($item) {
$product->setData($this->_usedProducts, $usedProducts);
}
\Magento\Framework\Profiler::stop('CONFIGURABLE:' . __METHOD__);
- $usedProducts = $product->getData($this->_usedProducts);
+ $usedProducts = $product->getData($this->_usedProducts);
+
return $usedProducts;
}
@@ -660,7 +683,7 @@ protected function getGalleryReadHandler()
* Retrieve related products collection
*
* @param \Magento\Catalog\Model\Product $product
- * @return \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection
+ * @return ProductTypeConfigurable\Product\Collection
*/
public function getUsedProductCollection($product)
{
@@ -670,7 +693,7 @@ public function getUsedProductCollection($product)
)->setProductFilter(
$product
);
- if (!is_null($this->getStoreFilter($product))) {
+ if ($this->getStoreFilter($product) !== null) {
$collection->addStoreFilter($this->getStoreFilter($product));
}
@@ -725,7 +748,7 @@ public function save($product)
{
parent::save($product);
$metadata = $this->getMetadataPool()->getMetadata(ProductInterface::class);
- $cacheId = __CLASS__ . $product->getData($metadata->getLinkField()) . '_' . $product->getStoreId();
+ $cacheId = __CLASS__ . $product->getData($metadata->getLinkField()) . '_' . $product->getStoreId();
$this->cache->remove($cacheId);
$extensionAttributes = $product->getExtensionAttributes();
@@ -738,6 +761,7 @@ public function save($product)
if (empty($extensionAttributes->getConfigurableProductLinks())) {
$this->saveRelatedProducts($product);
}
+
return $this;
}
@@ -767,7 +791,8 @@ private function saveConfigurableOptions(ProductInterface $product)
$attributeData['attribute_id'] = $configurableAttribute->getAttributeId();
} elseif (!empty($attributeData['attribute_id'])) {
$attribute = $this->_eavConfig->getAttribute(
- \Magento\Catalog\Model\Product::ENTITY, $attributeData['attribute_id']
+ \Magento\Catalog\Model\Product::ENTITY,
+ $attributeData['attribute_id']
);
$attributeData['attribute_id'] = $attribute->getId();
if (!$this->canUseAttribute($attribute)) {
@@ -785,7 +810,7 @@ private function saveConfigurableOptions(ProductInterface $product)
->setProductId($product->getData($metadata->getLinkField()))
->save();
}
- /** @var $configurableAttributesCollection \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection */
+ /** @var $configurableAttributesCollection ProductTypeConfigurable\Attribute\Collection */
$configurableAttributesCollection = $this->_attributeCollectionFactory->create();
$configurableAttributesCollection->setProductFilter($product);
$configurableAttributesCollection->addFieldToFilter(
@@ -824,10 +849,10 @@ public function isSalable($product)
$salable = parent::isSalable($product);
if ($salable !== false) {
- if (!is_null($product)) {
- $this->setStoreFilter($product->getStoreId(), $product);
- }
- $salable = count($this->getSalableUsedProducts($product)) > 0;
+ $collection = $this->getUsedProductCollection($product);
+ $collection->addStoreFilter($this->getStoreFilter($product));
+ $collection = $this->salableProcessor->process($collection);
+ $salable = 0 !== $collection->getSize();
}
return $salable;
@@ -883,6 +908,7 @@ public function getProductByAttributes($attributesInfo, $product)
}
}
}
+
return null;
}
@@ -922,6 +948,7 @@ public function getSelectedAttributesInfo($product)
}
}
\Magento\Framework\Profiler::stop('CONFIGURABLE:' . __METHOD__);
+
return $attributes;
}
@@ -1013,6 +1040,7 @@ protected function _prepareProduct(\Magento\Framework\DataObject $buyRequest, $p
$_result[0]->setCartQty(1);
}
$result[] = $_result[0];
+
return $result;
} else {
if (!$this->_isStrictProcessMode($processMode)) {
@@ -1050,6 +1078,7 @@ public function checkProductBuyState($product)
throw new \Magento\Framework\Exception\LocalizedException($this->getSpecifyOptionMessage());
}
}
+
return $this;
}
@@ -1099,6 +1128,7 @@ public function isVirtual($product)
return $optionProduct->isVirtual();
}
}
+
return parent::isVirtual($product);
}
@@ -1158,6 +1188,7 @@ public function assignProductToOption($optionProduct, $option, $product)
} else {
$option->getItem()->setHasConfigurationUnavailableError(true);
}
+
return $this;
}
@@ -1232,6 +1263,7 @@ public function getConfigurableOptions($product)
* Delete data specific for Configurable product type
*
* @param \Magento\Catalog\Model\Product $product
+ * @return void
*/
public function deleteTypeSpecificData(\Magento\Catalog\Model\Product $product)
{
@@ -1252,6 +1284,7 @@ public function deleteTypeSpecificData(\Magento\Catalog\Model\Product $product)
public function getAttributeById($attributeId, $product)
{
$attribute = parent::getAttributeById($attributeId, $product);
+
return $attribute ?: $this->_eavAttributeFactory->create()->load($attributeId);
}
@@ -1271,6 +1304,7 @@ public function setImageFromChildProduct(\Magento\Catalog\Model\Product $product
}
}
}
+
return parent::setImageFromChildProduct($product);
}
@@ -1283,6 +1317,7 @@ private function getMetadataPool()
if (!$this->metadataPool) {
$this->metadataPool = ObjectManager::getInstance()->get(MetadataPool::class);
}
+
return $this->metadataPool;
}
@@ -1296,6 +1331,7 @@ private function getCatalogConfig()
if (!$this->catalogConfig) {
$this->catalogConfig = ObjectManager::getInstance()->get(Config::class);
}
+
return $this->catalogConfig;
}
@@ -1314,8 +1350,10 @@ public function getSalableUsedProducts(Product $product, $requiredAttributeIds =
$product->getId(),
$product->getStore()->getWebsiteId()
);
+
return (int)$stockStatus->getStockStatus() === Status::STATUS_IN_STOCK && $product->isSalable();
});
+
return $usedSalableProducts;
}
}
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/Collection/SalableProcessorTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/Collection/SalableProcessorTest.php
new file mode 100644
index 0000000000000..b6f9066b60e18
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/Collection/SalableProcessorTest.php
@@ -0,0 +1,75 @@
+objectManager = new ObjectManager($this);
+
+ $this->stockStatusFactory = $this->getMockBuilder(
+ \Magento\CatalogInventory\Model\ResourceModel\Stock\StatusFactory::class
+ )
+ ->setMethods(['create'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->model = $this->objectManager->getObject(
+ \Magento\ConfigurableProduct\Model\Product\Type\Collection\SalableProcessor::class,
+ [
+ 'stockStatusFactory' => $this->stockStatusFactory,
+ ]
+ );
+ }
+
+ public function testProcess()
+ {
+ $productCollection = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product\Collection::class)
+ ->setMethods(['addAttributeToFilter'])
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $productCollection->expects($this->once())
+ ->method('addAttributeToFilter')
+ ->with(ProductInterface::STATUS, Status::STATUS_ENABLED)
+ ->will($this->returnSelf());
+
+ $stockStatusResource = $this->getMockBuilder(\Magento\CatalogInventory\Model\ResourceModel\Stock\Status::class)
+ ->setMethods(['addStockDataToCollection'])
+ ->disableOriginalConstructor()
+ ->getMock();
+ $stockStatusResource->expects($this->once())
+ ->method('addStockDataToCollection')
+ ->with($productCollection, true)
+ ->will($this->returnSelf());
+
+ $this->stockStatusFactory
+ ->expects($this->once())
+ ->method('create')
+ ->will($this->returnValue($stockStatusResource));
+
+ $this->model->process($productCollection);
+
+ $this->assertTrue($productCollection->hasFlag(self::STOCK_FLAG));
+ }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
index 638080f225920..68339bdde3acc 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
@@ -13,15 +13,20 @@
use Magento\Catalog\Model\Config;
use Magento\CatalogInventory\Model\Stock\Status;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute;
+use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection;
+use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\CollectionFactory;
use Magento\Framework\EntityManager\EntityMetadata;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Customer\Model\Session;
+use Magento\ConfigurableProduct\Model\Product\Type\Collection\SalableProcessor;
/**
* Class \Magento\ConfigurableProduct\Test\Unit\Model\Product\Type\ConfigurableTest
*
* @SuppressWarnings(PHPMD.LongVariable)
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.TooManyFields)
*/
class ConfigurableTest extends \PHPUnit_Framework_TestCase
{
@@ -104,6 +109,11 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
*/
private $productFactory;
+ /**
+ * @var SalableProcessor|\PHPUnit_Framework_MockObject_MockObject
+ */
+ private $salableProcessor;
+
/**
* @SuppressWarnings(PHPMD.ExcessiveMethodLength)
*/
@@ -111,7 +121,13 @@ protected function setUp()
{
$this->_objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
$eventManager = $this->getMock(\Magento\Framework\Event\ManagerInterface::class, [], [], '', false);
- $fileStorageDbMock = $this->getMock(\Magento\MediaStorage\Helper\File\Storage\Database::class, [], [], '', false);
+ $fileStorageDbMock = $this->getMock(
+ \Magento\MediaStorage\Helper\File\Storage\Database::class,
+ [],
+ [],
+ '',
+ false
+ );
$filesystem = $this->getMockBuilder(\Magento\Framework\Filesystem::class)
->disableOriginalConstructor()
->getMock();
@@ -142,7 +158,7 @@ protected function setUp()
false
);
$this->_attributeCollectionFactory = $this->getMock(
- \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\CollectionFactory::class,
+ CollectionFactory::class,
['create'],
[],
'',
@@ -181,6 +197,14 @@ protected function setUp()
->disableOriginalConstructor()
->getMock();
+ $this->salableProcessor = $this->getMock(
+ SalableProcessor::class,
+ [],
+ [],
+ '',
+ false
+ );
+
$this->_model = $this->_objectHelper->getObject(
Configurable::class,
[
@@ -199,13 +223,11 @@ protected function setUp()
'cache' => $this->cache,
'catalogConfig' => $this->catalogConfig,
'stockRegistry' => $this->stockRegistry,
- 'productFactory' => $this->productFactory
+ 'productFactory' => $this->productFactory,
+ 'salableProcessor' => $this->salableProcessor,
+ 'metadataPool' => $this->metadataPool,
]
);
- $refClass = new \ReflectionClass(Configurable::class);
- $refProperty = $refClass->getProperty('metadataPool');
- $refProperty->setAccessible(true);
- $refProperty->setValue($this->_model, $this->metadataPool);
}
public function testHasWeightTrue()
@@ -259,7 +281,7 @@ public function testSave()
$product->expects($this->any())
->method('getData')
->willReturnMap($dataMap);
- $attribute = $this->getMockBuilder(\Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class)
+ $attribute = $this->getMockBuilder(Attribute::class)
->disableOriginalConstructor()
->setMethods(['addData', 'setStoreId', 'setProductId', 'save', '__wakeup', '__sleep'])
->getMock();
@@ -273,9 +295,9 @@ public function testSave()
$this->_configurableAttributeFactoryMock->expects($this->any())->method('create')
->will($this->returnValue($attribute));
- $attributeCollection = $this->getMockBuilder(
- \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection::class
- )->setMethods(['setProductFilter', 'addFieldToFilter', 'walk'])->disableOriginalConstructor()
+ $attributeCollection = $this->getMockBuilder(Collection::class)
+ ->setMethods(['setProductFilter', 'addFieldToFilter', 'walk'])
+ ->disableOriginalConstructor()
->getMock();
$this->_attributeCollectionFactory->expects($this->any())->method('create')
->will($this->returnValue($attributeCollection));
@@ -312,27 +334,19 @@ public function testCanUseAttribute()
'',
false
);
- $attribute->expects($this->once())
- ->method('getIsGlobal')
- ->will($this->returnValue(1));
- $attribute->expects($this->once())
- ->method('getIsVisible')
- ->will($this->returnValue(1));
- $attribute->expects($this->once())
- ->method('usesSource')
- ->will($this->returnValue(1));
- $attribute->expects($this->once())
- ->method('getIsUserDefined')
- ->will($this->returnValue(1));
+ $attribute->expects($this->once())->method('getIsGlobal')->will($this->returnValue(1));
+ $attribute->expects($this->once())->method('getIsVisible')->will($this->returnValue(1));
+ $attribute->expects($this->once())->method('usesSource')->will($this->returnValue(1));
+ $attribute->expects($this->once())->method('getIsUserDefined')->will($this->returnValue(1));
$this->assertTrue($this->_model->canUseAttribute($attribute));
}
public function testGetUsedProducts()
{
- $attributeCollection = $this->getMockBuilder(
- \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection::class
- )->setMethods(['setProductFilter', 'addFieldToFilter', 'walk'])->disableOriginalConstructor()
+ $attributeCollection = $this->getMockBuilder(Collection::class)
+ ->setMethods(['setProductFilter', 'addFieldToFilter', 'walk'])
+ ->disableOriginalConstructor()
->getMock();
$attributeCollection->expects($this->any())->method('setProductFilter')->will($this->returnSelf());
$this->_attributeCollectionFactory->expects($this->any())->method('create')
@@ -407,7 +421,6 @@ public function testGetUsedProducts()
new \ArrayIterator([])
);
-
$this->_productCollectionFactory->expects($this->any())->method('create')
->will($this->returnValue($productCollection));
$this->_model->getUsedProducts($product);
@@ -490,7 +503,7 @@ public function testGetConfigurableAttributesAsArray($productStore, $attributeSt
$eavAttribute->expects($this->any())->method('getStoreLabel')->will($this->returnValue('Store Label'));
$eavAttribute->expects($this->any())->method('setStoreId')->with($attributeStore);
- $attribute = $this->getMockBuilder(\Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class)
+ $attribute = $this->getMockBuilder(Attribute::class)
->disableOriginalConstructor()
->setMethods(['getProductAttribute', '__wakeup', '__sleep'])
->getMock();
@@ -539,7 +552,7 @@ public function testGetConfigurableAttributes()
$configurableAttributes = '_cache_instance_configurable_attributes';
/** @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject $product */
- $product = $this->getMockBuilder('Magento\Catalog\Model\Product')
+ $product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
->setMethods(['getData', 'hasData', 'setData', 'getIdentities', 'getId', 'getStoreId'])
->disableOriginalConstructor()
->getMock();
@@ -563,7 +576,7 @@ public function testGetConfigurableAttributes()
->willReturn('link');
$attributeCollection = $this->getMockBuilder(
- \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection::class
+ Collection::class
)
->setMethods(['setProductFilter', 'orderByPosition', 'load'])
->disableOriginalConstructor()
@@ -576,7 +589,7 @@ public function testGetConfigurableAttributes()
->method('process')
->with(
$this->isInstanceOf(
- \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Attribute\Collection::class
+ Collection::class
)
);
@@ -613,7 +626,7 @@ public function testHasOptionsConfigurableAttribute()
->setMethods(['__wakeup', 'getAttributeCode', 'getOptions', 'hasData', 'getData'])
->disableOriginalConstructor()
->getMock();
- $attributeMock = $this->getMockBuilder(\Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class)
+ $attributeMock = $this->getMockBuilder(Attribute::class)
->disableOriginalConstructor()
->getMock();
@@ -652,29 +665,49 @@ public function testIsSalable()
->setMethods(['__wakeup', 'getStatus', 'hasData', 'getData', 'getStoreId', 'setData'])
->disableOriginalConstructor()
->getMock();
- $childProductMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
- ->setMethods(['__wakeup', 'isSalable', 'getStore'])
- ->disableOriginalConstructor()
- ->getMock();
-
- $storeMock = $this->getMockBuilder(\Magento\Store\Api\Data\StoreInterface::class)
- ->setMethods(['getWebsiteId'])
- ->getMockForAbstractClass();
-
- $stockStatus = $this->getMockBuilder(\Magento\CatalogInventory\Api\Data\StockStatusInterface::class)
- ->setMethods(['getStockStatus'])
- ->getMockForAbstractClass();
$productMock->expects($this->once())->method('getStatus')->willReturn(1);
$productMock->expects($this->any())->method('hasData')->willReturn(true);
$productMock->expects($this->at(2))->method('getData')->with('is_salable')->willReturn(true);
- $productMock->expects($this->once())->method('getStoreId')->willReturn(1);
- $productMock->expects($this->once())->method('setData')->willReturnSelf();
- $productMock->expects($this->at(6))->method('getData')->willReturn([$childProductMock]);
- $childProductMock->expects($this->once())->method('getStore')->willReturn($storeMock);
- $this->stockRegistry->expects($this->once())->method('getStockStatus')->willReturn($stockStatus);
- $stockStatus->expects($this->once())->method('getStockStatus')->willReturn(1);
- $childProductMock->expects($this->once())->method('isSalable')->willReturn(true);
+
+ $productCollection = $this->getMockBuilder(
+ \Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable\Product\Collection::class
+ )
+ ->setMethods(
+ [
+ 'setFlag',
+ 'setProductFilter',
+ 'addStoreFilter',
+ 'getSize'
+ ]
+ )
+ ->disableOriginalConstructor()
+ ->getMock();
+ $productCollection->expects($this->any())->method('setFlag')->will($this->returnSelf());
+ $productCollection
+ ->expects($this->once())
+ ->method('setProductFilter')
+ ->with($productMock)
+ ->will($this->returnSelf());
+ $productCollection
+ ->expects($this->once())
+ ->method('addStoreFilter')
+ ->will($this->returnSelf());
+ $productCollection
+ ->expects($this->once())
+ ->method('getSize')
+ ->willReturn(1);
+
+ $this->salableProcessor
+ ->expects($this->once())
+ ->method('process')
+ ->with($productCollection)
+ ->will($this->returnValue($productCollection));
+
+ $this->_productCollectionFactory
+ ->expects($this->once())
+ ->method('create')
+ ->will($this->returnValue($productCollection));
$this->assertTrue($this->_model->isSalable($productMock));
}
@@ -748,12 +781,14 @@ public function testGetSelectedAttributesInfo()
->setMethods(['__wakeup', 'getCustomOption', 'hasData', 'getData'])
->disableOriginalConstructor()
->getMock();
- $optionMock = $this->getMockBuilder(\Magento\Catalog\Model\Product\Configuration\Item\Option\OptionInterface::class)
+ $optionMock = $this->getMockBuilder(
+ \Magento\Catalog\Model\Product\Configuration\Item\Option\OptionInterface::class
+ )
->setMethods(['getValue'])
->disableOriginalConstructor()
->getMock();
$usedAttributeMock = $this->getMockBuilder(
- \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute::class
+ Attribute::class
)
->setMethods(['getProductAttribute'])
->disableOriginalConstructor()
@@ -965,4 +1000,3 @@ public function testSetImageFromChildProduct()
$this->_model->setImageFromChildProduct($productMock);
}
}
-
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php
index 350c9585d15fd..54398f8bf9dc7 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php
@@ -41,7 +41,7 @@ public function __construct(CurlTransport $transport)
* @param array $options [optional]
* @return void
*/
- protected function execute($command, $options = [])
+ public function execute($command, $options = [])
{
$curl = $this->transport;
$curl->write($this->prepareUrl($command, $options), [], CurlInterface::GET);
@@ -53,10 +53,10 @@ protected function execute($command, $options = [])
* Prepare url.
*
* @param string $command
- * @param array $options
+ * @param array $options [optional]
* @return string
*/
- private function prepareUrl($command, array $options)
+ private function prepareUrl($command, $options = [])
{
$command .= ' ' . implode(' ', $options);
return $_ENV['app_frontend_url'] . self::URL . '?command=' . urlencode($command);
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Cache.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Cache.php
index 272e3158d3c27..4b0fc013d04ec 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Cache.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Cache.php
@@ -11,8 +11,24 @@
/**
* Handle cache for tests executions.
*/
-class Cache extends Cli
+class Cache
{
+ /**
+ * Perform bin/magento commands from command line for functional tests executions.
+ *
+ * @var Cli
+ */
+ private $cli;
+
+ /**
+ * Cache constructor.
+ * @param Cli $cli
+ */
+ public function __construct(Cli $cli)
+ {
+ $this->cli = $cli;
+ }
+
/**
* Parameter for flush cache command.
*/
@@ -38,7 +54,7 @@ class Cache extends Cli
public function flush(array $cacheTypes = [])
{
$options = empty($cacheTypes) ? '' : ' ' . implode(' ', $cacheTypes);
- parent::execute(Cache::PARAM_CACHE_FLUSH . $options);
+ $this->cli->execute(Cache::PARAM_CACHE_FLUSH . $options);
}
/**
@@ -49,7 +65,7 @@ public function flush(array $cacheTypes = [])
*/
public function disableCache($cacheType = null)
{
- parent::execute(Cache::PARAM_CACHE_DISABLE . ($cacheType ? " $cacheType" : ''));
+ $this->cli->execute(Cache::PARAM_CACHE_DISABLE . ($cacheType ? " $cacheType" : ''));
}
/**
@@ -60,6 +76,6 @@ public function disableCache($cacheType = null)
*/
public function enableCache($cacheType = null)
{
- parent::execute(Cache::PARAM_CACHE_ENABLE . ($cacheType ? " $cacheType" : ''));
+ $this->cli->execute(Cache::PARAM_CACHE_ENABLE . ($cacheType ? " $cacheType" : ''));
}
}
diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php b/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php
index a1f3996197517..b5df8040b575d 100644
--- a/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php
+++ b/dev/tests/functional/tests/app/Magento/Config/Test/TestStep/SetupConfigurationStep.php
@@ -38,11 +38,11 @@ class SetupConfigurationStep implements TestStepInterface
protected $rollback;
/**
- * Flush cache.
+ * Flush cache after change config flag.
*
* @var bool
*/
- protected $flushCache;
+ private $flushCache;
/**
* Cli command to do operations with cache.
@@ -94,7 +94,7 @@ public function run()
$config = $this->fixtureFactory->createByCode('configData', ['dataset' => $configDataSet . $prefix]);
if ($config->hasData('section')) {
$config->persist();
- $result = array_merge($result, $config->getSection());
+ $result = array_replace_recursive($result, $config->getSection());
}
if ($this->flushCache) {
$this->cache->flush();
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigData.xml
new file mode 100644
index 0000000000000..c04ba239a9ca5
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigData.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ - default
+ - 0
+ - 1
+
+
+
+
+
+ - default
+ - 0
+ - 0
+
+
+
+
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml
index 5839ec2562bc7..66a4748e71288 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Repository/ConfigurableProduct/ConfigurableAttributesData.xml
@@ -508,6 +508,61 @@
+
+
+ -
+
-
+
-
+
- 12.00
+ - Yes
+
+
+
+
+
+ - catalogProductSimple::offline
+
+
+ - catalogProductAttribute::attribute_type_dropdown_one_option
+
+
+
+
+
+ -
+
-
+
-
+
- option_key_1_%isolation%
+ - 560
+ - Yes
+
+ -
+
- option_key_2_%isolation%
+ - 560
+ - Yes
+
+
+
+
+
+ - catalogProductAttribute::attribute_type_dropdown_two_options
+
+
+ - catalogProductSimple::out_of_stock
+ - catalogProductSimple::offline
+
+
+ -
+
- 10
+ - 1
+
+ -
+
- 20
+ - 2
+
+
+
+
-
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php
index 2344e3eb80e75..f220109f86ca6 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.php
@@ -8,8 +8,10 @@
use Magento\Catalog\Test\Page\Adminhtml\CatalogProductIndex;
use Magento\Catalog\Test\Page\Adminhtml\CatalogProductNew;
+use Magento\Config\Test\TestStep\SetupConfigurationStep;
use Magento\ConfigurableProduct\Test\Fixture\ConfigurableProduct;
use Magento\Mtf\TestCase\Injectable;
+use Magento\Mtf\TestStep\TestStepFactory;
/**
* Test Coverage for CreateConfigurableProductEntity
@@ -58,31 +60,69 @@ class CreateConfigurableProductEntityTest extends Injectable
*/
protected $productNew;
+ /**
+ * Factory for creation SetupConfigurationStep.
+ *
+ * @var TestStepFactory
+ */
+ protected $testStepFactory;
+
+ /**
+ * Configuration data holder.
+ *
+ * @var string
+ */
+ protected $configData = null;
+
/**
* Injection data.
*
* @param CatalogProductIndex $productIndex
* @param CatalogProductNew $productNew
+ * @param TestStepFactory $testStepFactory
* @return void
*/
- public function __inject(CatalogProductIndex $productIndex, CatalogProductNew $productNew)
- {
+ public function __inject(
+ CatalogProductIndex $productIndex,
+ CatalogProductNew $productNew,
+ TestStepFactory $testStepFactory
+ ) {
$this->productIndex = $productIndex;
$this->productNew = $productNew;
+ $this->testStepFactory = $testStepFactory;
}
/**
* Test create catalog Configurable product run.
*
* @param ConfigurableProduct $product
+ * @param string|null $configData
* @return void
*/
- public function test(ConfigurableProduct $product)
+ public function test(ConfigurableProduct $product, $configData = null)
{
+ //Preconditions
+ $this->configData = $configData;
+ $this->testStepFactory->create(
+ SetupConfigurationStep::class,
+ ['configData' => $this->configData, 'flushCache' => true]
+ )->run();
+
// Steps
$this->productIndex->open();
$this->productIndex->getGridPageActionBlock()->addProduct('configurable');
$this->productNew->getProductForm()->fill($product);
$this->productNew->getFormPageActions()->save($product);
}
+
+ /**
+ * Revert Display Out Of Stock Products configuration.
+ */
+ public function teatDown()
+ {
+ $this->testStepFactory->create(
+ SetupConfigurationStep::class,
+ ['configData' => $this->configData, 'flushCache' => true]
+ )->cleanUp();
+ }
}
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml
index 2f46e7dd3adc3..2e86dd00971a1 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateConfigurableProductEntityTest.xml
@@ -129,5 +129,59 @@
+
+ test_type:acceptance_test, test_type:extended_acceptance_test
+ with_out_of_stock_item
+ Configurable Product %isolation%
+ configurable_sku_%isolation%
+ 100
+ default
+ no
+ default_subcategory
+ configurable-product-%isolation%
+ custom_attribute_set_%isolation%
+ display_out_of_stock_products
+
+
+
+
+
+
+
+ test_type:acceptance_test, test_type:extended_acceptance_test
+ with_disabled_item
+ Configurable Product %isolation%
+ configurable_sku_%isolation%
+ 100
+ default
+ no
+ default_subcategory
+ configurable-product-%isolation%
+ custom_attribute_set_%isolation%
+ display_out_of_stock_products
+
+
+
+
+
+
+
+ test_type:acceptance_test, test_type:extended_acceptance_test
+ with_one_disabled_item_and_one_out_of_stock_item
+ Configurable Product %isolation%
+ configurable_sku_%isolation%
+ 100
+ default
+ no
+ default_subcategory
+ configurable-product-%isolation%
+ custom_attribute_set_%isolation%
+ display_out_of_stock_products
+
+
+
+
+
+
diff --git a/dev/tests/functional/utils/command.php b/dev/tests/functional/utils/command.php
index 397f60cd07ea1..fd99536659423 100644
--- a/dev/tests/functional/utils/command.php
+++ b/dev/tests/functional/utils/command.php
@@ -4,9 +4,17 @@
* See COPYING.txt for license details.
*/
+$commandList = [
+ 'cache:flush',
+ 'cache:disable',
+ 'cache:enable',
+];
+
if (isset($_GET['command'])) {
$command = urldecode($_GET['command']);
- exec('php -f ../../../../bin/magento ' . $command);
+ if (in_array($command, $commandList)) {
+ exec('php -f ../../../../bin/magento ' . $command);
+ }
} else {
throw new \InvalidArgumentException("Command GET parameter is not set.");
}
diff --git a/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/FullTest.php b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/FullTest.php
new file mode 100644
index 0000000000000..8ee4f8dd7d61b
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/CatalogSearch/Model/Indexer/Fulltext/Action/FullTest.php
@@ -0,0 +1,56 @@
+fullAction = Bootstrap::getObjectManager()->create(
+ \Magento\CatalogSearch\Model\Indexer\Fulltext\Action\Full::class
+ );
+ }
+
+ public function testRebuildStoreIndexConfigurable()
+ {
+ $storeId = 1;
+
+ $simpleProductId = $this->getIdBySku('simple_10');
+ $configProductId = $this->getIdBySku('configurable');
+
+ $expected = [
+ $simpleProductId,
+ $configProductId
+ ];
+ $storeIndexDataSimple = $this->fullAction->rebuildStoreIndex($storeId, [$simpleProductId]);
+ $storeIndexDataExpected = $this->fullAction->rebuildStoreIndex($storeId, $expected);
+
+ $this->assertEquals($storeIndexDataSimple, $storeIndexDataExpected);
+ }
+
+ /**
+ * @param string $sku
+ * @return int
+ */
+ private function getIdBySku($sku)
+ {
+ /** @var Product $product */
+ $product = Bootstrap::getObjectManager()->get(Product::class);
+
+ return $product->getIdBySku($sku);
+ }
+}