diff --git a/.php_cs b/.php_cs
index c7f43f02f4fc521b53bf797e30a3cc5d3e3f2821..5bd1a01537611de83ce9e9a8bb4bae01da274a9f 100644
--- a/.php_cs
+++ b/.php_cs
@@ -33,7 +33,6 @@ return Symfony\CS\Config\Config::create()
         'extra_empty_lines',
         'include',
         'join_function',
-        'multiline_array_trailing_comma',
         'namespace_no_leading_whitespace',
         'new_with_braces',
         'object_operator',
diff --git a/app/code/Magento/Backend/App/Action/Plugin/MassactionKey.php b/app/code/Magento/Backend/App/Action/Plugin/MassactionKey.php
index e2ce581806f63f7870249ff20e7abbe14263185d..44cfe2bb17dc86ded0078af0b2ef000a87e97137 100644
--- a/app/code/Magento/Backend/App/Action/Plugin/MassactionKey.php
+++ b/app/code/Magento/Backend/App/Action/Plugin/MassactionKey.php
@@ -7,29 +7,27 @@
  */
 namespace Magento\Backend\App\Action\Plugin;
 
+use Magento\Framework\App\RequestInterface;
+use Magento\Backend\App\AbstractAction;
+
 class MassactionKey
 {
     /**
      * Process massaction key
      *
-     * @param \Magento\Backend\App\AbstractAction $subject
-     * @param callable $proceed
-     * @param \Magento\Framework\App\RequestInterface $request
+     * @param AbstractAction $subject
+     * @param RequestInterface $request
      *
-     * @return mixed
+     * @return void
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundDispatch(
-        \Magento\Backend\App\AbstractAction $subject,
-        \Closure $proceed,
-        \Magento\Framework\App\RequestInterface $request
-    ) {
+    public function beforeDispatch(AbstractAction $subject, RequestInterface $request)
+    {
         $key = $request->getPost('massaction_prepare_key');
         if ($key) {
             $postData = $request->getPost($key);
             $value = is_array($postData) ? $postData : explode(',', $postData);
             $request->setPostValue($key, $value ? $value : null);
         }
-        return $proceed($request);
     }
 }
diff --git a/app/code/Magento/Backend/Test/Unit/App/Action/Plugin/MassactionKeyTest.php b/app/code/Magento/Backend/Test/Unit/App/Action/Plugin/MassactionKeyTest.php
index b615385f0546e031086e17f179b13e13d6d06cac..3f4af8c3259e95aebc109b3ca08a16babe5ee6db 100644
--- a/app/code/Magento/Backend/Test/Unit/App/Action/Plugin/MassactionKeyTest.php
+++ b/app/code/Magento/Backend/Test/Unit/App/Action/Plugin/MassactionKeyTest.php
@@ -6,6 +6,8 @@
 namespace Magento\Backend\Test\Unit\App\Action\Plugin;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Backend\App\AbstractAction;
+use Magento\Framework\App\RequestInterface;
 
 class MassactionKeyTest extends \PHPUnit_Framework_TestCase
 {
@@ -15,17 +17,12 @@ class MassactionKeyTest extends \PHPUnit_Framework_TestCase
     protected $plugin;
 
     /**
-     * @var \Closure
-     */
-    protected $closureMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \PHPUnit_Framework_MockObject_MockObject|RequestInterface
      */
     protected $requestMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \PHPUnit_Framework_MockObject_MockObject|AbstractAction
      */
     protected $subjectMock;
 
@@ -35,27 +32,32 @@ class MassactionKeyTest extends \PHPUnit_Framework_TestCase
             return 'Expected';
         };
         $this->subjectMock = $this->getMock(\Magento\Backend\App\AbstractAction::class, [], [], '', false);
-        $this->requestMock = $this->getMock(\Magento\Framework\App\Request\Http::class, [], [], '', false);
+        $this->requestMock = $this->getMockForAbstractClass(
+            RequestInterface::class,
+            [],
+            '',
+            false,
+            false,
+            true,
+            ['getPost', 'setPostValue']
+        );
 
         $objectManager = new ObjectManager($this);
         $this->plugin = $objectManager->getObject(
             \Magento\Backend\App\Action\Plugin\MassactionKey::class,
             [
                 'subject' => $this->subjectMock,
-                'closure' => $this->closureMock,
                 'request' => $this->requestMock,
             ]
         );
     }
 
     /**
-     * @covers \Magento\Backend\App\Action\Plugin\MassactionKey::aroundDispatch
-     *
      * @param $postData array|string
      * @param array $convertedData
-     * @dataProvider aroundDispatchDataProvider
+     * @dataProvider beforeDispatchDataProvider
      */
-    public function testAroundDispatchWhenMassactionPrepareKeyRequestExists($postData, $convertedData)
+    public function testBeforeDispatchWhenMassactionPrepareKeyRequestExists($postData, $convertedData)
     {
         $this->requestMock->expects($this->at(0))
             ->method('getPost')
@@ -69,13 +71,10 @@ class MassactionKeyTest extends \PHPUnit_Framework_TestCase
             ->method('setPostValue')
             ->with('key', $convertedData);
 
-        $this->assertEquals(
-            'Expected',
-            $this->plugin->aroundDispatch($this->subjectMock, $this->closureMock, $this->requestMock)
-        );
+        $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock);
     }
 
-    public function aroundDispatchDataProvider()
+    public function beforeDispatchDataProvider()
     {
         return [
             'post_data_is_array' => [['key'], ['key']],
@@ -83,10 +82,7 @@ class MassactionKeyTest extends \PHPUnit_Framework_TestCase
         ];
     }
 
-    /**
-     * @covers \Magento\Backend\App\Action\Plugin\MassactionKey::aroundDispatch
-     */
-    public function testAroundDispatchWhenMassactionPrepareKeyRequestNotExists()
+    public function testBeforeDispatchWhenMassactionPrepareKeyRequestNotExists()
     {
         $this->requestMock->expects($this->once())
             ->method('getPost')
@@ -95,9 +91,6 @@ class MassactionKeyTest extends \PHPUnit_Framework_TestCase
         $this->requestMock->expects($this->never())
             ->method('setPostValue');
 
-        $this->assertEquals(
-            'Expected',
-            $this->plugin->aroundDispatch($this->subjectMock, $this->closureMock, $this->requestMock)
-        );
+        $this->plugin->beforeDispatch($this->subjectMock, $this->requestMock);
     }
 }
diff --git a/app/code/Magento/Bundle/Model/Plugin/QuoteItem.php b/app/code/Magento/Bundle/Model/Plugin/QuoteItem.php
index 8861d864b8180f0c11191a3014c5e49791263656..4009f6e3496bbb1ef6f463cac588dc15d416481b 100644
--- a/app/code/Magento/Bundle/Model/Plugin/QuoteItem.php
+++ b/app/code/Magento/Bundle/Model/Plugin/QuoteItem.php
@@ -5,34 +5,34 @@
  */
 namespace Magento\Bundle\Model\Plugin;
 
-use Closure;
+use Magento\Quote\Model\Quote\Item\ToOrderItem;
+use Magento\Sales\Api\Data\OrderItemInterface;
+use Magento\Quote\Model\Quote\Item\AbstractItem;
 
+/**
+ * Plugin for Magento\Quote\Model\Quote\Item\ToOrderItem
+ */
 class QuoteItem
 {
     /**
      * Add bundle attributes to order data
      *
-     * @param \Magento\Quote\Model\Quote\Item\ToOrderItem $subject
-     * @param callable $proceed
-     * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item
-     * @param array $additional
-     * @return \Magento\Sales\Model\Order\Item
+     * @param ToOrderItem $subject
+     * @param OrderItemInterface $orderItem
+     * @param AbstractItem $item
+     * @param array $data
+     * @return OrderItemInterface
+     *
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundConvert(
-        \Magento\Quote\Model\Quote\Item\ToOrderItem $subject,
-        Closure $proceed,
-        \Magento\Quote\Model\Quote\Item\AbstractItem $item,
-        $additional = []
-    ) {
-        /** @var $orderItem \Magento\Sales\Model\Order\Item */
-        $orderItem = $proceed($item, $additional);
-
+    public function afterConvert(ToOrderItem $subject, OrderItemInterface $orderItem, AbstractItem $item, $data = [])
+    {
         if ($attributes = $item->getProduct()->getCustomOption('bundle_selection_attributes')) {
             $productOptions = $orderItem->getProductOptions();
             $productOptions['bundle_selection_attributes'] = $attributes->getValue();
             $orderItem->setProductOptions($productOptions);
         }
+
         return $orderItem;
     }
 }
diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Plugin/QuoteItemTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Plugin/QuoteItemTest.php
index 6feb4472aaa9a938165f16eb1f37b9523246bad5..03bac48a71be10d28343a935c3e198363003e69e 100644
--- a/app/code/Magento/Bundle/Test/Unit/Model/Plugin/QuoteItemTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Model/Plugin/QuoteItemTest.php
@@ -5,42 +5,66 @@
  */
 namespace Magento\Bundle\Test\Unit\Model\Plugin;
 
+use Magento\Quote\Model\Quote\Item\ToOrderItem;
+use Magento\Sales\Api\Data\OrderItemInterface;
+use Magento\Quote\Model\Quote\Item\AbstractItem;
+use Magento\Catalog\Model\Product;
+
 class QuoteItemTest extends \PHPUnit_Framework_TestCase
 {
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|Product
+     */
+    private $productMock;
+
     /** @var \Magento\Bundle\Model\Plugin\QuoteItem */
     protected $model;
 
-    /** @var \PHPUnit_Framework_MockObject_MockObject */
+    /** @var \PHPUnit_Framework_MockObject_MockObject|AbstractItem */
     protected $quoteItemMock;
 
-    /** @var \PHPUnit_Framework_MockObject_MockObject */
+    /** @var \PHPUnit_Framework_MockObject_MockObject|OrderItemInterface */
     protected $orderItemMock;
 
     /**
-     * @var /PHPUnit_Framework_MockObject_MockObject
+     * @var \PHPUnit_Framework_MockObject_MockObject|ToOrderItem
      */
     protected $subjectMock;
 
-    /**
-     * @var /Closure
-     */
-    protected $closureMock;
-
     protected function setUp()
     {
-        $this->orderItemMock = $this->getMock(\Magento\Sales\Model\Order\Item::class, [], [], '', false);
-        $this->quoteItemMock = $this->getMock(\Magento\Quote\Model\Quote\Item::class, [], [], '', false);
-        $orderItem = $this->orderItemMock;
-        $this->closureMock = function () use ($orderItem) {
-            return $orderItem;
-        };
-        $this->subjectMock = $this->getMock(\Magento\Quote\Model\Quote\Item\ToOrderItem::class, [], [], '', false);
+        $this->orderItemMock = $this->getMockForAbstractClass(
+            OrderItemInterface::class,
+            [],
+            '',
+            false,
+            false,
+            true,
+            ['getProductOptions', 'setProductOptions']
+        );
+        $this->quoteItemMock = $this->getMockForAbstractClass(
+            AbstractItem::class,
+            [],
+            '',
+            false,
+            false,
+            true,
+            ['getProduct']
+        );
+        $this->subjectMock = $this->getMock(ToOrderItem::class, [], [], '', false);
+        $this->productMock = $this->getMock(Product::class, [], [], '', false);
         $this->model = new \Magento\Bundle\Model\Plugin\QuoteItem();
     }
 
     public function testAroundItemToOrderItemPositive()
     {
-        $productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false);
+        $attributeValue = 'test_value';
+        $productOptions = [
+            'option_1' => 'value_1',
+            'option_2' => 'value_2'
+        ];
+        $expectedOptions = $productOptions + ['bundle_selection_attributes' => $attributeValue];
+
         $bundleAttribute = $this->getMock(
             \Magento\Catalog\Model\Product\Configuration\Item\Option::class,
             [],
@@ -48,38 +72,34 @@ class QuoteItemTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $productMock->expects(
-            $this->once()
-        )->method(
-            'getCustomOption'
-        )->with(
-            'bundle_selection_attributes'
-        )->will(
-            $this->returnValue($bundleAttribute)
-        );
-        $this->quoteItemMock->expects($this->once())->method('getProduct')->will($this->returnValue($productMock));
-        $this->orderItemMock->expects($this->once())->method('setProductOptions');
+        $bundleAttribute->expects($this->once())
+            ->method('getValue')
+            ->willReturn($attributeValue);
 
-        $orderItem = $this->model->aroundConvert($this->subjectMock, $this->closureMock, $this->quoteItemMock, []);
+        $this->productMock->expects($this->once())
+            ->method('getCustomOption')
+            ->with('bundle_selection_attributes')
+            ->willReturn($bundleAttribute);
+        $this->quoteItemMock->expects($this->once())->method('getProduct')->willReturn($this->productMock);
+
+        $this->orderItemMock->expects($this->once())->method('getProductOptions')->willReturn($productOptions);
+        $this->orderItemMock->expects($this->once())->method('setProductOptions')->with($expectedOptions);
+
+        $orderItem = $this->model->afterConvert($this->subjectMock, $this->orderItemMock, $this->quoteItemMock);
         $this->assertSame($this->orderItemMock, $orderItem);
     }
 
     public function testAroundItemToOrderItemNegative()
     {
-        $productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false);
-        $productMock->expects(
-            $this->once()
-        )->method(
-            'getCustomOption'
-        )->with(
-            'bundle_selection_attributes'
-        )->will(
-            $this->returnValue(false)
-        );
-        $this->quoteItemMock->expects($this->once())->method('getProduct')->will($this->returnValue($productMock));
+        $this->productMock->expects($this->once())
+            ->method('getCustomOption')
+            ->with('bundle_selection_attributes')->willReturn(false);
+
+        $this->quoteItemMock->expects($this->once())->method('getProduct')
+            ->willReturn($this->productMock);
         $this->orderItemMock->expects($this->never())->method('setProductOptions');
 
-        $orderItem = $this->model->aroundConvert($this->subjectMock, $this->closureMock, $this->quoteItemMock, []);
+        $orderItem = $this->model->afterConvert($this->subjectMock, $this->orderItemMock, $this->quoteItemMock);
         $this->assertSame($this->orderItemMock, $orderItem);
     }
 }
diff --git a/app/code/Magento/Catalog/Model/CatalogRegistry.php b/app/code/Magento/Catalog/Model/CatalogRegistry.php
deleted file mode 100644
index 7eb7b3f77f8b1d614d5455f455ee229440bcef9e..0000000000000000000000000000000000000000
--- a/app/code/Magento/Catalog/Model/CatalogRegistry.php
+++ /dev/null
@@ -1,51 +0,0 @@
-<?php
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Catalog\Model;
-
-use Magento\Framework\Model\EntityRegistry;
-use Magento\Framework\EntityManager\EntityManager;
-
-/**
- * Class CatalogRegistry
- */
-class CatalogRegistry
-{
-    /**
-     * @var EntityRegistry
-     */
-    protected $entityRegistry;
-
-    /**
-     * CatalogRegistry constructor.
-     *
-     * @param EntityRegistry $entityRegistry
-     */
-    public function __construct(
-        EntityRegistry $entityRegistry
-    ) {
-        $this->entityRegistry = $entityRegistry;
-    }
-
-    /**
-     * @param EntityManager $subject
-     * @param \Closure $proceed
-     * @param string $entityType
-     * @param object $entity
-     * @param string $identifier
-     * @return null|object
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
-     */
-    public function aroundLoad(EntityManager $subject, \Closure $proceed, $entityType, $entity, $identifier)
-    {
-        $object = $this->entityRegistry->retrieve($entityType, $identifier);
-        if (!$object) {
-            $object = $proceed($entityType, $entity, $identifier);
-            $this->entityRegistry->register($entityType, $identifier, $object);
-        }
-        return $object;
-    }
-}
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Plugin/IndexerConfigData.php b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Plugin/IndexerConfigData.php
index ae796a8b979fc402d6e6722dde06f8f50b94aeec..3b8061d2f93387ffdb15cf65dbee9193ce3964a7 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Plugin/IndexerConfigData.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Plugin/IndexerConfigData.php
@@ -5,17 +5,20 @@
  */
 namespace Magento\Catalog\Model\Indexer\Category\Flat\Plugin;
 
+use Magento\Indexer\Model\Config\Data;
+use Magento\Catalog\Model\Indexer\Category\Flat\State;
+
 class IndexerConfigData
 {
     /**
-     * @var \Magento\Catalog\Model\Indexer\Category\Flat\State
+     * @var State
      */
     protected $state;
 
     /**
-     * @param \Magento\Catalog\Model\Indexer\Category\Flat\State $state
+     * @param State $state
      */
-    public function __construct(\Magento\Catalog\Model\Indexer\Category\Flat\State $state)
+    public function __construct(State $state)
     {
         $this->state = $state;
     }
@@ -23,24 +26,18 @@ class IndexerConfigData
     /**
      *  Unset indexer data in configuration if flat is disabled
      *
-     * @param \Magento\Indexer\Model\Config\Data $subject
-     * @param callable $proceed
+     * @param Data $subject
+     * @param mixed $data
      * @param string $path
      * @param mixed $default
      *
      * @return mixed
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundGet(
-        \Magento\Indexer\Model\Config\Data $subject,
-        \Closure $proceed,
-        $path = null,
-        $default = null
-    ) {
-        $data = $proceed($path, $default);
-
+    public function afterGet(Data $subject, $data, $path = null, $default = null)
+    {
         if (!$this->state->isFlatEnabled()) {
-            $indexerId = \Magento\Catalog\Model\Indexer\Category\Flat\State::INDEXER_ID;
+            $indexerId = State::INDEXER_ID;
             if (!$path && isset($data[$indexerId])) {
                 unset($data[$indexerId]);
             } elseif ($path) {
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Plugin/StoreGroup.php b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Plugin/StoreGroup.php
index 7c1c87278fb7184817f75af47f56ca084765431e..502bb8b542f4efaa122bf341548615b93a4fa751 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Plugin/StoreGroup.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Flat/Plugin/StoreGroup.php
@@ -5,24 +5,34 @@
  */
 namespace Magento\Catalog\Model\Indexer\Category\Flat\Plugin;
 
+use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
+use Magento\Framework\Model\AbstractModel;
+use Magento\Framework\Indexer\IndexerRegistry;
+use Magento\Catalog\Model\Indexer\Category\Flat\State;
+
 class StoreGroup
 {
-    /** @var \Magento\Framework\Indexer\IndexerRegistry */
+    /**
+     * @var bool
+     */
+    private $needInvalidating;
+
+    /**
+     * @var IndexerRegistry
+     */
     protected $indexerRegistry;
 
     /**
-     * @var \Magento\Catalog\Model\Indexer\Category\Flat\State
+     * @var State
      */
     protected $state;
 
     /**
-     * @param \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry
-     * @param \Magento\Catalog\Model\Indexer\Category\Flat\State $state
+     * @param IndexerRegistry $indexerRegistry
+     * @param State $state
      */
-    public function __construct(
-        \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry,
-        \Magento\Catalog\Model\Indexer\Category\Flat\State $state
-    ) {
+    public function __construct(IndexerRegistry $indexerRegistry, State $state)
+    {
         $this->indexerRegistry = $indexerRegistry;
         $this->state = $state;
     }
@@ -30,31 +40,41 @@ class StoreGroup
     /**
      * Validate changes for invalidating indexer
      *
-     * @param \Magento\Framework\Model\AbstractModel $group
+     * @param AbstractModel $group
      * @return bool
      */
-    protected function validate(\Magento\Framework\Model\AbstractModel $group)
+    protected function validate(AbstractModel $group)
     {
         return $group->dataHasChangedFor('root_category_id') && !$group->isObjectNew();
     }
 
     /**
-     * @param \Magento\Framework\Model\ResourceModel\Db\AbstractDb $subject
-     * @param callable $proceed
-     * @param \Magento\Framework\Model\AbstractModel $group
+     * Check if need invalidate flat category indexer
      *
-     * @return \Magento\Framework\Model\ResourceModel\Db\AbstractDb
+     * @param AbstractDb $subject
+     * @param AbstractModel $group
+     *
+     * @return void
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundSave(
-        \Magento\Framework\Model\ResourceModel\Db\AbstractDb $subject,
-        \Closure $proceed,
-        \Magento\Framework\Model\AbstractModel $group
-    ) {
-        $needInvalidating = $this->validate($group);
-        $objectResource = $proceed($group);
-        if ($needInvalidating && $this->state->isFlatEnabled()) {
-            $this->indexerRegistry->get(\Magento\Catalog\Model\Indexer\Category\Flat\State::INDEXER_ID)->invalidate();
+    public function beforeSave(AbstractDb $subject, AbstractModel $group)
+    {
+        $this->needInvalidating = $this->validate($group);
+    }
+
+    /**
+     * Invalidate flat category indexer if root category changed for store group
+     *
+     * @param AbstractDb $subject
+     * @param AbstractDb $objectResource
+     *
+     * @return AbstractDb
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterSave(AbstractDb $subject, AbstractDb $objectResource)
+    {
+        if ($this->needInvalidating && $this->state->isFlatEnabled()) {
+            $this->indexerRegistry->get(State::INDEXER_ID)->invalidate();
         }
 
         return $objectResource;
diff --git a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php
index dce748c34fa3fc9e8534af16b895df94d92f9f40..f81c0165b638a2034a1c57209a8959cb404d49a2 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Category/Product/Plugin/StoreGroup.php
@@ -5,35 +5,58 @@
  */
 namespace Magento\Catalog\Model\Indexer\Category\Product\Plugin;
 
+use Magento\Framework\Indexer\IndexerRegistry;
+use Magento\Framework\Model\ResourceModel\Db\AbstractDb;
+use Magento\Framework\Model\AbstractModel;
+use Magento\Catalog\Model\Indexer\Category\Product;
+
 class StoreGroup
 {
-    /** @var \Magento\Framework\Indexer\IndexerRegistry */
+    /**
+     * @var bool
+     */
+    private $needInvalidating;
+
+    /**
+     * @var IndexerRegistry
+     */
     protected $indexerRegistry;
 
     /**
-     * @param \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry
+     * @param IndexerRegistry $indexerRegistry
      */
-    public function __construct(\Magento\Framework\Indexer\IndexerRegistry $indexerRegistry)
+    public function __construct(IndexerRegistry $indexerRegistry)
     {
         $this->indexerRegistry = $indexerRegistry;
     }
 
     /**
-     * @param \Magento\Framework\Model\ResourceModel\Db\AbstractDb $subject
-     * @param callable $proceed
-     * @param \Magento\Framework\Model\AbstractModel $group
-     * @return mixed
+     * Check if need invalidate flat category indexer
+     *
+     * @param AbstractDb $subject
+     * @param AbstractModel $group
+     *
+     * @return void
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundSave(
-        \Magento\Framework\Model\ResourceModel\Db\AbstractDb $subject,
-        \Closure $proceed,
-        \Magento\Framework\Model\AbstractModel $group
-    ) {
-        $needInvalidating = $this->validate($group);
-        $objectResource = $proceed($group);
-        if ($needInvalidating) {
-            $this->indexerRegistry->get(\Magento\Catalog\Model\Indexer\Category\Product::INDEXER_ID)->invalidate();
+    public function beforeSave(AbstractDb $subject, AbstractModel $group)
+    {
+        $this->needInvalidating = $this->validate($group);
+    }
+
+    /**
+     * Invalidate flat product
+     *
+     * @param AbstractDb $subject
+     * @param AbstractDb $objectResource
+     *
+     * @return AbstractDb
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterSave(AbstractDb $subject, AbstractDb $objectResource)
+    {
+        if ($this->needInvalidating) {
+            $this->indexerRegistry->get(Product::INDEXER_ID)->invalidate();
         }
 
         return $objectResource;
@@ -42,15 +65,12 @@ class StoreGroup
     /**
      * Validate changes for invalidating indexer
      *
-     * @param \Magento\Framework\Model\AbstractModel $group
+     * @param AbstractModel $group
      * @return bool
      */
-    protected function validate(\Magento\Framework\Model\AbstractModel $group)
+    protected function validate(AbstractModel $group)
     {
-        return ($group->dataHasChangedFor(
-            'website_id'
-        ) || $group->dataHasChangedFor(
-            'root_category_id'
-        )) && !$group->isObjectNew();
+        return ($group->dataHasChangedFor('website_id') || $group->dataHasChangedFor('root_category_id'))
+               && !$group->isObjectNew();
     }
 }
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Plugin/AttributeSet.php b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Plugin/AttributeSet.php
index e9119405143444984bc7895fecc04909aeb19fed..66251853e2bbb8e147ffa21541634820d0e388cd 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Plugin/AttributeSet.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Eav/Plugin/AttributeSet.php
@@ -5,10 +5,25 @@
  */
 namespace Magento\Catalog\Model\Indexer\Product\Eav\Plugin;
 
+use Magento\Eav\Model\Entity\Attribute\Set as EavAttributeSet;
+use Magento\Catalog\Model\Indexer\Product\Eav\Processor;
+use Magento\Eav\Model\Entity\Attribute\SetFactory;
+use Magento\Framework\App\ObjectManager;
+
 class AttributeSet
 {
     /**
-     * @var \Magento\Catalog\Model\Indexer\Product\Eav\Processor
+     * @var bool
+     */
+    private $requiresReindex;
+
+    /**
+     * @var SetFactory
+     */
+    private $setFactory;
+
+    /**
+     * @var Processor
      */
     protected $_indexerEavProcessor;
 
@@ -18,43 +33,66 @@ class AttributeSet
     protected $_attributeFilter;
 
     /**
-     * @param \Magento\Catalog\Model\Indexer\Product\Eav\Processor $indexerEavProcessor
+     * @param Processor $indexerEavProcessor
      * @param AttributeSet\IndexableAttributeFilter $filter
      */
-    public function __construct(
-        \Magento\Catalog\Model\Indexer\Product\Eav\Processor $indexerEavProcessor,
-        AttributeSet\IndexableAttributeFilter $filter
-    ) {
+    public function __construct(Processor $indexerEavProcessor, AttributeSet\IndexableAttributeFilter $filter)
+    {
         $this->_indexerEavProcessor = $indexerEavProcessor;
         $this->_attributeFilter = $filter;
     }
 
     /**
-     * Invalidate EAV indexer if attribute set has indexable attributes changes
+     * Return attribute set factory
      *
-     * @param \Magento\Eav\Model\Entity\Attribute\Set $subject
-     * @param callable $proceed
+     * @return SetFactory
+     * @deprecated
+     */
+    private function getAttributeSetFactory()
+    {
+        if ($this->setFactory === null) {
+            $this->setFactory = ObjectManager::getInstance()->get(SetFactory::class);
+        }
+        return $this->setFactory;
+    }
+
+    /**
+     * Check whether is needed to invalidate EAV indexer
      *
-     * @return \Magento\Eav\Model\Entity\Attribute\Set
+     * @param EavAttributeSet $subject
      *
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     * @return void
      */
-    public function aroundSave(\Magento\Eav\Model\Entity\Attribute\Set $subject, \Closure $proceed)
+    public function beforeSave(EavAttributeSet $subject)
     {
-        $requiresReindex = false;
+        $this->requiresReindex = false;
         if ($subject->getId()) {
-            /** @var \Magento\Eav\Model\Entity\Attribute\Set $originalSet */
-            $originalSet = clone $subject;
+            /** @var EavAttributeSet $originalSet */
+            $originalSet = $this->getAttributeSetFactory()->create();
             $originalSet->initFromSkeleton($subject->getId());
             $originalAttributeCodes = array_flip($this->_attributeFilter->filter($originalSet));
-            $subjectAttributeCodes = array_flip($this->_attributeFilter->filter($subject));
-            $requiresReindex = (bool)count(array_merge(
-                array_diff_key($subjectAttributeCodes, $originalAttributeCodes),
-                array_diff_key($originalAttributeCodes, $subjectAttributeCodes)
-            ));
+            $subjectAttributeCodes  = array_flip($this->_attributeFilter->filter($subject));
+            $this->requiresReindex  = (bool)count(
+                array_merge(
+                    array_diff_key($subjectAttributeCodes, $originalAttributeCodes),
+                    array_diff_key($originalAttributeCodes, $subjectAttributeCodes)
+                )
+            );
         }
-        $result = $proceed();
-        if ($requiresReindex) {
+    }
+
+    /**
+     * Invalidate EAV indexer if attribute set has indexable attributes changes
+     *
+     * @param EavAttributeSet $subject
+     * @param EavAttributeSet $result
+     * @return EavAttributeSet
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterSave(EavAttributeSet $subject, EavAttributeSet $result)
+    {
+        if ($this->requiresReindex) {
             $this->_indexerEavProcessor->markIndexerAsInvalid();
         }
         return $result;
diff --git a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Plugin/IndexerConfigData.php b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Plugin/IndexerConfigData.php
index 60394766f4b529d28a977dd1453c4a3539d8f49c..0777e9a06e3484ac2e1cd7ac586207603a81b8b2 100644
--- a/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Plugin/IndexerConfigData.php
+++ b/app/code/Magento/Catalog/Model/Indexer/Product/Flat/Plugin/IndexerConfigData.php
@@ -5,51 +5,62 @@
  */
 namespace Magento\Catalog\Model\Indexer\Product\Flat\Plugin;
 
+use Magento\Catalog\Model\Indexer\Product\Flat\State as ProductFlatIndexerState;
+use Magento\Indexer\Model\Config\Data as ConfigData;
+use Magento\Catalog\Model\Indexer\Product\Flat\Processor as ProductFlatIndexerProcessor;
+
+/**
+ * Plugin for Magento\Indexer\Model\Config\Data
+ */
 class IndexerConfigData
 {
     /**
-     * @var \Magento\Catalog\Model\Indexer\Product\Flat\State
+     * @var ProductFlatIndexerState
      */
-    protected $_state;
+    protected $state;
 
     /**
-     * @param \Magento\Catalog\Model\Indexer\Product\Flat\State $state
+     * @param ProductFlatIndexerState $state
      */
-    public function __construct(\Magento\Catalog\Model\Indexer\Product\Flat\State $state)
+    public function __construct(ProductFlatIndexerState $state)
     {
-        $this->_state = $state;
+        $this->state = $state;
     }
 
     /**
-     * Around get handler
+     * Modify returned config when flat indexer is disabled
      *
-     * @param \Magento\Indexer\Model\Config\Data $subject
-     * @param callable $proceed
+     * @param ConfigData $subject
+     * @param mixed $data
      * @param string $path
      * @param string $default
+     * @return mixed
      *
-     * @return mixed|null
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      *
      */
-    public function aroundGet(
-        \Magento\Indexer\Model\Config\Data $subject,
-        \Closure $proceed,
-        $path = null,
-        $default = null
-    ) {
-        $data = $proceed($path, $default);
-
-        if (!$this->_state->isFlatEnabled()) {
-            $indexerId = \Magento\Catalog\Model\Indexer\Product\Flat\Processor::INDEXER_ID;
-            if (!$path && isset($data[$indexerId])) {
-                unset($data[$indexerId]);
-            } elseif ($path) {
-                list($firstKey,) = explode('/', $path);
-                if ($firstKey == $indexerId) {
-                    $data = $default;
-                }
-            }
+    public function afterGet(ConfigData $subject, $data, $path = null, $default = null)
+    {
+        if ($this->state->isFlatEnabled()) {
+            return $data;
+        }
+
+        $indexerId = ProductFlatIndexerProcessor::INDEXER_ID;
+
+        if (!$path && isset($data[$indexerId])) {
+            unset($data[$indexerId]);
+
+            return $data;
+        }
+
+        if (!$path) {
+            return $data;
+        }
+
+        list($firstKey) = explode('/', $path);
+
+        if ($firstKey == $indexerId) {
+            $data = $default;
         }
 
         return $data;
diff --git a/app/code/Magento/Catalog/Model/Plugin/QuoteItemProductOption.php b/app/code/Magento/Catalog/Model/Plugin/QuoteItemProductOption.php
index 206acf7bf0f9595b9cdd4e827accd0fa2b70d530..7c8249b728cab55dd1d607dc307970a0e79abff3 100644
--- a/app/code/Magento/Catalog/Model/Plugin/QuoteItemProductOption.php
+++ b/app/code/Magento/Catalog/Model/Plugin/QuoteItemProductOption.php
@@ -5,44 +5,54 @@
  */
 namespace Magento\Catalog\Model\Plugin;
 
+use Magento\Quote\Model\Quote\Item\ToOrderItem as QuoteToOrderItem;
+use Magento\Quote\Model\Quote\Item\AbstractItem as AbstractQuoteItem;
+use Magento\Catalog\Model\Product\Option as ProductOption;
+
+/**
+ * Plugin for Magento\Quote\Model\Quote\Item\ToOrderItem
+ */
 class QuoteItemProductOption
 {
     /**
-     * @param \Magento\Quote\Model\Quote\Item\ToOrderItem $subject
-     * @param callable $proceed
-     * @param \Magento\Quote\Model\Quote\Item\AbstractItem $item
-     * @param array $additional
-     * @return \Magento\Sales\Model\Order\Item
+     * Perform preparations for custom options
+     *
+     * @param QuoteToOrderItem $subject
+     * @param AbstractQuoteItem $quoteItem
+     * @param array $data
+     * @return void
+     *
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundConvert(
-        \Magento\Quote\Model\Quote\Item\ToOrderItem $subject,
-        \Closure $proceed,
-        \Magento\Quote\Model\Quote\Item\AbstractItem $item,
-        $additional = []
+    public function beforeConvert(
+        QuoteToOrderItem $subject,
+        AbstractQuoteItem $quoteItem,
+        $data = []
     ) {
-        /** @var $orderItem \Magento\Sales\Model\Order\Item */
-        $orderItem = $proceed($item, $additional);
+        if (!is_array($quoteItem->getOptions())) {
+            return;
+        }
+
+        foreach ($quoteItem->getOptions() as $itemOption) {
+            $code = explode('_', $itemOption->getCode());
+
+            if (!isset($code[1]) || !is_numeric($code[1])) {
+                continue;
+            }
+
+            $option = $quoteItem->getProduct()->getOptionById($code[1]);
+
+            if (!$option || $option->getType() != ProductOption::OPTION_TYPE_FILE) {
+                continue;
+            }
 
-        if (is_array($item->getOptions())) {
-            foreach ($item->getOptions() as $itemOption) {
-                $code = explode('_', $itemOption->getCode());
-                if (isset($code[1]) && is_numeric($code[1])) {
-                    $option = $item->getProduct()->getOptionById($code[1]);
-                    if ($option && $option->getType() == \Magento\Catalog\Model\Product\Option::OPTION_TYPE_FILE) {
-                        try {
-                            $option->groupFactory(
-                                $option->getType()
-                            )->setQuoteItemOption(
-                                $itemOption
-                            )->copyQuoteToOrder();
-                        } catch (\Exception $e) {
-                            continue;
-                        }
-                    }
-                }
+            try {
+                $option->groupFactory($option->getType())
+                    ->setQuoteItemOption($itemOption)
+                    ->copyQuoteToOrder();
+            } catch (\Exception $e) {
+                continue;
             }
         }
-        return $orderItem;
     }
 }
diff --git a/app/code/Magento/Catalog/Plugin/Model/ResourceModel/Attribute/Save.php b/app/code/Magento/Catalog/Plugin/Model/ResourceModel/Attribute/Save.php
index 1f1f4d3fdb2e2e97a7a073ab46f1f365d0c953b7..b7d77f40f6899dc99f0baf3efacbd72d56b99594 100644
--- a/app/code/Magento/Catalog/Plugin/Model/ResourceModel/Attribute/Save.php
+++ b/app/code/Magento/Catalog/Plugin/Model/ResourceModel/Attribute/Save.php
@@ -6,44 +6,43 @@
 
 namespace Magento\Catalog\Plugin\Model\ResourceModel\Attribute;
 
+use Magento\Catalog\Model\ResourceModel\Attribute;
+use Magento\PageCache\Model\Config;
+use Magento\Framework\App\Cache\TypeListInterface;
+
 class Save
 {
     /**
-     * @var \Magento\PageCache\Model\Config
+     * @var Config
      */
     protected $config;
 
     /**
-     * @var \Magento\Framework\App\Cache\TypeListInterface
+     * @var TypeListInterface
      */
     protected $typeList;
 
     /**
-     * @param \Magento\PageCache\Model\Config $config
-     * @param \Magento\Framework\App\Cache\TypeListInterface $typeList
+     * @param Config $config
+     * @param TypeListInterface $typeList
      */
-    public function __construct(
-        \Magento\PageCache\Model\Config $config,
-        \Magento\Framework\App\Cache\TypeListInterface $typeList
-    ) {
+    public function __construct(Config $config, TypeListInterface $typeList)
+    {
         $this->config = $config;
         $this->typeList = $typeList;
     }
 
     /**
-     * @param \Magento\Catalog\Model\ResourceModel\Attribute $subject
-     * @param callable $proceed
-     * @param \Magento\Framework\Model\AbstractModel $attribute
-     * @return mixed
+     * Invalidate full page cache after saving attribute
+     *
+     * @param Attribute $subject
+     * @param Attribute $result
+     * @return Attribute $result
      *
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundSave(
-        \Magento\Catalog\Model\ResourceModel\Attribute $subject,
-        \Closure $proceed,
-        \Magento\Framework\Model\AbstractModel $attribute
-    ) {
-        $result = $proceed($attribute);
+    public function afterSave(Attribute $subject, Attribute $result)
+    {
         if ($this->config->isEnabled()) {
             $this->typeList->invalidate('full_page');
         }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/IndexerConfigDataTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/IndexerConfigDataTest.php
index 4cc35fd0cafb54f7fe78ef10be77b449ad0b6d5e..cde2365e21b6b649a5b3cb46a2221a3b728ea58e 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/IndexerConfigDataTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/IndexerConfigDataTest.php
@@ -5,36 +5,33 @@
  */
 namespace Magento\Catalog\Test\Unit\Model\Indexer\Category\Flat\Plugin;
 
+use Magento\Catalog\Model\Indexer\Category\Flat\Plugin\IndexerConfigData;
+use Magento\Catalog\Model\Indexer\Category\Flat\State;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Indexer\Model\Config\Data;
+
 class IndexerConfigDataTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Catalog\Model\Indexer\Category\Flat\Plugin\IndexerConfigData
+     * @var IndexerConfigData
      */
     protected $model;
 
     /**
-     * @var \Magento\Catalog\Model\Indexer\Category\Flat\State|\PHPUnit_Framework_MockObject_MockObject
+     * @var State|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $stateMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var Data|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $subjectMock;
 
     protected function setUp()
     {
-        $this->stateMock = $this->getMock(
-            \Magento\Catalog\Model\Indexer\Category\Flat\State::class,
-            ['isFlatEnabled'],
-            [],
-            '',
-            false
-        );
-
-        $this->subjectMock = $this->getMock(\Magento\Indexer\Model\Config\Data::class, [], [], '', false);
-
-        $this->model = new \Magento\Catalog\Model\Indexer\Category\Flat\Plugin\IndexerConfigData($this->stateMock);
+        $this->stateMock = $this->getMock(State::class, ['isFlatEnabled'], [], '', false);
+        $this->subjectMock = $this->getMock(Data::class, [], [], '', false);
+        $this->model = (new ObjectManager($this))->getObject(IndexerConfigData::class, ['state' => $this->stateMock]);
     }
 
     /**
@@ -48,10 +45,7 @@ class IndexerConfigDataTest extends \PHPUnit_Framework_TestCase
     public function testAroundGet($isFlat, $path, $default, $inputData, $outputData)
     {
         $this->stateMock->expects($this->once())->method('isFlatEnabled')->will($this->returnValue($isFlat));
-        $closureMock = function () use ($inputData) {
-            return $inputData;
-        };
-        $this->assertEquals($outputData, $this->model->aroundGet($this->subjectMock, $closureMock, $path, $default));
+        $this->assertEquals($outputData, $this->model->afterGet($this->subjectMock, $inputData, $path, $default));
     }
 
     public function aroundGetDataProvider()
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/StoreGroupTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/StoreGroupTest.php
index 32d7e19e6d46e9f04730c3162c9aea8833d7b091..9757f0aef26aaed6db2aa143b521b5bb53d94c94 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/StoreGroupTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/StoreGroupTest.php
@@ -5,17 +5,23 @@
  */
 namespace Magento\Catalog\Test\Unit\Model\Indexer\Category\Flat\Plugin;
 
-use \Magento\Catalog\Model\Indexer\Category\Flat\Plugin\StoreGroup;
+use Magento\Catalog\Model\Indexer\Category\Flat\Plugin\StoreGroup;
+use Magento\Framework\Indexer\IndexerInterface;
+use Magento\Catalog\Model\Indexer\Category\Flat\State;
+use Magento\Framework\Indexer\IndexerRegistry;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Store\Model\ResourceModel\Group;
+use Magento\Store\Model\Group as GroupModel;
 
 class StoreGroupTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Indexer\IndexerInterface
+     * @var \PHPUnit_Framework_MockObject_MockObject|IndexerInterface
      */
     protected $indexerMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\Indexer\Category\Flat\State
+     * @var \PHPUnit_Framework_MockObject_MockObject|State
      */
     protected $stateMock;
 
@@ -25,29 +31,24 @@ class StoreGroupTest extends \PHPUnit_Framework_TestCase
     protected $model;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \PHPUnit_Framework_MockObject_MockObject|Group
      */
     protected $subjectMock;
 
     /**
-     * @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
+     * @var IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $indexerRegistryMock;
 
     /**
-     * @var \Closure
-     */
-    protected $closureMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \PHPUnit_Framework_MockObject_MockObject|GroupModel
      */
     protected $groupMock;
 
     protected function setUp()
     {
         $this->indexerMock = $this->getMockForAbstractClass(
-            \Magento\Framework\Indexer\IndexerInterface::class,
+            IndexerInterface::class,
             [],
             '',
             false,
@@ -55,78 +56,64 @@ class StoreGroupTest extends \PHPUnit_Framework_TestCase
             true,
             ['getId', 'getState', '__wakeup']
         );
-        $this->stateMock = $this->getMock(
-            \Magento\Catalog\Model\Indexer\Category\Flat\State::class,
-            ['isFlatEnabled'],
-            [],
-            '',
-            false
-        );
-        $this->subjectMock = $this->getMock(\Magento\Store\Model\ResourceModel\Group::class, [], [], '', false);
+        $this->stateMock = $this->getMock(State::class, ['isFlatEnabled'], [], '', false);
+        $this->subjectMock = $this->getMock(Group::class, [], [], '', false);
 
         $this->groupMock = $this->getMock(
-            \Magento\Store\Model\Group::class,
+            GroupModel::class,
             ['dataHasChangedFor', 'isObjectNew', '__wakeup'],
             [],
             '',
             false
         );
-        $this->closureMock = function () {
-            return false;
-        };
 
         $this->indexerRegistryMock = $this->getMock(
-            \Magento\Framework\Indexer\IndexerRegistry::class,
+            IndexerRegistry::class,
             ['get'],
             [],
             '',
             false
         );
 
-        $this->model = new StoreGroup($this->indexerRegistryMock, $this->stateMock);
+        $this->model = (new ObjectManager($this))
+            ->getObject(
+                StoreGroup::class,
+                ['indexerRegistry' => $this->indexerRegistryMock, 'state' => $this->stateMock]
+            );
     }
 
-    public function testAroundSave()
+    public function testBeforeAndAfterSave()
     {
-        $this->stateMock->expects($this->once())->method('isFlatEnabled')->will($this->returnValue(true));
+        $this->stateMock->expects($this->once())->method('isFlatEnabled')->willReturn(true);
         $this->indexerMock->expects($this->once())->method('invalidate');
         $this->indexerRegistryMock->expects($this->once())
             ->method('get')
-            ->with(\Magento\Catalog\Model\Indexer\Category\Flat\State::INDEXER_ID)
-            ->will($this->returnValue($this->indexerMock));
-        $this->groupMock->expects(
-            $this->once()
-        )->method(
-            'dataHasChangedFor'
-        )->with(
-            'root_category_id'
-        )->will(
-            $this->returnValue(true)
+            ->with(State::INDEXER_ID)
+            ->willReturn($this->indexerMock);
+        $this->groupMock->expects($this->once())
+            ->method('dataHasChangedFor')
+            ->with('root_category_id')
+            ->willReturn(true);
+        $this->groupMock->expects($this->once())->method('isObjectNew')->willReturn(false);
+        $this->model->beforeSave($this->subjectMock, $this->groupMock);
+        $this->assertSame(
+            $this->subjectMock,
+            $this->model->afterSave($this->subjectMock, $this->subjectMock, $this->groupMock)
         );
-        $this->groupMock->expects($this->once())->method('isObjectNew')->will($this->returnValue(false));
-        $this->assertFalse($this->model->aroundSave($this->subjectMock, $this->closureMock, $this->groupMock));
     }
 
-    public function testAroundSaveNotNew()
+    public function testBeforeAndAfterSaveNotNew()
     {
         $this->stateMock->expects($this->never())->method('isFlatEnabled');
-        $this->groupMock = $this->getMock(
-            \Magento\Store\Model\Group::class,
-            ['dataHasChangedFor', 'isObjectNew', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $this->groupMock->expects(
-            $this->once()
-        )->method(
-            'dataHasChangedFor'
-        )->with(
-            'root_category_id'
-        )->will(
-            $this->returnValue(true)
+        $this->groupMock->expects($this->once())
+            ->method('dataHasChangedFor')
+            ->with('root_category_id')
+            ->willReturn(true);
+        $this->groupMock->expects($this->once())->method('isObjectNew')->willReturn(true);
+        $this->model->beforeSave($this->subjectMock, $this->groupMock);
+        $this->assertSame(
+            $this->subjectMock,
+            $this->model->afterSave($this->subjectMock, $this->subjectMock, $this->groupMock)
         );
-        $this->groupMock->expects($this->once())->method('isObjectNew')->will($this->returnValue(true));
-        $this->assertFalse($this->model->aroundSave($this->subjectMock, $this->closureMock, $this->groupMock));
     }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/StoreViewTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/StoreViewTest.php
index 21d3403c775a540d1329db3815f3e87198ee06c8..88d2d7c3e394c51205c1eb33f8e2c59341003258 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/StoreViewTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Flat/Plugin/StoreViewTest.php
@@ -29,11 +29,6 @@ class StoreViewTest extends \PHPUnit_Framework_TestCase
      */
     protected $indexerRegistryMock;
 
-    /**
-     * @var \Closure
-     */
-    protected $closureMock;
-
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
@@ -57,9 +52,6 @@ class StoreViewTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $this->closureMock = function () {
-            return false;
-        };
         $this->subjectMock = $this->getMock(\Magento\Store\Model\ResourceModel\Store::class, [], [], '', false);
         $this->indexerRegistryMock = $this->getMock(
             \Magento\Framework\Indexer\IndexerRegistry::class,
@@ -71,7 +63,7 @@ class StoreViewTest extends \PHPUnit_Framework_TestCase
         $this->model = new StoreView($this->indexerRegistryMock, $this->stateMock);
     }
 
-    public function testAroundSaveNewObject()
+    public function testBeforeAndAfterSaveNewObject()
     {
         $this->mockConfigFlatEnabled();
         $this->mockIndexerMethods();
@@ -83,10 +75,14 @@ class StoreViewTest extends \PHPUnit_Framework_TestCase
             false
         );
         $storeMock->expects($this->once())->method('isObjectNew')->will($this->returnValue(true));
-        $this->assertFalse($this->model->aroundSave($this->subjectMock, $this->closureMock, $storeMock));
+        $this->model->beforeSave($this->subjectMock, $storeMock);
+        $this->assertSame(
+            $this->subjectMock,
+            $this->model->afterSave($this->subjectMock, $this->subjectMock, $storeMock)
+        );
     }
 
-    public function testAroundSaveHasChanged()
+    public function testBeforeAndAfterSaveHasChanged()
     {
         $storeMock = $this->getMock(
             \Magento\Store\Model\Store::class,
@@ -95,10 +91,14 @@ class StoreViewTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $this->assertFalse($this->model->aroundSave($this->subjectMock, $this->closureMock, $storeMock));
+        $this->model->beforeSave($this->subjectMock, $storeMock);
+        $this->assertSame(
+            $this->subjectMock,
+            $this->model->afterSave($this->subjectMock, $this->subjectMock, $storeMock)
+        );
     }
 
-    public function testAroundSaveNoNeed()
+    public function testBeforeAndAfterSaveNoNeed()
     {
         $this->mockConfigFlatEnabledNeever();
         $storeMock = $this->getMock(
@@ -108,7 +108,11 @@ class StoreViewTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $this->assertFalse($this->model->aroundSave($this->subjectMock, $this->closureMock, $storeMock));
+        $this->model->beforeSave($this->subjectMock, $storeMock);
+        $this->assertSame(
+            $this->subjectMock,
+            $this->model->afterSave($this->subjectMock, $this->subjectMock, $storeMock)
+        );
     }
 
     protected function mockIndexerMethods()
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/StoreGroupTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/StoreGroupTest.php
index 58385e8d38d7a4075de78fac4183cc112a70ff21..da2f90b313fbc48b5c5e3b51da5fb1d8381cd70c 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/StoreGroupTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/StoreGroupTest.php
@@ -5,39 +5,52 @@
  */
 namespace Magento\Catalog\Test\Unit\Model\Indexer\Category\Product\Plugin;
 
-use \Magento\Catalog\Model\Indexer\Category\Product\Plugin\StoreGroup;
+use Magento\Catalog\Model\Indexer\Category\Product\Plugin\StoreGroup;
+use Magento\Framework\Indexer\IndexerInterface;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Store\Model\ResourceModel\Group;
+use Magento\Framework\Indexer\IndexerRegistry;
+use Magento\Store\Model\Group as GroupModel;
+use Magento\Catalog\Model\Indexer\Category\Product;
 
 class StoreGroupTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Indexer\IndexerInterface
+     * @var GroupModel|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $indexerMock;
+    private $groupMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|
+     * @var \PHPUnit_Framework_MockObject_MockObject|IndexerInterface
      */
-    protected $pluginMock;
+    private $indexerMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \PHPUnit_Framework_MockObject_MockObject|Group
      */
-    protected $subject;
+    private $subject;
 
     /**
-     * @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
+     * @var IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $indexerRegistryMock;
+    private $indexerRegistryMock;
 
     /**
      * @var StoreGroup
      */
-    protected $model;
+    private $model;
 
     protected function setUp()
     {
+        $this->groupMock = $this->getMock(
+            GroupModel::class,
+            ['dataHasChangedFor', 'isObjectNew', '__wakeup'],
+            [],
+            '',
+            false
+        );
         $this->indexerMock = $this->getMockForAbstractClass(
-            \Magento\Framework\Indexer\IndexerInterface::class,
+            IndexerInterface::class,
             [],
             '',
             false,
@@ -45,57 +58,44 @@ class StoreGroupTest extends \PHPUnit_Framework_TestCase
             true,
             ['getId', 'getState', '__wakeup']
         );
-        $this->subject = $this->getMock(\Magento\Store\Model\ResourceModel\Group::class, [], [], '', false);
+        $this->subject = $this->getMock(Group::class, [], [], '', false);
         $this->indexerRegistryMock = $this->getMock(
-            \Magento\Framework\Indexer\IndexerRegistry::class,
+            IndexerRegistry::class,
             ['get'],
             [],
             '',
             false
         );
 
-        $this->model = new StoreGroup($this->indexerRegistryMock);
+        $this->model = (new ObjectManager($this))
+            ->getObject(StoreGroup::class, ['indexerRegistry' => $this->indexerRegistryMock]);
     }
 
     /**
      * @param array $valueMap
      * @dataProvider changedDataProvider
      */
-    public function testAroundSave($valueMap)
+    public function testBeforeAndAfterSave($valueMap)
     {
         $this->mockIndexerMethods();
-        $groupMock = $this->getMock(
-            \Magento\Store\Model\Group::class,
-            ['dataHasChangedFor', 'isObjectNew', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $groupMock->expects($this->exactly(2))->method('dataHasChangedFor')->will($this->returnValueMap($valueMap));
-        $groupMock->expects($this->once())->method('isObjectNew')->will($this->returnValue(false));
+        $this->groupMock->expects($this->exactly(2))->method('dataHasChangedFor')->willReturnMap($valueMap);
+        $this->groupMock->expects($this->once())->method('isObjectNew')->willReturn(false);
 
-        $proceed = $this->mockPluginProceed();
-        $this->assertFalse($this->model->aroundSave($this->subject, $proceed, $groupMock));
+        $this->model->beforeSave($this->subject, $this->groupMock);
+        $this->assertSame($this->subject, $this->model->afterSave($this->subject, $this->subject, $this->groupMock));
     }
 
     /**
      * @param array $valueMap
      * @dataProvider changedDataProvider
      */
-    public function testAroundSaveNotNew($valueMap)
+    public function testBeforeAndAfterSaveNotNew($valueMap)
     {
-        $groupMock = $this->getMock(
-            \Magento\Store\Model\Group::class,
-            ['dataHasChangedFor', 'isObjectNew', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $groupMock->expects($this->exactly(2))->method('dataHasChangedFor')->will($this->returnValueMap($valueMap));
-        $groupMock->expects($this->once())->method('isObjectNew')->will($this->returnValue(true));
+        $this->groupMock->expects($this->exactly(2))->method('dataHasChangedFor')->willReturnMap($valueMap);
+        $this->groupMock->expects($this->once())->method('isObjectNew')->willReturn(true);
 
-        $proceed = $this->mockPluginProceed();
-        $this->assertFalse($this->model->aroundSave($this->subject, $proceed, $groupMock));
+        $this->model->beforeSave($this->subject, $this->groupMock);
+        $this->assertSame($this->subject, $this->model->afterSave($this->subject, $this->subject, $this->groupMock));
     }
 
     public function changedDataProvider()
@@ -108,41 +108,23 @@ class StoreGroupTest extends \PHPUnit_Framework_TestCase
         ];
     }
 
-    public function testAroundSaveWithoutChanges()
+    public function testBeforeAndAfterSaveWithoutChanges()
     {
-        $groupMock = $this->getMock(
-            \Magento\Store\Model\Group::class,
-            ['dataHasChangedFor', 'isObjectNew', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $groupMock->expects(
-            $this->exactly(2)
-        )->method(
-            'dataHasChangedFor'
-        )->will(
-            $this->returnValueMap([['root_category_id', false], ['website_id', false]])
-        );
-        $groupMock->expects($this->never())->method('isObjectNew');
+        $this->groupMock->expects($this->exactly(2))
+            ->method('dataHasChangedFor')
+            ->willReturnMap([['root_category_id', false], ['website_id', false]]);
+        $this->groupMock->expects($this->never())->method('isObjectNew');
 
-        $proceed = $this->mockPluginProceed();
-        $this->assertFalse($this->model->aroundSave($this->subject, $proceed, $groupMock));
+        $this->model->beforeSave($this->subject, $this->groupMock);
+        $this->assertSame($this->subject, $this->model->afterSave($this->subject, $this->subject, $this->groupMock));
     }
 
-    protected function mockIndexerMethods()
+    private function mockIndexerMethods()
     {
         $this->indexerMock->expects($this->once())->method('invalidate');
         $this->indexerRegistryMock->expects($this->once())
             ->method('get')
-            ->with(\Magento\Catalog\Model\Indexer\Category\Product::INDEXER_ID)
-            ->will($this->returnValue($this->indexerMock));
-    }
-
-    protected function mockPluginProceed($returnValue = false)
-    {
-        return function () use ($returnValue) {
-            return $returnValue;
-        };
+            ->with(Product::INDEXER_ID)
+            ->willReturn($this->indexerMock);
     }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/StoreViewTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/StoreViewTest.php
index 26dcfd206b124a5583915df373dcd258aa974500..f27d2b14f31cd3c7463b47ff8d01ad73e20dcfd5 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/StoreViewTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Category/Product/Plugin/StoreViewTest.php
@@ -5,19 +5,23 @@
  */
 namespace Magento\Catalog\Test\Unit\Model\Indexer\Category\Product\Plugin;
 
-use \Magento\Catalog\Model\Indexer\Category\Product\Plugin\StoreView;
+use Magento\Catalog\Model\Indexer\Category\Product\Plugin\StoreView;
+use Magento\Framework\Indexer\IndexerInterface;
+use Magento\Framework\Indexer\IndexerRegistry;
+use Magento\Store\Model\ResourceModel\Group;
+use Magento\Store\Model\Store;
 
 class StoreViewTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Indexer\IndexerInterface
+     * @var Store|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $indexerMock;
+    private $storeMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|
+     * @var \PHPUnit_Framework_MockObject_MockObject|IndexerInterface
      */
-    protected $pluginMock;
+    protected $indexerMock;
 
     /**
      * @var StoreView
@@ -25,7 +29,7 @@ class StoreViewTest extends \PHPUnit_Framework_TestCase
     protected $model;
 
     /**
-     * @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
+     * @var IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $indexerRegistryMock;
 
@@ -37,7 +41,7 @@ class StoreViewTest extends \PHPUnit_Framework_TestCase
     protected function setUp()
     {
         $this->indexerMock = $this->getMockForAbstractClass(
-            \Magento\Framework\Indexer\IndexerInterface::class,
+            IndexerInterface::class,
             [],
             '',
             false,
@@ -45,14 +49,21 @@ class StoreViewTest extends \PHPUnit_Framework_TestCase
             true,
             ['getId', 'getState', '__wakeup']
         );
-        $this->subject = $this->getMock(\Magento\Store\Model\ResourceModel\Group::class, [], [], '', false);
+        $this->subject = $this->getMock(Group::class, [], [], '', false);
         $this->indexerRegistryMock = $this->getMock(
-            \Magento\Framework\Indexer\IndexerRegistry::class,
+            IndexerRegistry::class,
             ['get'],
             [],
             '',
             false
         );
+        $this->storeMock = $this->getMock(
+            Store::class,
+            ['isObjectNew', 'dataHasChangedFor', '__wakeup'],
+            [],
+            '',
+            false
+        );
 
         $this->model = new StoreView($this->indexerRegistryMock);
     }
@@ -60,94 +71,38 @@ class StoreViewTest extends \PHPUnit_Framework_TestCase
     public function testAroundSaveNewObject()
     {
         $this->mockIndexerMethods();
-        $storeMock = $this->getMock(
-            \Magento\Store\Model\Store::class,
-            ['isObjectNew', 'dataHasChangedFor', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $storeMock->expects($this->once())->method('isObjectNew')->will($this->returnValue(true));
-        $proceed = $this->mockPluginProceed();
-        $this->assertFalse($this->model->aroundSave($this->subject, $proceed, $storeMock));
+        $this->storeMock->expects($this->once())->method('isObjectNew')->willReturn(true);
+        $this->model->beforeSave($this->subject, $this->storeMock);
+        $this->assertSame($this->subject, $this->model->afterSave($this->subject, $this->subject, $this->storeMock));
     }
 
     public function testAroundSaveHasChanged()
     {
         $this->mockIndexerMethods();
-        $storeMock = $this->getMock(
-            \Magento\Store\Model\Store::class,
-            ['isObjectNew', 'dataHasChangedFor', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $storeMock->expects(
-            $this->once()
-        )->method(
-            'dataHasChangedFor'
-        )->with(
-            'group_id'
-        )->will(
-            $this->returnValue(true)
-        );
-        $proceed = $this->mockPluginProceed();
-        $this->assertFalse($this->model->aroundSave($this->subject, $proceed, $storeMock));
+        $this->storeMock->expects($this->once())
+            ->method('dataHasChangedFor')
+            ->with('group_id')
+            ->willReturn(true);
+        $this->model->beforeSave($this->subject, $this->storeMock);
+        $this->assertSame($this->subject, $this->model->afterSave($this->subject, $this->subject, $this->storeMock));
     }
 
     public function testAroundSaveNoNeed()
     {
-        $storeMock = $this->getMock(
-            \Magento\Store\Model\Store::class,
-            ['isObjectNew', 'dataHasChangedFor', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $storeMock->expects(
-            $this->once()
-        )->method(
-            'dataHasChangedFor'
-        )->with(
-            'group_id'
-        )->will(
-            $this->returnValue(false)
-        );
-        $proceed = $this->mockPluginProceed();
-        $this->assertFalse($this->model->aroundSave($this->subject, $proceed, $storeMock));
-    }
-
-    /**
-     * @return \PHPUnit_Framework_MockObject_MockObject|\Magento\Indexer\Model\Indexer\State
-     */
-    protected function getStateMock()
-    {
-        $stateMock = $this->getMock(
-            \Magento\Indexer\Model\Indexer\State::class,
-            ['setStatus', 'save', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $stateMock->expects($this->once())->method('setStatus')->with('invalid')->will($this->returnSelf());
-        $stateMock->expects($this->once())->method('save')->will($this->returnSelf());
-
-        return $stateMock;
+        $this->storeMock->expects($this->once())
+            ->method('dataHasChangedFor')
+            ->with('group_id')
+            ->willReturn(false);
+        $this->model->beforeSave($this->subject, $this->storeMock);
+        $this->assertSame($this->subject, $this->model->afterSave($this->subject, $this->subject, $this->storeMock));
     }
 
-    protected function mockIndexerMethods()
+    private function mockIndexerMethods()
     {
         $this->indexerMock->expects($this->once())->method('invalidate');
         $this->indexerRegistryMock->expects($this->once())
             ->method('get')
             ->with(\Magento\Catalog\Model\Indexer\Category\Product::INDEXER_ID)
-            ->will($this->returnValue($this->indexerMock));
-    }
-
-    protected function mockPluginProceed($returnValue = false)
-    {
-        return function () use ($returnValue) {
-            return $returnValue;
-        };
+            ->willReturn($this->indexerMock);
     }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Plugin/AttributeSetTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Plugin/AttributeSetTest.php
index 38f74d7c730c2d8d54b23ea71dd9c84dc9b3ee53..48410da746584d31d3bb5e543354fc1f8092019b 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Plugin/AttributeSetTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Eav/Plugin/AttributeSetTest.php
@@ -5,47 +5,105 @@
  */
 namespace Magento\Catalog\Test\Unit\Model\Indexer\Product\Eav\Plugin;
 
+use Magento\Catalog\Model\Indexer\Product\Eav\Plugin\AttributeSet\IndexableAttributeFilter;
+use Magento\Eav\Model\Entity\Attribute\Set as EavAttributeSet;
+use Magento\Eav\Model\Entity\Attribute\SetFactory;
+use Magento\Catalog\Model\Indexer\Product\Eav\Processor;
+use Magento\Catalog\Model\Indexer\Product\Eav\Plugin\AttributeSet;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
 class AttributeSetTest extends \PHPUnit_Framework_TestCase
 {
-    public function testAroundSave()
+    /**
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var AttributeSet
+     */
+    private $model;
+
+    /**
+     * @var Processor|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $eavProcessorMock;
+
+    /**
+     * @var IndexableAttributeFilter|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filterMock;
+
+    /**
+     * @var EavAttributeSet|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $subjectMock;
+
+    /**
+     * @var SetFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $setFactoryMock;
+
+    /**
+     * @var EavAttributeSet|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $originalSetMock;
+
+    public function setUp()
     {
-        $eavProcessorMock = $this->getMockBuilder(\Magento\Catalog\Model\Indexer\Product\Eav\Processor::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $eavProcessorMock->expects($this->once())
-            ->method('markIndexerAsInvalid');
-
-        $filter = $this->getMockBuilder(
-            \Magento\Catalog\Model\Indexer\Product\Eav\Plugin\AttributeSet\IndexableAttributeFilter::class
-        )
-            ->disableOriginalConstructor()
-            ->getMock();
-        $filter->expects($this->at(0))
-            ->method('filter')
-            ->will($this->returnValue([1, 2, 3]));
-        $filter->expects($this->at(1))
+        $this->filterMock = $this->getMock(IndexableAttributeFilter::class, [], [], '', false);
+        $this->subjectMock = $this->getMock(EavAttributeSet::class, [], [], '', false);
+        $this->eavProcessorMock = $this->getMock(Processor::class, [], [], '', false);
+        $this->setFactoryMock = $this->getMock(SetFactory::class, ['create'], [], '', false);
+        $this->objectManager = new ObjectManager($this);
+    }
+
+    public function testBeforeSave()
+    {
+        $setId = 1;
+        $this->originalSetMock = $this->getMock(EavAttributeSet::class, [], [], '', false);
+        $this->originalSetMock->expects($this->once())->method('initFromSkeleton')->with($setId);
+
+        $this->setFactoryMock->expects($this->once())->method('create')->willReturn($this->originalSetMock);
+        $this->model = $this->objectManager->getObject(
+            AttributeSet::class,
+            [
+                'indexerEavProcessor' => $this->eavProcessorMock,
+                'filter' => $this->filterMock,
+                'setFactory' => $this->setFactoryMock
+            ]
+        );
+
+        $this->filterMock->expects($this->exactly(2))
             ->method('filter')
-            ->will($this->returnValue([1, 2]));
+            ->willReturnMap(
+                [
+                    [$this->originalSetMock, [1, 2, 3]],
+                    [$this->subjectMock, [1, 2]]
+                ]
+            );
 
-        $subjectMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\Set::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $subjectMock->expects($this->any())
+        $this->subjectMock->expects($this->exactly(2))
             ->method('getId')
-            ->will($this->returnValue(11));
+            ->willReturn($setId);
 
-        $model = new \Magento\Catalog\Model\Indexer\Product\Eav\Plugin\AttributeSet(
-            $eavProcessorMock,
-            $filter
-        );
+        $this->model->beforeSave($this->subjectMock);
+    }
 
-        $closure  = function () use ($subjectMock) {
-            return $subjectMock;
-        };
+    public function testAfterSave()
+    {
+        $this->eavProcessorMock->expects($this->once())->method('markIndexerAsInvalid');
 
-        $this->assertEquals(
-            $subjectMock,
-            $model->aroundSave($subjectMock, $closure)
-        );
+        $this->model = $this->objectManager
+            ->getObject(
+                AttributeSet::class,
+                [
+                    'indexerEavProcessor' => $this->eavProcessorMock,
+                    'filter' => $this->filterMock,
+                    'requiresReindex' => true
+                ]
+            );
+
+        $this->assertSame($this->subjectMock, $this->model->afterSave($this->subjectMock, $this->subjectMock));
     }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Plugin/IndexerConfigDataTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Plugin/IndexerConfigDataTest.php
index 6624f2fa8260976ad2bec18aaff4ccde1f281e77..53d1a8fd004a080f6e3a9ac81d6962e7e72f6a73 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Plugin/IndexerConfigDataTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Indexer/Product/Flat/Plugin/IndexerConfigDataTest.php
@@ -5,35 +5,47 @@
  */
 namespace Magento\Catalog\Test\Unit\Model\Indexer\Product\Flat\Plugin;
 
+use Magento\Catalog\Model\Indexer\Product\Flat\Plugin\IndexerConfigData as IndexerConfigDataPlugin;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Catalog\Model\Indexer\Product\Flat\State as ProductFlatIndexerState;
+use Magento\Indexer\Model\Config\Data as ConfigData;
+
 class IndexerConfigDataTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Catalog\Model\Indexer\Product\Flat\Plugin\IndexerConfigData
+     * @var IndexerConfigDataPlugin
      */
-    protected $model;
+    private $plugin;
 
     /**
-     * @var \Magento\Catalog\Model\Indexer\Product\Flat\State|\PHPUnit_Framework_MockObject_MockObject
+     * @var ObjectManagerHelper
      */
-    protected $_stateMock;
+    private $objectManagerHelper;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var ProductFlatIndexerState|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $subjectMock;
+    private $indexerStateMock;
+
+    /**
+     * @var ConfigData|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $subjectMock;
 
     protected function setUp()
     {
-        $this->_stateMock = $this->getMock(
-            \Magento\Catalog\Model\Indexer\Product\Flat\State::class,
-            ['isFlatEnabled'],
-            [],
-            '',
-            false
-        );
-        $this->subjectMock = $this->getMock(\Magento\Indexer\Model\Config\Data::class, [], [], '', false);
+        $this->indexerStateMock = $this->getMockBuilder(ProductFlatIndexerState::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->subjectMock = $this->getMockBuilder(ConfigData::class)
+            ->disableOriginalConstructor()
+            ->getMock();
 
-        $this->model = new \Magento\Catalog\Model\Indexer\Product\Flat\Plugin\IndexerConfigData($this->_stateMock);
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->plugin = $this->objectManagerHelper->getObject(
+            IndexerConfigDataPlugin::class,
+            ['state' => $this->indexerStateMock]
+        );
     }
 
     /**
@@ -42,32 +54,36 @@ class IndexerConfigDataTest extends \PHPUnit_Framework_TestCase
      * @param mixed $default
      * @param array $inputData
      * @param array $outputData
-     * @dataProvider aroundGetDataProvider
+     *
+     * @dataProvider afterGetDataProvider
      */
-    public function testAroundGet($isFlat, $path, $default, $inputData, $outputData)
+    public function testAfterGet($isFlat, $path, $default, $inputData, $outputData)
     {
-        $closureMock = function () use ($inputData) {
-            return $inputData;
-        };
-        $this->_stateMock->expects($this->once())->method('isFlatEnabled')->will($this->returnValue($isFlat));
+        $this->indexerStateMock->expects(static::once())
+            ->method('isFlatEnabled')
+            ->willReturn($isFlat);
 
-        $this->assertEquals($outputData, $this->model->aroundGet($this->subjectMock, $closureMock, $path, $default));
+        $this->assertEquals($outputData, $this->plugin->afterGet($this->subjectMock, $inputData, $path, $default));
     }
 
-    public function aroundGetDataProvider()
+    /**
+     * @return array
+     */
+    public function afterGetDataProvider()
     {
         $flatIndexerData = [
             'indexer_id' => 'catalog_product_flat',
             'action' => '\Action\Class',
             'title' => 'Title',
-            'description' => 'Description',
+            'description' => 'Description'
         ];
         $otherIndexerData = [
             'indexer_id' => 'other_indexer',
             'action' => '\Action\Class',
             'title' => 'Title',
-            'description' => 'Description',
+            'description' => 'Description'
         ];
+
         return [
             // flat is enabled, nothing is being changed
             [
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Plugin/QuoteItemProductOptionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Plugin/QuoteItemProductOptionTest.php
index 6b6b0921e506aa2e81bee14e52c1d88ac6d221e6..13e9ef8b327874e97d9641aaeb568b9352ffc4c2 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Plugin/QuoteItemProductOptionTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Plugin/QuoteItemProductOptionTest.php
@@ -5,76 +5,95 @@
  */
 namespace Magento\Catalog\Test\Unit\Model\Plugin;
 
+use Magento\Catalog\Model\Plugin\QuoteItemProductOption as QuoteItemProductOptionPlugin;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Quote\Model\Quote\Item\ToOrderItem as QuoteToOrderItem;
+use Magento\Quote\Model\Quote\Item\AbstractItem as AbstractQuoteItem;
+use Magento\Quote\Model\Quote\Item\Option as QuoteItemOption;
+use Magento\Catalog\Model\Product;
+use Magento\Framework\DataObject;
+use Magento\Catalog\Model\Product\Option as ProductOption;
+
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class QuoteItemProductOptionTest extends \PHPUnit_Framework_TestCase
 {
-    /** @var \PHPUnit_Framework_MockObject_MockObject */
-    protected $quoteItemMock;
+    /**
+     * @var QuoteItemProductOptionPlugin
+     */
+    private $plugin;
 
-    /** @var \PHPUnit_Framework_MockObject_MockObject */
-    protected $orderItemMock;
+    /**
+     * @var ObjectManagerHelper
+     */
+    private $objectManagerHelper;
 
-    /** @var \Magento\Catalog\Model\Plugin\QuoteItemProductOption */
-    protected $model;
+    /**
+     * @var QuoteToOrderItem|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $subjectMock;
 
     /**
-     * @var \Closure
+     * @var AbstractQuoteItem|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $closureMock;
+    private $quoteItemMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var QuoteItemOption|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $subjectMock;
+    private $quoteItemOptionMock;
+
+    /**
+     * @var Product|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $productMock;
 
     protected function setUp()
     {
-        $this->orderItemMock = $this->getMock(\Magento\Sales\Model\Order\Item::class, [], [], '', false);
-        $this->quoteItemMock = $this->getMock(\Magento\Quote\Model\Quote\Item::class, [], [], '', false);
-        $orderItem = $this->orderItemMock;
-        $this->subjectMock = $this->getMock(\Magento\Quote\Model\Quote\Item\ToOrderItem::class, [], [], '', false);
-        $this->closureMock = function () use ($orderItem) {
-            return $orderItem;
-        };
-        $this->model = new \Magento\Catalog\Model\Plugin\QuoteItemProductOption();
+        $this->subjectMock = $this->getMockBuilder(QuoteToOrderItem::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->quoteItemMock = $this->getMockBuilder(AbstractQuoteItem::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getOptions', 'getProduct'])
+            ->getMockForAbstractClass();
+        $this->quoteItemOptionMock = $this->getMockBuilder(QuoteItemOption::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getCode'])
+            ->getMock();
+        $this->productMock = $this->getMockBuilder(Product::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->plugin = $this->objectManagerHelper->getObject(QuoteItemProductOptionPlugin::class);
     }
 
-    public function testAroundItemToOrderItemEmptyOptions()
+    public function testBeforeItemToOrderItemEmptyOptions()
     {
-        $this->quoteItemMock->expects($this->exactly(2))->method('getOptions')->will($this->returnValue([]));
+        $this->quoteItemMock->expects(static::once())
+            ->method('getOptions')
+            ->willReturn(null);
 
-        $orderItem = $this->model->aroundConvert($this->subjectMock, $this->closureMock, $this->quoteItemMock);
-        $this->assertSame($this->orderItemMock, $orderItem);
+        $this->plugin->beforeConvert($this->subjectMock, $this->quoteItemMock);
     }
 
-    public function testAroundItemToOrderItemWithOptions()
+    public function testBeforeItemToOrderItemWithOptions()
     {
-        $itemOption = $this->getMock(
-            \Magento\Quote\Model\Quote\Item\Option::class,
-            ['getCode', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $this->quoteItemMock->expects(
-            $this->exactly(2)
-        )->method(
-            'getOptions'
-        )->will(
-            $this->returnValue([$itemOption, $itemOption])
-        );
-
-        $itemOption->expects($this->at(0))->method('getCode')->will($this->returnValue('someText_8'));
-        $itemOption->expects($this->at(1))->method('getCode')->will($this->returnValue('not_int_text'));
-
-        $productMock = $this->getMock(\Magento\Catalog\Model\Product::class, [], [], '', false);
-        $optionMock = $this->getMock(\stdClass::class, ['getType']);
-        $optionMock->expects($this->once())->method('getType');
-
-        $productMock->expects($this->once())->method('getOptionById')->will($this->returnValue($optionMock));
-
-        $this->quoteItemMock->expects($this->once())->method('getProduct')->will($this->returnValue($productMock));
+        $this->quoteItemMock->expects(static::exactly(2))
+            ->method('getOptions')
+            ->willReturn([$this->quoteItemOptionMock, $this->quoteItemOptionMock]);
+        $this->quoteItemOptionMock->expects(static::exactly(2))
+            ->method('getCode')
+            ->willReturnOnConsecutiveCalls('someText_8', 'not_int_text');
+        $this->productMock->expects(static::once())
+            ->method('getOptionById')
+            ->willReturn(new DataObject(['type' => ProductOption::OPTION_TYPE_FILE]));
+        $this->quoteItemMock->expects(static::once())
+            ->method('getProduct')
+            ->willReturn($this->productMock);
 
-        $orderItem = $this->model->aroundConvert($this->subjectMock, $this->closureMock, $this->quoteItemMock);
-        $this->assertSame($this->orderItemMock, $orderItem);
+        $this->plugin->beforeConvert($this->subjectMock, $this->quoteItemMock);
     }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Plugin/Model/ResourceModel/Attribute/SaveTest.php b/app/code/Magento/Catalog/Test/Unit/Plugin/Model/ResourceModel/Attribute/SaveTest.php
index cb01f50605f664e01d1aee21c735054ea471e9a4..58e88952de2266f434a1ad0bbd1a99617edf1e8b 100644
--- a/app/code/Magento/Catalog/Test/Unit/Plugin/Model/ResourceModel/Attribute/SaveTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Plugin/Model/ResourceModel/Attribute/SaveTest.php
@@ -6,46 +6,51 @@
 
 namespace Magento\Catalog\Test\Unit\Plugin\Model\ResourceModel\Attribute;
 
-use \Magento\Catalog\Plugin\Model\ResourceModel\Attribute\Save;
+use Magento\Catalog\Plugin\Model\ResourceModel\Attribute\Save;
+use Magento\PageCache\Model\Config;
+use Magento\Framework\App\Cache\TypeListInterface;
+use Magento\Catalog\Model\ResourceModel\Attribute;
 
 class SaveTest extends \PHPUnit_Framework_TestCase
 {
-    /** @var \Magento\Catalog\Plugin\Model\ResourceModel\Attribute\Save */
+    /**
+     * @var Attribute|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $subjectMock;
+
+    /**
+     * @var Save
+     */
     protected $save;
 
-    /** @var \Magento\PageCache\Model\Config|\PHPUnit_Framework_MockObject_MockObject */
+    /**
+     * @var Config|\PHPUnit_Framework_MockObject_MockObject
+     */
     protected $config;
 
-    /** @var \Magento\Framework\App\Cache\TypeListInterface|\PHPUnit_Framework_MockObject_MockObject */
+    /**
+     * @var TypeListInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
     protected $typeList;
 
     protected function setUp()
     {
-        $this->config = $this->getMockBuilder(\Magento\PageCache\Model\Config::class)
-            ->disableOriginalConstructor()
-            ->setMethods(['isEnabled'])
-            ->getMock();
-        $this->typeList = $this->getMockBuilder(\Magento\Framework\App\Cache\TypeListInterface::class)
-            ->disableOriginalConstructor()
-            ->setMethods(['invalidate'])
-            ->getMockForAbstractClass();
-
+        $this->config = $this->getMock(Config::class, ['isEnabled'], [], '', false);
+        $this->typeList = $this->getMockForAbstractClass(
+            TypeListInterface::class,
+            [],
+            '',
+            false,
+            false,
+            true,
+            ['invalidate']
+        );
+        $this->subjectMock = $this->getMock(Attribute::class, [], [], '', false);
         $this->save = new Save($this->config, $this->typeList);
     }
 
-    public function testAroundSaveWithoutInvalidate()
+    public function testAfterSaveWithoutInvalidate()
     {
-        $subject = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Attribute::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $attribute = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $self = $this;
-        $proceed = function ($object) use ($self, $attribute) {
-            $self->assertEquals($object, $attribute);
-        };
-
         $this->config->expects($this->once())
             ->method('isEnabled')
             ->willReturn(false);
@@ -53,23 +58,11 @@ class SaveTest extends \PHPUnit_Framework_TestCase
         $this->typeList->expects($this->never())
             ->method('invalidate');
 
-        $this->save->aroundSave($subject, $proceed, $attribute);
+        $this->assertSame($this->subjectMock, $this->save->afterSave($this->subjectMock, $this->subjectMock));
     }
 
-    public function testAroundSave()
+    public function testAfterSave()
     {
-        $subject = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Attribute::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $attribute = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $self = $this;
-        $proceed = function ($object) use ($self, $attribute) {
-            $self->assertEquals($object, $attribute);
-        };
-
         $this->config->expects($this->once())
             ->method('isEnabled')
             ->willReturn(true);
@@ -78,6 +71,6 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ->method('invalidate')
             ->with('full_page');
 
-        $this->save->aroundSave($subject, $proceed, $attribute);
+        $this->assertSame($this->subjectMock, $this->save->afterSave($this->subjectMock, $this->subjectMock));
     }
 }
diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml
index c9680034e1e210c8b0c9eacadc51b12344b3b082..3f15701216005a7486d1e7b8f6368b0126d4b0a5 100644
--- a/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml
+++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml
@@ -53,9 +53,7 @@
 <script type="text/x-magento-init">
     {
         "#product_addtocart_form": {
-            "catalogAddToCart": {
-                "bindSubmit": false
-            }
+            "catalogAddToCart": {}
         }
     }
 </script>
diff --git a/app/code/Magento/CatalogInventory/Model/Plugin/AroundProductRepositorySave.php b/app/code/Magento/CatalogInventory/Model/Plugin/AroundProductRepositorySave.php
index df910254082185145212c325568a971a75a9bd85..14b7207a1e43bafe167f8a8e73ec2ae3281b87ba 100644
--- a/app/code/Magento/CatalogInventory/Model/Plugin/AroundProductRepositorySave.php
+++ b/app/code/Magento/CatalogInventory/Model/Plugin/AroundProductRepositorySave.php
@@ -14,7 +14,13 @@ use Magento\CatalogInventory\Api\StockConfigurationInterface;
 use Magento\CatalogInventory\Api\StockRegistryInterface;
 use Magento\Framework\Exception\LocalizedException;
 use Magento\Store\Model\StoreManagerInterface;
+use Magento\Framework\Exception\CouldNotSaveException;
 
+/**
+ * Plugin for Magento\Catalog\Api\ProductRepositoryInterface
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class AroundProductRepositorySave
 {
     /**
@@ -53,26 +59,22 @@ class AroundProductRepositorySave
      *
      * Pay attention that in this code we mostly work with original product object to process stock item data,
      * not with received result (saved product) because it is already contains new empty stock item object.
-     * It is a reason why this plugin cannot be rewritten to after plugin
      *
-     * @param \Magento\Catalog\Api\ProductRepositoryInterface $subject
-     * @param callable $proceed
-     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param ProductRepositoryInterface $subject
+     * @param ProductInterface $result
+     * @param ProductInterface $product
      * @param bool $saveOptions
-     * @return \Magento\Catalog\Api\Data\ProductInterface
-     * @throws \Magento\Framework\Exception\CouldNotSaveException
+     * @return ProductInterface
+     * @throws CouldNotSaveException
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundSave(
-        \Magento\Catalog\Api\ProductRepositoryInterface $subject,
-        \Closure $proceed,
-        \Magento\Catalog\Api\Data\ProductInterface $product,
+    public function afterSave(
+        ProductRepositoryInterface $subject,
+        ProductInterface $result,
+        ProductInterface $product,
         $saveOptions = false
     ) {
-        /**
-         * @var \Magento\Catalog\Api\Data\ProductInterface $result
-         */
-        $result = $proceed($product, $saveOptions);
-
         /* @var StockItemInterface $stockItem */
         $stockItem = $this->getStockItemToBeUpdated($product);
         if (null === $stockItem) {
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php
index d4146182e205f353a9368bf07f0da07ce7ff7985..2d997c92f266687953ce72833f0924f06ae6fdd4 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php
@@ -6,7 +6,7 @@
 
 namespace Magento\CatalogInventory\Test\Unit\Model\Plugin;
 
-use Magento\Catalog\Api\Data\ProductExtension;
+use Magento\Catalog\Api\Data\ProductExtensionInterface;
 use Magento\Catalog\Api\Data\ProductInterface;
 use Magento\Catalog\Api\ProductRepositoryInterface;
 use Magento\CatalogInventory\Api\Data\StockInterface;
@@ -23,22 +23,17 @@ use Magento\Store\Model\StoreManagerInterface;
 class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Closure
-     */
-    private $closure;
-
-    /**
-     * @var ProductInterface
+     * @var ProductInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $product;
 
     /**
-     * @var ProductInterface
+     * @var ProductInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $savedProduct;
 
     /**
-     * @var ProductExtension|\PHPUnit_Framework_MockObject_MockObject
+     * @var ProductExtensionInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     private $productExtension;
 
@@ -73,7 +68,7 @@ class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
     private $stockConfiguration;
 
     /**
-     * @var \Magento\CatalogInventory\Model\Plugin\AroundProductRepositorySave
+     * @var AroundProductRepositorySave
      */
     private $plugin;
 
@@ -97,23 +92,25 @@ class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
             $this->stockConfiguration
         );
 
-        $this->savedProduct = $savedProduct = $this->getMockBuilder(ProductInterface::class)
+        $this->savedProduct = $this->getMockBuilder(ProductInterface::class)
             ->setMethods(['getExtensionAttributes', 'getStoreId'])
             ->getMockForAbstractClass();
 
-        $this->closure = function () use ($savedProduct) {
-            return $savedProduct;
-        };
-
         $this->productRepository = $this->getMockBuilder(ProductRepositoryInterface::class)
             ->setMethods(['get'])
             ->getMockForAbstractClass();
         $this->product = $this->getMockBuilder(ProductInterface::class)
             ->setMethods(['getExtensionAttributes', 'getStoreId'])
             ->getMockForAbstractClass();
-        $this->productExtension = $this->getMockBuilder(ProductExtension::class)
-            ->setMethods(['getStockItem'])
-            ->getMock();
+        $this->productExtension = $this->getMockForAbstractClass(
+            ProductExtensionInterface::class,
+            [],
+            '',
+            false,
+            false,
+            true,
+            ['getStockItem']
+        );
         $this->stockItem = $this->getMockBuilder(StockItemInterface::class)
             ->setMethods(['setWebsiteId', 'getWebsiteId', 'getStockId'])
             ->getMockForAbstractClass();
@@ -122,7 +119,7 @@ class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
             ->getMockForAbstractClass();
     }
 
-    public function testAroundSaveWhenProductHasNoStockItemNeedingToBeUpdated()
+    public function testAfterSaveWhenProductHasNoStockItemNeedingToBeUpdated()
     {
         // pretend we have no extension attributes at all
         $this->product->expects($this->once())
@@ -137,14 +134,14 @@ class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
         $this->stockItem->expects($this->never())->method('setWebsiteId');
 
         // expect that there are no changes to the existing stock item information
-        $result = $this->plugin->aroundSave($this->productRepository, $this->closure, $this->product);
+        $result = $this->plugin->afterSave($this->productRepository, $this->savedProduct, $this->product);
         $this->assertEquals(
             $this->savedProduct,
             $result
         );
     }
 
-    public function testAroundSaveWhenProductHasNoPersistentStockItemInfo()
+    public function testAfterSaveWhenProductHasNoPersistentStockItemInfo()
     {
         // pretend we do have extension attributes, but none for 'stock_item'
         $this->product->expects($this->once())
@@ -169,11 +166,11 @@ class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals(
             $newProductMock,
-            $this->plugin->aroundSave($this->productRepository, $this->closure, $this->product)
+            $this->plugin->afterSave($this->productRepository, $this->savedProduct, $this->product)
         );
     }
 
-    public function testAroundSave()
+    public function testAfterSave()
     {
         $productId = 5494;
         $storeId = 2;
@@ -224,7 +221,7 @@ class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals(
             $newProductMock,
-            $this->plugin->aroundSave($this->productRepository, $this->closure, $this->product)
+            $this->plugin->afterSave($this->productRepository, $this->savedProduct, $this->product)
         );
     }
 
@@ -232,7 +229,7 @@ class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
      * @expectedException \Magento\Framework\Exception\LocalizedException
      * @expectedExceptionMessage Invalid stock id: 100500. Only default stock with id 50 allowed
      */
-    public function testAroundSaveWithInvalidStockId()
+    public function testAfterSaveWithInvalidStockId()
     {
         $stockId = 100500;
         $defaultScopeId = 100;
@@ -259,14 +256,14 @@ class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
             ->method('getStockItem')
             ->willReturn($this->stockItem);
 
-        $this->plugin->aroundSave($this->productRepository, $this->closure, $this->product);
+        $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 testAroundSaveWithInvalidStockItemId()
+    public function testAfterSaveWithInvalidStockItemId()
     {
         $stockId = 80;
         $stockItemId = 0;
@@ -298,14 +295,14 @@ class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
             ->method('getItemId')
             ->willReturn($stockItemId);
 
-        $this->plugin->aroundSave($this->productRepository, $this->closure, $this->product);
+        $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 testAroundSaveWithNotAssignedStockItemId()
+    public function testAfterSaveWithNotAssignedStockItemId()
     {
         $stockId = 80;
         $stockItemId = 35;
@@ -348,6 +345,6 @@ class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
             ->method('getStockItem')
             ->willReturn($storedStockItem);
 
-        $this->plugin->aroundSave($this->productRepository, $this->closure, $this->product);
+        $this->plugin->afterSave($this->productRepository, $this->savedProduct, $this->product);
     }
 }
diff --git a/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Save/ApplyRules.php b/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Save/ApplyRules.php
index 2f007a83a5fe1bec524a2c4b9db5f5ce39fb15c2..00cdfb5aaaf79e22d350d95bbb523a097c1c5fe4 100644
--- a/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Save/ApplyRules.php
+++ b/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Save/ApplyRules.php
@@ -26,18 +26,16 @@ class ApplyRules
      * Apply catalog rules after product resource model save
      *
      * @param \Magento\Catalog\Model\ResourceModel\Product $subject
-     * @param callable $proceed
+     * @param \Magento\Catalog\Model\ResourceModel\Product $productResource
      * @param \Magento\Framework\Model\AbstractModel $product
      * @return \Magento\Catalog\Model\ResourceModel\Product
-     *
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundSave(
+    public function afterSave(
         \Magento\Catalog\Model\ResourceModel\Product $subject,
-        callable $proceed,
+        \Magento\Catalog\Model\ResourceModel\Product $productResource,
         \Magento\Framework\Model\AbstractModel $product
     ) {
-        $productResource = $proceed($product);
         if (!$product->getIsMassupdate()) {
             $this->productRuleProcessor->reindexRow($product->getId());
         }
diff --git a/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Save/ApplyRulesAfterReindex.php b/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Save/ApplyRulesAfterReindex.php
index af00ef3aada024fe5f16e275247a6c7b18d0522f..5416c2e59b00cae1f4f9d94475f955ba4561593b 100644
--- a/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Save/ApplyRulesAfterReindex.php
+++ b/app/code/Magento/CatalogRule/Plugin/Indexer/Product/Save/ApplyRulesAfterReindex.php
@@ -6,7 +6,11 @@
 namespace Magento\CatalogRule\Plugin\Indexer\Product\Save;
 
 use Magento\CatalogRule\Model\Indexer\Product\ProductRuleProcessor;
+use Magento\Catalog\Model\Product;
 
+/**
+ * Plugin for Magento\Catalog\Model\Product
+ */
 class ApplyRulesAfterReindex
 {
     /**
@@ -25,16 +29,11 @@ class ApplyRulesAfterReindex
     /**
      * Apply catalog rules after product resource model save
      *
-     * @param \Magento\Catalog\Model\Product $subject
-     * @param callable $proceed
-     * @return \Magento\Catalog\Model\Product
+     * @param Product $subject
+     * @return void
      */
-    public function aroundReindex(
-        \Magento\Catalog\Model\Product $subject,
-        callable $proceed
-    ) {
-        $proceed();
+    public function afterReindex(Product $subject)
+    {
         $this->productRuleProcessor->reindexRow($subject->getId());
-        return;
     }
 }
diff --git a/app/code/Magento/CatalogRule/Test/Unit/Plugin/Indexer/Product/Save/ApplyRulesAfterReindexTest.php b/app/code/Magento/CatalogRule/Test/Unit/Plugin/Indexer/Product/Save/ApplyRulesAfterReindexTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4d2068c9f52651d95682a2b493d4481fb5349706
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Test/Unit/Plugin/Indexer/Product/Save/ApplyRulesAfterReindexTest.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogRule\Test\Unit\Plugin\Indexer\Product\Save;
+
+use Magento\CatalogRule\Plugin\Indexer\Product\Save\ApplyRulesAfterReindex;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\CatalogRule\Model\Indexer\Product\ProductRuleProcessor;
+use Magento\Catalog\Model\Product;
+
+class ApplyRulesAfterReindexTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ApplyRulesAfterReindex
+     */
+    private $plugin;
+
+    /**
+     * @var ObjectManagerHelper
+     */
+    private $objectManagerHelper;
+
+    /**
+     * @var ProductRuleProcessor|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $productRuleProcessorMock;
+
+    /**
+     * @var Product|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $subjectMock;
+
+    protected function setUp()
+    {
+        $this->productRuleProcessorMock = $this->getMockBuilder(ProductRuleProcessor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->subjectMock = $this->getMockBuilder(Product::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->plugin = $this->objectManagerHelper->getObject(
+            ApplyRulesAfterReindex::class,
+            ['productRuleProcessor' => $this->productRuleProcessorMock]
+        );
+    }
+
+    public function testAfterReindex()
+    {
+        $id = 'test_id';
+
+        $this->subjectMock->expects(static::any())
+            ->method('getId')
+            ->willReturn($id);
+        $this->productRuleProcessorMock->expects(static::once())
+            ->method('reindexRow')
+            ->with($id, false);
+
+        $this->plugin->afterReindex($this->subjectMock);
+    }
+}
diff --git a/app/code/Magento/CatalogRule/Test/Unit/Plugin/Indexer/Product/Save/ApplyRulesTest.php b/app/code/Magento/CatalogRule/Test/Unit/Plugin/Indexer/Product/Save/ApplyRulesTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..59031959b51adce5ef0320dbbeac5aa174d15eb1
--- /dev/null
+++ b/app/code/Magento/CatalogRule/Test/Unit/Plugin/Indexer/Product/Save/ApplyRulesTest.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogRule\Test\Unit\Plugin\Indexer\Product\Save;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class ApplyRulesTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogRule\Model\Indexer\Product\ProductRuleProcessor|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $productRuleProcessor;
+
+    /**
+     * @var \Magento\Catalog\Model\ResourceModel\Product|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $subject;
+
+    /**
+     * @var \Magento\Framework\Model\AbstractModel|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $model;
+
+    /**
+     * @var \Magento\CatalogRule\Plugin\Indexer\Product\Save\ApplyRules
+     */
+    private $plugin;
+
+    protected function setUp()
+    {
+        $this->productRuleProcessor = $this
+            ->getMockBuilder(\Magento\CatalogRule\Model\Indexer\Product\ProductRuleProcessor::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->subject = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Product::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->model = $this->getMockForAbstractClass(
+            \Magento\Framework\Model\AbstractModel::class,
+            [],
+            '',
+            false,
+            true,
+            true,
+            ['getIsMassupdate', 'getId']
+        );
+
+        $this->plugin = (new ObjectManager($this))->getObject(
+            \Magento\CatalogRule\Plugin\Indexer\Product\Save\ApplyRules::class,
+            [
+                'productRuleProcessor' => $this->productRuleProcessor,
+            ]
+        );
+    }
+
+    public function testAfterSave()
+    {
+        $this->model->expects($this->once())->method('getIsMassupdate')->willReturn(null);
+        $this->model->expects($this->once())->method('getId')->willReturn(1);
+
+        $this->productRuleProcessor->expects($this->once())->method('reindexRow')->willReturnSelf();
+
+        $this->assertSame(
+            $this->subject,
+            $this->plugin->afterSave($this->subject, $this->subject, $this->model)
+        );
+    }
+}
diff --git a/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/Validation.php b/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/Validation.php
index 7164de93bc705f06647f1ef847bbc0a81cb8a7a3..607f02ba7902c921a8d3ad2f12d7d5798cd6024f 100644
--- a/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/Validation.php
+++ b/app/code/Magento/CatalogRuleConfigurable/Plugin/CatalogRule/Model/Rule/Validation.php
@@ -6,18 +6,23 @@
  */
 namespace Magento\CatalogRuleConfigurable\Plugin\CatalogRule\Model\Rule;
 
-use \Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+use Magento\ConfigurableProduct\Model\Product\Type\Configurable;
+use Magento\CatalogRule\Model\Rule;
+use Magento\Framework\DataObject;
+use Magento\Catalog\Model\Product;
 
 /**
  * Class Validation. Call validate method for configurable product instead simple product
  */
 class Validation
 {
-    /** @var Configurable */
+    /**
+     * @var Configurable
+     */
     private $configurable;
 
     /**
-     * @param \Magento\ConfigurableProduct\Model\Product\Type\Configurable $configurableType
+     * @param Configurable $configurableType
      */
     public function __construct(Configurable $configurableType)
     {
@@ -25,17 +30,15 @@ class Validation
     }
 
     /**
-     * @param \Magento\CatalogRule\Model\Rule $rule
-     * @param \Closure $proceed
-     * @param \Magento\Framework\DataObject|\Magento\Catalog\Model\Product $product
+     * Define if it is needed to apply rule if parent configurable product match conditions
+     *
+     * @param Rule $rule
+     * @param bool $validateResult
+     * @param DataObject|Product $product
      * @return bool
      */
-    public function aroundValidate(
-        \Magento\CatalogRule\Model\Rule $rule,
-        \Closure $proceed,
-        \Magento\Framework\DataObject $product
-    ) {
-        $validateResult = $proceed($product);
+    public function afterValidate(Rule $rule, $validateResult, DataObject $product)
+    {
         if (!$validateResult && ($configurableProducts = $this->configurable->getParentIdsByChild($product->getId()))) {
             foreach ($configurableProducts as $configurableProductId) {
                 $validateResult = $rule->getConditions()->validateByEntityId($configurableProductId);
diff --git a/app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ValidationTest.php b/app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ValidationTest.php
index b7c95fe97ac2082d2a5e48b5722c4f9e2516688d..6ed0cb1d48979ad7a715c09eedd0556f0e742e15 100644
--- a/app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ValidationTest.php
+++ b/app/code/Magento/CatalogRuleConfigurable/Test/Unit/Plugin/CatalogRule/Model/Rule/ValidationTest.php
@@ -62,16 +62,12 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
      * @dataProvider dataProviderForValidateWithValidConfigurableProduct
      * @return void
      */
-    public function testAroundValidateWithValidConfigurableProduct(
+    public function testAfterValidateWithValidConfigurableProduct(
         $parentsIds,
         $validationResult,
         $runValidateAmount,
         $result
     ) {
-        $closureMock = function () {
-            return false;
-        };
-
         $this->productMock->expects($this->once())->method('getId')->willReturn('product_id');
         $this->configurableMock->expects($this->once())->method('getParentIdsByChild')->with('product_id')
             ->willReturn($parentsIds);
@@ -82,7 +78,7 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals(
             $result,
-            $this->validation->aroundValidate($this->ruleMock, $closureMock, $this->productMock)
+            $this->validation->afterValidate($this->ruleMock, false, $this->productMock)
         );
     }
 
diff --git a/app/code/Magento/CatalogRuleConfigurable/composer.json b/app/code/Magento/CatalogRuleConfigurable/composer.json
index 06c3019cfb12fefeebfca78acd1b9553628df57d..cc51269e2d9720e380612cf56c712ff2459bbe35 100644
--- a/app/code/Magento/CatalogRuleConfigurable/composer.json
+++ b/app/code/Magento/CatalogRuleConfigurable/composer.json
@@ -5,6 +5,7 @@
         "php": "~5.6.0|7.0.2|7.0.4|~7.0.6",
         "magento/module-configurable-product": "100.2.*",
         "magento/framework": "100.2.*",
+        "magento/module-catalog": "101.1.*",
         "magento/module-catalog-rule": "100.2.*",
         "magento/module-store": "100.2.*",
         "magento/module-customer": "100.2.*",
diff --git a/app/code/Magento/CatalogSearch/Block/Plugin/FrontTabPlugin.php b/app/code/Magento/CatalogSearch/Block/Plugin/FrontTabPlugin.php
index de344754d16fe8dd79d0bb4aca61cb1e7070aa76..9b5c324d0dfa01f784d34307104fc9141128f301 100644
--- a/app/code/Magento/CatalogSearch/Block/Plugin/FrontTabPlugin.php
+++ b/app/code/Magento/CatalogSearch/Block/Plugin/FrontTabPlugin.php
@@ -5,11 +5,14 @@
  */
 namespace Magento\CatalogSearch\Block\Plugin;
 
-use Magento\Catalog\Block\Adminhtml\Product\Attribute\Edit\Tab\Front;
+use Magento\Catalog\Block\Adminhtml\Product\Attribute\Edit\Tab\Front as ProductAttributeFrontTabBlock;
 use Magento\CatalogSearch\Model\Source\Weight;
 use Magento\Framework\Data\Form;
 use Magento\Framework\Data\Form\Element\Fieldset;
 
+/**
+ * Plugin for Magento\Catalog\Block\Adminhtml\Product\Attribute\Edit\Tab\Front
+ */
 class FrontTabPlugin
 {
     /**
@@ -26,15 +29,14 @@ class FrontTabPlugin
     }
 
     /**
-     * @param Front $subject
-     * @param callable $proceed
+     * Add Search Weight field
+     *
+     * @param ProductAttributeFrontTabBlock $subject
      * @param Form $form
-     * @return Front
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     * @return void
      */
-    public function aroundSetForm(Front $subject, \Closure $proceed, Form $form)
+    public function beforeSetForm(ProductAttributeFrontTabBlock $subject, Form $form)
     {
-        $block = $proceed($form);
         /** @var Fieldset $fieldset */
         $fieldset = $form->getElement('front_fieldset');
         $fieldset->addField(
@@ -47,17 +49,8 @@ class FrontTabPlugin
             ],
             'is_searchable'
         );
-
         $subject->getChildBlock('form_after')
-            ->addFieldMap(
-                'search_weight',
-                'search_weight'
-            )
-            ->addFieldDependence(
-                'search_weight',
-                'searchable',
-                '1'
-            );
-        return $block;
+            ->addFieldMap('search_weight', 'search_weight')
+            ->addFieldDependence('search_weight', 'searchable', '1');
     }
 }
diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/AbstractPlugin.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/AbstractPlugin.php
index bbdb24bec0918b8bbc4eef14b60867bfcceff5a2..956f07206c20f03f6930c56b62a25ec8f3fceda0 100644
--- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/AbstractPlugin.php
+++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/AbstractPlugin.php
@@ -5,19 +5,24 @@
  */
 namespace Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin;
 
-use Magento\CatalogSearch\Model\Indexer\Fulltext;
+use Magento\Framework\Indexer\IndexerRegistry;
+use Magento\CatalogSearch\Model\Indexer\Fulltext as FulltextIndexer;
 
+/**
+ * Abstract plugin for indexers
+ */
 abstract class AbstractPlugin
 {
-    /** @var \Magento\Framework\Indexer\IndexerRegistry */
+    /**
+     * @var IndexerRegistry
+     */
     protected $indexerRegistry;
 
     /**
-     * @param \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry
+     * @param IndexerRegistry $indexerRegistry
      */
-    public function __construct(
-        \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry
-    ) {
+    public function __construct(IndexerRegistry $indexerRegistry)
+    {
         $this->indexerRegistry = $indexerRegistry;
     }
 
@@ -29,7 +34,8 @@ abstract class AbstractPlugin
      */
     protected function reindexRow($productId)
     {
-        $indexer = $this->indexerRegistry->get(Fulltext::INDEXER_ID);
+        $indexer = $this->indexerRegistry->get(FulltextIndexer::INDEXER_ID);
+
         if (!$indexer->isScheduled()) {
             $indexer->reindexRow($productId);
         }
@@ -43,7 +49,8 @@ abstract class AbstractPlugin
      */
     protected function reindexList(array $productIds)
     {
-        $indexer = $this->indexerRegistry->get(Fulltext::INDEXER_ID);
+        $indexer = $this->indexerRegistry->get(FulltextIndexer::INDEXER_ID);
+
         if (!$indexer->isScheduled()) {
             $indexer->reindexList($productIds);
         }
diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Attribute.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Attribute.php
index e358fe2ca5a28d8a9a098c6b771799a9335083e4..e21f4a976af8ecd6aa920e71dd50755e614ece61 100644
--- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Attribute.php
+++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Attribute.php
@@ -14,6 +14,21 @@ class Attribute extends AbstractPlugin
      */
     private $config;
 
+    /**
+     * @var boolean
+     */
+    private $deleteNeedInvalidation;
+
+    /**
+     * @var boolean
+     */
+    private $saveNeedInvalidation;
+
+    /**
+     * @var boolean
+     */
+    private $saveIsNew;
+
     /**
      * @param \Magento\Framework\Indexer\IndexerRegistry $indexerRegistry
      * @param \Magento\Framework\Search\Request\Config $config
@@ -27,32 +42,43 @@ class Attribute extends AbstractPlugin
     }
 
     /**
-     * Invalidate indexer on attribute save (searchable flag change)
+     * Check if indexer invalidation is needed on attribute save (searchable flag change)
      *
      * @param \Magento\Catalog\Model\ResourceModel\Attribute $subject
-     * @param \Closure $proceed
      * @param \Magento\Framework\Model\AbstractModel $attribute
      *
-     * @return \Magento\Catalog\Model\ResourceModel\Attribute
+     * @return void
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundSave(
+    public function beforeSave(
         \Magento\Catalog\Model\ResourceModel\Attribute $subject,
-        \Closure $proceed,
         \Magento\Framework\Model\AbstractModel $attribute
     ) {
-        $isNew = $attribute->isObjectNew();
-        $needInvalidation = (
+        $this->saveIsNew = $attribute->isObjectNew();
+        $this->saveNeedInvalidation = (
                 $attribute->dataHasChangedFor('is_searchable')
                 || $attribute->dataHasChangedFor('is_filterable')
                 || $attribute->dataHasChangedFor('is_visible_in_advanced_search')
-            ) && !$isNew;
+            ) && ! $this->saveIsNew;
+    }
 
-        $result = $proceed($attribute);
-        if ($needInvalidation) {
+    /**
+     * Invalidate indexer on attribute save (searchable flag change)
+     *
+     * @param \Magento\Catalog\Model\ResourceModel\Attribute $subject
+     * @param \Magento\Catalog\Model\ResourceModel\Attribute $result
+     *
+     * @return \Magento\Catalog\Model\ResourceModel\Attribute
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterSave(
+        \Magento\Catalog\Model\ResourceModel\Attribute $subject,
+        \Magento\Catalog\Model\ResourceModel\Attribute $result
+    ) {
+        if ($this->saveNeedInvalidation) {
             $this->indexerRegistry->get(Fulltext::INDEXER_ID)->invalidate();
         }
-        if ($isNew || $needInvalidation) {
+        if ($this->saveIsNew || $this->saveNeedInvalidation) {
             $this->config->reset();
         }
 
@@ -60,26 +86,37 @@ class Attribute extends AbstractPlugin
     }
 
     /**
-     * Invalidate indexer on searchable attribute delete
+     * Check if indexer invalidation is needed on searchable attribute delete
      *
      * @param \Magento\Catalog\Model\ResourceModel\Attribute $subject
-     * @param \Closure $proceed
      * @param \Magento\Framework\Model\AbstractModel $attribute
      *
-     * @return \Magento\Catalog\Model\ResourceModel\Attribute
+     * @return void
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundDelete(
+    public function beforeDelete(
         \Magento\Catalog\Model\ResourceModel\Attribute $subject,
-        \Closure $proceed,
         \Magento\Framework\Model\AbstractModel $attribute
     ) {
-        $needInvalidation = !$attribute->isObjectNew() && $attribute->getIsSearchable();
-        $result = $proceed($attribute);
-        if ($needInvalidation) {
+        $this->deleteNeedInvalidation = !$attribute->isObjectNew() && $attribute->getIsSearchable();
+    }
+
+    /**
+     * Invalidate indexer on searchable attribute delete
+     *
+     * @param \Magento\Catalog\Model\ResourceModel\Attribute $subject
+     * @param \Magento\Catalog\Model\ResourceModel\Attribute $result
+     *
+     * @return \Magento\Catalog\Model\ResourceModel\Attribute
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function afterDelete(
+        \Magento\Catalog\Model\ResourceModel\Attribute $subject,
+        \Magento\Catalog\Model\ResourceModel\Attribute $result
+    ) {
+        if ($this->deleteNeedInvalidation) {
             $this->indexerRegistry->get(Fulltext::INDEXER_ID)->invalidate();
         }
-
         return $result;
     }
 }
diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Product/Action.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Product/Action.php
index 5c43eb673591adf00e9e9eb6bd2e491cd5f585af..c144737606a3809cba52448a7485f3000aa51343 100644
--- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Product/Action.php
+++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Product/Action.php
@@ -3,56 +3,54 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Product;
 
-use Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\AbstractPlugin;
+use Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\AbstractPlugin as AbstractIndexerPlugin;
+use Magento\Catalog\Model\Product\Action as ProductAction;
 
-class Action extends AbstractPlugin
+/**
+ * Plugin for Magento\Catalog\Model\Product\Action
+ */
+class Action extends AbstractIndexerPlugin
 {
     /**
      * Reindex on product attribute mass change
      *
-     * @param \Magento\Catalog\Model\Product\Action $subject
-     * @param \Closure $closure
+     * @param ProductAction $subject
+     * @param ProductAction $action
      * @param array $productIds
      * @param array $attrData
      * @param int $storeId
-     * @return \Magento\Catalog\Model\Product\Action
+     * @return ProductAction
+     *
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundUpdateAttributes(
-        \Magento\Catalog\Model\Product\Action $subject,
-        \Closure $closure,
-        array $productIds,
-        array $attrData,
+    public function afterUpdateAttributes(
+        ProductAction $subject,
+        ProductAction $action,
+        $productIds,
+        $attrData,
         $storeId
     ) {
-        $result = $closure($productIds, $attrData, $storeId);
         $this->reindexList(array_unique($productIds));
-        return $result;
+
+        return $action;
     }
 
     /**
      * Reindex on product websites mass change
      *
-     * @param \Magento\Catalog\Model\Product\Action $subject
-     * @param \Closure $closure
+     * @param ProductAction $subject
+     * @param null $result
      * @param array $productIds
      * @param array $websiteIds
      * @param string $type
-     * @return \Magento\Catalog\Model\Product\Action
+     * @return void
+     *
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundUpdateWebsites(
-        \Magento\Catalog\Model\Product\Action $subject,
-        \Closure $closure,
-        array $productIds,
-        array $websiteIds,
-        $type
-    ) {
-        $result = $closure($productIds, $websiteIds, $type);
+    public function afterUpdateWebsites(ProductAction $subject, $result, $productIds, $websiteIds, $type)
+    {
         $this->reindexList(array_unique($productIds));
-        return $result;
     }
 }
diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Store/Group.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Store/Group.php
index 0836760a2f5897f991914ae6d27f51566a5207e1..ed431110e04902f962f662d6b82d85e3a9f0426c 100644
--- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Store/Group.php
+++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Store/Group.php
@@ -5,30 +5,48 @@
  */
 namespace Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Store;
 
-use Magento\CatalogSearch\Model\Indexer\Fulltext;
-use Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\AbstractPlugin;
+use Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\AbstractPlugin as AbstractIndexerPlugin;
+use Magento\Store\Model\ResourceModel\Group as StoreGroupResourceModel;
+use Magento\Framework\Model\AbstractModel;
+use Magento\CatalogSearch\Model\Indexer\Fulltext as FulltextIndexer;
 
-class Group extends AbstractPlugin
+/**
+ * Plugin for Magento\Store\Model\ResourceModel\Group
+ */
+class Group extends AbstractIndexerPlugin
 {
+    /**
+     * @var bool
+     */
+    private $needInvalidation;
+
+    /**
+     * Check if indexer requires invalidation after store group save
+     *
+     * @param StoreGroupResourceModel $subject
+     * @param AbstractModel $group
+     * @return void
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function beforeSave(StoreGroupResourceModel $subject, AbstractModel $group)
+    {
+        $this->needInvalidation = !$group->isObjectNew() && $group->dataHasChangedFor('website_id');
+    }
+
     /**
      * Invalidate indexer on store group save
      *
-     * @param \Magento\Store\Model\ResourceModel\Group $subject
-     * @param \Closure $proceed
-     * @param \Magento\Framework\Model\AbstractModel $group
+     * @param StoreGroupResourceModel $subject
+     * @param StoreGroupResourceModel $result
+     * @return StoreGroupResourceModel
      *
-     * @return \Magento\Store\Model\ResourceModel\Group
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundSave(
-        \Magento\Store\Model\ResourceModel\Group $subject,
-        \Closure $proceed,
-        \Magento\Framework\Model\AbstractModel $group
-    ) {
-        $needInvalidation = !$group->isObjectNew() && $group->dataHasChangedFor('website_id');
-        $result = $proceed($group);
-        if ($needInvalidation) {
-            $this->indexerRegistry->get(Fulltext::INDEXER_ID)->invalidate();
+    public function afterSave(StoreGroupResourceModel $subject, StoreGroupResourceModel $result)
+    {
+        if ($this->needInvalidation) {
+            $this->indexerRegistry->get(FulltextIndexer::INDEXER_ID)->invalidate();
         }
 
         return $result;
@@ -37,17 +55,16 @@ class Group extends AbstractPlugin
     /**
      * Invalidate indexer on store group delete
      *
-     * @param \Magento\Store\Model\ResourceModel\Group $subject
-     * @param \Magento\Store\Model\ResourceModel\Group $result
+     * @param StoreGroupResourceModel $subject
+     * @param StoreGroupResourceModel $result
+     * @return StoreGroupResourceModel
      *
-     * @return \Magento\Store\Model\ResourceModel\Group
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function afterDelete(
-        \Magento\Store\Model\ResourceModel\Group $subject,
-        \Magento\Store\Model\ResourceModel\Group $result
-    ) {
-        $this->indexerRegistry->get(Fulltext::INDEXER_ID)->invalidate();
+    public function afterDelete(StoreGroupResourceModel $subject, StoreGroupResourceModel $result)
+    {
+        $this->indexerRegistry->get(FulltextIndexer::INDEXER_ID)->invalidate();
+
         return $result;
     }
 }
diff --git a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Store/View.php b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Store/View.php
index 128a1c07e93ffa179dc96be8cf7624b34ce6a446..5d57b71634d56153b94dd37f566f70323a4565de 100644
--- a/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Store/View.php
+++ b/app/code/Magento/CatalogSearch/Model/Indexer/Fulltext/Plugin/Store/View.php
@@ -5,48 +5,66 @@
  */
 namespace Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Store;
 
-use Magento\CatalogSearch\Model\Indexer\Fulltext;
-use Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\AbstractPlugin;
+use Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\AbstractPlugin as AbstractIndexerPlugin;
+use Magento\Store\Model\ResourceModel\Store as StoreResourceModel;
+use Magento\Framework\Model\AbstractModel;
+use Magento\CatalogSearch\Model\Indexer\Fulltext as FulltextIndexer;
 
-class View extends AbstractPlugin
+/**
+ * Plugin for Magento\Store\Model\ResourceModel\Store
+ */
+class View extends AbstractIndexerPlugin
 {
+    /**
+     * @var bool
+     */
+    private $needInvalidation;
+
+    /**
+     * Check if indexer requires invalidation after store view save
+     *
+     * @param StoreResourceModel $subject
+     * @param AbstractModel $store
+     * @return void
+     *
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function beforeSave(StoreResourceModel $subject, AbstractModel $store)
+    {
+        $this->needInvalidation = $store->isObjectNew();
+    }
+
     /**
      * Invalidate indexer on store view save
      *
-     * @param \Magento\Store\Model\ResourceModel\Store $subject
-     * @param \Closure $proceed
-     * @param \Magento\Framework\Model\AbstractModel $store
+     * @param StoreResourceModel $subject
+     * @param StoreResourceModel $result
+     * @return StoreResourceModel
      *
-     * @return \Magento\Store\Model\ResourceModel\Store
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundSave(
-        \Magento\Store\Model\ResourceModel\Store $subject,
-        \Closure $proceed,
-        \Magento\Framework\Model\AbstractModel $store
-    ) {
-        $needInvalidation = $store->isObjectNew();
-        $result = $proceed($store);
-        if ($needInvalidation) {
-            $this->indexerRegistry->get(Fulltext::INDEXER_ID)->invalidate();
+    public function afterSave(StoreResourceModel $subject, StoreResourceModel $result)
+    {
+        if ($this->needInvalidation) {
+            $this->indexerRegistry->get(FulltextIndexer::INDEXER_ID)->invalidate();
         }
+
         return $result;
     }
 
     /**
      * Invalidate indexer on store view delete
      *
-     * @param \Magento\Store\Model\ResourceModel\Store $subject
-     * @param \Magento\Store\Model\ResourceModel\Store $result
+     * @param StoreResourceModel $subject
+     * @param StoreResourceModel $result
+     * @return StoreResourceModel
      *
-     * @return \Magento\Store\Model\ResourceModel\Store
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function afterDelete(
-        \Magento\Store\Model\ResourceModel\Store $subject,
-        \Magento\Store\Model\ResourceModel\Store $result
-    ) {
-        $this->indexerRegistry->get(Fulltext::INDEXER_ID)->invalidate();
+    public function afterDelete(StoreResourceModel $subject, StoreResourceModel $result)
+    {
+        $this->indexerRegistry->get(FulltextIndexer::INDEXER_ID)->invalidate();
+
         return $result;
     }
 }
diff --git a/app/code/Magento/CatalogSearch/Model/Layer/Search/Plugin/CollectionFilter.php b/app/code/Magento/CatalogSearch/Model/Layer/Search/Plugin/CollectionFilter.php
index b2e26dc04236b2528bd8580175e8fa785d63a822..bc50949736116b340accaffe7bea2b4bd4414cc6 100644
--- a/app/code/Magento/CatalogSearch/Model/Layer/Search/Plugin/CollectionFilter.php
+++ b/app/code/Magento/CatalogSearch/Model/Layer/Search/Plugin/CollectionFilter.php
@@ -28,19 +28,18 @@ class CollectionFilter
      * Add search filter criteria to search collection
      *
      * @param \Magento\Catalog\Model\Layer\Search\CollectionFilter $subject
-     * @param \Closure $proceed
+     * @param null $result
      * @param \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $collection
      * @param Category $category
      * @return void
      * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
-    public function aroundFilter(
+    public function afterFilter(
         \Magento\Catalog\Model\Layer\Search\CollectionFilter $subject,
-        \Closure $proceed,
+        $result,
         $collection,
         Category $category
     ) {
-        $proceed($collection, $category);
         /** @var \Magento\Search\Model\Query $query */
         $query = $this->queryFactory->get();
         if (!$query->isQueryTextShort()) {
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Block/Plugin/FrontTabPluginTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Block/Plugin/FrontTabPluginTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e108def990bfecb8f12b6d07bc09e49f758e22fe
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Block/Plugin/FrontTabPluginTest.php
@@ -0,0 +1,131 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogSearch\Test\Unit\Block\Plugin;
+
+use Magento\CatalogSearch\Block\Plugin\FrontTabPlugin;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\CatalogSearch\Model\Source\Weight as WeightSource;
+use Magento\Catalog\Block\Adminhtml\Product\Attribute\Edit\Tab\Front as ProductAttributeFrontTabBlock;
+use Magento\Framework\Data\Form;
+use Magento\Framework\Data\Form\Element\Fieldset;
+use Magento\Framework\Data\Form\Element\AbstractElement;
+use Magento\Framework\View\Element\AbstractBlock;
+
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class FrontTabPluginTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var FrontTabPlugin
+     */
+    private $plugin;
+
+    /**
+     * @var ObjectManagerHelper
+     */
+    private $objectManagerHelper;
+
+    /**
+     * @var WeightSource|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $weightSourceMock;
+
+    /**
+     * @var ProductAttributeFrontTabBlock|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $subjectMock;
+
+    /**
+     * @var Form|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $formMock;
+
+    /**
+     * @var Fieldset|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $fieldsetMock;
+
+    /**
+     * @var AbstractElement|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $childElementMock;
+
+    /**
+     * @var AbstractBlock|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $childBlockMock;
+
+    protected function setUp()
+    {
+        $this->weightSourceMock = $this->getMockBuilder(WeightSource::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->subjectMock = $this->getMockBuilder(ProductAttributeFrontTabBlock::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->formMock = $this->getMockBuilder(Form::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->fieldsetMock = $this->getMockBuilder(Fieldset::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->childElementMock = $this->getMockBuilder(AbstractElement::class)
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $this->childBlockMock = $this->getMockBuilder(AbstractBlock::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['addFieldMap', 'addFieldDependence'])
+            ->getMockForAbstractClass();
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->plugin = $this->objectManagerHelper->getObject(
+            FrontTabPlugin::class,
+            ['weightSource' => $this->weightSourceMock]
+        );
+    }
+
+    public function testBeforeSetForm()
+    {
+        $weightOptions = [1 => '1', 2 => '2'];
+
+        $this->formMock->expects(static::any())
+            ->method('getElement')
+            ->with('front_fieldset')
+            ->willReturn($this->fieldsetMock);
+        $this->weightSourceMock->expects(static::any())
+            ->method('getOptions')
+            ->willReturn($weightOptions);
+        $this->fieldsetMock->expects(static::once())
+            ->method('addField')
+            ->with(
+                'search_weight',
+                'select',
+                [
+                    'name' => 'search_weight',
+                    'label' => __('Search Weight'),
+                    'values' => $weightOptions
+                ],
+                'is_searchable',
+                false
+            )
+            ->willReturn($this->childElementMock);
+        $this->subjectMock->expects(static::any())
+            ->method('getChildBlock')
+            ->with('form_after')
+            ->willReturn($this->childBlockMock);
+        $this->childBlockMock->expects(static::once())
+            ->method('addFieldMap')
+            ->with('search_weight', 'search_weight')
+            ->willReturnSelf();
+        $this->childBlockMock->expects(static::once())
+            ->method('addFieldDependence')
+            ->with('search_weight', 'searchable', '1')
+            ->willReturnSelf();
+
+        $this->plugin->beforeSetForm($this->subjectMock, $this->formMock);
+    }
+}
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/AttributeTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/AttributeTest.php
index 086b2606457bab80a79e19022743e525357278c8..6375b659fc76c7bb80d89d65bdd0a64d0a220376 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/AttributeTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/AttributeTest.php
@@ -5,7 +5,8 @@
  */
 namespace Magento\CatalogSearch\Test\Unit\Model\Indexer\Fulltext\Plugin;
 
-use \Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Attribute;
+use Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Attribute;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 class AttributeTest extends \PHPUnit_Framework_TestCase
 {
@@ -24,13 +25,29 @@ class AttributeTest extends \PHPUnit_Framework_TestCase
      */
     protected $indexerRegistryMock;
 
+    /**
+     * @var \Magento\Catalog\Model\ResourceModel\Attribute|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $attributeMock;
+
     /**
      * @var Attribute
      */
     protected $model;
 
+    /**
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Framework\Search\Request\Config|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $config;
+
     protected function setUp()
     {
+        $this->objectManager = new ObjectManager($this);
         $this->subjectMock = $this->getMock(\Magento\Catalog\Model\ResourceModel\Attribute::class, [], [], '', false);
         $this->indexerMock = $this->getMockForAbstractClass(
             \Magento\Framework\Indexer\IndexerInterface::class,
@@ -48,113 +65,117 @@ class AttributeTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->attributeMock = $this->getMock(
+            \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class,
+            ['dataHasChangedFor', 'isObjectNew', 'getIsSearchable'],
+            [],
+            '',
+            false
+        );
         $this->config =  $this->getMockBuilder(\Magento\Framework\Search\Request\Config::class)
             ->disableOriginalConstructor()
+            ->setMethods(['reset'])
             ->getMock();
-        $this->model = new Attribute($this->indexerRegistryMock, $this->config);
+        $this->model = $this->objectManager->getObject(
+            Attribute::class,
+            [
+                'indexerRegistry' => $this->indexerRegistryMock,
+                'config' => $this->config
+            ]
+        );
     }
 
-    /**
-     * @param bool $isObjectNew
-     * @param bool $isSearchableChanged
-     * @param int $invalidateCounter
-     * @return void
-     * @dataProvider aroundSaveDataProvider
-     */
-    public function testAroundSave($isObjectNew, $isSearchableChanged, $invalidateCounter)
+    public function testBeforeSave()
     {
-        $attributeMock = $this->getMock(
-            \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class,
-            ['dataHasChangedFor', 'isObjectNew', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $attributeMock->expects($this->any())
+        $this->attributeMock->expects($this->once())
+            ->method('isObjectNew')
+            ->willReturn(true);
+        $this->attributeMock->expects($this->once())
             ->method('dataHasChangedFor')
-            ->will($this->returnValue($isSearchableChanged));
+            ->with('is_searchable')
+            ->willReturn(true);
+        $this->assertEquals(
+            null,
+            $this->model->beforeSave($this->subjectMock, $this->attributeMock)
+        );
+    }
 
-        $attributeMock->expects($this->any())->method('isObjectNew')->will($this->returnValue($isObjectNew));
+    public function testAfterSaveNoInvalidation()
+    {
+        $this->assertEquals(
+            $this->subjectMock,
+            $this->model->afterSave($this->subjectMock, $this->subjectMock)
+        );
+    }
 
-        $closureMock = function (\Magento\Catalog\Model\ResourceModel\Eav\Attribute $object) use ($attributeMock) {
-            $this->assertEquals($object, $attributeMock);
-            return $this->subjectMock;
-        };
+    public function testAfterSaveWithInvalidation()
+    {
+        $model = $this->objectManager->getObject(
+            Attribute::class,
+            [
+                'indexerRegistry' => $this->indexerRegistryMock,
+                'config' => $this->config,
+                'saveNeedInvalidation' => true,
+                'saveIsNew' => true
+            ]
+        );
 
-        $this->indexerMock->expects($this->exactly($invalidateCounter))->method('invalidate');
-        $this->prepareIndexer($invalidateCounter);
+        $this->indexerMock->expects($this->once())->method('invalidate');
+        $this->prepareIndexer();
+        $this->config->expects($this->once())
+            ->method('reset');
 
         $this->assertEquals(
             $this->subjectMock,
-            $this->model->aroundSave($this->subjectMock, $closureMock, $attributeMock)
+            $model->afterSave($this->subjectMock, $this->subjectMock)
         );
     }
 
-    /**
-     * @return array
-     */
-    public function aroundSaveDataProvider()
+    public function testBeforeDelete()
     {
-        return [
-            [false, false, 0],
-            [false, true, 1],
-            [true, false, 0],
-            [true, true, 0],
-        ];
+        $this->attributeMock->expects($this->once())
+            ->method('isObjectNew')
+            ->willReturn(false);
+        $this->attributeMock->expects($this->once())
+            ->method('getIsSearchable')
+            ->willReturn(true);
+        $this->assertEquals(
+            null,
+            $this->model->beforeDelete($this->subjectMock, $this->attributeMock)
+        );
     }
 
-    /**
-     * @param bool $isObjectNew
-     * @param bool $isSearchable
-     * @param int $invalidateCounter
-     * @return void
-     * @dataProvider aroundDeleteDataProvider
-     */
-    public function testAroundDelete($isObjectNew, $isSearchable, $invalidateCounter)
+    public function testAfterDeleteNoInvalidation()
     {
-        $attributeMock = $this->getMock(
-            \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class,
-            ['getIsSearchable', 'isObjectNew', '__wakeup'],
-            [],
-            '',
-            false
+        $this->assertEquals(
+            $this->subjectMock,
+            $this->model->afterDelete($this->subjectMock, $this->subjectMock)
         );
-        $attributeMock->expects($this->any())->method('getIsSearchable')->will($this->returnValue($isSearchable));
-        $attributeMock->expects($this->once())->method('isObjectNew')->will($this->returnValue($isObjectNew));
+    }
 
-        $closureMock = function (\Magento\Catalog\Model\ResourceModel\Eav\Attribute $object) use ($attributeMock) {
-            $this->assertEquals($object, $attributeMock);
-            return $this->subjectMock;
-        };
+    public function testAfterDeleteWithInvalidation()
+    {
+        $model = $this->objectManager->getObject(
+            Attribute::class,
+            [
+                'indexerRegistry' => $this->indexerRegistryMock,
+                'config' => $this->config,
+                'deleteNeedInvalidation' => true
+            ]
+        );
 
-        $this->indexerMock->expects($this->exactly($invalidateCounter))->method('invalidate');
-        $this->prepareIndexer($invalidateCounter);
+        $this->indexerMock->expects($this->once())->method('invalidate');
+        $this->prepareIndexer();
 
         $this->assertEquals(
             $this->subjectMock,
-            $this->model->aroundDelete($this->subjectMock, $closureMock, $attributeMock)
+            $model->afterDelete($this->subjectMock, $this->subjectMock)
         );
     }
 
-    /**
-     * @return array
-     */
-    public function aroundDeleteDataProvider()
-    {
-        return [
-            [false, false, 0],
-            [false, true, 1],
-            [true, false, 0],
-            [true, true, 0],
-        ];
-    }
-
-    /**
-     * @param $invalidateCounter
-     */
-    protected function prepareIndexer($invalidateCounter)
+    private function prepareIndexer()
     {
-        $this->indexerRegistryMock->expects($this->exactly($invalidateCounter))
+        $this->indexerRegistryMock->expects($this->once())
             ->method('get')
             ->with(\Magento\CatalogSearch\Model\Indexer\Fulltext::INDEXER_ID)
             ->will($this->returnValue($this->indexerMock));
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Product/ActionTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Product/ActionTest.php
index 3ffa164d149b875196df8448682eecd1a3ae53a1..f6767c3fc9d1c62a4d3c06b6e984135f168d177b 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Product/ActionTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Product/ActionTest.php
@@ -3,132 +3,122 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\CatalogSearch\Test\Unit\Model\Indexer\Fulltext\Plugin\Product;
 
-use \Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Product\Action;
+use Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Product\Action as ProductActionIndexerPlugin;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Framework\Indexer\IndexerRegistry;
+use Magento\Framework\Indexer\IndexerInterface;
+use Magento\Catalog\Model\Product\Action as ProductAction;
+use Magento\CatalogSearch\Model\Indexer\Fulltext as FulltextIndexer;
 
 class ActionTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Indexer\IndexerInterface
+     * @var ProductActionIndexerPlugin
      */
-    protected $indexerMock;
+    private $plugin;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\Product\Action
+     * @var ObjectManagerHelper
      */
-    protected $subjectMock;
+    private $objectManagerHelper;
 
     /**
-     * @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
+     * @var IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $indexerRegistryMock;
+    private $indexerRegistryMock;
 
     /**
-     * @var Action
+     * @var IndexerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $model;
+    private $indexerMock;
+
+    /**
+     * @var ProductAction|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $subjectMock;
 
     protected function setUp()
     {
-        $this->subjectMock = $this->getMock(\Magento\Catalog\Model\Product\Action::class, [], [], '', false);
-
-        $this->indexerMock = $this->getMockForAbstractClass(
-            \Magento\Framework\Indexer\IndexerInterface::class,
-            [],
-            '',
-            false,
-            false,
-            true,
-            ['getId', 'getState', '__wakeup']
-        );
-        $this->indexerRegistryMock = $this->getMock(
-            \Magento\Framework\Indexer\IndexerRegistry::class,
-            ['get'],
-            [],
-            '',
-            false
-        );
+        $this->indexerRegistryMock = $this->getMockBuilder(IndexerRegistry::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->indexerMock = $this->getMockBuilder(IndexerInterface::class)
+            ->getMockForAbstractClass();
+        $this->subjectMock = $this->getMockBuilder(ProductAction::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->indexerRegistryMock->expects(static::once())
+            ->method('get')
+            ->with(FulltextIndexer::INDEXER_ID)
+            ->willReturn($this->indexerMock);
 
-        $this->model = new Action($this->indexerRegistryMock);
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->plugin = $this->objectManagerHelper->getObject(
+            ProductActionIndexerPlugin::class,
+            ['indexerRegistry' => $this->indexerRegistryMock]
+        );
     }
 
-    public function testAroundUpdateAttributesNonScheduled()
+    public function testAfterUpdateAttributesNonScheduled()
     {
-        $this->indexerMock->expects($this->once())->method('isScheduled')->will($this->returnValue(false));
-        $this->indexerMock->expects($this->once())->method('reindexList')->with([1, 2, 3]);
-        $this->prepareIndexer();
-
-        $closureMock = function ($productIds, $attrData, $storeId) {
-            $this->assertEquals([1, 2, 3], $productIds);
-            $this->assertEquals([4, 5, 6], $attrData);
-            $this->assertEquals(1, $storeId);
-            return $this->subjectMock;
-        };
-
-        $this->assertEquals(
+        $productIds = [1, 2, 3];
+
+        $this->indexerMock->expects(static::once())
+            ->method('isScheduled')
+            ->willReturn(false);
+        $this->indexerMock->expects(static::once())
+            ->method('reindexList')
+            ->with($productIds);
+
+        $this->assertSame(
             $this->subjectMock,
-            $this->model->aroundUpdateAttributes($this->subjectMock, $closureMock, [1, 2, 3], [4, 5, 6], 1)
+            $this->plugin->afterUpdateAttributes($this->subjectMock, $this->subjectMock, $productIds, [], null)
         );
     }
 
-    public function testAroundUpdateAttributesScheduled()
+    public function testAfterUpdateAttributesScheduled()
     {
-        $this->indexerMock->expects($this->once())->method('isScheduled')->will($this->returnValue(true));
-        $this->indexerMock->expects($this->never())->method('reindexList');
-        $this->prepareIndexer();
-
-        $closureMock = function ($productIds, $attrData, $storeId) {
-            $this->assertEquals([1, 2, 3], $productIds);
-            $this->assertEquals([4, 5, 6], $attrData);
-            $this->assertEquals(1, $storeId);
-            return $this->subjectMock;
-        };
-
-        $this->assertEquals(
+        $productIds = [1, 2, 3];
+
+        $this->indexerMock->expects(static::once())
+            ->method('isScheduled')
+            ->willReturn(true);
+        $this->indexerMock->expects(static::never())
+            ->method('reindexList');
+
+        $this->assertSame(
             $this->subjectMock,
-            $this->model->aroundUpdateAttributes($this->subjectMock, $closureMock, [1, 2, 3], [4, 5, 6], 1)
+            $this->plugin->afterUpdateAttributes($this->subjectMock, $this->subjectMock, $productIds, [], null)
         );
     }
 
-    public function testAroundUpdateWebsitesNonScheduled()
+    public function testAfterUpdateWebsitesNonScheduled()
     {
-        $this->indexerMock->expects($this->once())->method('isScheduled')->will($this->returnValue(false));
-        $this->indexerMock->expects($this->once())->method('reindexList')->with([1, 2, 3]);
-        $this->prepareIndexer();
-
-        $closureMock = function ($productIds, $websiteIds, $type) {
-            $this->assertEquals([1, 2, 3], $productIds);
-            $this->assertEquals([4, 5, 6], $websiteIds);
-            $this->assertEquals('type', $type);
-            return $this->subjectMock;
-        };
-
-        $this->model->aroundUpdateWebsites($this->subjectMock, $closureMock, [1, 2, 3], [4, 5, 6], 'type');
-    }
+        $productIds = [1, 2, 3];
 
-    public function testAroundUpdateWebsitesScheduled()
-    {
-        $this->indexerMock->expects($this->once())->method('isScheduled')->will($this->returnValue(true));
-        $this->indexerMock->expects($this->never())->method('reindexList');
-        $this->prepareIndexer();
-
-        $closureMock = function ($productIds, $websiteIds, $type) {
-            $this->assertEquals([1, 2, 3], $productIds);
-            $this->assertEquals([4, 5, 6], $websiteIds);
-            $this->assertEquals('type', $type);
-            return $this->subjectMock;
-        };
-
-        $this->model->aroundUpdateWebsites($this->subjectMock, $closureMock, [1, 2, 3], [4, 5, 6], 'type');
+        $this->indexerMock->expects(static::once())
+            ->method('isScheduled')
+            ->willReturn(false);
+        $this->indexerMock->expects(static::once())
+            ->method('reindexList')
+            ->with($productIds);
+
+        $this->plugin->afterUpdateWebsites($this->subjectMock, $this->subjectMock, $productIds, [], null);
     }
 
-    protected function prepareIndexer()
+    public function testAfterUpdateWebsitesScheduled()
     {
-        $this->indexerRegistryMock->expects($this->once())
-            ->method('get')
-            ->with(\Magento\CatalogSearch\Model\Indexer\Fulltext::INDEXER_ID)
-            ->will($this->returnValue($this->indexerMock));
+        $productIds = [1, 2, 3];
+
+        $this->indexerMock->expects(static::once())
+            ->method('isScheduled')
+            ->willReturn(true);
+        $this->indexerMock->expects(static::never())
+            ->method('reindexList');
+
+        $this->plugin->afterUpdateWebsites($this->subjectMock, $this->subjectMock, $productIds, [], null);
     }
 }
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Store/GroupTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Store/GroupTest.php
index eb6328f249d621b77b923e20b8a5f5ffae0304bc..2fccfb7743de4476565416591dba80a94546f227 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Store/GroupTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Store/GroupTest.php
@@ -5,50 +5,66 @@
  */
 namespace Magento\CatalogSearch\Test\Unit\Model\Indexer\Fulltext\Plugin\Store;
 
-use \Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Store\Group;
+use Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Store\Group as StoreGroupIndexerPlugin;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Framework\Indexer\IndexerRegistry;
+use Magento\Framework\Indexer\IndexerInterface;
+use Magento\Store\Model\ResourceModel\Group as StoreGroupResourceModel;
+use Magento\Store\Model\Group as StoreGroup;
+use Magento\CatalogSearch\Model\Indexer\Fulltext as FulltextIndexer;
 
 class GroupTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Indexer\IndexerInterface
+     * @var StoreGroupIndexerPlugin
      */
-    protected $indexerMock;
+    private $plugin;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Store\Model\ResourceModel\Group
+     * @var ObjectManagerHelper
      */
-    protected $subjectMock;
+    private $objectManagerHelper;
 
     /**
-     * @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
+     * @var IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $indexerRegistryMock;
+    private $indexerRegistryMock;
 
     /**
-     * @var Group
+     * @var IndexerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $model;
+    private $indexerMock;
+
+    /**
+     * @var StoreGroupResourceModel|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $subjectMock;
+
+    /**
+     * @var StoreGroup|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeGroupMock;
 
     protected function setUp()
     {
-        $this->subjectMock = $this->getMock(\Magento\Store\Model\ResourceModel\Group::class, [], [], '', false);
-        $this->indexerMock = $this->getMockForAbstractClass(
-            \Magento\Framework\Indexer\IndexerInterface::class,
-            [],
-            '',
-            false,
-            false,
-            true,
-            ['getId', 'getState', '__wakeup']
-        );
-        $this->indexerRegistryMock = $this->getMock(
-            \Magento\Framework\Indexer\IndexerRegistry::class,
-            ['get'],
-            [],
-            '',
-            false
+        $this->indexerRegistryMock = $this->getMockBuilder(IndexerRegistry::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->indexerMock = $this->getMockBuilder(IndexerInterface::class)
+            ->getMockForAbstractClass();
+        $this->subjectMock = $this->getMockBuilder(StoreGroupResourceModel::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->storeGroupMock = $this->getMockBuilder(StoreGroup::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['dataHasChangedFor', 'isObjectNew'])
+            ->getMock();
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->plugin = $this->objectManagerHelper->getObject(
+            StoreGroupIndexerPlugin::class,
+            ['indexerRegistry' => $this->indexerRegistryMock]
         );
-        $this->model = new Group($this->indexerRegistryMock);
     }
 
     /**
@@ -56,72 +72,58 @@ class GroupTest extends \PHPUnit_Framework_TestCase
      * @param bool $websiteChanged
      * @param int $invalidateCounter
      * @return void
-     * @dataProvider aroundSaveDataProvider
+     * @dataProvider beforeAfterSaveDataProvider
      */
-    public function testAroundSave($isObjectNew, $websiteChanged, $invalidateCounter)
+    public function testBeforeAfterSave($isObjectNew, $websiteChanged, $invalidateCounter)
     {
-        $groupMock = $this->getMock(
-            \Magento\Store\Model\Group::class,
-            ['dataHasChangedFor', 'isObjectNew', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $groupMock->expects($this->any())
+        $this->prepareIndexer($invalidateCounter);
+        $this->storeGroupMock->expects(static::any())
             ->method('dataHasChangedFor')
             ->with('website_id')
-            ->will($this->returnValue($websiteChanged));
-        $groupMock->expects($this->once())->method('isObjectNew')->will($this->returnValue($isObjectNew));
+            ->willReturn($websiteChanged);
+        $this->storeGroupMock->expects(static::once())
+            ->method('isObjectNew')
+            ->willReturn($isObjectNew);
+        $this->indexerMock->expects(static::exactly($invalidateCounter))
+            ->method('invalidate');
 
-        $closureMock = function (\Magento\Store\Model\Group $object) use ($groupMock) {
-            $this->assertEquals($object, $groupMock);
-            return $this->subjectMock;
-        };
-
-        $this->indexerMock->expects($this->exactly($invalidateCounter))->method('invalidate');
-        $this->prepareIndexer($invalidateCounter);
-
-        $this->assertEquals(
-            $this->subjectMock,
-            $this->model->aroundSave($this->subjectMock, $closureMock, $groupMock)
-        );
+        $this->plugin->beforeSave($this->subjectMock, $this->storeGroupMock);
+        $this->assertSame($this->subjectMock, $this->plugin->afterSave($this->subjectMock, $this->subjectMock));
     }
 
     /**
      * @return array
      */
-    public function aroundSaveDataProvider()
+    public function beforeAfterSaveDataProvider()
     {
         return [
             [false, false, 0],
             [false, true, 1],
             [true, false, 0],
-            [true, true, 0],
+            [true, true, 0]
         ];
     }
 
-    /**
-     * @return void
-     */
     public function testAfterDelete()
     {
-        $this->indexerMock->expects($this->once())->method('invalidate');
         $this->prepareIndexer(1);
+        $this->indexerMock->expects(static::once())
+            ->method('invalidate');
 
-        $this->assertEquals(
-            $this->subjectMock,
-            $this->model->afterDelete($this->subjectMock, $this->subjectMock)
-        );
+        $this->assertSame($this->subjectMock, $this->plugin->afterDelete($this->subjectMock, $this->subjectMock));
     }
 
     /**
+     * Prepare expectations for indexer
+     * 
      * @param int $invalidateCounter
+     * @return void
      */
-    protected function prepareIndexer($invalidateCounter)
+    private function prepareIndexer($invalidateCounter)
     {
-        $this->indexerRegistryMock->expects($this->exactly($invalidateCounter))
+        $this->indexerRegistryMock->expects(static::exactly($invalidateCounter))
             ->method('get')
-            ->with(\Magento\CatalogSearch\Model\Indexer\Fulltext::INDEXER_ID)
-            ->will($this->returnValue($this->indexerMock));
+            ->with(FulltextIndexer::INDEXER_ID)
+            ->willReturn($this->indexerMock);
     }
 }
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Store/ViewTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Store/ViewTest.php
index 22239bb0efcaf3b48e2c221c990b9f17252bb316..d5db837eaa2bd77f29eab8984fda1ef3b001b8ad 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Store/ViewTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Indexer/Fulltext/Plugin/Store/ViewTest.php
@@ -5,116 +5,118 @@
  */
 namespace Magento\CatalogSearch\Test\Unit\Model\Indexer\Fulltext\Plugin\Store;
 
-use \Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Store\View;
+use Magento\CatalogSearch\Model\Indexer\Fulltext\Plugin\Store\View as StoreViewIndexerPlugin;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+use Magento\Framework\Indexer\IndexerRegistry;
+use Magento\Framework\Indexer\IndexerInterface;
+use Magento\Store\Model\ResourceModel\Store as StoreResourceModel;
+use Magento\Store\Model\Store;
+use Magento\CatalogSearch\Model\Indexer\Fulltext as FulltextIndexer;
 
 class ViewTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Indexer\IndexerInterface
+     * @var StoreViewIndexerPlugin
      */
-    protected $indexerMock;
+    private $plugin;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Store\Model\ResourceModel\Store
+     * @var ObjectManagerHelper
      */
-    protected $subjectMock;
+    private $objectManagerHelper;
 
     /**
-     * @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
+     * @var IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $indexerRegistryMock;
+    private $indexerRegistryMock;
 
     /**
-     * @var View
+     * @var IndexerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $model;
+    private $indexerMock;
+
+    /**
+     * @var StoreResourceModel|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $subjectMock;
+
+    /**
+     * @var Store|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeMock;
 
     protected function setUp()
     {
-        $this->subjectMock = $this->getMock(\Magento\Store\Model\ResourceModel\Store::class, [], [], '', false);
-        $this->indexerMock = $this->getMockForAbstractClass(
-            \Magento\Framework\Indexer\IndexerInterface::class,
-            [],
-            '',
-            false,
-            false,
-            true,
-            ['getId', 'getState', '__wakeup']
-        );
-        $this->indexerRegistryMock = $this->getMock(
-            \Magento\Framework\Indexer\IndexerRegistry::class,
-            ['get'],
-            [],
-            '',
-            false
+        $this->indexerRegistryMock = $this->getMockBuilder(IndexerRegistry::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->indexerMock = $this->getMockBuilder(IndexerInterface::class)
+            ->getMockForAbstractClass();
+        $this->subjectMock = $this->getMockBuilder(StoreResourceModel::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->storeMock = $this->getMockBuilder(Store::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['isObjectNew'])
+            ->getMock();
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->plugin = $this->objectManagerHelper->getObject(
+            StoreViewIndexerPlugin::class,
+            ['indexerRegistry' => $this->indexerRegistryMock]
         );
-        $this->model = new View($this->indexerRegistryMock);
     }
 
     /**
      * @param bool $isObjectNew
      * @param int $invalidateCounter
-     * @return void
-     * @dataProvider aroundSaveDataProvider
+     *
+     * @dataProvider beforeAfterSaveDataProvider
      */
-    public function testAroundSave($isObjectNew, $invalidateCounter)
+    public function testBeforeAfterSave($isObjectNew, $invalidateCounter)
     {
-        $viewMock = $this->getMock(
-            \Magento\Store\Model\Store::class,
-            ['dataHasChangedFor', 'isObjectNew', '__wakeup'],
-            [],
-            '',
-            false
-        );
-        $viewMock->expects($this->once())->method('isObjectNew')->will($this->returnValue($isObjectNew));
-
-        $closureMock = function (\Magento\Store\Model\Store $object) use ($viewMock) {
-            $this->assertEquals($object, $viewMock);
-            return $this->subjectMock;
-        };
-
-        $this->indexerMock->expects($this->exactly($invalidateCounter))->method('invalidate');
         $this->prepareIndexer($invalidateCounter);
+        $this->storeMock->expects(static::once())
+            ->method('isObjectNew')
+            ->willReturn($isObjectNew);
+        $this->indexerMock->expects(static::exactly($invalidateCounter))
+            ->method('invalidate');
 
-        $this->assertEquals(
-            $this->subjectMock,
-            $this->model->aroundSave($this->subjectMock, $closureMock, $viewMock)
-        );
+        $this->plugin->beforeSave($this->subjectMock, $this->storeMock);
+        $this->assertSame($this->subjectMock, $this->plugin->afterSave($this->subjectMock, $this->subjectMock));
     }
 
     /**
      * @return array
      */
-    public function aroundSaveDataProvider()
+    public function beforeAfterSaveDataProvider()
     {
         return [
             [false, 0],
-            [true, 1],
+            [true, 1]
         ];
     }
 
-    /**
-     * @return void
-     */
     public function testAfterDelete()
     {
-        $this->indexerMock->expects($this->once())->method('invalidate');
         $this->prepareIndexer(1);
+        $this->indexerMock->expects(static::once())
+            ->method('invalidate');
 
-        $this->assertEquals(
-            $this->subjectMock,
-            $this->model->afterDelete($this->subjectMock, $this->subjectMock)
-        );
+        $this->assertSame($this->subjectMock, $this->plugin->afterDelete($this->subjectMock, $this->subjectMock));
     }
 
     /**
+     * Prepare expectations for indexer
+     *
      * @param int $invalidateCounter
+     * @return void
      */
-    protected function prepareIndexer($invalidateCounter)
+    private function prepareIndexer($invalidateCounter)
     {
-        $this->indexerRegistryMock->expects($this->exactly($invalidateCounter))
+        $this->indexerRegistryMock->expects(static::exactly($invalidateCounter))
             ->method('get')
-            ->with(\Magento\CatalogSearch\Model\Indexer\Fulltext::INDEXER_ID)
-            ->will($this->returnValue($this->indexerMock));
+            ->with(FulltextIndexer::INDEXER_ID)
+            ->willReturn($this->indexerMock);
     }
 }
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Search/Plugin/CollectionFilterTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Search/Plugin/CollectionFilterTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6ba226c572dfe9866e6fad9cf6b83037d185e3f7
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Layer/Search/Plugin/CollectionFilterTest.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogSearch\Test\Unit\Model\Layer\Search\Plugin;
+
+use Magento\CatalogSearch\Model\Layer\Search\Plugin\CollectionFilter as CollectionFilterPlugin;
+use Magento\Catalog\Model\Layer\Search\CollectionFilter;
+use Magento\Catalog\Model\Category;
+use Magento\Search\Model\QueryFactory;
+use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Search\Model\Query;
+
+class CollectionFilterTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var CollectionFilterPlugin
+     */
+    private $plugin;
+
+    /**
+     * @var Collection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $collectionMock;
+
+    /**
+     * @var Category|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $categoryMock;
+
+    /**
+     * @var QueryFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $queryFactoryMock;
+
+    /**
+     * @var CollectionFilter|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $collectionFilterMock;
+
+    /**
+     * @var Query|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $queryMock;
+
+    /***
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    protected function setUp()
+    {
+        $this->objectManager = new ObjectManager($this);
+
+        $this->collectionMock = $this->getMockBuilder(Collection::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['addSearchFilter'])
+            ->getMock();
+        $this->categoryMock = $this->getMockBuilder(Category::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->queryFactoryMock = $this->getMockBuilder(QueryFactory::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['get'])
+            ->getMock();
+        $this->collectionFilterMock = $this->getMockBuilder(CollectionFilter::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->queryMock = $this->getMockBuilder(Query::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['isQueryTextShort', 'getQueryText'])
+            ->getMock();
+
+        $this->plugin = $this->objectManager->getObject(
+            CollectionFilterPlugin::class,
+            ['queryFactory' => $this->queryFactoryMock]
+        );
+    }
+
+    public function testAfterFilter()
+    {
+        $queryText = 'Test Query';
+
+        $this->queryFactoryMock->expects($this->once())
+            ->method('get')
+            ->willReturn($this->queryMock);
+        $this->queryMock->expects($this->once())
+            ->method('isQueryTextShort')
+            ->willReturn(false);
+        $this->queryMock->expects($this->once())
+            ->method('getQueryText')
+            ->willReturn($queryText);
+        $this->collectionMock->expects($this->once())
+            ->method('addSearchFilter')
+            ->with($queryText);
+
+        $this->plugin->afterFilter(
+            $this->collectionFilterMock,
+            null,
+            $this->collectionMock,
+            $this->categoryMock
+        );
+    }
+}
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js b/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js
index ab46c78c6f6e74f62a8c798c4c2b039b2eaf4876..4e2fbdc5dfa50fe1e7f27ed1c0935ce97f3e5cc7 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/model/new-customer-address.js
@@ -11,13 +11,18 @@ define([], function () {
      */
     return function (addressData) {
         var identifier = Date.now();
+        var regionId = null;
+
+        if (addressData.region && addressData.region.region_id) {
+            regionId = addressData.region.region_id;
+        } else if (addressData.country_id && addressData.country_id == window.checkoutConfig.defaultCountryId) {
+            regionId = window.checkoutConfig.defaultRegionId;
+        }
 
         return {
             email: addressData.email,
             countryId: (addressData.country_id) ? addressData.country_id : window.checkoutConfig.defaultCountryId,
-            regionId: (addressData.region && addressData.region.region_id) ?
-                addressData.region.region_id
-                : window.checkoutConfig.defaultRegionId,
+            regionId: regionId,
             regionCode: (addressData.region) ? addressData.region.region_code : null,
             region: (addressData.region) ? addressData.region.region : null,
             customerId: addressData.customer_id,
diff --git a/app/code/Magento/Quote/Model/Product/Plugin/RemoveQuoteItems.php b/app/code/Magento/Quote/Model/Product/Plugin/RemoveQuoteItems.php
new file mode 100644
index 0000000000000000000000000000000000000000..49d9be6bcf8ff748b00f67166856185b23a15f53
--- /dev/null
+++ b/app/code/Magento/Quote/Model/Product/Plugin/RemoveQuoteItems.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Model\Product\Plugin;
+
+class RemoveQuoteItems
+{
+    /**
+     * @var \Magento\Quote\Model\Product\QuoteItemsCleanerInterface
+     */
+    private $quoteItemsCleaner;
+
+    /**
+     * @param \Magento\Quote\Model\Product\QuoteItemsCleanerInterface $quoteItemsCleaner
+     */
+    public function __construct(\Magento\Quote\Model\Product\QuoteItemsCleanerInterface $quoteItemsCleaner)
+    {
+        $this->quoteItemsCleaner = $quoteItemsCleaner;
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\ResourceModel\Product $subject
+     * @param \Closure $proceed
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @return mixed
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     * TODO: reimplement with after plugin
+     */
+    public function aroundDelete(
+        \Magento\Catalog\Model\ResourceModel\Product $subject,
+        \Closure $proceed,
+        \Magento\Catalog\Api\Data\ProductInterface $product
+    ) {
+        $result = $proceed($product);
+        $this->quoteItemsCleaner->execute($product);
+        return $result;
+    }
+}
diff --git a/app/code/Magento/Quote/Model/Product/QuoteItemsCleaner.php b/app/code/Magento/Quote/Model/Product/QuoteItemsCleaner.php
new file mode 100644
index 0000000000000000000000000000000000000000..ec0e6809c48f72007a1e30c1d2e8b7d1c2534d90
--- /dev/null
+++ b/app/code/Magento/Quote/Model/Product/QuoteItemsCleaner.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Model\Product;
+
+class QuoteItemsCleaner implements \Magento\Quote\Model\Product\QuoteItemsCleanerInterface
+{
+    /**
+     * @var \Magento\Quote\Model\ResourceModel\Quote\Item
+     */
+    private $itemResource;
+
+    /**
+     * @param \Magento\Quote\Model\ResourceModel\Quote\Item $itemResource
+     */
+    public function __construct(\Magento\Quote\Model\ResourceModel\Quote\Item $itemResource)
+    {
+        $this->itemResource = $itemResource;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function execute(\Magento\Catalog\Api\Data\ProductInterface $product)
+    {
+        $this->itemResource->getConnection()->delete(
+            $this->itemResource->getMainTable(),
+            'product_id = ' . $product->getId()
+        );
+    }
+}
diff --git a/app/code/Magento/Quote/Model/Product/QuoteItemsCleanerInterface.php b/app/code/Magento/Quote/Model/Product/QuoteItemsCleanerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..1691efab5e5415b797695ad7939912ed71afd161
--- /dev/null
+++ b/app/code/Magento/Quote/Model/Product/QuoteItemsCleanerInterface.php
@@ -0,0 +1,17 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Model\Product;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+
+interface QuoteItemsCleanerInterface
+{
+    /**
+     * @param ProductInterface $product
+     * @return void
+     */
+    public function execute(ProductInterface $product);
+}
diff --git a/app/code/Magento/Quote/Setup/InstallSchema.php b/app/code/Magento/Quote/Setup/InstallSchema.php
index 154266579f9d7ba48315772b3023e9627f0cddce..7f3ce323bc71c92b18401aa306678fee1c2489be 100644
--- a/app/code/Magento/Quote/Setup/InstallSchema.php
+++ b/app/code/Magento/Quote/Setup/InstallSchema.php
@@ -964,12 +964,6 @@ class InstallSchema implements InstallSchemaInterface
             $installer->getTable('quote_item'),
             'item_id',
             \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE
-        )->addForeignKey(
-            $installer->getFkName('quote_item', 'product_id', 'catalog_product_entity', 'entity_id'),
-            'product_id',
-            $installer->getTable('catalog_product_entity'),
-            'entity_id',
-            \Magento\Framework\DB\Ddl\Table::ACTION_CASCADE
         )->addForeignKey(
             $installer->getFkName('quote_item', 'quote_id', 'quote', 'entity_id'),
             'quote_id',
diff --git a/app/code/Magento/Quote/Setup/Recurring.php b/app/code/Magento/Quote/Setup/Recurring.php
deleted file mode 100644
index 03fe30bf802727859a47444247f4b3b4150ee369..0000000000000000000000000000000000000000
--- a/app/code/Magento/Quote/Setup/Recurring.php
+++ /dev/null
@@ -1,73 +0,0 @@
-<?php
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Quote\Setup;
-
-use Magento\Framework\Setup\ExternalFKSetup;
-use Magento\Framework\Setup\InstallSchemaInterface;
-use Magento\Framework\Setup\ModuleContextInterface;
-use Magento\Framework\Setup\SchemaSetupInterface;
-use Magento\Framework\EntityManager\MetadataPool;
-use Magento\Catalog\Api\Data\ProductInterface;
-
-/**
- * @codeCoverageIgnore
- */
-class Recurring implements InstallSchemaInterface
-{
-    /**
-     * @var MetadataPool
-     */
-    protected $metadataPool;
-
-    /**
-     * @var ExternalFKSetup
-     */
-    protected $externalFKSetup;
-
-    /**
-     * @param MetadataPool $metadataPool
-     * @param ExternalFKSetup $externalFKSetup
-     */
-    public function __construct(
-        MetadataPool $metadataPool,
-        ExternalFKSetup $externalFKSetup
-    ) {
-        $this->metadataPool = $metadataPool;
-        $this->externalFKSetup = $externalFKSetup;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
-    {
-        $installer = $setup;
-        $installer->startSetup();
-
-        $this->addExternalForeignKeys($installer);
-
-        $installer->endSetup();
-    }
-
-    /**
-     * Add external foreign keys
-     *
-     * @param SchemaSetupInterface $installer
-     * @return void
-     * @throws \Exception
-     */
-    protected function addExternalForeignKeys(SchemaSetupInterface $installer)
-    {
-        $metadata = $this->metadataPool->getMetadata(ProductInterface::class);
-        $this->externalFKSetup->install(
-            $installer,
-            $metadata->getEntityTable(),
-            $metadata->getIdentifierField(),
-            'quote_item',
-            'product_id'
-        );
-    }
-}
diff --git a/app/code/Magento/Quote/Setup/UpgradeSchema.php b/app/code/Magento/Quote/Setup/UpgradeSchema.php
index 602f93e0445f079cd80d8da02a3ac3b3a6053355..d2163035bdcbf8ecf98bd048265c09bcbbda97b6 100644
--- a/app/code/Magento/Quote/Setup/UpgradeSchema.php
+++ b/app/code/Magento/Quote/Setup/UpgradeSchema.php
@@ -41,7 +41,15 @@ class UpgradeSchema implements UpgradeSchemaInterface
                 ]
             );
         }
-
+        //drop foreign key for single DB case
+        if (version_compare($context->getVersion(), '2.0.3', '<')
+            && $setup->tableExists($setup->getTable('quote_item'))
+        ) {
+            $setup->getConnection()->dropForeignKey(
+                $setup->getTable('quote_item'),
+                $setup->getFkName('quote_item', 'product_id', 'catalog_product_entity', 'entity_id')
+            );
+        }
         $setup->endSetup();
     }
 }
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Product/Plugin/RemoveQuoteItemsTest.php b/app/code/Magento/Quote/Test/Unit/Model/Product/Plugin/RemoveQuoteItemsTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..083722f3a1bb3d9044284f7f65ac1b1239b2d0c5
--- /dev/null
+++ b/app/code/Magento/Quote/Test/Unit/Model/Product/Plugin/RemoveQuoteItemsTest.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Test\Unit\Model\Product\Plugin;
+
+class RemoveQuoteItemsTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Quote\Model\Product\Plugin\RemoveQuoteItems
+     */
+    private $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Quote\Model\Product\QuoteItemsCleanerInterface
+     */
+    private $quoteItemsCleanerMock;
+
+    protected function setUp()
+    {
+        $this->quoteItemsCleanerMock = $this->getMock(\Magento\Quote\Model\Product\QuoteItemsCleanerInterface::class);
+        $this->model = new \Magento\Quote\Model\Product\Plugin\RemoveQuoteItems($this->quoteItemsCleanerMock);
+    }
+
+    public function testAroundDelete()
+    {
+        $productResourceMock = $this->getMock(\Magento\Catalog\Model\ResourceModel\Product::class, [], [], '', false);
+        $productMock = $this->getMock(\Magento\Catalog\Api\Data\ProductInterface::class);
+        $closure = function () use ($productResourceMock) {
+            return $productResourceMock;
+        };
+
+        $this->quoteItemsCleanerMock->expects($this->once())->method('execute')->with($productMock);
+        $result = $this->model->aroundDelete($productResourceMock, $closure, $productMock);
+        $this->assertEquals($result, $productResourceMock);
+    }
+}
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Product/QuoteItemsCleanerTest.php b/app/code/Magento/Quote/Test/Unit/Model/Product/QuoteItemsCleanerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d6bb3e5ae31a88da74cd008b2851ceeb03718f1b
--- /dev/null
+++ b/app/code/Magento/Quote/Test/Unit/Model/Product/QuoteItemsCleanerTest.php
@@ -0,0 +1,45 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Test\Unit\Model\Product;
+
+class QuoteItemsCleanerTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Quote\Model\Product\QuoteItemsCleaner
+     */
+    private $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Quote\Model\ResourceModel\Quote\Item
+     */
+    private $itemResourceMock;
+
+    protected function setUp()
+    {
+        $this->itemResourceMock = $this->getMock(
+            \Magento\Quote\Model\ResourceModel\Quote\Item::class,
+            [],
+            [],
+            '',
+            false
+        );
+        $this->model = new \Magento\Quote\Model\Product\QuoteItemsCleaner($this->itemResourceMock);
+    }
+
+    public function testExecute()
+    {
+        $tableName = 'table_name';
+        $productMock = $this->getMock(\Magento\Catalog\Api\Data\ProductInterface::class);
+        $productMock->expects($this->once())->method('getId')->willReturn(1);
+
+        $connectionMock = $this->getMock(\Magento\Framework\DB\Adapter\AdapterInterface::class);
+        $this->itemResourceMock->expects($this->once())->method('getConnection')->willReturn($connectionMock);
+        $this->itemResourceMock->expects($this->once())->method('getMainTable')->willReturn($tableName);
+
+        $connectionMock->expects($this->once())->method('delete')->with($tableName, 'product_id = 1');
+        $this->model->execute($productMock);
+    }
+}
diff --git a/app/code/Magento/Quote/etc/di.xml b/app/code/Magento/Quote/etc/di.xml
index e3192f1c1d58e684623a03ab2221b2b97dabdb40..384f5ca143b8610dc7587a9ae8df3c0b30eeb35e 100644
--- a/app/code/Magento/Quote/etc/di.xml
+++ b/app/code/Magento/Quote/etc/di.xml
@@ -40,7 +40,6 @@
     <preference for="Magento\Quote\Api\GuestCartTotalManagementInterface" type="\Magento\Quote\Model\GuestCart\GuestCartTotalManagement" />
     <preference for="Magento\Quote\Api\Data\EstimateAddressInterface" type="Magento\Quote\Model\EstimateAddress" />
     <preference for="Magento\Quote\Api\Data\ProductOptionInterface" type="\Magento\Quote\Model\Quote\ProductOption" />
-    <!--<preference for="Magento\Quote\Model\Quote\Address\Total\CollectorInterface" type="\Magento\Quote\Model\Quote\Address\Total\Composite" />-->
     <type name="Magento\Webapi\Controller\Rest\ParamsOverrider">
         <arguments>
             <argument name="paramOverriders" xsi:type="array">
@@ -90,4 +89,8 @@
     <preference for="Magento\Quote\Model\ShippingMethodManagementInterface" type="Magento\Quote\Model\ShippingMethodManagement" />
     <preference for="Magento\Quote\Api\Data\ShippingInterface" type="Magento\Quote\Model\Shipping" />
     <preference for="Magento\Quote\Api\Data\ShippingAssignmentInterface" type="Magento\Quote\Model\ShippingAssignment" />
+    <preference for="Magento\Quote\Model\Product\QuoteItemsCleanerInterface" type="Magento\Quote\Model\Product\QuoteItemsCleaner" />
+    <type name="Magento\Catalog\Model\ResourceModel\Product">
+        <plugin name="clean_quote_items_after_product_delete" type="Magento\Quote\Model\Product\Plugin\RemoveQuoteItems"/>
+    </type>
 </config>
diff --git a/app/code/Magento/Quote/etc/module.xml b/app/code/Magento/Quote/etc/module.xml
index 8350b4c4f87eae47da241af2e83283423a975612..281cde9eeb9d18bc559cd0979e593a43c3b70ebb 100644
--- a/app/code/Magento/Quote/etc/module.xml
+++ b/app/code/Magento/Quote/etc/module.xml
@@ -6,6 +6,6 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Quote" setup_version="2.0.2">
+    <module name="Magento_Quote" setup_version="2.0.3">
     </module>
 </config>
diff --git a/app/code/Magento/Sales/Setup/UpgradeSchema.php b/app/code/Magento/Sales/Setup/UpgradeSchema.php
index 907d782e8deafd5649712ead99a6d94cbc93c1f1..34e7c29b6c6a09b33d58ac150e8d563103ef82de 100644
--- a/app/code/Magento/Sales/Setup/UpgradeSchema.php
+++ b/app/code/Magento/Sales/Setup/UpgradeSchema.php
@@ -4,6 +4,8 @@
  * See COPYING.txt for license details.
  */
 namespace Magento\Sales\Setup;
+
+use Magento\Framework\App\ResourceConnection;
 use Magento\Framework\Setup\UpgradeSchemaInterface;
 use Magento\Framework\Setup\ModuleContextInterface;
 use Magento\Framework\Setup\SchemaSetupInterface;
@@ -14,6 +16,11 @@ use Magento\Framework\DB\Adapter\AdapterInterface;
  */
 class UpgradeSchema implements UpgradeSchemaInterface
 {
+    /**
+     * @var AdapterInterface
+     */
+    private $salesConnection;
+
     /**
      * {@inheritdoc}
      */
@@ -30,7 +37,8 @@ class UpgradeSchema implements UpgradeSchemaInterface
                     'sales_bestsellers_aggregated_daily',
                     'product_id',
                     'catalog_product_entity',
-                    'entity_id')
+                    'entity_id'
+                )
             );
             //sales_bestsellers_aggregated_monthly
             $connection->dropForeignKey(
@@ -39,7 +47,8 @@ class UpgradeSchema implements UpgradeSchemaInterface
                     'sales_bestsellers_aggregated_monthly',
                     'product_id',
                     'catalog_product_entity',
-                    'entity_id')
+                    'entity_id'
+                )
             );
 
             //sales_bestsellers_aggregated_yearly
@@ -49,7 +58,8 @@ class UpgradeSchema implements UpgradeSchemaInterface
                     'sales_bestsellers_aggregated_yearly',
                     'product_id',
                     'catalog_product_entity',
-                    'entity_id')
+                    'entity_id'
+                )
             );
 
             $installer->endSetup();
@@ -66,7 +76,7 @@ class UpgradeSchema implements UpgradeSchemaInterface
      */
     private function addColumnBaseGrandTotal(SchemaSetupInterface $installer)
     {
-        $connection = $installer->getConnection();
+        $connection = $this->getSalesConnection();
         $connection->addColumn(
             $installer->getTable('sales_invoice_grid'),
             'base_grand_total',
@@ -86,11 +96,29 @@ class UpgradeSchema implements UpgradeSchemaInterface
      */
     private function addIndexBaseGrandTotal(SchemaSetupInterface $installer)
     {
-        $connection = $installer->getConnection();
+        $connection = $this->getSalesConnection();
         $connection->addIndex(
             $installer->getTable('sales_invoice_grid'),
             $installer->getIdxName('sales_invoice_grid', ['base_grand_total']),
             ['base_grand_total']
         );
     }
+
+    /**
+     * @return AdapterInterface
+     */
+    private function getSalesConnection()
+    {
+        if ($this->salesConnection === null) {
+            $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+            /** @var ResourceConnection $resourceConnection */
+            $resourceConnection = $objectManager->get(ResourceConnection::class);
+            try {
+                $this->salesConnection = $resourceConnection->getConnectionByName('sales');
+            } catch (\DomainException $e) {
+                $this->salesConnection = $resourceConnection->getConnection();
+            }
+        }
+        return $this->salesConnection;
+    }
 }
diff --git a/app/code/Magento/Tax/Model/TaxConfigProvider.php b/app/code/Magento/Tax/Model/TaxConfigProvider.php
index a56663a8d558ad9c903d65dd9d08f66e482a8641..95f371da1726a92929c168282e3599b080c947d8 100644
--- a/app/code/Magento/Tax/Model/TaxConfigProvider.php
+++ b/app/code/Magento/Tax/Model/TaxConfigProvider.php
@@ -55,6 +55,14 @@ class TaxConfigProvider implements ConfigProviderInterface
      */
     public function getConfig()
     {
+        $defaultRegionId = $this->scopeConfig->getValue(
+            \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_REGION,
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+        );
+        // prevent wrong assignment on shipping rate estimation requests
+        if (0 == $defaultRegionId) {
+            $defaultRegionId = null;
+        }
         return [
             'isDisplayShippingPriceExclTax' => $this->isDisplayShippingPriceExclTax(),
             'isDisplayShippingBothPrices' => $this->isDisplayShippingBothPrices(),
@@ -69,10 +77,7 @@ class TaxConfigProvider implements ConfigProviderInterface
                 \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_COUNTRY,
                 \Magento\Store\Model\ScopeInterface::SCOPE_STORE
             ),
-            'defaultRegionId' => $this->scopeConfig->getValue(
-                \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_REGION,
-                \Magento\Store\Model\ScopeInterface::SCOPE_STORE
-            ),
+            'defaultRegionId' => $defaultRegionId,
             'defaultPostcode' => $this->scopeConfig->getValue(
                 \Magento\Tax\Model\Config::CONFIG_XML_PATH_DEFAULT_POSTCODE,
                 \Magento\Store\Model\ScopeInterface::SCOPE_STORE
diff --git a/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php b/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php
index 0cb720329c1342bad460efca82e312eed7e45d1d..0ce7a40a5d1dbd10804fe0effedca4caa0cd9d5a 100644
--- a/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php
+++ b/app/code/Magento/Tax/Test/Unit/Model/TaxConfigProviderTest.php
@@ -302,6 +302,35 @@ class TaxConfigProviderTest extends \PHPUnit_Framework_TestCase
                     Config::CONFIG_XML_PATH_DEFAULT_POSTCODE => '*',
                 ],
             ],
+            'zeroRegionToNull' => [
+                'expectedResult' => [
+                    'isDisplayShippingPriceExclTax' => 1,
+                    'isDisplayShippingBothPrices' => 1,
+                    'reviewShippingDisplayMode' => 'excluding',
+                    'reviewItemPriceDisplayMode' => 'including',
+                    'reviewTotalsDisplayMode' => 'both',
+                    'includeTaxInGrandTotal' => 1,
+                    'isFullTaxSummaryDisplayed' => 1,
+                    'isZeroTaxDisplayed' => 1,
+                    'reloadOnBillingAddress' => false,
+                    'defaultCountryId' => 'US',
+                    'defaultRegionId' => null,
+                    'defaultPostcode' => '*',
+                ],
+                'cartShippingBoth' => 0,
+                'cartShippingExclTax' => 1,
+                'cartBothPrices' => 0,
+                'cartPriceExclTax' => 0,
+                'cartSubTotalBoth' => 1,
+                'cartSubTotalExclTax' => 0,
+                'isQuoteVirtual' => false,
+                'config' => [
+                    Config::CONFIG_XML_PATH_BASED_ON => 'shipping',
+                    Config::CONFIG_XML_PATH_DEFAULT_COUNTRY => 'US',
+                    Config::CONFIG_XML_PATH_DEFAULT_REGION => 0,
+                    Config::CONFIG_XML_PATH_DEFAULT_POSTCODE => '*',
+                ],
+            ],
         ];
     }
 }
diff --git a/dev/tests/functional/composer.json b/dev/tests/functional/composer.json
index 0e464d5e40357ea0cdd089aff913409c7d9df08c..4e36f1fa54f2197b79646374dfea39cdede39ec6 100644
--- a/dev/tests/functional/composer.json
+++ b/dev/tests/functional/composer.json
@@ -1,6 +1,6 @@
 {
     "require": {
-        "magento/mtf": "1.0.0-rc44",
+        "magento/mtf": "1.0.0-rc46",
         "php": "~5.6.0|7.0.2|~7.0.6",
         "phpunit/phpunit": "4.1.0",
         "phpunit/phpunit-selenium": ">=1.2"
diff --git a/dev/tests/functional/etc/repository_replacer.xml b/dev/tests/functional/etc/repository_replacer.xml
new file mode 100644
index 0000000000000000000000000000000000000000..61046fbac44c4b6fdc85e9f75c3d4cb6105644f6
--- /dev/null
+++ b/dev/tests/functional/etc/repository_replacer.xml
@@ -0,0 +1,147 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:noNamespaceSchemaLocation="../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd">
+
+    <repository class="Magento\Catalog\Test\Repository\CatalogAttributeSet">
+        <dataset name="default">
+            <field name="attribute_set_id" xsi:type="number">4</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\Catalog\Test\Repository\CatalogProductAttribute">
+        <dataset name="quantity_and_stock_status">
+            <field name="attribute_id" xsi:type="number">113</field>
+        </dataset>
+
+        <dataset name="tax_class_id">
+            <field name="attribute_id" xsi:type="number">172</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\Catalog\Test\Repository\Category">
+        <dataset name="default_category">
+            <field name="parent_id" xsi:type="number">1</field>
+            <field name="id" xsi:type="number">2</field>
+        </dataset>
+
+        <dataset name="root_category">
+            <field name="parent_id" xsi:type="number">1</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\Customer\Test\Repository\CustomerGroup">
+        <dataset name="General">
+            <field name="customer_group_id" xsi:type="number">1</field>
+        </dataset>
+
+        <dataset name="Retailer">
+            <field name="customer_group_id" xsi:type="number">3</field>
+        </dataset>
+
+        <dataset name="Wholesale">
+            <field name="customer_group_id" xsi:type="number">2</field>
+        </dataset>
+
+        <dataset name="all_customer_groups">
+            <field name="customer_group_id" xsi:type="number">0</field>
+        </dataset>
+
+        <dataset name="NOT_LOGGED_IN">
+            <field name="customer_group_id" xsi:type="number">0</field>
+        </dataset>
+
+        <dataset name="ALL_GROUPS">
+            <field name="customer_group_id" xsi:type="number">32000</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\Store\Test\Repository\Store">
+        <dataset name="default">
+            <field name="store_id" xsi:type="number">1</field>
+        </dataset>
+
+        <dataset name="default_store_view">
+            <field name="store_id" xsi:type="number">1</field>
+        </dataset>
+
+        <dataset name="all_store_views">
+            <field name="store_id" xsi:type="number">0</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\Store\Test\Repository\StoreGroup">
+        <dataset name="default">
+            <field name="group_id" xsi:type="number">1</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\Store\Test\Repository\Website">
+        <dataset name="default">
+            <field name="website_id" xsi:type="number">1</field>
+        </dataset>
+
+        <dataset name="all_websites">
+            <field name="website_id" xsi:type="number">0</field>
+        </dataset>
+
+        <dataset name="main_website">
+            <field name="website_id" xsi:type="number">1</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\Tax\Test\Repository\TaxClass">
+        <dataset name="taxable_goods">
+            <field name="id" xsi:type="number">2</field>
+            <field name="class_id" xsi:type="number">2</field>
+        </dataset>
+
+        <dataset name="retail_customer">
+            <field name="class_id" xsi:type="number">3</field>
+            <field name="id" xsi:type="number">3</field>
+        </dataset>
+
+        <dataset name="None">
+            <field name="id" xsi:type="number">0</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\Tax\Test\Repository\TaxRate">
+        <dataset name="US-CA-Rate_1">
+            <field name="tax_calculation_rate_id" xsi:type="number">1</field>
+            <field name="tax_region_id" xsi:type="number">12</field>
+        </dataset>
+
+        <dataset name="US-IL-Rate_1">
+            <field name="tax_region_id" xsi:type="number">23</field>
+        </dataset>
+
+        <dataset name="US-NY-Rate_1">
+            <field name="tax_calculation_rate_id" xsi:type="number">2</field>
+            <field name="tax_region_id" xsi:type="number">43</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\User\Test\Repository\Role">
+        <dataset name="Administrators">
+            <field name="role_id" xsi:type="number">1</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\User\Test\Repository\User">
+        <dataset name="default">
+            <field name="user_id" xsi:type="number">1</field>
+        </dataset>
+    </repository>
+
+    <repository class="Magento\Catalog\Test\Repository\CatalogProductSimple">
+        <dataset name="sample_data_simple_product">
+            <field name="id" xsi:type="number">1</field>
+        </dataset>
+    </repository>
+</config>
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 1e29a988ff196bf695e97dc052227ef373295659..96be468a6eb377f619339c02a2be00835f8425eb 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli.php
@@ -47,6 +47,7 @@ class Cli
     {
         $curl = $this->transport;
         $curl->write($this->prepareUrl($command, $options), [], CurlInterface::GET);
+        $curl->read();
         $curl->close();
     }
 
@@ -60,6 +61,6 @@ class Cli
     private function prepareUrl($command, array $options)
     {
         $command .= ' ' . implode(' ', $options);
-        return $_ENV['app_frontend_url'] . Cli::URL . '?command=' . urldecode($command);
+        return $_ENV['app_frontend_url'] . Cli::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
new file mode 100644
index 0000000000000000000000000000000000000000..425abfd85590d0848ea9292752cc4d48a0102065
--- /dev/null
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Cli/Cache.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Mtf\Util\Command\Cli;
+
+use Magento\Mtf\Util\Command\Cli;
+
+/**
+ * Handle cache for tests executions.
+ */
+class Cache extends Cli
+{
+    /**
+     * Parameter for flush cache command.
+     */
+    const PARAM_CACHE_FLUSH = 'cache:flush';
+
+    /**
+     * Parameter for cache disable command.
+     */
+    const PARAM_CACHE_DISABLE = 'cache:disable';
+
+    /**
+     * Parameter for cache enable command.
+     */
+    const PARAM_CACHE_ENABLE = 'cache:enable';
+
+    /**
+     * Flush cache.
+     *
+     * @return void
+     */
+    public function flush()
+    {
+        parent::execute(Cache::PARAM_CACHE_FLUSH);
+    }
+
+    /**
+     * Disable all cache or one cache type.
+     *
+     * @param string $cacheType [optional]
+     * @return void
+     */
+    public function disableCache($cacheType = null)
+    {
+        parent::execute(Cache::PARAM_CACHE_DISABLE . ($cacheType ? " $cacheType" : ''));
+    }
+
+    /**
+     * Enable all cache or one cache type.
+     *
+     * @param string $cacheType [optional]
+     * @return void
+     */
+    public function enableCache($cacheType = null)
+    {
+        parent::execute(Cache::PARAM_CACHE_ENABLE . ($cacheType ? " $cacheType" : ''));
+    }
+}
diff --git a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php
index 3ca2ee86a8ee6470addfdd4eaf0e526462b7b749..611f46894c8bca850d10a519fe7a2850f31b5533 100644
--- a/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php
+++ b/dev/tests/functional/lib/Magento/Mtf/Util/Command/Website.php
@@ -58,6 +58,6 @@ class Website
      */
     private function prepareUrl($websiteCode)
     {
-        return $_ENV['app_frontend_url'] . Website::URL . '?website_code=' . urldecode($websiteCode);
+        return $_ENV['app_frontend_url'] . Website::URL . '?website_code=' . urlencode($websiteCode);
     }
 }
diff --git a/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages.php b/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages.php
index 3ad5f846b2af5414d76bb11d4ef04496dafa8935..f9cd7d34e2a1eeec26688f900211a59c235c72d9 100644
--- a/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages.php
+++ b/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages.php
@@ -7,6 +7,7 @@
 namespace Magento\AdminNotification\Test\Block\System;
 
 use Magento\Mtf\Block\Block;
+use Magento\Mtf\Client\Locator;
 
 /**
  * Global messages block.
@@ -20,6 +21,13 @@ class Messages extends Block
      */
     protected $closePopup = '[data-role="closeBtn"]';
 
+    /**
+     * Locator for popup text.
+     *
+     * @var string
+     */
+    protected $popupText = ".//*[@id='system_messages_list']/ul/li";
+
     /**
      * Close popup block.
      *
@@ -31,4 +39,14 @@ class Messages extends Block
             $this->_rootElement->find($this->closePopup)->click();
         }
     }
+
+    /**
+     * Get pop up text.
+     *
+     * @return string
+     */
+    public function getPopupText()
+    {
+        return $this->_rootElement->find($this->popupText, Locator::SELECTOR_XPATH)->getText();
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages/System.php b/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages/System.php
new file mode 100644
index 0000000000000000000000000000000000000000..6f376246927367fc5a98511e36a1239d56ebf021
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/AdminNotification/Test/Block/System/Messages/System.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\AdminNotification\Test\Block\System\Messages;
+
+use Magento\Mtf\Block\Block;
+
+/**
+ * System message block.
+ */
+class System extends Block
+{
+    /**
+     * Get block text content.
+     *
+     * @return string
+     */
+    public function getContent()
+    {
+        return $this->_rootElement->getText();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Category/View.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Category/View.php
index 72c2ab77fefa21169e422c1f13f2cda2862d8636..83d2c10752374492ebde4e93e0b653f23656f516 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Category/View.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Category/View.php
@@ -20,7 +20,14 @@ class View extends Block
      *
      * @var string
      */
-    protected $recentlyViewedProducts = './/*[contains(@class,"widget")]//strong[@class="product-item-name"]';
+    protected $recentlyViewedProducts = '.block-viewed-products-grid strong.product-item-name';
+
+    /**
+     * New Products selectors.
+     *
+     * @var string
+     */
+    protected $newProducts = '.block-new-products strong.product-item-name';
 
     /**
      * Description CSS selector.
@@ -65,8 +72,24 @@ class View extends Block
     public function getProductsFromRecentlyViewedBlock()
     {
         $products = [];
-        $this->waitForElementVisible($this->recentlyViewedProducts, Locator::SELECTOR_XPATH);
-        $productNames = $this->_rootElement->getElements($this->recentlyViewedProducts, Locator::SELECTOR_XPATH);
+        $this->waitForElementVisible($this->recentlyViewedProducts, Locator::SELECTOR_CSS);
+        $productNames = $this->_rootElement->getElements($this->recentlyViewedProducts, Locator::SELECTOR_CSS);
+        foreach ($productNames as $productName) {
+            $products[] = $productName->getText();
+        }
+        return $products;
+    }
+
+    /**
+     * Get products from Catalog New Products List block.
+     *
+     * @return array
+     */
+    public function getProductsFromCatalogNewProductsListBlock()
+    {
+        $products = [];
+        $this->waitForElementVisible($this->newProducts, Locator::SELECTOR_CSS);
+        $productNames = $this->_rootElement->getElements($this->newProducts, Locator::SELECTOR_CSS);
         foreach ($productNames as $productName) {
             $products[] = $productName->getText();
         }
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/TierPrice.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/TierPrice.php
index 528ff52b172825abb10eed5e927e8566b5845119..40e0a0c014f0f5ad92e19da81882b21648f307e2 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/TierPrice.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/Product/TierPrice.php
@@ -41,7 +41,7 @@ class TierPrice extends DataSource
     private $fixtureFactory;
 
     /**
-     * Rought fixture field data.
+     * Rough fixture field data.
      *
      * @var array
      */
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogAttributeSet.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogAttributeSet.xml
index 975d3b3ce8d867b16a281ca39237a30b8d8dbdc2..a62bef0680a9eaf1eff6adf99f809e3f9c538353 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogAttributeSet.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogAttributeSet.xml
@@ -8,8 +8,8 @@
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd">
     <repository class="Magento\Catalog\Test\Repository\CatalogAttributeSet">
         <dataset name="default">
+            <field name="attribute_set_id" xsi:type="string">%id%</field>
             <field name="attribute_set_name" xsi:type="string">Default</field>
-            <field name="attribute_set_id" xsi:type="string">4</field>
         </dataset>
 
         <dataset name="custom_attribute_set">
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml
index 8ebc57837ec8f4f0e1d12e15db0ab17afb50cb5c..e94af12754af5615b48c81f37fe2a3df21470eff 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductAttribute.xml
@@ -14,7 +14,7 @@
         </dataset>
 
         <dataset name="quantity_and_stock_status">
-            <field name="attribute_id" xsi:type="number">113</field>
+            <field name="attribute_id" xsi:type="string">%id%</field>
             <field name="frontend_label" xsi:type="string">Quantity</field>
             <field name="attribute_code" xsi:type="string">quantity_and_stock_status</field>
             <field name="frontend_input" xsi:type="string">Dropdown</field>
@@ -34,7 +34,7 @@
         </dataset>
 
         <dataset name="tax_class_id">
-            <field name="attribute_id" xsi:type="number">172</field>
+            <field name="attribute_id" xsi:type="string">%id%</field>
             <field name="frontend_label" xsi:type="string">Tax Class%isolation%</field>
             <field name="attribute_code" xsi:type="string">tax_class_id%isolation%</field>
             <field name="frontend_input" xsi:type="string">Dropdown</field>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
index 83d736e479f94b8e9602221217410815ff687688..23c13fb1206df158e3f9824651cba9cb6a1ff30e 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/CatalogProductSimple.xml
@@ -1225,7 +1225,7 @@
         </dataset>
 
         <dataset name="sample_data_simple_product">
-            <field name="id" xsi:type="string">1</field>
+            <field name="id" xsi:type="string">%id%</field>
             <field name="name" xsi:type="string">Overnight Duffle</field>
             <field name="sku" xsi:type="string">24-WB07</field>
             <field name="url_key" xsi:type="string">overnight-duffle</field>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml
index 5e0d3af502d631cfa8cc0f34da3e7c9b133fefc7..30f870dea88f063a7278d7380f5d4fe24f508c9f 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Category.xml
@@ -18,13 +18,14 @@
         </dataset>
 
         <dataset name="default_category">
+            <field name="id" xsi:type="string">%id%</field>
+            <field name="parent_id" xsi:type="string">%id%</field>
             <field name="name" xsi:type="string">Default Category</field>
-            <field name="parent_id" xsi:type="string">1</field>
             <field name="is_active" xsi:type="string">Yes</field>
-            <field name="id" xsi:type="string">2</field>
         </dataset>
 
         <dataset name="default_subcategory">
+            <field name="id" xsi:type="string">%id%</field>
             <field name="name" xsi:type="string">DefaultSubcategory%isolation%</field>
             <field name="url_key" xsi:type="string">default-subcategory-%isolation%</field>
             <field name="parent_id" xsi:type="array">
@@ -46,8 +47,8 @@
         </dataset>
 
         <dataset name="root_category">
+            <field name="parent_id" xsi:type="string">%id%</field>
             <field name="name" xsi:type="string">RootCategory%isolation%</field>
-            <field name="parent_id" xsi:type="string">1</field>
             <field name="is_active" xsi:type="string">Yes</field>
             <field name="include_in_menu" xsi:type="string">Yes</field>
         </dataset>
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/CreateProductsStep.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/CreateProductsStep.php
index 7daac0f1a12d3acbc5aa64851456c6a0fd07aa2e..ab0b558c9f5ee36e5ad488a2805907508a1553f6 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/CreateProductsStep.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/TestStep/CreateProductsStep.php
@@ -19,7 +19,7 @@ class CreateProductsStep implements TestStepInterface
     /**
      * Products names in data set
      *
-     * @var array
+     * @var string|array
      */
     protected $products;
 
@@ -42,10 +42,10 @@ class CreateProductsStep implements TestStepInterface
      *
      * @constructor
      * @param FixtureFactory $fixtureFactory
-     * @param array $products
+     * @param string|array $products
      * @param array $data [optional]
      */
-    public function __construct(FixtureFactory $fixtureFactory, array $products, array $data = [])
+    public function __construct(FixtureFactory $fixtureFactory, $products, array $data = [])
     {
         $this->products = $products;
         $this->data = $data;
@@ -60,6 +60,9 @@ class CreateProductsStep implements TestStepInterface
     public function run()
     {
         $products = [];
+        if (!is_array($this->products)) { // for backward compatible changes
+            $this->products = explode(',', $this->products);
+        }
         foreach ($this->products as $key => $productDataSet) {
             $productDataSet = explode('::', $productDataSet);
             $fixtureClass = $productDataSet[0];
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.xml
index 38e702c1a1953bf0a8e9880c3385a17264fb77f6..1c60b0f156bae087433d03ac12e84c733bb9258f 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateProductFromMiniShoppingCartEntityTest.xml
@@ -11,7 +11,7 @@
             <data name="tag" xsi:type="string">test_type:extended_acceptance_test</data>
             <data name="originalProduct/0" xsi:type="string">catalogProductSimple::with_two_custom_option</data>
             <data name="checkoutData/dataset" xsi:type="string">simple_update_mini_shopping_cart</data>
-            <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInMiniShoppingCart" />
+            <constraint name="Magento\Checkout\Test\Constraint\AssertProductDataInMiniShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" />
         </variation>
         <variation name="UpdateProductFromMiniShoppingCartEntityTestVariation2" summary="Update Configurable and verify previous product was updated to new one in shopping cart and mini shopping cart">
@@ -19,7 +19,7 @@
             <data name="originalProduct/0" xsi:type="string">configurableProduct::default</data>
             <data name="checkoutData/dataset" xsi:type="string">configurable_update_mini_shopping_cart</data>
             <constraint name="Magento\Checkout\Test\Constraint\AssertCartItemsOptions" />
-            <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInMiniShoppingCart" />
+            <constraint name="Magento\Checkout\Test\Constraint\AssertProductDataInMiniShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductOptionsAbsentInShoppingCart" />
         </variation>
@@ -28,7 +28,7 @@
             <data name="originalProduct/0" xsi:type="string">bundleProduct::bundle_fixed_product</data>
             <data name="checkoutData/dataset" xsi:type="string">bundle_update_mini_shopping_cart</data>
             <constraint name="Magento\Checkout\Test\Constraint\AssertCartItemsOptions" />
-            <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInMiniShoppingCart" />
+            <constraint name="Magento\Checkout\Test\Constraint\AssertProductDataInMiniShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductOptionsAbsentInShoppingCart" />
         </variation>
@@ -37,7 +37,7 @@
             <data name="originalProduct/0" xsi:type="string">downloadableProduct::with_two_separately_links</data>
             <data name="checkoutData/dataset" xsi:type="string">downloadable_update_mini_shopping_cart</data>
             <constraint name="Magento\Checkout\Test\Constraint\AssertCartItemsOptions" />
-            <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInMiniShoppingCart" />
+            <constraint name="Magento\Checkout\Test\Constraint\AssertProductDataInMiniShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductOptionsAbsentInShoppingCart" />
         </variation>
@@ -45,7 +45,7 @@
             <data name="tag" xsi:type="string">test_type:extended_acceptance_test</data>
             <data name="originalProduct/0" xsi:type="string">catalogProductVirtual::default</data>
             <data name="checkoutData/dataset" xsi:type="string">virtual_update_mini_shopping_cart</data>
-            <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInMiniShoppingCart" />
+            <constraint name="Magento\Checkout\Test\Constraint\AssertProductDataInMiniShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" />
         </variation>
     </testCase>
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.xml
index c0d68a18b8c4694a939dc8d32cbdb5ff14592a3f..42428189f44b06b3c33550efb453d34900045133 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/TestCase/UpdateShoppingCartTest.xml
@@ -15,7 +15,7 @@
             <data name="product/data/checkout_data/cartItem/subtotal" xsi:type="string">300</data>
             <constraint name="Magento\Checkout\Test\Constraint\AssertPriceInShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" />
-            <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInMiniShoppingCart" />
+            <constraint name="Magento\Checkout\Test\Constraint\AssertProductDataInMiniShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertSubtotalInShoppingCart" />
         </variation>
         <variation name="UpdateShoppingCartTestVariation2">
@@ -26,7 +26,7 @@
             <data name="product/data/checkout_data/cartItem/subtotal" xsi:type="string">715</data>
             <constraint name="Magento\Checkout\Test\Constraint\AssertPriceInShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInShoppingCart" />
-            <constraint name="Magento\Checkout\Test\Constraint\AssertProductQtyInMiniShoppingCart" />
+            <constraint name="Magento\Checkout\Test\Constraint\AssertProductDataInMiniShoppingCart" />
             <constraint name="Magento\Checkout\Test\Constraint\AssertSubtotalInShoppingCart" />
         </variation>
     </testCase>
diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData.xml
index cea290304a771caf1d8ca19c6b671ced45fcfb2f..5d2c0338420b412cdb4a2759853483e4bd224fa5 100644
--- a/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData.xml
+++ b/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData.xml
@@ -14,7 +14,7 @@
              repository_class="Magento\Config\Test\Repository\ConfigData"
              handler_interface="Magento\Config\Test\Handler\ConfigData\ConfigDataInterface"
              class="Magento\Config\Test\Fixture\ConfigData">
-        <field name="section" />
+        <field name="section" source="Magento\Config\Test\Fixture\ConfigData\Section" />
         <field name="config_id" is_required="1" />
         <field name="scope" is_required="" />
         <field name="scope_id" is_required="" />
diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData/Section.php b/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData/Section.php
new file mode 100644
index 0000000000000000000000000000000000000000..60d43e1da95f7edf29a012c4da95d0450a47b2f9
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Config/Test/Fixture/ConfigData/Section.php
@@ -0,0 +1,170 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Config\Test\Fixture\ConfigData;
+
+use Magento\Store\Test\Fixture\Store;
+use Magento\Store\Test\Fixture\Website;
+use Magento\Mtf\Fixture\FixtureFactory;
+use Magento\Mtf\Fixture\DataSource;
+
+/**
+ * Prepare Section entity.
+ */
+class Section extends DataSource
+{
+    /**
+     * Code of website.
+     */
+    const WEBSITE_CODE = 'website';
+
+    /**
+     * Code of store view.
+     */
+    const STORE_CODE = 'store';
+
+    /**
+     * Store View or Website fixture.
+     *
+     * @var Store|Website
+     */
+    private $scope;
+
+    /**
+     * Scope type. [website|store]
+     *
+     * @var string
+     */
+    private $scopeType;
+
+    /**
+     * Fixture Factory instance.
+     *
+     * @var FixtureFactory
+     */
+    private $fixtureFactory;
+
+    /**
+     * Rough fixture field data.
+     *
+     * @var array|null
+     */
+    private $fixtureData = null;
+
+    /**
+     * Scope data.
+     *
+     * @var array|null
+     */
+    private $scopeData = null;
+
+    /**
+     * Level of scope for set.
+     * If 'scope_type' = 'website', then 'set_level' MUST be 'website' only.
+     *
+     * @var string
+     */
+    private $setLevel = null;
+
+    /**
+     * @constructor
+     * @param FixtureFactory $fixtureFactory
+     * @param array $params
+     * @param array $data [optional]
+     */
+    public function __construct(FixtureFactory $fixtureFactory, array $params, array $data = [])
+    {
+        $this->fixtureFactory = $fixtureFactory;
+        $this->params = $params;
+        $this->fixtureData = $data;
+    }
+
+    /**
+     * Return prepared data set.
+     *
+     * @param string $key [optional]
+     * @return mixed
+     */
+    public function getData($key = null)
+    {
+        if ($this->data === null) {
+            if (isset($this->fixtureData['scope']['scope_type'])) {
+                $this->scopeData = $this->fixtureData['scope'];
+                $this->scopeType = $this->fixtureData['scope']['scope_type'];
+                $this->setLevel = $this->fixtureData['scope']['set_level'];
+                $this->prepareScopeData();
+                unset($this->fixtureData['scope']);
+            }
+            $this->data = $this->fixtureData;
+        }
+
+        return parent::getData($key);
+    }
+
+    /**
+     * Prepare scope data.
+     *
+     * @return void
+     * @throws \Exception
+     */
+    private function prepareScopeData()
+    {
+        if (isset($this->scopeData['dataset'])) {
+            /** @var Store|Website $store */
+            $this->scope = $this->fixtureFactory->createByCode(
+                $this->scopeType,
+                ['dataset' => $this->scopeData['dataset']]
+            );
+            if (!$this->scope->hasData($this->scopeType . '_id')) {
+                $this->scope->persist();
+            }
+        } elseif (isset($this->scopeData['fixture'])) {
+            $this->scope = $this->scopeData['fixture'];
+        } else {
+            throw new \Exception('Parameters "dataset" and "fixture" aren\'t identify.');
+        }
+
+        $this->prepareScope();
+    }
+
+    /**
+     * Prepare scope.
+     *
+     * @return void
+     * @throws \Exception
+     */
+    private function prepareScope()
+    {
+        if ($this->setLevel == self::STORE_CODE && $this->scopeType == self::WEBSITE_CODE) {
+            throw new \Exception('Store level can\'t set to ["scope_type" = "website"].');
+        } elseif ($this->setLevel == self::WEBSITE_CODE && $this->scopeType == self::STORE_CODE) {
+            $this->scopeType = $this->setLevel;
+            $this->scope = $this->scope
+                ->getDataFieldConfig('group_id')['source']->getStoreGroup()
+                ->getDataFieldConfig('website_id')['source']->getWebsite();
+        }
+    }
+
+    /**
+     * Return Store View or Website fixture.
+     *
+     * @return Store|Website
+     */
+    public function getScope()
+    {
+        return $this->scope;
+    }
+
+    /**
+     * Get get scope type [website|store].
+     *
+     * @return string
+     */
+    public function getScopeType()
+    {
+        return $this->scopeType;
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/Curl.php b/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/Curl.php
index 32672d63873b03a57c7de48e4ceeeef1c55204f7..aed3510118a2d579f7c998950c1c061da4d2fa4f 100644
--- a/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/Curl.php
+++ b/dev/tests/functional/tests/app/Magento/Config/Test/Handler/ConfigData/Curl.php
@@ -6,16 +6,26 @@
 
 namespace Magento\Config\Test\Handler\ConfigData;
 
+use Magento\Config\Test\Fixture\ConfigData\Section;
 use Magento\Mtf\Fixture\FixtureInterface;
 use Magento\Mtf\Handler\Curl as AbstractCurl;
 use Magento\Mtf\Util\Protocol\CurlTransport;
 use Magento\Mtf\Util\Protocol\CurlTransport\BackendDecorator;
+use Magento\Store\Test\Fixture\Store;
+use Magento\Store\Test\Fixture\Website;
 
 /**
  * Setting config.
  */
 class Curl extends AbstractCurl implements ConfigDataInterface
 {
+    /**
+     * FixtureInterface object.
+     *
+     * @var FixtureInterface
+     */
+    private $fixture;
+
     /**
      * Mapping values for data.
      *
@@ -37,6 +47,7 @@ class Curl extends AbstractCurl implements ConfigDataInterface
      */
     public function persist(FixtureInterface $fixture = null)
     {
+        $this->fixture = $fixture;
         $data = $this->prepareData($fixture);
         foreach ($data as $scope => $item) {
             $this->applyConfigSettings($item, $scope);
@@ -121,7 +132,9 @@ class Curl extends AbstractCurl implements ConfigDataInterface
 
         if (strpos($response, 'data-ui-id="messages-message-success"') === false) {
             $this->_eventManager->dispatchEvent(['curl_failed'], [$response]);
-            throw new \Exception("Configuration settings are not applied! Url: $url");
+            throw new \Exception(
+                "Configuration settings are not applied! Url: $url" . PHP_EOL . "data: " . print_r($data, true)
+            );
         }
     }
 
@@ -133,6 +146,26 @@ class Curl extends AbstractCurl implements ConfigDataInterface
      */
     protected function getUrl($section)
     {
-        return $_ENV['app_backend_url'] . 'admin/system_config/save/section/' . $section;
+        return $_ENV['app_backend_url'] . 'admin/system_config/save/section/' . $section . $this->getStoreViewUrl();
+    }
+
+    /**
+     * Get store view url.
+     *
+     * @return string
+     */
+    private function getStoreViewUrl()
+    {
+        $result = '';
+        /** @var Section $source */
+        $source = $this->fixture->getDataFieldConfig('section')['source'];
+        /** @var Store|Website $scope */
+        $scope = $source->getScope();
+        if ($scope !== null) {
+            $code = $source->getScopeType();
+            $result = $code . '/' . $scope->getData($code . '_id');
+        }
+
+        return $result ? '/' . $result : '';
     }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/CustomerGroup.xml b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/CustomerGroup.xml
index 0813e2b52c69236224953ed7d2e9324a9037a737..f72d6279f3a37ba92976b3cbaae8f49a6444262a 100644
--- a/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/CustomerGroup.xml
+++ b/dev/tests/functional/tests/app/Magento/Customer/Test/Repository/CustomerGroup.xml
@@ -15,7 +15,7 @@
         </dataset>
 
         <dataset name="General">
-            <field name="customer_group_id" xsi:type="string">1</field>
+            <field name="customer_group_id" xsi:type="string">%id%</field>
             <field name="customer_group_code" xsi:type="string">General</field>
             <field name="tax_class_id" xsi:type="array">
                 <item name="dataset" xsi:type="string">retail_customer</item>
@@ -23,7 +23,7 @@
         </dataset>
 
         <dataset name="Retailer">
-            <field name="customer_group_id" xsi:type="string">3</field>
+            <field name="customer_group_id" xsi:type="string">%id%</field>
             <field name="customer_group_code" xsi:type="string">Retailer</field>
             <field name="tax_class_id" xsi:type="array">
                 <item name="dataset" xsi:type="string">retail_customer</item>
@@ -31,7 +31,7 @@
         </dataset>
 
         <dataset name="Wholesale">
-            <field name="customer_group_id" xsi:type="string">2</field>
+            <field name="customer_group_id" xsi:type="string">%id%</field>
             <field name="customer_group_code" xsi:type="string">Wholesale</field>
             <field name="tax_class_id" xsi:type="array">
                 <item name="dataset" xsi:type="string">retail_customer</item>
@@ -39,12 +39,12 @@
         </dataset>
 
         <dataset name="all_customer_groups">
-            <field name="customer_group_id" xsi:type="string">0</field>
+            <field name="customer_group_id" xsi:type="string">%id%</field>
             <field name="customer_group_code" xsi:type="string">All Customer Groups</field>
         </dataset>
 
         <dataset name="NOT_LOGGED_IN">
-            <field name="customer_group_id" xsi:type="string">0</field>
+            <field name="customer_group_id" xsi:type="string">%id%</field>
             <field name="customer_group_code" xsi:type="string">NOT LOGGED IN</field>
             <field name="tax_class_id" xsi:type="array">
                 <item name="dataset" xsi:type="string">retail_customer</item>
@@ -52,7 +52,7 @@
         </dataset>
 
         <dataset name="ALL_GROUPS">
-            <field name="customer_group_id" xsi:type="string">32000</field>
+            <field name="customer_group_id" xsi:type="string">%id%</field>
             <field name="customer_group_code" xsi:type="string">ALL GROUPS</field>
             <field name="tax_class_id" xsi:type="array">
                 <item name="dataset" xsi:type="string">retail_customer</item>
diff --git a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/CreateDownloadableProductEntityTest.xml b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/CreateDownloadableProductEntityTest.xml
index a4141b79e9e64ef5d246c887746f6ac0ea0f2b95..e2f49d40cac7395734acc42783f5fce6b0c74083 100644
--- a/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/CreateDownloadableProductEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Downloadable/Test/TestCase/CreateDownloadableProductEntityTest.xml
@@ -284,5 +284,17 @@
             <constraint name="Magento\Catalog\Test\Constraint\AssertProductPage" />
             <constraint name="Magento\Catalog\Test\Constraint\AssertProductTierPriceOnProductPage" />
         </variation>
+        <variation name="CreateDownloadableProductEntityTestVariation16" summary="Create downloadable product and assign it to custom website">
+            <data name="product/data/name" xsi:type="string">DownloadableProduct_%isolation%</data>
+            <data name="product/data/sku" xsi:type="string">DownloadableProduct_%isolation%</data>
+            <data name="product/data/price/value" xsi:type="string">350</data>
+            <data name="product/data/quantity_and_stock_status/qty" xsi:type="string">75</data>
+            <data name="product/data/quantity_and_stock_status/is_in_stock" xsi:type="string">In Stock</data>
+            <data name="product/data/downloadable_links/dataset" xsi:type="string">one_separately_link</data>
+            <data name="product/data/url_key" xsi:type="string">downloadableproduct-%isolation%</data>
+            <data name="product/data/website_ids/0/dataset" xsi:type="string">custom_store</data>
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductSaveMessage" />
+            <constraint name="Magento\Catalog\Test\Constraint\AssertProductOnCustomWebsite" />
+        </variation>
     </testCase>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CheckoutWithGiftMessagesTest.xml b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CheckoutWithGiftMessagesTest.xml
index 2b460e9fe6a6f6a986f524b9b7b55e7802f0d58b..3913817d8f3205105356b39d39e48bc212e6ca66 100644
--- a/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CheckoutWithGiftMessagesTest.xml
+++ b/dev/tests/functional/tests/app/Magento/GiftMessage/Test/TestCase/CheckoutWithGiftMessagesTest.xml
@@ -8,7 +8,8 @@
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd">
     <testCase name="Magento\GiftMessage\Test\TestCase\CheckoutWithGiftMessagesTest" summary="One Page Checkout with Gift Messages" ticketId="MAGETWO-28978">
         <variation name="CheckoutWithGiftMessagesTestVariation1">
-            <data name="products" xsi:type="string">catalogProductSimple::default, catalogProductVirtual::default</data>
+            <data name="products/0" xsi:type="string">catalogProductSimple::default</data>
+            <data name="products/1" xsi:type="string">catalogProductVirtual::default</data>
             <data name="customer/dataset" xsi:type="string">default</data>
             <data name="shippingAddress/dataset" xsi:type="string">US_address_1_without_email</data>
             <data name="checkoutMethod" xsi:type="string">login</data>
@@ -26,7 +27,8 @@
             <constraint name="Magento\GiftMessage\Test\Constraint\AssertGiftMessageInFrontendOrder" />
         </variation>
         <variation name="CheckoutWithGiftMessagesTestVariation2">
-            <data name="products" xsi:type="string">catalogProductSimple::default, catalogProductVirtual::default</data>
+            <data name="products/0" xsi:type="string">catalogProductSimple::default</data>
+            <data name="products/1" xsi:type="string">catalogProductVirtual::default</data>
             <data name="customer/dataset" xsi:type="string">default</data>
             <data name="shippingAddress/dataset" xsi:type="string">US_address_1_without_email</data>
             <data name="checkoutMethod" xsi:type="string">login</data>
diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Block/Cache/Grid.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Block/Cache/Grid.php
index 4398f42cb11f28d8907924685a232b58b1177eba..a2d9dac2442f777eefb3fb68b217ff2184d77dbb 100644
--- a/dev/tests/functional/tests/app/Magento/PageCache/Test/Block/Cache/Grid.php
+++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Block/Cache/Grid.php
@@ -6,6 +6,7 @@
 
 namespace Magento\PageCache\Test\Block\Cache;
 
+use Magento\Mtf\Client\Locator;
 use Magento\Backend\Test\Block\Widget\Grid as ParentGrid;
 
 /**
@@ -13,6 +14,13 @@ use Magento\Backend\Test\Block\Widget\Grid as ParentGrid;
  */
 class Grid extends ParentGrid
 {
+    /**
+     * Locator value for cache status.
+     *
+     * @var string
+     */
+    private $cacheStatus = "//tr[td[contains(text(), '%s')]]/td//span[contains(text(), '%s')]";
+
     /**
      * Search for item and select it.
      *
@@ -29,4 +37,17 @@ class Grid extends ParentGrid
             throw new \Exception("Searched item was not found by filter\n" . print_r($filter, true));
         }
     }
+
+    /**
+     * Checks cache status.
+     *
+     * @param string $cacheType
+     * @param string $cacheStatus
+     * @return bool
+     */
+    public function isCacheStatusCorrect($cacheType, $cacheStatus)
+    {
+        return $this->_rootElement->find(sprintf($this->cacheStatus, $cacheType, $cacheStatus), Locator::SELECTOR_XPATH)
+            ->isVisible();
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidateNotice.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidateNotice.php
new file mode 100644
index 0000000000000000000000000000000000000000..bedaebbd4c7dbccb13a649ca5e630c946bcaaab9
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidateNotice.php
@@ -0,0 +1,60 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\PageCache\Test\Constraint;
+
+use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
+use Magento\Mtf\Constraint\AbstractConstraint;
+
+/**
+ * Assert cache invalidate notice.
+ */
+class AssertCacheInvalidateNotice extends AbstractConstraint
+{
+    /**
+     * Cache types array.
+     *
+     * @var array
+     */
+    private $cacheTypes = [
+        'block_html' => "Blocks HTML output",
+    ];
+
+    /**
+     * Assert cache invalidate notice.
+     *
+     * @param AdminCache $adminCache
+     * @param array $caches
+     * @return void
+     */
+    public function processAssert(AdminCache $adminCache, array $caches)
+    {
+        $adminCache->getSystemMessageDialog()->closePopup();
+        foreach ($caches as $cacheType => $cacheStatus) {
+            if ($cacheStatus === 'Invalidated') {
+                \PHPUnit_Framework_Assert::assertContains(
+                    $this->cacheTypes[$cacheType],
+                    $adminCache->getSystemMessageBlock()->getContent()
+                );
+            } else {
+                \PHPUnit_Framework_Assert::assertNotContains(
+                    $this->cacheTypes[$cacheType],
+                    $adminCache->getSystemMessageBlock()->getContent()
+                );
+            }
+        }
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Cache invalidate notice is correct.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidatePopUp.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidatePopUp.php
new file mode 100644
index 0000000000000000000000000000000000000000..27b77110c47b9f0e45ce8d709315f6bffda9b5b0
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheInvalidatePopUp.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\PageCache\Test\Constraint;
+
+use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
+use Magento\Mtf\Constraint\AbstractConstraint;
+
+/**
+ * Assert cache invalidate pop up.
+ */
+class AssertCacheInvalidatePopUp extends AbstractConstraint
+{
+    /**
+     * Cache types array.
+     *
+     * @var array
+     */
+    private $cacheTypes = [
+        'block_html' => "Blocks HTML output",
+    ];
+
+    /**
+     * Assert cache invalidate pop up.
+     *
+     * @param AdminCache $adminCache
+     * @param array $caches
+     * @return void
+     */
+    public function processAssert(AdminCache $adminCache, array $caches)
+    {
+        foreach ($caches as $cacheType => $cacheStatus) {
+            if ($cacheStatus === 'Invalidated') {
+                \PHPUnit_Framework_Assert::assertContains(
+                    $this->cacheTypes[$cacheType],
+                    $adminCache->getSystemMessageDialog()->getPopupText()
+                );
+            } else {
+                \PHPUnit_Framework_Assert::assertNotContains(
+                    $this->cacheTypes[$cacheType],
+                    $adminCache->getSystemMessageDialog()->getPopupText()
+                );
+            }
+        }
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Cache invalidate pop up is correct.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheStatus.php b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheStatus.php
new file mode 100644
index 0000000000000000000000000000000000000000..22adf03401c77b8fb7663ad6a234f4141cd3cb79
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Constraint/AssertCacheStatus.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\PageCache\Test\Constraint;
+
+use Magento\Mtf\Constraint\AbstractConstraint;
+use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
+
+/**
+ * Assert cache status.
+ */
+class AssertCacheStatus extends AbstractConstraint
+{
+    /**
+     * Cache types array.
+     *
+     * @var array
+     */
+    private $cacheTypes = [
+        'block_html' => "Blocks HTML output",
+    ];
+
+    /**
+     * Assert cache status equals to passed from variation.
+     *
+     * @param AdminCache $adminCache
+     * @param array $caches
+     * @return void
+     */
+    public function processAssert(AdminCache $adminCache, array $caches)
+    {
+        $adminCache->open();
+        foreach ($caches as $cacheType => $cacheStatus) {
+            \PHPUnit_Framework_Assert::assertTrue(
+                $adminCache->getGridBlock()->isCacheStatusCorrect($this->cacheTypes[$cacheType], $cacheStatus),
+                $this->cacheTypes[$cacheType] . " cache status in grid does not equal to " . $cacheStatus
+            );
+        }
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Cache status is correct.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/PageCache/Test/Page/Adminhtml/AdminCache.xml b/dev/tests/functional/tests/app/Magento/PageCache/Test/Page/Adminhtml/AdminCache.xml
index 8e4f538d9e6ca1da6a2f4cb1120733b0a7abb91e..8e067e92c1ddc52454c554cf70bed8e3a6c41174 100644
--- a/dev/tests/functional/tests/app/Magento/PageCache/Test/Page/Adminhtml/AdminCache.xml
+++ b/dev/tests/functional/tests/app/Magento/PageCache/Test/Page/Adminhtml/AdminCache.xml
@@ -12,5 +12,7 @@
         <block name="additionalBlock" class="Magento\PageCache\Test\Block\Cache\Additional" locator="div.additional-cache-management" strategy="css selector"/>
         <block name="gridBlock" class="Magento\PageCache\Test\Block\Cache\Grid" locator="div#cache_grid" strategy="css selector"/>
         <block name="modalBlock" class="Magento\Ui\Test\Block\Adminhtml\Modal" locator="._show[data-role=modal]" strategy="css selector"/>
+        <block name="systemMessageDialog" class="Magento\AdminNotification\Test\Block\System\Messages" locator='.ui-popup-message .modal-inner-wrap' strategy="css selector" />
+        <block name="systemMessageBlock" class="Magento\AdminNotification\Test\Block\System\Messages\System" locator="#system_messages" strategy="css selector" />
     </page>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewIsAvailableForProduct.php b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewIsAvailableForProduct.php
index 485a7abf63f64e22c6829e82cdabab4b212099b9..a68749473dee5d18335b2ea65cdde866051f0618 100644
--- a/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewIsAvailableForProduct.php
+++ b/dev/tests/functional/tests/app/Magento/Reports/Test/Constraint/AssertProductReviewIsAvailableForProduct.php
@@ -6,6 +6,7 @@
 
 namespace Magento\Reports\Test\Constraint;
 
+use Magento\Mtf\Fixture\FixtureInterface;
 use Magento\Reports\Test\Page\Adminhtml\ProductReportReview;
 use Magento\Review\Test\Constraint\AssertProductReviewInGrid;
 use Magento\Review\Test\Fixture\Review;
@@ -13,31 +14,32 @@ use Magento\Review\Test\Page\Adminhtml\ReviewIndex;
 use Magento\Mtf\Constraint\AbstractConstraint;
 
 /**
- * Class AssertProductReviewIsVisibleInGrid
- * Assert that review is visible in review grid for select product
+ * Assert that review is visible in review grid for select product.
  */
 class AssertProductReviewIsAvailableForProduct extends AbstractConstraint
 {
     /**
-     * Assert that review is visible in review grid for select product
+     * Assert that review is visible in review grid for select product.
      *
      * @param ReviewIndex $reviewIndex
      * @param Review $review
      * @param ProductReportReview $productReportReview
      * @param AssertProductReviewInGrid $assertProductReviewInGrid
+     * @param FixtureInterface $product
      * @return void
      */
     public function processAssert(
         ReviewIndex $reviewIndex,
         Review $review,
         ProductReportReview $productReportReview,
-        AssertProductReviewInGrid $assertProductReviewInGrid
+        AssertProductReviewInGrid $assertProductReviewInGrid,
+        FixtureInterface $product
     ) {
         $productReportReview->open();
-        $product = $review->getDataFieldConfig('entity_id')['source']->getEntity();
         $productReportReview->getGridBlock()->openReview($product->getName());
         unset($assertProductReviewInGrid->filter['visible_in']);
         $filter = $assertProductReviewInGrid->prepareFilter($product, $review->getData(), '');
+        $reviewIndex->getReviewGrid()->resetFilter();
         \PHPUnit_Framework_Assert::assertTrue(
             $reviewIndex->getReviewGrid()->isRowVisible($filter, false),
             'Review for ' . $product->getName() . ' product is not visible in reports grid.'
@@ -45,7 +47,7 @@ class AssertProductReviewIsAvailableForProduct extends AbstractConstraint
     }
 
     /**
-     * Returns a string representation of the object
+     * Returns a string representation of the object.
      *
      * @return string
      */
diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductReviewReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductReviewReportEntityTest.php
deleted file mode 100644
index cdc7f443132a39aa49619b6cdd81e0b6c47147d5..0000000000000000000000000000000000000000
--- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductReviewReportEntityTest.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Reports\Test\TestCase;
-
-use Magento\Review\Test\Fixture\Review;
-use Magento\Mtf\TestCase\Injectable;
-
-/**
- * Preconditions:
- * 1. Create simple product
- * 2. Create review for this product
- *
- * Test Flow:
- * 1. Login as admin
- * 2. Navigate to the Reports>Reviews>By Products
- * 3. Perform appropriate assertions.
- *
- * @group Reports_(MX)
- * @ZephyrId MAGETWO-27223
- */
-class ProductReviewReportEntityTest extends Injectable
-{
-    /* tags */
-    const MVP = 'no';
-    const DOMAIN = 'MX';
-    /* end tags */
-
-    /**
-     * Creation product review report entity
-     *
-     * @param Review $review
-     * @return void
-     */
-    public function test(Review $review)
-    {
-        // Preconditions
-        $review->persist();
-    }
-}
diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductReviewReportEntityTest.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductReviewReportEntityTest.xml
deleted file mode 100644
index 4299894c46f99c35855110e7b1943449a811cd5c..0000000000000000000000000000000000000000
--- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ProductReviewReportEntityTest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
- -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd">
-    <testCase name="Magento\Reports\Test\TestCase\ProductReviewReportEntityTest" summary="Product Review Report" ticketId="MAGETWO-27223">
-        <variation name="ProductReviewReportEntityTestVariation1">
-            <data name="review/dataset" xsi:type="string">frontend_review</data>
-            <constraint name="Magento\Reports\Test\Constraint\AssertProductReviewReportIsVisibleInGrid" />
-            <constraint name="Magento\Reports\Test\Constraint\AssertProductReviewIsAvailableForProduct" />
-        </variation>
-    </testCase>
-</config>
diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomerReviewReportEntityTest.php b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ReviewReportEntityTest.php
similarity index 62%
rename from dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomerReviewReportEntityTest.php
rename to dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ReviewReportEntityTest.php
index 208fba464a3bc224490a0e774a3301beb7d39a8a..9ed56a46e565ef0c489229d3b89af959cad8fc5b 100644
--- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomerReviewReportEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ReviewReportEntityTest.php
@@ -3,7 +3,6 @@
  * Copyright © 2016 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Reports\Test\TestCase;
 
 use Magento\Catalog\Test\Fixture\CatalogProductSimple;
@@ -20,25 +19,23 @@ use Magento\Mtf\TestCase\Injectable;
 
 /**
  * Preconditions:
- * 1. Create customer
- * 2. Create simple product
- * 3. Open Product created in preconditions
- * 4. Click "Be the first to review this product "
- * 5. Fill data according to DataSet
- * 6. Click Submit review
+ * 1. Create customer.
+ * 2. Create simple product.
  *
  * Steps:
- * 1. Open Reports -> Review : By Customers
- * 2. Assert Reviews qty
- * 3. Click Show Reviews
- * 4. Perform appropriate assertions.
+ * 1. Open Product created in preconditions.
+ * 2. Click "Be the first to review this product".
+ * 3. Fill data according to DataSet.
+ * 4. Click Submit review.
+ * 5. Perform appropriate assertions.
  *
  * @group Reports_(MX)
  * @ZephyrId MAGETWO-27555
+ * @ZephyrId MAGETWO-27223
  *
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
-class CustomerReviewReportEntityTest extends Injectable
+class ReviewReportEntityTest extends Injectable
 {
     /* tags */
     const MVP = 'no';
@@ -46,42 +43,42 @@ class CustomerReviewReportEntityTest extends Injectable
     /* end tags */
 
     /**
-     * Customer frontend logout page
+     * Customer frontend logout page.
      *
      * @var CustomerAccountLogout
      */
     protected $customerAccountLogout;
 
     /**
-     * Product reviews report page
+     * Product reviews report page.
      *
      * @var ProductReportReview
      */
     protected $productReportReview;
 
     /**
-     * Frontend product view page
+     * Frontend product view page.
      *
      * @var CatalogProductView
      */
     protected $pageCatalogProductView;
 
     /**
-     * Cms Index page
+     * Cms Index page.
      *
      * @var CmsIndex
      */
     protected $cmsIndex;
 
     /**
-     * Catalog Category page
+     * Catalog Category page.
      *
      * @var CatalogCategoryView
      */
     protected $catalogCategoryView;
 
     /**
-     * Prepare data
+     * Prepare data.
      *
      * @param FixtureFactory $fixtureFactory
      * @return array
@@ -90,12 +87,11 @@ class CustomerReviewReportEntityTest extends Injectable
     {
         $customer = $fixtureFactory->createByCode('customer', ['dataset' => 'johndoe_unique']);
         $customer->persist();
-
         return ['customer' => $customer];
     }
 
     /**
-     * Preparing pages for test
+     * Preparing pages for test.
      *
      * @param ProductReportReview $productReportReview
      * @param CatalogProductView $pageCatalogProductView
@@ -119,44 +115,58 @@ class CustomerReviewReportEntityTest extends Injectable
     }
 
     /**
-     * Test Creation for CustomerReviewReportEntity
+     * Test Creation for ReviewReportEntity.
      *
      * @param Review $review
      * @param Customer $customer
-     * @param $customerLogin
-     * @param CatalogProductSimple $product
      * @param BrowserInterface $browser
+     * @param CatalogProductSimple $product [optional]
+     * @param bool $isCustomerLoggedIn [optional]
      * @return array
-     *
-     * @SuppressWarnings(PHPMD.ConstructorWithNameAsEnclosingClass)
      */
     public function test(
         Review $review,
         Customer $customer,
-        CatalogProductSimple $product,
         BrowserInterface $browser,
-        $customerLogin
+        CatalogProductSimple $product = null,
+        $isCustomerLoggedIn = false
     ) {
         // Preconditions
-        $product->persist();
         $this->cmsIndex->open();
-        if ($customerLogin == 'Yes') {
-            $this->objectManager->create(
-                \Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep::class,
-                ['customer' => $customer]
-            )->run();
+        if ($isCustomerLoggedIn) {
+            $this->loginCustomer($customer);
         }
         // Steps
-        $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html');
-        $this->pageCatalogProductView->getReviewSummary()->getAddReviewLink()->click();
-        $this->pageCatalogProductView->getReviewFormBlock()->fill($review);
-        $this->pageCatalogProductView->getReviewFormBlock()->submit();
-
+        if ($review->getType() === "Administrator") {
+            $review->persist();
+            $product = $review->getDataFieldConfig('entity_id')['source']->getEntity();
+        } else {
+            $product->persist();
+            $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html');
+            $this->pageCatalogProductView->getReviewSummary()->getAddReviewLink()->click();
+            $this->pageCatalogProductView->getReviewFormBlock()->fill($review);
+            $this->pageCatalogProductView->getReviewFormBlock()->submit();
+        }
+        
         return ['product' => $product];
     }
 
     /**
-     * Logout customer from frontend account
+     * Login customer on frontend.
+     *
+     * @param Customer $customer
+     * @return void
+     */
+    private function loginCustomer(Customer $customer)
+    {
+        $this->objectManager->create(
+            'Magento\Customer\Test\TestStep\LoginCustomerOnFrontendStep',
+            ['customer' => $customer]
+        )->run();
+    }
+
+    /**
+     * Logout customer from frontend account.
      *
      * return void
      */
diff --git a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomerReviewReportEntityTest.xml b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ReviewReportEntityTest.xml
similarity index 64%
rename from dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomerReviewReportEntityTest.xml
rename to dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ReviewReportEntityTest.xml
index 9fd2c98536d357582e6ad32cf00012e2bedb7f34..0a6a95eecccde07d25c75951528462feb0643303 100644
--- a/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/CustomerReviewReportEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Reports/Test/TestCase/ReviewReportEntityTest.xml
@@ -6,9 +6,9 @@
  */
  -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd">
-    <testCase name="Magento\Reports\Test\TestCase\CustomerReviewReportEntityTest" summary="Customer Review Report" ticketId="MAGETWO-27555">
-        <variation name="CustomerReviewReportEntityTestVariation1">
-            <data name="customerLogin" xsi:type="string">Yes</data>
+    <testCase name="Magento\Reports\Test\TestCase\ReviewReportEntityTest" summary="Review Report">
+        <variation name="CustomerReviewReportEntityTestVariation1" summary="Customer Review Report" ticketId="MAGETWO-27555">
+            <data name="isCustomerLoggedIn" xsi:type="boolean">true</data>
             <data name="product/dataset" xsi:type="string">default</data>
             <data name="review/data/type" xsi:type="string">Customer</data>
             <data name="review/data/nickname" xsi:type="string">name_upd_%isolation%</data>
@@ -18,8 +18,8 @@
             <constraint name="Magento\Reports\Test\Constraint\AssertProductReviewsQtyByCustomer" />
             <constraint name="Magento\Reports\Test\Constraint\AssertProductReportByCustomerInGrid" />
         </variation>
-        <variation name="CustomerReviewReportEntityTestVariation2">
-            <data name="customerLogin" xsi:type="string">Yes</data>
+        <variation name="CustomerReviewReportEntityTestVariation2" summary="Customer Review Report" ticketId="MAGETWO-27555">
+            <data name="isCustomerLoggedIn" xsi:type="boolean">true</data>
             <data name="product/dataset" xsi:type="string">default</data>
             <data name="review/data/type" xsi:type="string">Customer</data>
             <data name="review/data/nickname" xsi:type="string">name_upd_%isolation%</data>
@@ -29,9 +29,9 @@
             <constraint name="Magento\Reports\Test\Constraint\AssertProductReviewsQtyByCustomer" />
             <constraint name="Magento\Reports\Test\Constraint\AssertProductReportByCustomerInGrid" />
         </variation>
-        <variation name="CustomerReviewReportEntityTestVariation3">
-            <data name="customerLogin" xsi:type="string">No</data>
+        <variation name="CustomerReviewReportEntityTestVariation3" summary="Guest Review Report by Customer" ticketId="MAGETWO-27555">
             <data name="product/dataset" xsi:type="string">default</data>
+            <data name="review/data/type" xsi:type="string">Guest</data>
             <data name="review/data/nickname" xsi:type="string">name_upd_%isolation%</data>
             <data name="review/data/title" xsi:type="string">title_upd_%isolation%</data>
             <data name="review/data/detail" xsi:type="string">review_upd_%isolation%</data>
@@ -39,5 +39,15 @@
             <constraint name="Magento\Reports\Test\Constraint\AssertProductReviewsQtyByCustomer" />
             <constraint name="Magento\Reports\Test\Constraint\AssertProductReportByCustomerNotInGrid" />
         </variation>
+        <variation name="ProductReviewReportEntityTestVariation4" summary="Assert product review report by guest" ticketId="MAGETWO-27223">
+            <data name="product/dataset" xsi:type="string">default</data>
+            <data name="review/dataset" xsi:type="string">frontend_guest</data>
+            <constraint name="Magento\Reports\Test\Constraint\AssertProductReviewIsAvailableForProduct" />
+        </variation>
+        <variation name="ProductReviewReportEntityTestVariation5" summary="Assert product Review Report by Administrator" ticketId="MAGETWO-27223">
+            <data name="review/dataset" xsi:type="string">frontend_review</data>
+            <constraint name="Magento\Reports\Test\Constraint\AssertProductReviewReportIsVisibleInGrid" />
+            <constraint name="Magento\Reports\Test\Constraint\AssertProductReviewIsAvailableForProduct" />
+        </variation>
     </testCase>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Review.xml b/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Review.xml
index 9a6431ce1a54b8d7fa0b4c36c11cded99e4edec0..05c96f78ad7834603aeb43d34c8d01020e03259d 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Review.xml
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Review.xml
@@ -57,6 +57,21 @@
             <field name="entity_id" xsi:type="array">
                 <item name="dataset" xsi:type="string">catalogProductSimple::default</item>
             </field>
+            <field name="type" xsi:type="string">Administrator</field>
+        </dataset>
+
+        <dataset name="frontend_guest">
+            <field name="status_id" xsi:type="string">Pending</field>
+            <field name="select_stores" xsi:type="array">
+                <item name="0" xsi:type="string">Main Website/Main Website Store/Default Store View</item>
+            </field>
+            <field name="nickname" xsi:type="string">Guest customer %isolation%</field>
+            <field name="title" xsi:type="string">Summary review %isolation%</field>
+            <field name="detail" xsi:type="string">Text review %isolation%</field>
+            <field name="entity_id" xsi:type="array">
+                <item name="dataset" xsi:type="string">catalogProductSimple::default</item>
+            </field>
+            <field name="type" xsi:type="string">Guest</field>
         </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Widget/Guest/Form.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Widget/Guest/Form.php
index c389725c1bd858bc5b7684aeffc65b3d58ba2b00..0fa3a67c8122ec5c0d86bfec707f528621904f8e 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Widget/Guest/Form.php
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Block/Widget/Guest/Form.php
@@ -43,16 +43,18 @@ class Form extends \Magento\Mtf\Block\Form
     public function fill(FixtureInterface $fixture, SimpleElement $element = null, $isSearchByEmail = true)
     {
         /** @var OrderInjectable $fixture */
-        /** @var Customer $customer */
-        $customer = $fixture->getDataFieldConfig('customer_id')['source']->getCustomer();
+        $searchData = $fixture->getData('customer_id')
+            ? $fixture->getDataFieldConfig('customer_id')['source']->getCustomer()->getData()
+            : $fixture->getDataFieldConfig('billing_address_id')['source']->getData();
+        
         $data = [
             'order_id' => $fixture->getId(),
-            'billing_last_name' => $customer->getLastname(),
+            'billing_last_name' => $searchData['lastname'],
         ];
 
         if ($isSearchByEmail) {
             $data['find_order_by'] = 'Email';
-            $data['email_address'] = $customer->getEmail();
+            $data['email_address'] = $searchData['email'];
         } else {
             $data['find_order_by'] = 'ZIP Code';
             $data['billing_zip_code'] = $fixture->getDataFieldConfig('billing_address_id')['source']->getPostcode();
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderInjectable/Webapi.php b/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderInjectable/Webapi.php
index ea4eb3ef9ec8681ed35b81d6939c6929001871f2..1286064662ebe097ae1239da04419ac1bad8b8a9 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderInjectable/Webapi.php
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Handler/OrderInjectable/Webapi.php
@@ -49,6 +49,13 @@ class Webapi extends AbstractWebapi implements OrderInjectableInterface
      */
     protected $url;
 
+    /**
+     * Either customer is a guest or not.
+     *
+     * @var bool
+     */
+    private $isCustomerGuest;
+
     /**
      * Creating order using quote via web API.
      *
@@ -57,9 +64,14 @@ class Webapi extends AbstractWebapi implements OrderInjectableInterface
      */
     public function persist(FixtureInterface $fixture = null)
     {
+        $this->isCustomerGuest = $fixture->getData('customer_id') ? false : true;
+
         /** @var OrderInjectable $fixture */
         $this->createQuote($fixture);
-        $this->url = $_ENV['app_frontend_url'] . 'rest/V1/carts/' . (int)$this->quote;
+
+        $url = $this->isCustomerGuest ? 'guest-carts/' . $this->quote  : 'carts/' . (int)$this->quote;
+        $this->url = $_ENV['app_frontend_url'] . 'rest/V1/' . $url;
+
         $this->setProducts($fixture);
         $this->setCoupon($fixture);
         $this->setBillingAddress($fixture);
@@ -79,16 +91,28 @@ class Webapi extends AbstractWebapi implements OrderInjectableInterface
      */
     protected function createQuote(OrderInjectable $order)
     {
-        $url = $_ENV['app_frontend_url'] . 'rest/V1/customers/' . $order->getCustomerId()->getId() . '/carts';
-        $data = '{"customerId": "' . $order->getCustomerId()->getId() . '"}';
-        $this->webapiTransport->write($url, $data);
-        $response = json_decode($this->webapiTransport->read(), true);
-        $this->webapiTransport->close();
-        if (!is_numeric($response)) {
-            $this->eventManager->dispatchEvent(['webapi_failed'], [$response]);
-            throw new \Exception('Could not create a checkout quote using web API.');
+        if ($this->isCustomerGuest) {
+            $url = $_ENV['app_frontend_url'] . 'rest/V1/guest-carts';
+            $this->webapiTransport->write($url);
+            $response = json_decode($this->webapiTransport->read(), true);
+            $this->webapiTransport->close();
+            if (!is_string($response)) {
+                $this->eventManager->dispatchEvent(['webapi_failed'], [$response]);
+                throw new \Exception('Could not create a checkout quote using web API.');
+            }
+            $this->quote = $response;
+        } else {
+            $url = $_ENV['app_frontend_url'] . 'rest/V1/customers/' . $order->getCustomerId()->getId() . '/carts';
+            $data = '{"customerId": "' . $order->getCustomerId()->getId() . '"}';
+            $this->webapiTransport->write($url, $data);
+            $response = json_decode($this->webapiTransport->read(), true);
+            $this->webapiTransport->close();
+            if (!is_numeric($response)) {
+                $this->eventManager->dispatchEvent(['webapi_failed'], [$response]);
+                throw new \Exception('Could not create a checkout quote using web API.');
+            }
+            $this->quote = $response;
         }
-        $this->quote = $response;
     }
 
     /**
@@ -100,7 +124,7 @@ class Webapi extends AbstractWebapi implements OrderInjectableInterface
      */
     protected function setProducts(OrderInjectable $order)
     {
-        $url = $_ENV['app_frontend_url'] . 'rest/V1/carts/' .  $this->quote . '/items';
+        $url = $this->url . '/items';
         $products = $order->getEntityId()['products'];
         foreach ($products as $product) {
             $data = [
diff --git a/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable.xml b/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable.xml
index d734a9a26906fb9892a1b334fb64719795ea4749..65335ced8ed4c24f2bee701f1be039274585fd55 100644
--- a/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable.xml
+++ b/dev/tests/functional/tests/app/Magento/Sales/Test/Repository/OrderInjectable.xml
@@ -230,5 +230,26 @@
             <field name="base_currency_code" xsi:type="string">0</field>
             <field name="order_currency_code" xsi:type="string">USD</field>
         </dataset>
+
+        <dataset name="guest">
+            <field name="entity_id" xsi:type="array">
+                <item name="products" xsi:type="string">catalogProductSimple::default</item>
+            </field>
+            <field name="billing_address_id" xsi:type="array">
+                <item name="dataset" xsi:type="string">US_address</item>
+            </field>
+            <field name="store_id" xsi:type="array">
+                <item name="dataset" xsi:type="string">default_store_view</item>
+            </field>
+            <field name="shipping_method" xsi:type="string">flatrate_flatrate</field>
+            <field name="payment_auth_expiration" xsi:type="array">
+                <item name="method" xsi:type="string">checkmo</item>
+            </field>
+            <field name="payment_authorization_amount" xsi:type="array">
+                <item name="method" xsi:type="string">free</item>
+            </field>
+            <field name="base_currency_code" xsi:type="string">0</field>
+            <field name="order_currency_code" xsi:type="string">USD</field>
+        </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Website/Curl.php b/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Website/Curl.php
index b8ac08b09054fe0c69778321fd20d8fa3578a75f..6d7eefa7889dfd272a9ed7a8a476bae453907f48 100644
--- a/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Website/Curl.php
+++ b/dev/tests/functional/tests/app/Magento/Store/Test/Handler/Website/Curl.php
@@ -6,6 +6,7 @@
 
 namespace Magento\Store\Test\Handler\Website;
 
+use Magento\Mtf\Fixture\FixtureFactory;
 use Magento\Mtf\Fixture\FixtureInterface;
 use Magento\Mtf\Handler\Curl as AbstractCurl;
 use Magento\Mtf\Util\Protocol\CurlInterface;
@@ -14,6 +15,7 @@ use Magento\Mtf\Util\Protocol\CurlTransport\BackendDecorator;
 use Magento\Mtf\Config\DataInterface;
 use Magento\Mtf\System\Event\EventManagerInterface;
 use Magento\Mtf\Util\Command\Website;
+use Magento\Store\Test\Fixture\Website as WebsiteFixture;
 
 /**
  * Curl handler for creating Website.
@@ -27,19 +29,36 @@ class Curl extends AbstractCurl implements WebsiteInterface
      */
     private $website;
 
+    /**
+     * Website fixture.
+     *
+     * @var WebsiteFixture
+     */
+    private $fixture;
+
+    /**
+     * Fixture factory.
+     *
+     * @var FixtureFactory
+     */
+    private $fixtureFactory;
+
     /**
      * @constructor
      * @param DataInterface $configuration
      * @param EventManagerInterface $eventManager
      * @param Website $website
+     * @param FixtureFactory $fixtureFactory
      */
     public function __construct(
         DataInterface $configuration,
         EventManagerInterface $eventManager,
-        Website $website
+        Website $website,
+        FixtureFactory $fixtureFactory
     ) {
         parent::__construct($configuration, $eventManager);
         $this->website = $website;
+        $this->fixtureFactory = $fixtureFactory;
     }
 
     /**
@@ -63,9 +82,14 @@ class Curl extends AbstractCurl implements WebsiteInterface
 
         $websiteId = $this->getWebSiteIdByWebsiteName($fixture->getName());
 
+        // Update website fixture data.
+        $this->fixture = $this->fixtureFactory->createByCode(
+            'website',
+            ['data' => array_merge($fixture->getData(), ['website_id' => $websiteId])]
+        );
         // Creates Website folder in root directory.
         $this->website->create($data['website']['code']);
-        $this->setConfiguration($data, $websiteId);
+        $this->setConfiguration($data);
 
         return ['website_id' => $websiteId];
     }
@@ -120,30 +144,19 @@ class Curl extends AbstractCurl implements WebsiteInterface
      * Set Website configuration Base url.
      *
      * @param array $data
-     * @param int $websiteId
      * @return void
      * @throws \Exception
      */
-    private function setConfiguration($data, $websiteId)
+    private function setConfiguration(array $data)
     {
         $configData = [
-            'groups' => [
-                'unsecure' => [
-                    'fields' => [
-                        'base_link_url' =>
-                            [
-                                'value' => '{{unsecure_base_url}}websites/' . $data['website']['code'] . '/',
-                            ]
-                    ]
-                ]
-            ]
+            'web/unsecure/base_link_url' => [
+                'value' => '{{unsecure_base_url}}websites/' . $data['website']['code'] . '/'
+            ],
+            'scope' => ['fixture' => $this->fixture, 'scope_type' => 'website', 'set_level' => 'website']
         ];
 
-        $url = $_ENV['app_backend_url'] .
-            'admin/system_config/save/section/web/website/' . $websiteId . '/';
-        $curl = new BackendDecorator(new CurlTransport(), $this->_configuration);
-        $curl->write($url, $configData);
-        $curl->read();
-        $curl->close();
+        $configFixture = $this->fixtureFactory->createByCode('configData', ['data' => $configData]);
+        $configFixture->persist();
     }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Store.xml b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Store.xml
index 09a78be796b01000c806231d87ade6c0a761cda4..12ca9f5e03a20568423ee565030c785e9eec5bba 100644
--- a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Store.xml
+++ b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Store.xml
@@ -8,13 +8,13 @@
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd">
     <repository class="Magento\Store\Test\Repository\Store">
         <dataset name="default">
+            <field name="store_id" xsi:type="string">%id%</field>
             <field name="group_id" xsi:type="array">
                 <item name="dataset" xsi:type="string">default</item>
             </field>
             <field name="name" xsi:type="string">Default Store View</field>
             <field name="code" xsi:type="string">default</field>
             <field name="is_active" xsi:type="string">Enabled</field>
-            <field name="store_id" xsi:type="string">1</field>
         </dataset>
 
         <dataset name="custom">
@@ -27,13 +27,13 @@
         </dataset>
 
         <dataset name="default_store_view">
+            <field name="store_id" xsi:type="string">%id%</field>
             <field name="name" xsi:type="string">Default Store View</field>
-            <field name="store_id" xsi:type="string">1</field>
         </dataset>
 
         <dataset name="all_store_views">
+            <field name="store_id" xsi:type="string">%id%</field>
             <field name="name" xsi:type="string">All Store Views</field>
-            <field name="store_id" xsi:type="string">0</field>
         </dataset>
 
         <dataset name="german">
diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/StoreGroup.xml b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/StoreGroup.xml
index cbda2a02eda72020b5da48e0d89fd44c0bd40bac..f07c79a8967d56b5b241feb049cd402f6d90ddef 100644
--- a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/StoreGroup.xml
+++ b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/StoreGroup.xml
@@ -8,11 +8,11 @@
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd">
     <repository class="Magento\Store\Test\Repository\StoreGroup">
         <dataset name="default">
+            <field name="group_id" xsi:type="string">%id%</field>
             <field name="website_id" xsi:type="array">
                 <item name="dataset" xsi:type="string">main_website</item>
             </field>
             <field name="name" xsi:type="string">Main Website Store</field>
-            <field name="group_id" xsi:type="string">1</field>
             <field name="root_category_id" xsi:type="array">
                 <item name="dataset" xsi:type="string">default_category</item>
             </field>
diff --git a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Website.xml b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Website.xml
index 8b90722866ae9be0204730f8ce851e14258acd20..5c2ec69efca98b581708ffd2eb4441d8275ee073 100644
--- a/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Website.xml
+++ b/dev/tests/functional/tests/app/Magento/Store/Test/Repository/Website.xml
@@ -8,21 +8,21 @@
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd">
     <repository class="Magento\Store\Test\Repository\Website">
         <dataset name="default">
+            <field name="website_id" xsi:type="string">%id%</field>
             <field name="name" xsi:type="string">Main Website</field>
             <field name="code" xsi:type="string">base</field>
-            <field name="website_id" xsi:type="string">1</field>
         </dataset>
 
         <dataset name="all_websites">
+            <field name="website_id" xsi:type="string">%id%</field>
             <field name="name" xsi:type="string">All Websites</field>
-            <field name="website_id" xsi:type="string">0</field>
         </dataset>
 
         <dataset name="main_website">
+            <field name="website_id" xsi:type="string">%id%</field>
             <field name="name" xsi:type="string">Main Website</field>
             <field name="code" xsi:type="string">base</field>
             <field name="sort_order" xsi:type="string">0</field>
-            <field name="website_id" xsi:type="string">1</field>
         </dataset>
 
         <dataset name="custom_website">
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxClass.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxClass.xml
index 35ece9e1fa394b1fba480c7b25486e78cc2c02b0..061bc05c07891a433ae37327c5e403e121870dec 100644
--- a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxClass.xml
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxClass.xml
@@ -12,17 +12,17 @@
         </dataset>
 
         <dataset name="taxable_goods">
-            <field name="class_id" xsi:type="string">2</field>
+            <field name="id" xsi:type="string">%id%</field>
+            <field name="class_id" xsi:type="string">%id%</field>
             <field name="class_name" xsi:type="string">Taxable Goods</field>
             <field name="class_type" xsi:type="string">PRODUCT</field>
-            <field name="id" xsi:type="string">2</field>
         </dataset>
 
         <dataset name="retail_customer">
-            <field name="class_id" xsi:type="string">3</field>
+            <field name="id" xsi:type="string">%id%</field>
+            <field name="class_id" xsi:type="string">%id%</field>
             <field name="class_name" xsi:type="string">Retail Customer</field>
             <field name="class_type" xsi:type="string">CUSTOMER</field>
-            <field name="id" xsi:type="string">3</field>
         </dataset>
 
         <dataset name="customer_tax_class">
@@ -36,9 +36,9 @@
         </dataset>
 
         <dataset name="None">
+            <field name="id" xsi:type="string">%id%</field>
             <field name="class_name" xsi:type="string">None</field>
             <field name="class_type" xsi:type="string">PRODUCT</field>
-            <field name="id" xsi:type="string">0</field>
         </dataset>
 
         <dataset name="all">
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRate.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRate.xml
index e60032248ab54be2b9f44b03b33a7ca42f5e43b2..acd8ef1d8cc9da9e6feb63d231f17174d859696a 100644
--- a/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRate.xml
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Repository/TaxRate.xml
@@ -16,9 +16,9 @@
         </dataset>
 
         <dataset name="US-CA-Rate_1">
-            <field name="tax_calculation_rate_id" xsi:type="string">1</field>
+            <field name="tax_calculation_rate_id" xsi:type="string">%id%</field>
+            <field name="tax_region_id" xsi:type="string">%id%</field>
             <field name="tax_country_id" xsi:type="string">US</field>
-            <field name="tax_region_id" xsi:type="string">12</field>
             <field name="tax_postcode" xsi:type="string">*</field>
             <field name="code" xsi:type="string">US-CA-*-Rate 1</field>
             <field name="rate" xsi:type="string">8.2500</field>
@@ -34,13 +34,13 @@
             <field name="rate" xsi:type="string">8.25</field>
             <field name="tax_country_id" xsi:type="string">United States</field>
             <field name="tax_postcode" xsi:type="string">*</field>
-            <field name="tax_region_id" xsi:type="string">23</field>
+            <field name="tax_region_id" xsi:type="string">%id%</field>
         </dataset>
 
         <dataset name="US-NY-Rate_1">
-            <field name="tax_calculation_rate_id" xsi:type="string">2</field>
+            <field name="tax_calculation_rate_id" xsi:type="string">%id%</field>
+            <field name="tax_region_id" xsi:type="string">%id%</field>
             <field name="tax_country_id" xsi:type="string">US</field>
-            <field name="tax_region_id" xsi:type="string">43</field>
             <field name="tax_postcode" xsi:type="string">*</field>
             <field name="code" xsi:type="string">US-NY-*-Rate 1</field>
             <field name="rate" xsi:type="string">8.3750</field>
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml b/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml
index 7aa989352a65658294050dd02eb6247b6aee129e..25b812bf77665d09877835e676fc5d11fdd1434a 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml
+++ b/dev/tests/functional/tests/app/Magento/User/Test/Repository/User.xml
@@ -8,13 +8,13 @@
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd">
     <repository class="Magento\User\Test\Repository\User">
         <dataset name="default">
+            <field name="user_id" xsi:type="string">%id%</field>
             <field name="username" xsi:type="string">admin</field>
             <field name="firstname" xsi:type="string">FirstName%isolation%</field>
             <field name="lastname" xsi:type="string">LastName%isolation%</field>
             <field name="email" xsi:type="string">email%isolation%@example.com</field>
             <field name="password" xsi:type="string">123123q</field>
             <field name="password_confirmation" xsi:type="string">123123q</field>
-            <field name="user_id" xsi:type="string">1</field>
             <field name="current_password" xsi:type="string">%current_password%</field>
         </dataset>
 
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/Parameters.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/Parameters.php
index 10d578adb9c36723d08b91d6831fcba2d0ba277a..f015be4ddcbbe30b767478e83b76e78ab453613e 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/Parameters.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/Parameters.php
@@ -28,7 +28,7 @@ class Parameters extends Tab
      *
      * @var string
      */
-    protected $path = 'Magento\Widget\Test\Block\Adminhtml\Widget\Instance\Edit\Tab\ParametersType\\';
+    protected $path = 'Magento\*\Test\Block\Adminhtml\Widget\Instance\Edit\Tab\ParametersType\\';
 
     /**
      * Fill Widget options form.
@@ -40,14 +40,29 @@ class Parameters extends Tab
     public function setFieldsData(array $fields, SimpleElement $element = null)
     {
         $data = $fields['parameters']['value'];
-        $path = $this->path . str_replace(' ', '', $fields['code']);
         /** @var ParametersForm $parametersForm */
         $parametersForm = $this->blockFactory->create(
-            $path,
+            $this->getElementClass($fields),
             ['element' => $this->_rootElement->find($this->formSelector)]
         );
         $parametersForm->fillForm($data, $element);
 
         return $this;
     }
+
+    /**
+     * Get element class.
+     *
+     * @param array $fields
+     * @return string
+     */
+    private function getElementClass(array $fields)
+    {
+        $path = $this->path . str_replace(' ', '', $fields['code']) . '.php';
+        $path = str_replace('\\', DIRECTORY_SEPARATOR, MTF_TESTS_PATH . $path);
+        $paths = glob($path);
+        $path = str_replace([MTF_TESTS_PATH, '.php'], '', $paths[0]);
+
+        return str_replace('/', '\\', $path);
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogNewProductsList.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogNewProductsList.php
new file mode 100644
index 0000000000000000000000000000000000000000..f86ce2c4cddd94c79275deb1282b033e3f2f418d
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogNewProductsList.php
@@ -0,0 +1,22 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Widget\Test\Block\Adminhtml\Widget\Instance\Edit\Tab\ParametersType;
+
+use Magento\Mtf\Fixture\InjectableFixture;
+
+/**
+ * Filling Widget Options that have catalog new products list type.
+ */
+class CatalogNewProductsList extends ParametersForm
+{
+    /**
+     * Catalog New Products List grid block.
+     *
+     * @var string
+     */
+    protected $gridBlock = './ancestor::body//*[contains(@id, "options_fieldset")]//div[contains(@class, "main-col")]';
+}
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogNewProductsList.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogNewProductsList.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9adce39f8464b2ee742b58d69edbd05c2fee7b06
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/Adminhtml/Widget/Instance/Edit/Tab/ParametersType/CatalogNewProductsList.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" ?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<mapping strict="1">
+    <fields>
+        <display_type>
+            <selector>.control [name="parameters[display_type]"]</selector>
+            <input>select</input>
+        </display_type>
+        <show_pager>
+            <selector>.control [name="parameters[show_pager]"]</selector>
+            <input>select</input>
+        </show_pager>
+        <products_count>
+            <selector>.control [name="parameters[products_count]"]</selector>
+        </products_count>
+    </fields>
+</mapping>
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/WidgetView.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/WidgetView.php
index 4e0e3634ae3887e25ef035065497708d0b9ac9a5..e1a8bfcc990e5cc75ed07ee21736e88443872c09 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Block/WidgetView.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Block/WidgetView.php
@@ -16,18 +16,18 @@ use Magento\Mtf\Client\Locator;
 class WidgetView extends Block
 {
     /**
-     * Widgets selectors.
+     * Widgets link selector.
      *
-     * @var array
+     * @var string
      */
-    protected $widgetSelectors = [
-        'cmsPageLink' => '/descendant-or-self::div//a[contains(.,"%s")]',
-        'catalogCategoryLink' => '//a[contains(.,"%s")]',
-        'catalogProductLink' => '//a[contains(.,"%s")]',
-        'recentlyComparedProducts' => '/descendant-or-self::div[contains(.,"%s")]',
-        'recentlyViewedProducts' => '/descendant-or-self::div[contains(.,"%s")]',
-        'cmsStaticBlock' => '/descendant-or-self::div[contains(.,"%s")]',
-    ];
+    protected $widgetLinkSelector = '//a[contains(.,"%s")]';
+
+    /**
+     * Widgets selector.
+     *
+     * @var string
+     */
+    protected $widgetSelector = '//div[contains(.,"%s")]';
 
     /**
      * Check is visible widget selector.
@@ -47,9 +47,9 @@ class WidgetView extends Block
                 ['widget' => $widget, 'widgetText' => $widgetText]
             );
         } else {
-            if (isset($this->widgetSelectors[$widgetType])) {
+            if (isset($this->widgetSelector)) {
                 return $this->_rootElement->find(
-                    sprintf($this->widgetSelectors[$widgetType], $widgetText),
+                    sprintf($this->widgetSelector, $widgetText),
                     Locator::SELECTOR_XPATH
                 )->isVisible();
             } else {
@@ -72,9 +72,9 @@ class WidgetView extends Block
         if ($this->hasRender($widgetType)) {
             $this->callRender($widgetType, 'clickToWidget', ['widget' => $widget, 'widgetText' => $widgetText]);
         } else {
-            if (isset($this->widgetSelectors[$widgetType])) {
+            if (isset($this->widgetLinkSelector)) {
                 $this->_rootElement->find(
-                    sprintf($this->widgetSelectors[$widgetType], $widgetText),
+                    sprintf($this->widgetLinkSelector, $widgetText),
                     Locator::SELECTOR_XPATH
                 )->click();
             } else {
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php
index 0de089a7aee5d085b6c1358e42322b33c3217801..f45b6184eec24506e6affa9b6fd24ea6d5a4fdf4 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetAbsentOnFrontendHome.php
@@ -6,34 +6,35 @@
 
 namespace Magento\Widget\Test\Constraint;
 
-use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
 use Magento\Cms\Test\Page\CmsIndex;
 use Magento\Widget\Test\Fixture\Widget;
 use Magento\Mtf\Constraint\AbstractConstraint;
+use Magento\Mtf\Util\Command\Cli\Cache;
 
 /**
- * Check that created widget does NOT displayed on frontend on Home page
+ * Check that created widget does NOT displayed on frontend on Home page.
  */
 class AssertWidgetAbsentOnFrontendHome extends AbstractConstraint
 {
     /**
-     * Assert that created widget is absent on frontend on Home page
+     * Assert that created widget is absent on frontend on Home page.
      *
      * @param CmsIndex $cmsIndex
      * @param Widget $widget
-     * @param AdminCache $adminCache
+     * @param Cache $cache
+     * @param array $caches [optional]
      * @return void
      */
     public function processAssert(
         CmsIndex $cmsIndex,
         Widget $widget,
-        AdminCache $adminCache
+        Cache $cache,
+        array $caches = []
     ) {
         // Flush cache
-        $adminCache->open();
-        $adminCache->getActionsBlock()->flushMagentoCache();
-        $adminCache->getMessagesBlock()->waitSuccessMessage();
-
+        if (!in_array('Invalidated', $caches)) {
+            $cache->flush();
+        }
         $cmsIndex->open();
         $widgetText = $widget->getParameters()['anchor_text'];
         \PHPUnit_Framework_Assert::assertFalse(
@@ -43,7 +44,7 @@ class AssertWidgetAbsentOnFrontendHome extends AbstractConstraint
     }
 
     /**
-     * Returns a string representation of the object
+     * Returns a string representation of the object.
      *
      * @return string
      * @return string
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php
index 6fc8d33130cd77136f633f3c40b74bfa836e9b58..e66899b6580757e99805fef84e1f02e8420f05a5 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogCategoryLink.php
@@ -6,7 +6,7 @@
 
 namespace Magento\Widget\Test\Constraint;
 
-use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
+use Magento\Mtf\Util\Command\Cli\Cache;
 use Magento\Catalog\Test\Page\Category\CatalogCategoryView;
 use Magento\Cms\Test\Page\CmsIndex;
 use Magento\Widget\Test\Fixture\Widget;
@@ -29,19 +29,17 @@ class AssertWidgetCatalogCategoryLink extends AbstractConstraint
      * @param CmsIndex $cmsIndex
      * @param CatalogCategoryView $categoryView
      * @param Widget $widget
-     * @param AdminCache $adminCache
+     * @param Cache $cache
      * @return void
      */
     public function processAssert(
         CmsIndex $cmsIndex,
         CatalogCategoryView $categoryView,
         Widget $widget,
-        AdminCache $adminCache
+        Cache $cache
     ) {
         // Flush cache
-        $adminCache->open();
-        $adminCache->getActionsBlock()->flushMagentoCache();
-        $adminCache->getMessagesBlock()->waitSuccessMessage();
+        $cache->flush();
 
         $cmsIndex->open();
         $widgetText = $widget->getParameters()['anchor_text'];
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogNewProductsList.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogNewProductsList.php
new file mode 100644
index 0000000000000000000000000000000000000000..dbb9a5012c0945525bb68cec6f369edb673aa809
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCatalogNewProductsList.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Widget\Test\Constraint;
+
+use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
+use Magento\Catalog\Test\Page\Category\CatalogCategoryView;
+use Magento\Cms\Test\Page\CmsIndex;
+use Magento\Widget\Test\Fixture\Widget;
+use Magento\Mtf\Constraint\AbstractConstraint;
+use Magento\Catalog\Test\Fixture\CatalogProductSimple;
+
+/**
+ * Check that created Catalog New Products List widget displayed on frontend on Category Page.
+ */
+class AssertWidgetCatalogNewProductsList extends AbstractConstraint
+{
+    /**
+     * Category Page on Frontend.
+     *
+     * @var CatalogCategoryView
+     */
+    protected $catalogCategoryView;
+    
+    /**
+     * Assert that created Catalog New Products List widget displayed on frontend on Category Page.
+     *
+     * @param CmsIndex $cmsIndex
+     * @param CatalogCategoryView $catalogCategoryView
+     * @param CatalogProductSimple $productSimple1
+     * @param CatalogProductSimple $productSimple2
+     * @param Widget $widget
+     * @param AdminCache $adminCache
+     * @return void
+     */
+    public function processAssert(
+        CmsIndex $cmsIndex,
+        CatalogCategoryView $catalogCategoryView,
+        CatalogProductSimple $productSimple1,
+        CatalogProductSimple $productSimple2,
+        Widget $widget,
+        AdminCache $adminCache
+    ) {
+        $this->catalogCategoryView = $catalogCategoryView;
+        
+        // Flush cache
+        $adminCache->open();
+        $adminCache->getActionsBlock()->flushMagentoCache();
+        $adminCache->getMessagesBlock()->waitSuccessMessage();
+
+        $productSimple1->persist();
+        $productSimple2->persist();
+        $products[] = $productSimple2->getName();
+        $products[] = $productSimple1->getName();
+
+        $cmsIndex->open();
+        $categoryName = $widget->getWidgetInstance()[0]['entities']->getName();
+        $cmsIndex->getTopmenu()->selectCategoryByName($categoryName);
+        \PHPUnit_Framework_Assert::assertTrue(
+            $catalogCategoryView->getWidgetView()->isWidgetVisible($widget, 'New Products'),
+            'Widget is absent on Category page.'
+        );
+        \PHPUnit_Framework_Assert::assertEquals(
+            $products,
+            $this->catalogCategoryView->getViewBlock()->getProductsFromCatalogNewProductsListBlock(),
+            'There are wrong products or products are absent on Catalog New Products List block on Category page.'
+        );
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return "Catalog New Products List widget is present on Category page.";
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php
index 448b9be9fc68f74888ff4fe48436ebb88c82ec9b..e0369dde574589bc4234191ef45636f99ce38dcf 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetCmsPageLink.php
@@ -6,7 +6,7 @@
 
 namespace Magento\Widget\Test\Constraint;
 
-use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
+use Magento\Mtf\Util\Command\Cli\Cache;
 use Magento\Cms\Test\Page\CmsIndex;
 use Magento\Widget\Test\Fixture\Widget;
 use Magento\Mtf\Constraint\AbstractConstraint;
@@ -23,18 +23,16 @@ class AssertWidgetCmsPageLink extends AbstractConstraint
      *
      * @param CmsIndex $cmsIndex
      * @param Widget $widget
-     * @param AdminCache $adminCache
+     * @param Cache $cache
      * @return void
      */
     public function processAssert(
         CmsIndex $cmsIndex,
         Widget $widget,
-        AdminCache $adminCache
+        Cache $cache
     ) {
         // Flush cache
-        $adminCache->open();
-        $adminCache->getActionsBlock()->flushMagentoCache();
-        $adminCache->getMessagesBlock()->waitSuccessMessage();
+        $cache->flush();
 
         $cmsIndex->open();
         $widgetText = $widget->getParameters()['anchor_text'];
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php
index d3af59e62a9fd0ca43eb8c9b8004a549a07dde06..4825fd4958ff845b5113635e2f3ee852852286e3 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnFrontendInCatalog.php
@@ -6,36 +6,34 @@
 
 namespace Magento\Widget\Test\Constraint;
 
-use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
 use Magento\Catalog\Test\Page\Category\CatalogCategoryView;
 use Magento\Cms\Test\Page\CmsIndex;
 use Magento\Widget\Test\Fixture\Widget;
 use Magento\Mtf\Constraint\AbstractConstraint;
+use Magento\Mtf\Util\Command\Cli\Cache;
 
 /**
- * Check that created widget displayed on frontent in Catalog.
+ * Check that created widget displayed on frontend in Catalog.
  */
 class AssertWidgetOnFrontendInCatalog extends AbstractConstraint
 {
     /**
-     * Assert that created widget displayed on frontent in Catalog.
+     * Assert that created widget displayed on frontend in Catalog.
      *
      * @param CmsIndex $cmsIndex
      * @param CatalogCategoryView $catalogCategoryView
      * @param Widget $widget
-     * @param AdminCache $adminCache
+     * @param Cache $cache
      * @return void
      */
     public function processAssert(
         CmsIndex $cmsIndex,
         CatalogCategoryView $catalogCategoryView,
         Widget $widget,
-        AdminCache $adminCache
+        Cache $cache
     ) {
         // Flush cache
-        $adminCache->open();
-        $adminCache->getActionsBlock()->flushMagentoCache();
-        $adminCache->getMessagesBlock()->waitSuccessMessage();
+        $cache->flush();
 
         $cmsIndex->open();
         if (isset($widget->getWidgetInstance()[0]['entities'])) {
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnProductPage.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnProductPage.php
index ebdc3ececd062e3af4f326362c0d00f0701415d3..4912d2457b78dc7de25c657d38bfb80a5da847b9 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnProductPage.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetOnProductPage.php
@@ -6,7 +6,7 @@
 
 namespace Magento\Widget\Test\Constraint;
 
-use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
+use Magento\Mtf\Util\Command\Cli\Cache;
 use Magento\Catalog\Test\Page\Product\CatalogProductView;
 use Magento\Widget\Test\Fixture\Widget;
 use Magento\Mtf\Client\BrowserInterface;
@@ -23,19 +23,17 @@ class AssertWidgetOnProductPage extends AbstractConstraint
      * @param CatalogProductView $productView
      * @param BrowserInterface $browser
      * @param Widget $widget
-     * @param AdminCache $adminCache
+     * @param Cache $cache
      * @return void
      */
     public function processAssert(
         CatalogProductView $productView,
         BrowserInterface $browser,
         Widget $widget,
-        AdminCache $adminCache
+        Cache $cache
     ) {
         // Flush cache
-        $adminCache->open();
-        $adminCache->getActionsBlock()->flushMagentoCache();
-        $adminCache->getMessagesBlock()->waitSuccessMessage();
+        $cache->flush();
 
         $urlKey = $widget->getWidgetInstance()[0]['entities']['url_key'];
         $browser->open($_ENV['app_frontend_url'] . $urlKey . '.html');
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetProductLink.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetProductLink.php
index 94cdded4b3234d8256b22d25f97753c43f04a736..28766632edd6b705444be93da2b2e4fd3db55117 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetProductLink.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetProductLink.php
@@ -6,7 +6,7 @@
 
 namespace Magento\Widget\Test\Constraint;
 
-use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
+use Magento\Mtf\Util\Command\Cli\Cache;
 use Magento\Catalog\Test\Page\Product\CatalogProductView;
 use Magento\Cms\Test\Page\CmsIndex;
 use Magento\Widget\Test\Fixture\Widget;
@@ -23,19 +23,17 @@ class AssertWidgetProductLink extends AbstractConstraint
      * @param CmsIndex $cmsIndex
      * @param CatalogProductView $productView
      * @param Widget $widget
-     * @param AdminCache $adminCache
+     * @param Cache $cache
      * @return void
      */
     public function processAssert(
         CmsIndex $cmsIndex,
         CatalogProductView $productView,
         Widget $widget,
-        AdminCache $adminCache
+        Cache $cache
     ) {
         // Flush cache
-        $adminCache->open();
-        $adminCache->getActionsBlock()->flushMagentoCache();
-        $adminCache->getMessagesBlock()->waitSuccessMessage();
+        $cache->flush();
 
         $cmsIndex->open();
         $cmsIndex->getTopmenu()->selectCategoryByName($widget->getWidgetInstance()[0]['entities']->getName());
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php
index 3a9eab2ff8c4395dd77aead3528509fff990f156..745c3afe0aa91cc794d99e7312b620128d3306b4 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyComparedProducts.php
@@ -6,7 +6,7 @@
 
 namespace Magento\Widget\Test\Constraint;
 
-use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
+use Magento\Mtf\Util\Command\Cli\Cache;
 use Magento\Catalog\Test\Fixture\CatalogProductSimple;
 use Magento\Catalog\Test\Page\Product\CatalogProductCompare;
 use Magento\Catalog\Test\Page\Product\CatalogProductView;
@@ -58,7 +58,7 @@ class AssertWidgetRecentlyComparedProducts extends AbstractConstraint
      * @param Widget $widget
      * @param CatalogProductSimple $productSimple1
      * @param CatalogProductSimple $productSimple2
-     * @param AdminCache $adminCache
+     * @param Cache $cache
      * @var string
      * @return void
      */
@@ -70,12 +70,10 @@ class AssertWidgetRecentlyComparedProducts extends AbstractConstraint
         Widget $widget,
         CatalogProductSimple $productSimple1,
         CatalogProductSimple $productSimple2,
-        AdminCache $adminCache
+        Cache $cache
     ) {
         // Flush cache
-        $adminCache->open();
-        $adminCache->getActionsBlock()->flushMagentoCache();
-        $adminCache->getMessagesBlock()->waitSuccessMessage();
+        $cache->flush();
 
         $this->catalogProductCompare = $catalogProductCompare;
         $this->catalogProductView = $catalogProductView;
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php
index 30a8c755b5d0675662e0ec5a3cf7c263ff291dff..f2d4a3146fc3aadbfb47eab26d62104e166c48f6 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Constraint/AssertWidgetRecentlyViewedProducts.php
@@ -6,7 +6,7 @@
 
 namespace Magento\Widget\Test\Constraint;
 
-use Magento\PageCache\Test\Page\Adminhtml\AdminCache;
+use Magento\Mtf\Util\Command\Cli\Cache;
 use Magento\Catalog\Test\Fixture\Category;
 use Magento\Catalog\Test\Fixture\CatalogProductSimple;
 use Magento\Catalog\Test\Page\Category\CatalogCategoryView;
@@ -45,7 +45,7 @@ class AssertWidgetRecentlyViewedProducts extends AbstractConstraint
      * Assert that widget with type Recently Viewed Products is present on category page
      *
      * @param CmsIndex $cmsIndex
-     * @param AdminCache $adminCache
+     * @param Cache $cache
      * @param CatalogCategoryView $catalogCategoryView
      * @param BrowserInterface $browser
      * @param CatalogProductSimple $productSimple
@@ -55,7 +55,7 @@ class AssertWidgetRecentlyViewedProducts extends AbstractConstraint
      */
     public function processAssert(
         CmsIndex $cmsIndex,
-        AdminCache $adminCache,
+        Cache $cache,
         CatalogCategoryView $catalogCategoryView,
         BrowserInterface $browser,
         CatalogProductSimple $productSimple,
@@ -67,9 +67,7 @@ class AssertWidgetRecentlyViewedProducts extends AbstractConstraint
         $this->catalogCategoryView = $catalogCategoryView;
 
         // Flush cache
-        $adminCache->open();
-        $adminCache->getActionsBlock()->flushMagentoCache();
-        $adminCache->getMessagesBlock()->waitSuccessMessage();
+        $cache->flush();
 
         // Log in customer
         $customer->persist();
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/Parameters.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/Parameters.xml
index 46e71d910006a3481ab023b14746d55cd900a0f0..6b1651de83234d8baa1ae7774f3e6138ba872960 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/Parameters.xml
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/Parameters.xml
@@ -31,10 +31,10 @@
             </field>
         </dataset>
 
-        <dataset name="catalogNewProductList">
+        <dataset name="catalogNewProductsList">
             <field name="display_type" xsi:type="string">All products</field>
-            <field name="show_pager" xsi:type="string">Yes</field>
-            <field name="products_count" xsi:type="string">4</field>
+            <field name="show_pager" xsi:type="string">No</field>
+            <field name="products_count" xsi:type="string">2</field>
         </dataset>
 
         <dataset name="catalogProductLink">
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/WidgetInstance.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/WidgetInstance.xml
index 7c417cd0a902b802781217e984dd0ed445f4cbbb..b463ef34f6855be0eca87f1cb28b207789051eb2 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/WidgetInstance.xml
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/Repository/Widget/WidgetInstance.xml
@@ -41,6 +41,16 @@
             </field>
         </dataset>
 
+        <dataset name="for_new_products_list">
+            <field name="0" xsi:type="array">
+                <item name="page_group" xsi:type="string">Categories/Non-Anchor Categories</item>
+                <item name="for" xsi:type="string">Yes</item>
+                <item name="entities" xsi:type="string">category::default_subcategory</item>
+                <item name="block" xsi:type="string">Main Content Area</item>
+                <item name="template" xsi:type="string">New Products List Template</item>
+            </field>
+        </dataset>
+
         <dataset name="for_compared_products">
             <field name="0" xsi:type="array">
                 <item name="page_group" xsi:type="string">Generic Pages/All Pages</item>
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/AbstractCreateWidgetEntityTest.php b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/AbstractCreateWidgetEntityTest.php
index 123e5381e69191dc5607d489eb510c8b2d498cd5..235361aee8b7eea30618663ecf1067a6dbc303a0 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/AbstractCreateWidgetEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/AbstractCreateWidgetEntityTest.php
@@ -6,11 +6,12 @@
 
 namespace Magento\Widget\Test\TestCase;
 
-use Magento\Widget\Test\Fixture\Widget;
 use Magento\Widget\Test\Page\Adminhtml\WidgetInstanceEdit;
 use Magento\Widget\Test\Page\Adminhtml\WidgetInstanceIndex;
 use Magento\Widget\Test\Page\Adminhtml\WidgetInstanceNew;
 use Magento\Mtf\TestCase\Injectable;
+use Magento\Mtf\Util\Command\Cli\Cache;
+use Magento\Cms\Test\Page\CmsIndex;
 
 /**
  * Test Creation for New Instance of WidgetEntity.
@@ -38,22 +39,42 @@ abstract class AbstractCreateWidgetEntityTest extends Injectable
      */
     protected $widgetInstanceEdit;
 
+    /**
+     * CmsIndex page.
+     *
+     * @var WidgetInstanceIndex
+     */
+    protected $cmsIndex;
+
+    /**
+     * Handle cache for tests executions.
+     *
+     * @var Cache
+     */
+    protected $cache;
+
     /**
      * Injection data.
      *
      * @param WidgetInstanceIndex $widgetInstanceIndex
      * @param WidgetInstanceNew $widgetInstanceNew
      * @param WidgetInstanceEdit $widgetInstanceEdit
+     * @param CmsIndex $cmsIndex
+     * @param Cache $cache
      * @return void
      */
     public function __inject(
         WidgetInstanceIndex $widgetInstanceIndex,
         WidgetInstanceNew $widgetInstanceNew,
-        WidgetInstanceEdit $widgetInstanceEdit
+        WidgetInstanceEdit $widgetInstanceEdit,
+        CmsIndex $cmsIndex,
+        Cache $cache
     ) {
         $this->widgetInstanceIndex = $widgetInstanceIndex;
         $this->widgetInstanceNew = $widgetInstanceNew;
         $this->widgetInstanceEdit = $widgetInstanceEdit;
+        $this->cmsIndex = $cmsIndex;
+        $this->cache = $cache;
     }
 
     /**
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.php b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.php
index 46383765d2520f5fe09d044b44dc592d870d76eb..0583cacb1a40bf655c9c146a3c13a6d1bb71efa9 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.php
@@ -29,18 +29,61 @@ class CreateWidgetEntityTest extends AbstractCreateWidgetEntityTest
     const TEST_TYPE = 'extended_acceptance_test';
     /* end tags */
 
+    /**
+     * Cache data.
+     *
+     * @var array
+     */
+    private $caches = [];
+
     /**
      * Create for New Widget.
      *
      * @param Widget $widget
+     * @param array $caches [optional]
      * @return void
      */
-    public function test(Widget $widget)
+    public function test(Widget $widget, array $caches = [])
     {
+        // Preconditions
+        $this->caches = $caches;
+        $this->adjustCacheSettings();
+        
         // Steps
         $this->widgetInstanceIndex->open();
         $this->widgetInstanceIndex->getPageActionsBlock()->addNew();
         $this->widgetInstanceNew->getWidgetForm()->fill($widget);
         $this->widgetInstanceEdit->getPageActionsBlock()->save();
     }
+
+    /**
+     * Adjust cache settings.
+     *
+     * @return void
+     */
+    private function adjustCacheSettings()
+    {
+        $this->cache->flush();
+        foreach ($this->caches as $cacheType => $cacheStatus) {
+            if ($cacheStatus === 'Disabled') {
+                $this->cache->disableCache($cacheType);
+            }
+        }
+        if (in_array('Invalidated', $this->caches)) {
+            $this->cmsIndex->open();
+        }
+    }
+    
+    /**
+     * Enable and flush all cache.
+     *
+     * return void
+     */
+    public function tearDown()
+    {
+        parent::tearDown();
+        if (!empty($this->caches)) {
+            $this->cache->enableCache();
+        }
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml
index 9f7640830b074964564085d81d07d552200e57e5..42d81d2f16c812933292f6355c2a0e5eb0842f88 100644
--- a/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Widget/Test/TestCase/CreateWidgetEntityTest.xml
@@ -76,5 +76,43 @@
             <constraint name="Magento\Widget\Test\Constraint\AssertWidgetOnFrontendInCatalog" />
             <constraint name="Magento\Widget\Test\Constraint\AssertWidgetProductLink" />
         </variation>
+        <variation name="CreateWidgetEntityTestVariation7" summary="Assert widget with disabled block_html cache type">
+            <data name="caches/block_html" xsi:type="string">Disabled</data>
+            <data name="widget/data/code" xsi:type="string">CMS Static Block</data>
+            <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data>
+            <data name="widget/data/title" xsi:type="string">Title_%isolation%</data>
+            <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data>
+            <data name="widget/data/widget_instance/dataset" xsi:type="string">on_category</data>
+            <data name="widget/data/parameters/dataset" xsi:type="string">cmsStaticBlock</data>
+            <constraint name="Magento\Widget\Test\Constraint\AssertWidgetSuccessSaveMessage" />
+            <constraint name="Magento\PageCache\Test\Constraint\AssertCacheInvalidatePopUp" />
+            <constraint name="Magento\PageCache\Test\Constraint\AssertCacheInvalidateNotice" />
+            <constraint name="Magento\PageCache\Test\Constraint\AssertCacheStatus" />
+            <constraint name="Magento\Widget\Test\Constraint\AssertWidgetOnFrontendInCatalog" />
+        </variation>
+        <variation name="CreateWidgetEntityTestVariation8" summary="Assert widget with invalidated block_html cache type">
+            <data name="caches/block_html" xsi:type="string">Invalidated</data>
+            <data name="widget/data/code" xsi:type="string">Catalog Category Link</data>
+            <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data>
+            <data name="widget/data/title" xsi:type="string">Title_%isolation%</data>
+            <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data>
+            <data name="widget/data/widget_instance/dataset" xsi:type="string">for_category_link</data>
+            <data name="widget/data/parameters/dataset" xsi:type="string">catalogCategoryLink</data>
+            <constraint name="Magento\Widget\Test\Constraint\AssertWidgetSuccessSaveMessage" />
+            <constraint name="Magento\PageCache\Test\Constraint\AssertCacheInvalidatePopUp" />
+            <constraint name="Magento\PageCache\Test\Constraint\AssertCacheInvalidateNotice" />
+            <constraint name="Magento\PageCache\Test\Constraint\AssertCacheStatus" />
+            <constraint name="Magento\Widget\Test\Constraint\AssertWidgetAbsentOnFrontendHome" />
+        </variation>
+        <variation name="CreateWidgetEntityTestVariation9" summary="Create Catalog New Products List type widget">
+            <data name="widget/data/code" xsi:type="string">Catalog New Products List</data>
+            <data name="widget/data/theme_id" xsi:type="string">Magento Luma</data>
+            <data name="widget/data/title" xsi:type="string">Title_%isolation%</data>
+            <data name="widget/data/store_ids/dataset" xsi:type="string">all_store_views</data>
+            <data name="widget/data/widget_instance/dataset" xsi:type="string">for_new_products_list</data>
+            <data name="widget/data/parameters/dataset" xsi:type="string">catalogNewProductsList</data>
+            <constraint name="Magento\Widget\Test\Constraint\AssertWidgetSuccessSaveMessage" />
+            <constraint name="Magento\Widget\Test\Constraint\AssertWidgetCatalogNewProductsList" />
+        </variation>
     </testCase>
 </config>
diff --git a/dev/tests/functional/utils/command.php b/dev/tests/functional/utils/command.php
index da1775f6f340ab3a1cac411f41daeb533721f473..4061b07c783e4b0e8cbf4a7e4daa08d445834f68 100644
--- a/dev/tests/functional/utils/command.php
+++ b/dev/tests/functional/utils/command.php
@@ -6,7 +6,7 @@
 
 if (isset($_GET['command'])) {
     $command = urldecode($_GET['command']);
-    exec('../../../../bin/magento ' . $command);
+    exec('php -f ../../../../bin/magento ' . $command);
 } else {
     throw new \Exception("Command GET parameter is not set.");
 }
diff --git a/dev/tests/integration/framework/Magento/TestFramework/Event/Transaction.php b/dev/tests/integration/framework/Magento/TestFramework/Event/Transaction.php
index 531a4fc174083a8c7dc378a5f018af62a7cdd679..faffeadcad27ee2d573eae746d8bcb4dd592cdf0 100644
--- a/dev/tests/integration/framework/Magento/TestFramework/Event/Transaction.php
+++ b/dev/tests/integration/framework/Magento/TestFramework/Event/Transaction.php
@@ -113,6 +113,7 @@ class Transaction
             $this->_getConnection()->rollbackTransparentTransaction();
             $this->_isTransactionActive = false;
             $this->_eventManager->fireEvent('rollbackTransaction');
+            $this->_getConnection()->closeConnection();
         }
     }
 
diff --git a/dev/tests/integration/framework/Magento/TestFramework/Listener/ExtededTestdox.php b/dev/tests/integration/framework/Magento/TestFramework/Listener/ExtededTestdox.php
index 656305c6aeb021f12a8e99a82d90f7e930e973c9..5016891ca72b58c54eab526f9fc473a74f96771d 100644
--- a/dev/tests/integration/framework/Magento/TestFramework/Listener/ExtededTestdox.php
+++ b/dev/tests/integration/framework/Magento/TestFramework/Listener/ExtededTestdox.php
@@ -296,7 +296,7 @@ class ExtededTestdox extends \PHPUnit_Util_Printer implements \PHPUnit_Framework
     protected function doEndClass()
     {
         foreach ($this->tests as $name => $data) {
-            $check = $data['failure'] == 0 ? ' [x] ' : ' [ ] ';
+            $check = $data['failure'] == 0 ? ' - [x] ' : ' - [ ] ';
             $this->write(
                 "\n" . $check . $name . ($data['failure'] + $data['success'] ==
                 0 ? ' (skipped)' : '') . ($data['time'] > 1 ? ' - ' . number_format(
diff --git a/dev/tests/integration/framework/Magento/TestFramework/Workaround/Cleanup/StaticProperties.php b/dev/tests/integration/framework/Magento/TestFramework/Workaround/Cleanup/StaticProperties.php
index b866253c30609e7532bfc8a5409fba270d810f9c..a90ab7b633dc2c791b39594258740a457e4fbc31 100644
--- a/dev/tests/integration/framework/Magento/TestFramework/Workaround/Cleanup/StaticProperties.php
+++ b/dev/tests/integration/framework/Magento/TestFramework/Workaround/Cleanup/StaticProperties.php
@@ -33,7 +33,6 @@ class StaticProperties
      * @var array
      */
     protected static $_classesToSkip = [
-        'Mage',
         \Magento\Framework\App\ObjectManager::class,
         \Magento\TestFramework\Helper\Bootstrap::class,
         \Magento\TestFramework\Event\Magento::class,
@@ -107,6 +106,23 @@ class StaticProperties
         return false; // File is not in an "include" directory
     }
 
+    /**
+     * @var \ReflectionClass[]
+     */
+    static protected $classes = [];
+
+    /**
+     * @param string $class
+     * @return \ReflectionClass
+     */
+    private static function getReflectionClass($class)
+    {
+        if (!isset(self::$classes[$class])) {
+            self::$classes[$class] = new \ReflectionClass($class);
+        }
+        return self::$classes[$class];
+    }
+
     /**
      * Restore static variables (after running controller test case)
      * @TODO: refactor all code where objects are stored to static variables to use object manager instead
@@ -114,7 +130,7 @@ class StaticProperties
     public static function restoreStaticVariables()
     {
         foreach (array_keys(self::$backupStaticVariables) as $class) {
-            $reflectionClass = new \ReflectionClass($class);
+            $reflectionClass = self::getReflectionClass($class);
             $staticProperties = $reflectionClass->getProperties(\ReflectionProperty::IS_STATIC);
             foreach ($staticProperties as $staticProperty) {
                 $staticProperty->setAccessible(true);
@@ -129,44 +145,48 @@ class StaticProperties
      */
     public static function backupStaticVariables()
     {
-        $classFiles = Files::init()->getPhpFiles(
-            Files::INCLUDE_APP_CODE
-            | Files::INCLUDE_LIBS
-            | Files::INCLUDE_TESTS
+        if (count(self::$backupStaticVariables) > 0) {
+            return;
+        }
+        $classFiles = array_filter(
+            Files::init()->getPhpFiles(
+                Files::INCLUDE_APP_CODE
+                | Files::INCLUDE_LIBS
+                | Files::INCLUDE_TESTS
+            ),
+            function ($classFile) {
+                return StaticProperties::_isClassInCleanableFolders($classFile)
+                && strpos(file_get_contents($classFile), ' static ')  > 0;
+            }
         );
         $namespacePattern = '/namespace [a-zA-Z0-9\\\\]+;/';
         $classPattern = '/\nclass [a-zA-Z0-9_]+/';
         foreach ($classFiles as $classFile) {
-            if (self::_isClassInCleanableFolders($classFile)) {
-                $file = @fopen($classFile, 'r');
-                $code = fread($file, 4096);
-                preg_match($namespacePattern, $code, $namespace);
-                preg_match($classPattern, $code, $class);
-                if (!isset($namespace[0]) || !isset($class[0])) {
-                    fclose($file);
-                    continue;
-                }
-                // trim namespace and class name
-                $namespace = substr($namespace[0], 10, strlen($namespace[0]) - 11);
-                $class = substr($class[0], 7, strlen($class[0]) - 7);
-                $className = $namespace . '\\' . $class;
-
-                try {
-                    $reflectionClass = new \ReflectionClass($className);
-                } catch (\Exception $e) {
-                    fclose($file);
-                    continue;
-                }
-                if (self::_isClassCleanable($reflectionClass)) {
-                    $staticProperties = $reflectionClass->getProperties(\ReflectionProperty::IS_STATIC);
-                    foreach ($staticProperties as $staticProperty) {
-                        $staticProperty->setAccessible(true);
-                        $value = $staticProperty->getValue();
-                        self::$backupStaticVariables[$className][$staticProperty->getName()] = $value;
-                    }
+            $code = file_get_contents($classFile);
+            preg_match($namespacePattern, $code, $namespace);
+            preg_match($classPattern, $code, $class);
+            if (!isset($namespace[0]) || !isset($class[0])) {
+                continue;
+            }
+            // trim namespace and class name
+            $namespace = substr($namespace[0], 10, strlen($namespace[0]) - 11);
+            $class = substr($class[0], 7, strlen($class[0]) - 7);
+            $className = $namespace . '\\' . $class;
+
+            try {
+                $reflectionClass = self::getReflectionClass($className);
+            } catch (\Exception $e) {
+                continue;
+            }
+            if (self::_isClassCleanable($reflectionClass)) {
+                $staticProperties = $reflectionClass->getProperties(\ReflectionProperty::IS_STATIC);
+                foreach ($staticProperties as $staticProperty) {
+                    $staticProperty->setAccessible(true);
+                    $value = $staticProperty->getValue();
+                    self::$backupStaticVariables[$className][$staticProperty->getName()] = $value;
                 }
-                fclose($file);
             }
+
         }
     }
 
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php
index 1208785ea6d8b029be9790692667d6c75e118154..1b9a4d5eabcaa2a4c3bc425b1e9e8f23c9991723 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableImportExport/Model/ConfigurableTest.php
@@ -30,8 +30,10 @@ class ConfigurableTest extends AbstractProductExportImportTestCase
      */
     protected function assertEqualsSpecificAttributes($expectedProduct, $actualProduct)
     {
-        $expectedAssociatedProducts = $expectedProduct->getTypeInstance()->getUsedProducts($expectedProduct);
-        $actualAssociatedProducts = $actualProduct->getTypeInstance()->getUsedProducts($actualProduct);
+        /** @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable $prooductType */
+        $prooductType = $expectedProduct->getTypeInstance();
+        $expectedAssociatedProducts = $prooductType->getUsedProductCollection($expectedProduct);
+        $actualAssociatedProducts = iterator_to_array($prooductType->getUsedProductCollection($actualProduct));
 
         $expectedAssociatedProductSkus = [];
         $actualAssociatedProductSkus = [];
@@ -92,4 +94,20 @@ class ConfigurableTest extends AbstractProductExportImportTestCase
         }
         return $data;
     }
+
+    /**
+     * @magentoAppArea adminhtml
+     * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
+     *
+     * @param array $fixtures
+     * @param string[] $skus
+     * @param string[] $skippedAttributes
+     * @dataProvider importReplaceDataProvider
+     */
+    public function testImportReplace($fixtures, $skus, $skippedAttributes = [])
+    {
+        $this->markTestSkipped('MAGETWO-56530');
+        parent::testImportReplace($fixtures, $skus, $skippedAttributes);
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php
index d3ea0ce15eb68d45d415f186826f9122a5b085ed..5a5b1d5c4dbde7c2b02c2f77e59e1390cbd5d919 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php
@@ -107,6 +107,13 @@ $registry->register('isSecureArea', true);
 try {
     $productToDelete = $productRepository->getById(1);
     $productRepository->delete($productToDelete);
+
+    /** @var \Magento\Quote\Model\ResourceModel\Quote\Item $itemResource */
+    $itemResource = Bootstrap::getObjectManager()->get(\Magento\Quote\Model\ResourceModel\Quote\Item::class);
+    $itemResource->getConnection()->delete(
+        $itemResource->getMainTable(),
+        'product_id = ' . $productToDelete->getId()
+    );
 } catch (\Exception $e) {
     // Nothing to remove
 }
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Session/SaveHandlerTest.php b/dev/tests/integration/testsuite/Magento/Framework/Session/SaveHandlerTest.php
index b12c1d6b5eb032c98aba70c404347d25277125d7..7ba149d361f4fcd15c9d5989ff619d9f81b53cc2 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Session/SaveHandlerTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/Session/SaveHandlerTest.php
@@ -29,6 +29,7 @@ class SaveHandlerTest extends \PHPUnit_Framework_TestCase
      */
     public function testSetSaveHandler($deploymentConfigHandler, $iniHandler)
     {
+        $this->markTestSkipped('MAGETWO-56529');
         // Set expected session.save_handler config
         if ($deploymentConfigHandler) {
             if ($deploymentConfigHandler !== 'files') {
diff --git a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/Adminhtml/NewsletterQueueTest.php b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/Adminhtml/NewsletterQueueTest.php
index fc9888066f12e654e56626bcbc6547ce5db10590..1d1263fb8aa820039c8d42404bf0c94b60888ea8 100644
--- a/dev/tests/integration/testsuite/Magento/Newsletter/Controller/Adminhtml/NewsletterQueueTest.php
+++ b/dev/tests/integration/testsuite/Magento/Newsletter/Controller/Adminhtml/NewsletterQueueTest.php
@@ -38,7 +38,6 @@ class NewsletterQueueTest extends \Magento\TestFramework\TestCase\AbstractBacken
 
     /**
      * @magentoDataFixture Magento/Newsletter/_files/newsletter_sample.php
-     * @magentoAppIsolation disabled
      */
     public function testSaveActionQueueTemplateAndVerifySuccessMessage()
     {
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
index 6184dd7ee4355d727afaba9666effc83cd9f8f27..78342c886de968a02ceed79c215c5dc26ddd9928 100755
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
@@ -4225,4 +4225,5 @@ return [
     ['Magento\Catalog\Test\Unit\Webapi\Product\Option\Type\File\ValidatorTest'],
     ['Magento\Framework\Search\Document', 'Magento\Framework\Api\Search\Document'],
     ['Magento\Framework\Search\DocumentField'],
+    ['Magento\Quote\Setup\Recurring'],
 ];
diff --git a/lib/internal/Magento/Framework/Interception/Chain/Chain.php b/lib/internal/Magento/Framework/Interception/Chain/Chain.php
deleted file mode 100644
index 34a8308e021e86cfe85066462ca6ca22bd1cb79b..0000000000000000000000000000000000000000
--- a/lib/internal/Magento/Framework/Interception/Chain/Chain.php
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Framework\Interception\Chain;
-
-use Magento\Framework\Interception\InterceptorInterface;
-use Magento\Framework\Interception\DefinitionInterface;
-use Magento\Framework\Interception\PluginListInterface;
-
-class Chain implements \Magento\Framework\Interception\ChainInterface
-{
-    /**
-     * @var \Magento\Framework\Interception\PluginListInterface
-     */
-    protected $pluginList;
-
-    /**
-     * @param PluginListInterface $pluginList
-     */
-    public function __construct(PluginListInterface $pluginList)
-    {
-        $this->pluginList = $pluginList;
-    }
-
-    /**
-     * Invoke next plugin in chain
-     *
-     * @param string $type
-     * @param string $method
-     * @param string $previousPluginCode
-     * @param InterceptorInterface $subject
-     * @param array $arguments
-     * @return mixed|void
-     */
-    public function invokeNext(
-        $type,
-        $method,
-        InterceptorInterface $subject,
-        array $arguments,
-        $previousPluginCode = null
-    ) {
-        $pluginInfo = $this->pluginList->getNext($type, $method, $previousPluginCode);
-        $capMethod = ucfirst($method);
-        $result = null;
-        if (isset($pluginInfo[DefinitionInterface::LISTENER_BEFORE])) {
-            foreach ($pluginInfo[DefinitionInterface::LISTENER_BEFORE] as $code) {
-                $pluginInstance = $this->pluginList->getPlugin($type, $code);
-                $pluginMethod = 'before' . $capMethod;
-                $beforeResult = $pluginInstance->$pluginMethod($subject, ...array_values($arguments));
-                if ($beforeResult) {
-                    $arguments = $beforeResult;
-                }
-                unset($pluginInstance, $pluginMethod);
-            }
-        }
-        if (isset($pluginInfo[DefinitionInterface::LISTENER_AROUND])) {
-            $chain = $this;
-            $code = $pluginInfo[DefinitionInterface::LISTENER_AROUND];
-            $next = function () use ($chain, $type, $method, $subject, $code) {
-                return $chain->invokeNext($type, $method, $subject, func_get_args(), $code);
-            };
-            $pluginInstance = $this->pluginList->getPlugin($type, $code);
-            $pluginMethod = 'around' . $capMethod;
-            $result = $pluginInstance->$pluginMethod($subject, $next, ...array_values($arguments));
-            unset($pluginInstance, $pluginMethod);
-        } else {
-            $result = $subject->___callParent($method, $arguments);
-        }
-        if (isset($pluginInfo[DefinitionInterface::LISTENER_AFTER])) {
-            foreach ($pluginInfo[DefinitionInterface::LISTENER_AFTER] as $code) {
-                $result = $this->pluginList->getPlugin($type, $code)->{'after' . $capMethod}($subject, $result);
-            }
-        }
-        return $result;
-    }
-}
diff --git a/lib/internal/Magento/Framework/Interception/ChainInterface.php b/lib/internal/Magento/Framework/Interception/ChainInterface.php
deleted file mode 100644
index 648175b63038e5c929a60940c1c00300284e5c40..0000000000000000000000000000000000000000
--- a/lib/internal/Magento/Framework/Interception/ChainInterface.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Framework\Interception;
-
-interface ChainInterface
-{
-    /**
-     * @param string $type
-     * @param string $method
-     * @param InterceptorInterface $subject
-     * @param array $arguments
-     * @param string $previousPluginCode
-     * @return mixed
-     */
-    public function invokeNext(
-        $type,
-        $method,
-        InterceptorInterface $subject,
-        array $arguments,
-        $previousPluginCode = null
-    );
-}
diff --git a/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php b/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php
index 438589cd51172933d329926aa76f1363d71a1cda..1ff11552533b1e6514409402e778687483ae6d18 100644
--- a/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php
+++ b/lib/internal/Magento/Framework/Interception/Code/InterfaceValidator.php
@@ -49,7 +49,6 @@ class InterfaceValidator
         $plugin = new \ReflectionClass($pluginClass);
         $type = new \ReflectionClass($interceptedType);
 
-        $pluginMethods = [];
         foreach ($plugin->getMethods(\ReflectionMethod::IS_PUBLIC) as $pluginMethod) {
             /** @var  $pluginMethod \ReflectionMethod */
             $originMethodName = $this->getOriginMethodName($pluginMethod->getName());
@@ -112,12 +111,15 @@ class InterfaceValidator
                     );
                     break;
                 case self::METHOD_AFTER:
+                    // TODO: Remove this condition check in scope of MAGETWO-56123
                     if (count($pluginMethodParameters) > 1) {
-                        throw new ValidatorException(
-                            new Phrase(
-                                'Invalid method signature. Detected extra parameters in %1::%2',
-                                [$pluginClass, $pluginMethod->getName()]
-                            )
+                        // remove result
+                        array_shift($pluginMethodParameters);
+                        $this->validateMethodsParameters(
+                            $pluginMethodParameters,
+                            $originMethodParameters,
+                            $pluginClass,
+                            $pluginMethod->getName()
                         );
                     }
                     break;
diff --git a/lib/internal/Magento/Framework/Interception/Interceptor.php b/lib/internal/Magento/Framework/Interception/Interceptor.php
index 1ef8a0d9dc22f9018894c9aa94aa2e6eec762778..9aa00e1c751756a93cae6877c14f0337d38c8028 100644
--- a/lib/internal/Magento/Framework/Interception/Interceptor.php
+++ b/lib/internal/Magento/Framework/Interception/Interceptor.php
@@ -18,33 +18,19 @@ use Magento\Framework\App\ObjectManager;
  */
 trait Interceptor
 {
-    /**
-     * Object Manager instance
-     *
-     * @var \Magento\Framework\ObjectManagerInterface
-     */
-    protected $pluginLocator = null;
-
     /**
      * List of plugins
      *
-     * @var \Magento\Framework\Interception\PluginListInterface
+     * @var PluginListInterface
      */
-    protected $pluginList = null;
-
-    /**
-     * Invocation chain
-     *
-     * @var \Magento\Framework\Interception\ChainInterface
-     */
-    protected $chain = null;
+    private $pluginList;
 
     /**
      * Subject type name
      *
      * @var string
      */
-    protected $subjectType = null;
+    private $subjectType;
 
     /**
      * Initialize the Interceptor
@@ -53,9 +39,7 @@ trait Interceptor
      */
     public function ___init()
     {
-        $this->pluginLocator = ObjectManager::getInstance();
-        $this->pluginList = $this->pluginLocator->get(\Magento\Framework\Interception\PluginListInterface::class);
-        $this->chain = $this->pluginLocator->get(\Magento\Framework\Interception\ChainInterface::class);
+        $this->pluginList = ObjectManager::getInstance()->get(PluginListInterface::class);
         $this->subjectType = get_parent_class($this);
         if (method_exists($this->subjectType, '___init')) {
             parent::___init();
@@ -86,7 +70,7 @@ trait Interceptor
         } else {
             $properties = array_keys(get_object_vars($this));
         }
-        $properties = array_diff($properties, ['pluginLocator', 'pluginList', 'chain', 'subjectType', 'pluginLocator']);
+        $properties = array_diff($properties, ['pluginList', 'subjectType']);
         return $properties;
     }
 
@@ -113,45 +97,62 @@ trait Interceptor
      */
     protected function ___callPlugins($method, array $arguments, array $pluginInfo)
     {
-        $capMethod = ucfirst($method);
-        $result = null;
-        if (isset($pluginInfo[DefinitionInterface::LISTENER_BEFORE])) {
-            // Call 'before' listeners
-            foreach ($pluginInfo[DefinitionInterface::LISTENER_BEFORE] as $code) {
-                $pluginInstance = $this->pluginList->getPlugin($this->subjectType, $code);
-                $pluginMethod = 'before' . $capMethod;
-                $beforeResult = $pluginInstance->$pluginMethod($this, ...array_values($arguments));
-                if ($beforeResult) {
-                    $arguments = $beforeResult;
+        $subject = $this;
+        $type = $this->subjectType;
+        $pluginList = $this->pluginList;
+
+        $next = function (...$arguments) use (
+            $method,
+            &$pluginInfo,
+            $subject,
+            $type,
+            $pluginList,
+            &$next
+        ) {
+            $capMethod = ucfirst($method);
+            $currentPluginInfo = $pluginInfo;
+            $result = null;
+
+            if (isset($currentPluginInfo[DefinitionInterface::LISTENER_BEFORE])) {
+                // Call 'before' listeners
+                foreach ($currentPluginInfo[DefinitionInterface::LISTENER_BEFORE] as $code) {
+                    $pluginInstance = $pluginList->getPlugin($type, $code);
+                    $pluginMethod = 'before' . $capMethod;
+                    $beforeResult = $pluginInstance->$pluginMethod($this, ...array_values($arguments));
+
+                    if ($beforeResult !== null) {
+                        $arguments = (array)$beforeResult;
+                    }
                 }
-                unset($pluginInstance, $pluginMethod);
             }
-        }
-        if (isset($pluginInfo[DefinitionInterface::LISTENER_AROUND])) {
-            // Call 'around' listener
-            $chain = $this->chain;
-            $type = $this->subjectType;
-            /** @var \Magento\Framework\Interception\InterceptorInterface $subject */
-            $subject = $this;
-            $code = $pluginInfo[DefinitionInterface::LISTENER_AROUND];
-            $next = function () use ($chain, $type, $method, $subject, $code) {
-                return $chain->invokeNext($type, $method, $subject, func_get_args(), $code);
-            };
-            $pluginInstance = $this->pluginList->getPlugin($this->subjectType, $code);
-            $pluginMethod = 'around' . $capMethod;
-            $result = $pluginInstance->$pluginMethod($this, $next, ...array_values($arguments));
-            unset($pluginInstance, $pluginMethod);
-        } else {
-            // Call original method
-            $result = parent::$method(...array_values($arguments));
-        }
-        if (isset($pluginInfo[DefinitionInterface::LISTENER_AFTER])) {
-            // Call 'after' listeners
-            foreach ($pluginInfo[DefinitionInterface::LISTENER_AFTER] as $code) {
-                $result = $this->pluginList->getPlugin($this->subjectType, $code)
-                    ->{'after' . $capMethod}($this, $result);
+
+            if (isset($currentPluginInfo[DefinitionInterface::LISTENER_AROUND])) {
+                // Call 'around' listener
+                $code = $currentPluginInfo[DefinitionInterface::LISTENER_AROUND];
+                $pluginInfo = $pluginList->getNext($type, $method, $code);
+                $pluginInstance = $pluginList->getPlugin($type, $code);
+                $pluginMethod = 'around' . $capMethod;
+                $result = $pluginInstance->$pluginMethod($subject, $next, ...array_values($arguments));
+            } else {
+                // Call original method
+                $result = $subject->___callParent($method, $arguments);
             }
-        }
+
+            if (isset($currentPluginInfo[DefinitionInterface::LISTENER_AFTER])) {
+                // Call 'after' listeners
+                foreach ($currentPluginInfo[DefinitionInterface::LISTENER_AFTER] as $code) {
+                    $pluginInstance = $pluginList->getPlugin($type, $code);
+                    $pluginMethod = 'after' . $capMethod;
+                    $result = $pluginInstance->$pluginMethod($subject, $result, ...array_values($arguments));
+                }
+            }
+
+            return $result;
+        };
+
+        $result = $next(...array_values($arguments));
+        $next = null;
+
         return $result;
     }
 }
diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Chain/ChainTest.php b/lib/internal/Magento/Framework/Interception/Test/Unit/Chain/ChainTest.php
deleted file mode 100644
index 747ad56520c8c00a96f5108548bc575e17c095ba..0000000000000000000000000000000000000000
--- a/lib/internal/Magento/Framework/Interception/Test/Unit/Chain/ChainTest.php
+++ /dev/null
@@ -1,134 +0,0 @@
-<?php
-/**
- * Copyright © 2016 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Framework\Interception\Test\Unit\Chain;
-
-class ChainTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \Magento\Framework\Interception\Chain\Chain
-     */
-    protected $_model;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_pluginListMock;
-
-    protected function setUp()
-    {
-        $this->_pluginListMock = $this->getMock(\Magento\Framework\Interception\PluginListInterface::class);
-        $this->_model = new \Magento\Framework\Interception\Chain\Chain($this->_pluginListMock);
-    }
-
-    /**
-     * @covers \Magento\Framework\Interception\Chain\Chain::invokeNext
-     * @covers \Magento\Framework\Interception\Chain\Chain::__construct
-     */
-    public function testInvokeNextBeforePlugin()
-    {
-        $type = 'type';
-        $method = 'method';
-
-        $subjectMock = $this->getMock(\Magento\Framework\Interception\InterceptorInterface::class);
-        $pluginMock = $this->getMock('PluginClass', ['beforeMethod']);
-
-        $pluginMock->expects($this->once())
-            ->method('beforeMethod')
-            ->with($subjectMock, 1, 2)
-            ->will($this->returnValue(['beforeMethodResult']));
-
-        $this->_pluginListMock->expects($this->once())
-            ->method('getNext')
-            ->with($type, $method, null)
-            ->will(
-                $this->returnValue(
-                    [\Magento\Framework\Interception\DefinitionInterface::LISTENER_BEFORE => ['code']]
-                )
-            );
-
-        $this->_pluginListMock->expects($this->once())
-            ->method('getPlugin')
-            ->with($type, 'code')
-            ->will($this->returnValue($pluginMock));
-
-        $subjectMock->expects($this->once())
-            ->method('___callParent')
-            ->with('method', ['beforeMethodResult'])
-            ->will($this->returnValue('subjectMethodResult'));
-
-        $this->assertEquals('subjectMethodResult', $this->_model->invokeNext($type, $method, $subjectMock, [1, 2]));
-    }
-
-    /**
-     * @covers \Magento\Framework\Interception\Chain\Chain::invokeNext
-     */
-    public function testInvokeNextAroundPlugin()
-    {
-        $type = 'type';
-        $method = 'method';
-
-        $subjectMock = $this->getMock(\Magento\Framework\Interception\InterceptorInterface::class);
-        $pluginMock = $this->getMock('PluginClass', ['aroundMethod']);
-
-        $pluginMock->expects($this->once())
-            ->method('aroundMethod')
-            ->with($this->anything())
-            ->will($this->returnValue('subjectMethodResult'));
-
-        $this->_pluginListMock->expects($this->once())
-            ->method('getNext')
-            ->with($type, $method, null)
-            ->will($this->returnValue([
-                \Magento\Framework\Interception\DefinitionInterface::LISTENER_AROUND => 'code',
-            ]));
-
-        $this->_pluginListMock->expects($this->once())
-            ->method('getPlugin')
-            ->with($type, 'code')
-            ->will($this->returnValue($pluginMock));
-
-        $this->assertEquals('subjectMethodResult', $this->_model->invokeNext($type, $method, $subjectMock, []));
-    }
-
-    /**
-     * @covers \Magento\Framework\Interception\Chain\Chain::invokeNext
-     */
-    public function testInvokeNextAfterPlugin()
-    {
-        $type = 'type';
-        $method = 'method';
-
-        $subjectMock = $this->getMock(\Magento\Framework\Interception\InterceptorInterface::class);
-        $pluginMock = $this->getMock('PluginClass', ['afterMethod']);
-
-        $pluginMock->expects($this->once())
-            ->method('afterMethod')
-            ->with($subjectMock, 'subjectMethodResult')
-            ->will($this->returnValue('afterMethodResult'));
-
-        $this->_pluginListMock->expects($this->once())
-            ->method('getNext')
-            ->with($type, $method, null)
-            ->will(
-                $this->returnValue(
-                    [\Magento\Framework\Interception\DefinitionInterface::LISTENER_AFTER => ['code']]
-                )
-            );
-
-        $this->_pluginListMock->expects($this->once())
-            ->method('getPlugin')
-            ->with($type, 'code')
-            ->will($this->returnValue($pluginMock));
-
-        $subjectMock->expects($this->once())
-            ->method('___callParent')
-            ->with('method', [1, 2])
-            ->will($this->returnValue('subjectMethodResult'));
-
-        $this->assertEquals('afterMethodResult', $this->_model->invokeNext($type, $method, $subjectMock, [1, 2]));
-    }
-}
diff --git a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/InterfaceValidatorTest.php b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/InterfaceValidatorTest.php
index fb9a63c5c09e76014986c6439285ea1322fc64c5..a2660a4561fe9167918bf2d9dbae795b633ba953 100644
--- a/lib/internal/Magento/Framework/Interception/Test/Unit/Code/InterfaceValidatorTest.php
+++ b/lib/internal/Magento/Framework/Interception/Test/Unit/Code/InterfaceValidatorTest.php
@@ -114,7 +114,7 @@ class InterfaceValidatorTest extends \PHPUnit_Framework_TestCase
 
     /**
      * @expectedException \Magento\Framework\Exception\ValidatorException
-     * @expectedExceptionMessage Invalid method signature. Detected extra parameters
+     * @expectedExceptionMessage Invalid method signature. Invalid method parameters count
      * @covers \Magento\Framework\Interception\Code\InterfaceValidator::validate
      */
     public function testValidateExtraParameters()
diff --git a/lib/internal/Magento/Framework/Test/Unit/Interception/InterceptorTest.php b/lib/internal/Magento/Framework/Test/Unit/Interception/InterceptorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7b3624c501d8da24142923ce66347444a2754e7b
--- /dev/null
+++ b/lib/internal/Magento/Framework/Test/Unit/Interception/InterceptorTest.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Test\Unit\Interception;
+
+use Magento\Framework\Interception;
+
+class InterceptorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Sample\Interceptor
+     */
+    private $sampleInterceptor;
+
+    /**
+     * @var array
+     */
+    private $samplePlugins;
+
+    /**
+     * @var Interception\PluginListInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $pluginListMock;
+
+    protected function setUp()
+    {
+        $this->pluginListMock = $this->getMockBuilder(Interception\PluginListInterface::class)
+            ->getMockForAbstractClass();
+
+        $this->sampleInterceptor = new Sample\Interceptor();
+        $this->samplePlugins = [
+            'plugin1' => new Sample\Plugin1(),
+            'plugin2' => new Sample\Plugin2(),
+            'plugin3' => new Sample\Plugin3(),
+            'plugin4' => new Sample\Plugin4()
+        ];
+
+        $this->sampleInterceptor->setPluginList($this->pluginListMock);
+    }
+
+    public function testCallPlugins()
+    {
+        $subjectType = Sample\Entity::class;
+        $method = 'doSomething';
+        $capMethod = ucfirst($method);
+        $pluginMap = [
+            [$subjectType, 'plugin1', $this->samplePlugins['plugin1']],
+            [$subjectType, 'plugin2', $this->samplePlugins['plugin2']],
+            [$subjectType, 'plugin3', $this->samplePlugins['plugin3']],
+            [$subjectType, 'plugin4', $this->samplePlugins['plugin4']]
+        ];
+        $pluginInfoMap = [
+            [
+                $subjectType,
+                $method,
+                null,
+                [
+                    Interception\DefinitionInterface::LISTENER_BEFORE => ['plugin1', 'plugin2'],
+                    Interception\DefinitionInterface::LISTENER_AROUND => 'plugin3',
+                    Interception\DefinitionInterface::LISTENER_AFTER => ['plugin1', 'plugin2', 'plugin3']
+                ]
+            ],
+            [
+                $subjectType,
+                $method,
+                'plugin3',
+                [
+                    Interception\DefinitionInterface::LISTENER_BEFORE => ['plugin4'],
+                    Interception\DefinitionInterface::LISTENER_AROUND => 'plugin4',
+                    Interception\DefinitionInterface::LISTENER_AFTER => ['plugin4']
+                ]
+            ],
+            [
+                $subjectType,
+                $method,
+                'plugin4',
+                null
+            ]
+        ];
+        $expectedPluginCalls = [
+            Sample\Plugin1::class . '::before' . $capMethod,
+            Sample\Plugin2::class . '::before' . $capMethod,
+            Sample\Plugin3::class . '::around' . $capMethod,
+            Sample\Plugin4::class . '::before' . $capMethod,
+            Sample\Plugin4::class . '::around' . $capMethod,
+            Sample\Entity::class . '::' . $method,
+            Sample\Plugin4::class . '::after' . $capMethod,
+            Sample\Plugin1::class . '::after' . $capMethod,
+            Sample\Plugin2::class . '::after' . $capMethod,
+            Sample\Plugin3::class . '::after' . $capMethod
+        ];
+
+        $this->pluginListMock->expects(static::any())
+            ->method('getPlugin')
+            ->willReturnMap($pluginMap);
+        $this->pluginListMock->expects(static::exactly(3))
+            ->method('getNext')
+            ->willReturnMap($pluginInfoMap);
+
+        $this->assertTrue($this->sampleInterceptor->$method());
+        $this->assertEquals($expectedPluginCalls, $this->sampleInterceptor->getPluginCalls());
+    }
+}
diff --git a/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Entity.php b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Entity.php
new file mode 100644
index 0000000000000000000000000000000000000000..2ceff81795a707c445c3a50888ff93711ba1fefd
--- /dev/null
+++ b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Entity.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Test\Unit\Interception\Sample;
+
+/**
+ * Sample class
+ */
+class Entity
+{
+    /**
+     * @var array
+     */
+    private $pluginCalls = [];
+
+    /**
+     * Sample method
+     *
+     * @return bool
+     */
+    public function doSomething()
+    {
+        $this->addPluginCall(self::class . '::' . __FUNCTION__);
+
+        return true;
+    }
+
+    /**
+     * Get plugin calls info for testing
+     *
+     * @return array
+     */
+    public function getPluginCalls()
+    {
+        return $this->pluginCalls;
+    }
+
+    /**
+     * Add plugin call info for testing
+     *
+     * @param string $call
+     * @return void
+     */
+    public function addPluginCall($call)
+    {
+        $this->pluginCalls[] = $call;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Interceptor.php b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Interceptor.php
new file mode 100644
index 0000000000000000000000000000000000000000..0e5175ed6e5a2a1adce3e27ee7d1952210693f36
--- /dev/null
+++ b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Interceptor.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Test\Unit\Interception\Sample;
+
+use Magento\Framework\Interception;
+
+/**
+ * Sample interceptor
+ */
+class Interceptor extends Entity implements Interception\InterceptorInterface
+{
+    use Interception\Interceptor;
+
+    public function __construct()
+    {
+        $this->___init();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function ___init()
+    {
+        $this->subjectType = get_parent_class($this);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function doSomething()
+    {
+        $pluginInfo = $this->pluginList->getNext($this->subjectType, 'doSomething');
+        if (!$pluginInfo) {
+            return parent::doSomething();
+        } else {
+            return $this->___callPlugins('doSomething', func_get_args(), $pluginInfo);
+        }
+    }
+
+    /**
+     * Set plugin list
+     *
+     * @param Interception\PluginListInterface $pluginList
+     * @return void
+     */
+    public function setPluginList(Interception\PluginListInterface $pluginList)
+    {
+        $this->pluginList = $pluginList;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin1.php b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin1.php
new file mode 100644
index 0000000000000000000000000000000000000000..be3669c79930ee1c58bc93c3c36c71fc88ebb2a1
--- /dev/null
+++ b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin1.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Test\Unit\Interception\Sample;
+
+/**
+ * Sample plugin
+ */
+class Plugin1
+{
+    /**
+     * Sample before-plugin method
+     *
+     * @return void
+     */
+    public function beforeDoSomething(Entity $subject)
+    {
+        $subject->addPluginCall(static::class . '::' . __FUNCTION__);
+        //Not changing arguments
+    }
+
+    /**
+     * Sample around-plugin method
+     *
+     * @param Entity $subject
+     * @param \Closure $proceed
+     * @return mixed
+     */
+    public function aroundDoSomething(Entity $subject, \Closure $proceed)
+    {
+        $subject->addPluginCall(static::class . '::' . __FUNCTION__);
+        //Not breaking the chain
+        return $proceed();
+    }
+
+    /**
+     * Sample after-plugin method
+     *
+     * @param Entity $subject
+     * @param mixed $result
+     * @return mixed
+     */
+    public function afterDoSomething(Entity $subject, $result)
+    {
+        $subject->addPluginCall(static::class . '::' . __FUNCTION__);
+        //Not changing result
+        return $result;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin2.php b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin2.php
new file mode 100644
index 0000000000000000000000000000000000000000..df4c6d5fc18de37afe45cb9b05e526f6595ce526
--- /dev/null
+++ b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin2.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Test\Unit\Interception\Sample;
+
+/**
+ * Sample plugin
+ */
+class Plugin2 extends Plugin1
+{
+}
diff --git a/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin3.php b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin3.php
new file mode 100644
index 0000000000000000000000000000000000000000..0bb18890daf25f6e0e9969f1b493765d5496428b
--- /dev/null
+++ b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin3.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Test\Unit\Interception\Sample;
+
+/**
+ * Sample plugin
+ */
+class Plugin3 extends Plugin1
+{
+}
diff --git a/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin4.php b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin4.php
new file mode 100644
index 0000000000000000000000000000000000000000..02fc7dada8f63ccc92ee1e13f48d1f49a538feb3
--- /dev/null
+++ b/lib/internal/Magento/Framework/Test/Unit/Interception/Sample/Plugin4.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Test\Unit\Interception\Sample;
+
+/**
+ * Sample plugin
+ */
+class Plugin4 extends Plugin1
+{
+}