diff --git a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
index b349d7da577a4056c86e04e7293cc53a7406a4d8..30b0d6f2ac72cff0062ed5dec33dd8498c696200 100644
--- a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
+++ b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
@@ -78,9 +78,14 @@ class Bundle extends \Magento\Catalog\Block\Product\View\AbstractView
     }
 
     /**
+     * Returns the bundle product options
+     * Will return cached options data if the product options are already initialized
+     * In a case when $stripSelection parameter is true will reload stored bundle selections collection from DB
+     *
+     * @param bool $stripSelection
      * @return array
      */
-    public function getOptions()
+    public function getOptions($stripSelection = false)
     {
         if (!$this->options) {
             $product = $this->getProduct();
@@ -96,7 +101,7 @@ class Bundle extends \Magento\Catalog\Block\Product\View\AbstractView
 
             $this->options = $optionCollection->appendSelections(
                 $selectionCollection,
-                false,
+                $stripSelection,
                 $this->catalogProduct->getSkipSaleableCheck()
             );
         }
diff --git a/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php b/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php
index 362394ccd8bd1ddb245f17d27047fddb094f107d..f11fc30f5b28f90ec7f1a2c13a9b40b714f7cebe 100644
--- a/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Block/Catalog/Product/View/Type/BundleTest.php
@@ -19,32 +19,34 @@ class BundleTest extends \PHPUnit_Framework_TestCase
     /** @var  \Magento\Bundle\Model\Product\PriceFactory|\PHPUnit_Framework_MockObject_MockObject */
     private $bundleProductPriceFactory;
 
-    /**
-     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
-     */
-    protected $_objectHelper;
+    /** @var \Magento\Framework\Json\Encoder|\PHPUnit_Framework_MockObject_MockObject */
+    private $jsonEncoder;
+
+    /** @var \Magento\Catalog\Helper\Product|\PHPUnit_Framework_MockObject_MockObject */
+    private $catalogProduct;
 
     /**
-     * @var \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle
+     * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $_bundleBlock;
+    private $eventManager;
 
     /** @var  \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject */
     private $product;
 
+    /**
+     * @var \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle
+     */
+    private $bundleBlock;
+
     protected function setUp()
     {
         $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
         $this->bundleProductPriceFactory = $this->getMockBuilder(\Magento\Bundle\Model\Product\PriceFactory::class)
             ->disableOriginalConstructor()
             ->setMethods(['create'])
             ->getMock();
-        $this->_bundleBlock = $objectHelper->getObject(
-            \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::class,
-            [
-                'productPrice' => $this->bundleProductPriceFactory
-            ]
-        );
+
         $this->product = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->disableOriginalConstructor()
             ->setMethods(
@@ -57,45 +59,78 @@ class BundleTest extends \PHPUnit_Framework_TestCase
                     'getPreconfiguredValues'
                 ]
             )->getMock();
+        $registry = $this->getMockBuilder(\Magento\Framework\Registry::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['registry'])
+            ->getMock();
+        $registry->expects($this->any())
+            ->method('registry')
+            ->willReturn($this->product);
+        $this->eventManager = $this->getMockBuilder(\Magento\Framework\Event\ManagerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->jsonEncoder = $this->getMockBuilder(\Magento\Framework\Json\Encoder::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->catalogProduct = $this->getMockBuilder(\Magento\Catalog\Helper\Product::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        /** @var $bundleBlock BundleBlock */
+        $this->bundleBlock = $objectHelper->getObject(
+            \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::class,
+            [
+                'registry' => $registry,
+                'eventManager' => $this->eventManager,
+                'jsonEncoder' => $this->jsonEncoder,
+                'productPrice' => $this->bundleProductPriceFactory,
+                'catalogProduct' => $this->catalogProduct
+            ]
+        );
     }
 
     public function testGetOptionHtmlNoRenderer()
     {
-        $option = $this->getMock(\Magento\Bundle\Model\Option::class, ['getType', '__wakeup'], [], '', false);
-        $option->expects($this->exactly(2))->method('getType')->will($this->returnValue('checkbox'));
+        $option = $this->getMockBuilder(\Magento\Bundle\Model\Option::class)
+            ->setMethods(['getType'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $option->expects($this->any())->method('getType')->willReturn('checkbox');
+
+        $layout = $this->getMockBuilder(\Magento\Framework\View\Layout::class)
+            ->setMethods(['getChildName', 'getBlock'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $layout->expects($this->any())->method('getChildName')->willReturn(false);
+        $this->bundleBlock->setLayout($layout);
 
         $this->assertEquals(
             'There is no defined renderer for "checkbox" option type.',
-            $this->_bundleBlock->getOptionHtml($option)
+            $this->bundleBlock->getOptionHtml($option)
         );
     }
 
     public function testGetOptionHtml()
     {
-        $option = $this->getMock(\Magento\Bundle\Model\Option::class, ['getType', '__wakeup'], [], '', false);
-        $option->expects($this->exactly(1))->method('getType')->will($this->returnValue('checkbox'));
-
-        $optionBlock = $this->getMock(
-            \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Checkbox::class,
-            ['setOption', 'toHtml'],
-            [],
-            '',
-            false
-        );
-        $optionBlock->expects($this->any())->method('setOption')->will($this->returnValue($optionBlock));
-        $optionBlock->expects($this->any())->method('toHtml')->will($this->returnValue('option html'));
-        $layout = $this->getMock(
-            \Magento\Framework\View\Layout::class,
-            ['getChildName', 'getBlock'],
-            [],
-            '',
-            false
-        );
-        $layout->expects($this->any())->method('getChildName')->will($this->returnValue('name'));
-        $layout->expects($this->any())->method('getBlock')->will($this->returnValue($optionBlock));
-        $this->_bundleBlock->setLayout($layout);
+        $option = $this->getMockBuilder(\Magento\Bundle\Model\Option::class)
+            ->setMethods(['getType'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $option->expects($this->once())->method('getType')->willReturn('checkbox');
+
+        $optionBlock = $this->getMockBuilder(
+            \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle\Option\Checkbox::class
+        )->setMethods(['setOption', 'toHtml'])->disableOriginalConstructor()->getMock();
+        $optionBlock->expects($this->any())->method('setOption')->willReturnSelf();
+        $optionBlock->expects($this->any())->method('toHtml')->willReturn('option html');
+        $layout = $this->getMockBuilder(\Magento\Framework\View\Layout::class)
+            ->setMethods(['getChildName', 'getBlock'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $layout->expects($this->any())->method('getChildName')->willReturn('name');
+        $layout->expects($this->any())->method('getBlock')->willReturn($optionBlock);
+        $this->bundleBlock->setLayout($layout);
 
-        $this->assertEquals('option html', $this->_bundleBlock->getOptionHtml($option));
+        $this->assertEquals('option html', $this->bundleBlock->getOptionHtml($option));
     }
 
     public function testGetJsonConfigFixedPriceBundleNoOption()
@@ -127,12 +162,12 @@ class BundleTest extends \PHPUnit_Framework_TestCase
         ];
         $priceInfo = $this->getPriceInfoMock($prices);
 
-        $this->_bundleBlock = $this->setupBundleBlock(
+        $this->updateBundleBlock(
             $options,
             $priceInfo,
             \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED
         );
-        $jsonConfig = $this->_bundleBlock->getJsonConfig();
+        $jsonConfig = $this->bundleBlock->getJsonConfig();
         $this->assertEquals(110, $jsonConfig['prices']['oldPrice']['amount']);
         $this->assertEquals(100, $jsonConfig['prices']['basePrice']['amount']);
         $this->assertEquals(100, $jsonConfig['prices']['finalPrice']['amount']);
@@ -162,14 +197,14 @@ class BundleTest extends \PHPUnit_Framework_TestCase
         $bundleProductPrice->expects($this->at(0))
             ->method('getLowestPrice')
             ->with($this->product, $baseAmount)
-            ->will($this->returnValue(999));
+            ->willReturn(999);
         $bundleProductPrice->expects($this->at(1))
             ->method('getLowestPrice')
             ->with($this->product, $basePriceValue)
-            ->will($this->returnValue(888));
+            ->willReturn(888);
         $this->bundleProductPriceFactory->expects($this->once())
             ->method('create')
-            ->will($this->returnValue($bundleProductPrice));
+            ->willReturn($bundleProductPrice);
 
         $options = [
             $this->createOption(1, 'Title `1', $selections),
@@ -207,7 +242,7 @@ class BundleTest extends \PHPUnit_Framework_TestCase
 
         $this->product->expects($this->once())
             ->method('hasPreconfiguredValues')
-            ->will($this->returnValue(true));
+            ->willReturn(true);
         $preconfiguredValues = new \Magento\Framework\DataObject(
             [
                 'bundle_option' => [
@@ -217,14 +252,14 @@ class BundleTest extends \PHPUnit_Framework_TestCase
         );
         $this->product->expects($this->once())
             ->method('getPreconfiguredValues')
-            ->will($this->returnValue($preconfiguredValues));
+            ->willReturn($preconfiguredValues);
 
-        $this->_bundleBlock = $this->setupBundleBlock(
+        $this->updateBundleBlock(
             $options,
             $priceInfo,
             \Magento\Bundle\Model\Product\Price::PRICE_TYPE_FIXED
         );
-        $jsonConfig = $this->_bundleBlock->getJsonConfig();
+        $jsonConfig = $this->bundleBlock->getJsonConfig();
         $this->assertEquals(110, $jsonConfig['prices']['oldPrice']['amount']);
         $this->assertEquals(100, $jsonConfig['prices']['basePrice']['amount']);
         $this->assertEquals(100, $jsonConfig['prices']['finalPrice']['amount']);
@@ -236,86 +271,38 @@ class BundleTest extends \PHPUnit_Framework_TestCase
      * @param string $priceType
      * @return BundleBlock
      */
-    private function setupBundleBlock($options, $priceInfo, $priceType)
+    private function updateBundleBlock($options, $priceInfo, $priceType)
     {
-        $objectHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-
-
-        $eventManager = $this->getMockBuilder(\Magento\Framework\Event\Manager::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $eventManager->expects($this->any())->method('dispatch')->will($this->returnValue(true));
-
+        $this->eventManager->expects($this->any())->method('dispatch')->willReturn(true);
         $optionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Option\Collection::class)
             ->disableOriginalConstructor()
             ->getMock();
         $optionCollection->expects($this->any())
             ->method('appendSelections')
-            ->will($this->returnValue($options));
+            ->willReturn($options);
 
         $typeInstance = $this->getMockBuilder(\Magento\Bundle\Model\Product\Type::class)
             ->disableOriginalConstructor()
             ->getMock();
         $typeInstance->expects($this->any())
             ->method('getOptionsCollection')
-            ->will($this->returnValue($optionCollection));
+            ->willReturn($optionCollection);
         $typeInstance->expects($this->any())
             ->method('getStoreFilter')
-            ->will($this->returnValue(true));
+            ->willReturn(true);
 
         $this->product->expects($this->any())
             ->method('getTypeInstance')
-            ->will($this->returnValue($typeInstance));
+            ->willReturn($typeInstance);
         $this->product->expects($this->any())
             ->method('getPriceInfo')
-            ->will($this->returnValue($priceInfo));
+            ->willReturn($priceInfo);
         $this->product->expects($this->any())
             ->method('getPriceType')
-            ->will($this->returnValue($priceType));
-
-        $registry = $this->getMockBuilder(\Magento\Framework\Registry::class)
-            ->disableOriginalConstructor()
-            ->setMethods(['registry'])
-            ->getMock();
-        $registry->expects($this->once())
-            ->method('registry')
-            ->will($this->returnValue($this->product));
-
-        $taxHelperMock = $this->getMockBuilder(\Magento\Tax\Helper\Data::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $context = $this->getMockBuilder(\Magento\Catalog\Block\Product\Context::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $context->expects($this->any())
-            ->method('getRegistry')
-            ->will($this->returnValue($registry));
-        $context->expects($this->any())
-            ->method('getTaxData')
-            ->will($this->returnValue($taxHelperMock));
-        $context->expects($this->any())
-            ->method('getEventManager')
-            ->will($this->returnValue($eventManager));
-
-        $jsonEncoderMock = $this->getMockBuilder(\Magento\Framework\Json\Encoder::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $jsonEncoderMock->expects($this->any())
+            ->willReturn($priceType);
+        $this->jsonEncoder->expects($this->any())
             ->method('encode')
             ->will($this->returnArgument(0));
-
-        /** @var $bundleBlock BundleBlock */
-        $bundleBlock = $objectHelper->getObject(
-            \Magento\Bundle\Block\Catalog\Product\View\Type\Bundle::class,
-            [
-                'context' => $context,
-                'jsonEncoder' => $jsonEncoderMock,
-                'productPrice' => $this->bundleProductPriceFactory
-            ]
-        );
-
-        return $bundleBlock;
     }
 
     private function getPriceInfoMock($price)
@@ -331,13 +318,13 @@ class BundleTest extends \PHPUnit_Framework_TestCase
                 $priceInfoMock->expects($this->at($counter))
                     ->method('getPrice')
                     ->with($priceType)
-                    ->will($this->returnValue($priceValue));
+                    ->willReturn($priceValue);
                 $counter++;
             }
         } else {
             $priceInfoMock->expects($this->any())
                 ->method('getPrice')
-                ->will($this->returnValue($price));
+                ->willReturn($price);
         }
         return $priceInfoMock;
     }
@@ -355,7 +342,7 @@ class BundleTest extends \PHPUnit_Framework_TestCase
         foreach ($prices as $methodName => $amount) {
             $priceMock->expects($this->any())
                 ->method($methodName)
-                ->will($this->returnValue($amount));
+                ->willReturn($amount);
         }
 
         return $priceMock;
@@ -373,8 +360,8 @@ class BundleTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->setMethods(['getValue', 'getBaseAmount', 'getOptionSelectionAmount'])
             ->getMockForAbstractClass();
-        $amountPrice->expects($this->any())->method('getValue')->will($this->returnValue($value));
-        $amountPrice->expects($this->any())->method('getBaseAmount')->will($this->returnValue($baseAmount));
+        $amountPrice->expects($this->any())->method('getValue')->willReturn($value);
+        $amountPrice->expects($this->any())->method('getBaseAmount')->willReturn($baseAmount);
         foreach ($selectionAmounts as $selectionAmount) {
             $amountPrice->expects($this->any())
                 ->method('getOptionSelectionAmount')
@@ -414,7 +401,6 @@ class BundleTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->setMethods(
                 [
-                    '__wakeup',
                     'getId',
                     'getTitle',
                     'getSelections',
@@ -423,12 +409,12 @@ class BundleTest extends \PHPUnit_Framework_TestCase
                     'getIsDefault',
                 ]
             )
-            ->getMock();
-        $option->expects($this->any())->method('getId')->will($this->returnValue($id));
-        $option->expects($this->any())->method('getTitle')->will($this->returnValue($title));
-        $option->expects($this->any())->method('getSelections')->will($this->returnValue($selections));
-        $option->expects($this->any())->method('getType')->will($this->returnValue($type));
-        $option->expects($this->any())->method('getRequired')->will($this->returnValue($isRequired));
+            ->getMockForAbstractClass();
+        $option->expects($this->any())->method('getId')->willReturn($id);
+        $option->expects($this->any())->method('getTitle')->willReturn($title);
+        $option->expects($this->any())->method('getSelections')->willReturn($selections);
+        $option->expects($this->any())->method('getType')->willReturn($type);
+        $option->expects($this->any())->method('getRequired')->willReturn($isRequired);
         return $option;
     }
 
@@ -453,42 +439,72 @@ class BundleTest extends \PHPUnit_Framework_TestCase
     ) {
         $selection = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
             ->disableOriginalConstructor()
-            ->setMethods(
-                [
-                    'getSelectionId',
-                    'getSelectionQty',
-                    'getPriceInfo',
-                    'getSelectionCanChangeQty',
-                    'getName',
-                    'getIsDefault',
-                    'isSalable',
-                ]
-            )->getMock();
+            ->getMock();
         $tierPrice = $this->getMockBuilder(\Magento\Bundle\Pricing\Price\TierPrice::class)
             ->disableOriginalConstructor()
             ->setMethods(['getTierPriceList'])
             ->getMock();
-        $tierPrice->expects($this->any())
-            ->method('getTierPriceList')
-            ->will($this->returnValue($tierPriceList));
+        $tierPrice->expects($this->any())->method('getTierPriceList')->willReturn($tierPriceList);
         $priceInfo = $this->getMockBuilder(\Magento\Framework\Pricing\PriceInfo\Base::class)
             ->disableOriginalConstructor()
             ->setMethods(['getPrice'])
             ->getMock();
-        $priceInfo->expects($this->any())
-            ->method('getPrice')
-            ->will($this->returnValue($tierPrice));
-
-        $selection->expects($this->any())->method('getSelectionId')->will($this->returnValue($id));
-        $selection->expects($this->any())->method('getName')->will($this->returnValue($name));
-        $selection->expects($this->any())->method('getSelectionQty')->will($this->returnValue($qty));
-        $selection->expects($this->any())->method('getPriceInfo')->will($this->returnValue($priceInfo));
-        $selection->expects($this->any())->method('getSelectionCanChangeQty')->will(
-            $this->returnValue($isCanChangeQty)
-        );
-        $selection->expects($this->any())->method('getIsDefault')->will($this->returnValue($isDefault));
-        $selection->expects($this->any())->method('isSalable')->will($this->returnValue($isSalable));
+        $priceInfo->expects($this->any())->method('getPrice')->willReturn($tierPrice);
+        $selection->expects($this->any())->method('getSelectionId')->willReturn($id);
+        $selection->expects($this->any())->method('getName')->willReturn($name);
+        $selection->expects($this->any())->method('getSelectionQty')->willReturn($qty);
+        $selection->expects($this->any())->method('getPriceInfo')->willReturn($priceInfo);
+        $selection->expects($this->any())->method('getSelectionCanChangeQty')->willReturn($isCanChangeQty);
+        $selection->expects($this->any())->method('getIsDefault')->willReturn($isDefault);
+        $selection->expects($this->any())->method('isSalable')->willReturn($isSalable);
 
         return $selection;
     }
+
+    /**
+     * @dataProvider getOptionsDataProvider
+     * @param bool $stripSelection
+     */
+    public function testGetOptions($stripSelection)
+    {
+        $newOptions = ['option_1', 'option_2'];
+
+        $optionCollection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Option\Collection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $selectionConnection = $this->getMockBuilder(\Magento\Bundle\Model\ResourceModel\Selection\Collection::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $typeInstance = $this->getMockBuilder(\Magento\Bundle\Model\Product\Type::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $optionCollection->expects($this->any())->method('appendSelections')
+            ->with($selectionConnection, $stripSelection, true)
+            ->willReturn($newOptions);
+        $typeInstance->expects($this->any())->method('setStoreFilter')->with(0, $this->product)
+            ->willReturn($optionCollection);
+        $typeInstance->expects($this->any())->method('getStoreFilter')->willReturn(true);
+        $typeInstance->expects($this->any())->method('getOptionsCollection')->willReturn($optionCollection);
+        $typeInstance->expects($this->any())->method('getOptionsIds')->willReturn([1,2]);
+        $typeInstance->expects($this->once())->method('getSelectionsCollection')->with([1,2], $this->product)
+            ->willReturn($selectionConnection);
+        $this->product->expects($this->any())
+            ->method('getTypeInstance')->willReturn($typeInstance);
+        $this->product->expects($this->any())->method('getStoreId')  ->willReturn(0);
+        $this->catalogProduct->expects($this->once())->method('getSkipSaleableCheck')->willReturn(true);
+
+        $this->assertEquals($newOptions, $this->bundleBlock->getOptions($stripSelection));
+    }
+
+    /**
+     * @return array
+     */
+    public function getOptionsDataProvider()
+    {
+        return [
+            [true],
+            [false]
+        ];
+    }
 }
diff --git a/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/bundle.phtml b/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/bundle.phtml
index f0cb656843bcac4075a0df0659d97c8c349d2c00..1272e13e42526f1849e0e61695338ef107172428 100644
--- a/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/bundle.phtml
+++ b/app/code/Magento/Bundle/view/adminhtml/templates/product/composite/fieldset/options/bundle.phtml
@@ -9,7 +9,7 @@
 ?>
 
 <?php /* @var $block \Magento\Bundle\Block\Adminhtml\Catalog\Product\Composite\Fieldset\Bundle */ ?>
-<?php $options = $block->decorateArray($block->getOptions()); ?>
+<?php $options = $block->decorateArray($block->getOptions(true)); ?>
 <?php if (count($options)): ?>
 <fieldset id="catalog_product_composite_configure_fields_bundle"
           class="fieldset admin__fieldset composite-bundle<?php echo $block->getIsLastFieldset() ? ' last-fieldset' : '' ?>">
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php
index 285f4f1e3ffade4875266c634a241768b36215e9..25bd24ef70b9492d2da5b32e2a4146e3b1a0ab07 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Image/Upload.php
@@ -50,8 +50,10 @@ class Upload extends \Magento\Backend\App\Action
      */
     public function execute()
     {
+        $imageId = $this->_request->getParam('param_name', 'image');
+
         try {
-            $result = $this->imageUploader->saveFileToTmpDir('image');
+            $result = $this->imageUploader->saveFileToTmpDir($imageId);
 
             $result['cookie'] = [
                 'name' => $this->_getSession()->getName(),
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
index 55ae96faeb7e6424f51ec3d5a22054844ea5a812..fa29d46c615939533111d3f62c540f848f06710b 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Category/Save.php
@@ -6,6 +6,7 @@
 namespace Magento\Catalog\Controller\Adminhtml\Category;
 
 use Magento\Store\Model\StoreManagerInterface;
+use Magento\Catalog\Api\Data\CategoryAttributeInterface;
 
 /**
  * Class Save
@@ -48,6 +49,11 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
      */
     private $storeManager;
 
+    /**
+     * @var \Magento\Eav\Model\Config
+     */
+    private $eavConfig;
+
     /**
      * Constructor
      *
@@ -56,31 +62,35 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
      * @param \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory
      * @param \Magento\Framework\View\LayoutFactory $layoutFactory
      * @param StoreManagerInterface $storeManager
+     * @param \Magento\Eav\Model\Config $eavConfig
      */
     public function __construct(
         \Magento\Backend\App\Action\Context $context,
         \Magento\Framework\Controller\Result\RawFactory $resultRawFactory,
         \Magento\Framework\Controller\Result\JsonFactory $resultJsonFactory,
         \Magento\Framework\View\LayoutFactory $layoutFactory,
-        StoreManagerInterface $storeManager
+        StoreManagerInterface $storeManager,
+        \Magento\Eav\Model\Config $eavConfig = null
     ) {
         parent::__construct($context);
         $this->resultRawFactory = $resultRawFactory;
         $this->resultJsonFactory = $resultJsonFactory;
         $this->layoutFactory = $layoutFactory;
         $this->storeManager = $storeManager;
+        $this->eavConfig = $eavConfig
+            ?: \Magento\Framework\App\ObjectManager::getInstance()->get(\Magento\Eav\Model\Config::class);
     }
 
     /**
      * Filter category data
      *
+     * @deprecated
      * @param array $rawData
      * @return array
      */
     protected function _filterCategoryPostData(array $rawData)
     {
         $data = $rawData;
-        // @todo It is a workaround to prevent saving this data in category model and it has to be refactored in future
         if (isset($data['image']) && is_array($data['image'])) {
             if (!empty($data['image']['delete'])) {
                 $data['image'] = null;
@@ -126,7 +136,7 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
         $this->storeManager->setCurrentStore($store->getCode());
         $parentId = isset($categoryPostData['parent']) ? $categoryPostData['parent'] : null;
         if ($categoryPostData) {
-            $category->addData($this->_filterCategoryPostData($categoryPostData));
+            $category->addData($categoryPostData);
             if ($isNewCategory) {
                 $parentCategory = $this->getParentCategory($parentId, $storeId);
                 $category->setPath($parentCategory->getPath());
@@ -248,18 +258,30 @@ class Save extends \Magento\Catalog\Controller\Adminhtml\Category
     }
 
     /**
-     * Image data preprocessing
+     * Sets image attribute data to false if image was removed
      *
      * @param array $data
-     *
      * @return array
      */
     public function imagePreprocessing($data)
     {
-        if (empty($data['image'])) {
-            unset($data['image']);
-            $data['image']['delete'] = true;
+        $entityType = $this->eavConfig->getEntityType(CategoryAttributeInterface::ENTITY_TYPE_CODE);
+
+        foreach ($entityType->getAttributeCollection() as $attributeModel) {
+            $attributeCode = $attributeModel->getAttributeCode();
+            $backendModel = $attributeModel->getBackend();
+
+            if (isset($data[$attributeCode])) {
+                continue;
+            }
+
+            if (!$backendModel instanceof \Magento\Catalog\Model\Category\Attribute\Backend\Image) {
+                continue;
+            }
+
+            $data[$attributeCode] = false;
         }
+
         return $data;
     }
 
diff --git a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php
index d59492c4065e72706f8c1a168e4a33b1c2c9e825..4eed888b3cb08b18f07e403bc172ec9615108a09 100644
--- a/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php
+++ b/app/code/Magento/Catalog/Controller/Adminhtml/Product/Initialization/Helper.php
@@ -131,12 +131,7 @@ class Helper
                 $productData[$field] = [];
             }
         }
-
-        foreach ($productData['website_ids'] as $websiteId => $checkboxValue) {
-            if (!$checkboxValue) {
-                unset($productData['website_ids'][$websiteId]);
-            }
-        }
+        $productData['website_ids'] = $this->filterWebsiteIds($productData['website_ids']);
 
         $wasLockedMedia = false;
         if ($product->isLockedAttribute('media')) {
@@ -422,4 +417,23 @@ class Helper
         }
         return $this->dateTimeFilter;
     }
+
+    /**
+     * Remove ids of non selected websites from $websiteIds array and return filtered data
+     * $websiteIds parameter expects array with website ids as keys and 1 (selected) or 0 (non selected) as values
+     * Only one id (default website ID) will be set to $websiteIds array when the single store mode is turned on
+     *
+     * @param array $websiteIds
+     * @return array
+     */
+    private function filterWebsiteIds($websiteIds)
+    {
+        if (!$this->storeManager->isSingleStoreMode()) {
+            $websiteIds = array_filter((array)$websiteIds);
+        } else {
+            $websiteIds[$this->storeManager->getWebsite(true)->getId()] = 1;
+        }
+
+        return $websiteIds;
+    }
 }
diff --git a/app/code/Magento/Catalog/Model/Category.php b/app/code/Magento/Catalog/Model/Category.php
index 9e855e05c7ce388dd52c11829882d5b46f634d02..906718c64c6e0bf814bda973c81168d067d887ed 100644
--- a/app/code/Magento/Catalog/Model/Category.php
+++ b/app/code/Magento/Catalog/Model/Category.php
@@ -652,14 +652,14 @@ class Category extends \Magento\Catalog\Model\AbstractModel implements
     }
 
     /**
-     * Retrieve image URL
-     *
-     * @return string
+     * @param string $attributeCode
+     * @return bool|string
+     * @throws \Magento\Framework\Exception\LocalizedException
      */
-    public function getImageUrl()
+    public function getImageUrl($attributeCode = 'image')
     {
         $url = false;
-        $image = $this->getImage();
+        $image = $this->getData($attributeCode);
         if ($image) {
             if (is_string($image)) {
                 $url = $this->_storeManager->getStore()->getBaseUrl(
diff --git a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
index 5eb4461ace5f0e88583337a9b8c2efe2c71bad64..5e8589428fad1d17abe4480abf1d16a8b727abcb 100644
--- a/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
+++ b/app/code/Magento/Catalog/Model/Category/Attribute/Backend/Image.php
@@ -21,8 +21,6 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
     protected $_uploaderFactory;
 
     /**
-     * Filesystem facade
-     *
      * @var \Magento\Framework\Filesystem
      *
      * @deprecated
@@ -30,8 +28,6 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
     protected $_filesystem;
 
     /**
-     * File Uploader factory
-     *
      * @var \Magento\MediaStorage\Model\File\UploaderFactory
      *
      * @deprecated
@@ -46,15 +42,16 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
     protected $_logger;
 
     /**
-     * Image uploader
-     *
      * @var \Magento\Catalog\Model\ImageUploader
      */
     private $imageUploader;
 
     /**
-     * Image constructor.
-     *
+     * @var string
+     */
+    private $additionalData = '_additional_data_';
+
+    /**
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Filesystem $filesystem
      * @param \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory
@@ -70,8 +67,44 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
     }
 
     /**
-     * Get image uploader
+     * Gets image name from $value array.
+     * Will return empty string in a case when $value is not an array
+     *
+     * @param array $value Attribute value
+     * @return string
+     */
+    private function getUploadedImageName($value)
+    {
+        if (is_array($value) && isset($value[0]['name'])) {
+            return $value[0]['name'];
+        }
+
+        return '';
+    }
+
+    /**
+     * Avoiding saving potential upload data to DB
+     * Will set empty image attribute value if image was not uploaded
      *
+     * @param \Magento\Framework\DataObject $object
+     * @return $this
+     */
+    public function beforeSave($object)
+    {
+        $attributeName = $this->getAttribute()->getName();
+        $value = $object->getData($attributeName);
+
+        if ($imageName = $this->getUploadedImageName($value)) {
+            $object->setData($this->additionalData . $attributeName, $value);
+            $object->setData($attributeName, $imageName);
+        } else if (!is_string($value)) {
+            $object->setData($attributeName, '');
+        }
+
+        return parent::beforeSave($object);
+    }
+
+    /**
      * @return \Magento\Catalog\Model\ImageUploader
      *
      * @deprecated
@@ -79,10 +112,10 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
     private function getImageUploader()
     {
         if ($this->imageUploader === null) {
-            $this->imageUploader = \Magento\Framework\App\ObjectManager::getInstance()->get(
-                \Magento\Catalog\CategoryImageUpload::class
-            );
+            $this->imageUploader = \Magento\Framework\App\ObjectManager::getInstance()
+                ->get(\Magento\Catalog\CategoryImageUpload::class);
         }
+
         return $this->imageUploader;
     }
 
@@ -94,15 +127,16 @@ class Image extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
      */
     public function afterSave($object)
     {
-        $image = $object->getData($this->getAttribute()->getName(), null);
+        $value = $object->getData($this->additionalData . $this->getAttribute()->getName());
 
-        if ($image !== null) {
+        if ($imageName = $this->getUploadedImageName($value)) {
             try {
-                $this->getImageUploader()->moveFileFromTmp($image);
+                $this->getImageUploader()->moveFileFromTmp($imageName);
             } catch (\Exception $e) {
                 $this->_logger->critical($e);
             }
         }
+
         return $this;
     }
 }
diff --git a/app/code/Magento/Catalog/Model/Category/DataProvider.php b/app/code/Magento/Catalog/Model/Category/DataProvider.php
index 8626d183e2fac36e2b2fb194c418384d9ff87d82..aefd31e21ad62f8469837a801581170581555c6a 100644
--- a/app/code/Magento/Catalog/Model/Category/DataProvider.php
+++ b/app/code/Magento/Catalog/Model/Category/DataProvider.php
@@ -17,6 +17,7 @@ use Magento\Ui\Component\Form\Field;
 use Magento\Ui\DataProvider\EavValidationRules;
 use Magento\Catalog\Model\CategoryFactory;
 use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Catalog\Model\Category\Attribute\Backend\Image as ImageBackendModel;
 
 /**
  * Class DataProvider
@@ -206,11 +207,8 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
             $categoryData = $this->addUseDefaultSettings($category, $categoryData);
             $categoryData = $this->addUseConfigSettings($categoryData);
             $categoryData = $this->filterFields($categoryData);
-            if (isset($categoryData['image'])) {
-                unset($categoryData['image']);
-                $categoryData['image'][0]['name'] = $category->getData('image');
-                $categoryData['image'][0]['url'] = $category->getImageUrl();
-            }
+            $categoryData = $this->convertValues($category, $categoryData);
+
             $this->loadedData[$category->getId()] = $categoryData;
         }
         return $this->loadedData;
@@ -371,6 +369,31 @@ class DataProvider extends \Magento\Ui\DataProvider\AbstractDataProvider
         return array_diff_key($categoryData, array_flip($this->ignoreFields));
     }
 
+    /**
+     * Converts category image data to acceptable for rendering format
+     *
+     * @param \Magento\Catalog\Model\Category $category
+     * @param array $categoryData
+     * @return array
+     */
+    private function convertValues($category, $categoryData)
+    {
+        foreach ($category->getAttributes() as $attributeCode => $attribute) {
+            if (!isset($categoryData[$attributeCode])) {
+                continue;
+            }
+
+            if ($attribute->getBackend() instanceof ImageBackendModel) {
+                unset($categoryData[$attributeCode]);
+
+                $categoryData[$attributeCode][0]['name'] = $category->getData($attributeCode);
+                $categoryData[$attributeCode][0]['url'] = $category->getImageUrl($attributeCode);
+            }
+        }
+
+        return $categoryData;
+    }
+
     /**
      * Category's fields default values
      *
diff --git a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
index b2b20b9d223e223a093d7f6ae222e19631084528..c24460981afbf8d6c6cccb79255031d8320b726f 100644
--- a/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
+++ b/app/code/Magento/Catalog/Model/ResourceModel/Product/Collection.php
@@ -2182,12 +2182,17 @@ class Collection extends \Magento\Catalog\Model\ResourceModel\Collection\Abstrac
 
         $mediaGalleries = [];
         $linkField = $this->getMetadataPool()->getMetadata(ProductInterface::class)->getLinkField();
+        $items = $this->getItems();
+
+        $select->where('entity.' . $linkField . ' IN (?)', array_map(function ($item) {
+            return $item->getId();
+        }, $items));
 
         foreach ($this->getConnection()->fetchAll($select) as $row) {
             $mediaGalleries[$row[$linkField]][] = $row;
         }
 
-        foreach ($this->getItems() as $item) {
+        foreach ($items as $item) {
             $mediaEntries = isset($mediaGalleries[$item->getId()]) ? $mediaGalleries[$item->getId()] : [];
             $this->getGalleryReadHandler()->addMediaDataToProduct($item, $mediaEntries);
         }
diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/Image/UploadTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/Image/UploadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..387e9a8a6a891b305170253befcd5cedb046feeb
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/Image/UploadTest.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Category\Image;
+
+use Magento\Catalog\Controller\Adminhtml\Category\Image\Upload as Model;
+use Magento\Framework\App\Request\Http as Request;
+use Magento\Catalog\Model\ImageUploader;
+use Magento\Framework\Controller\ResultFactory;
+use Magento\Framework\DataObject;
+
+/**
+ * Class UploadTest
+ */
+class UploadTest extends \PHPUnit_Framework_TestCase
+{
+    private $objectManager;
+
+    protected function setUp()
+    {
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+    }
+
+    public function executeDataProvider()
+    {
+        return [
+            ['image1', 'image1'],
+            ['image2', 'image2'],
+            [null, 'image'],
+        ];
+    }
+
+    /**
+     * @param string $name
+     * @param string $savedName
+     *
+     * @dataProvider executeDataProvider
+     */
+    public function testExecute($name, $savedName)
+    {
+        $request = $this->objectManager->getObject(Request::class);
+
+        $uploader = $this->getMock(ImageUploader::class, ['saveFileToTmpDir'], [], '', false);
+
+        $resultFactory = $this->getMock(ResultFactory::class, ['create'], [], '', false);
+
+        $resultFactory->expects($this->once())
+            ->method('create')
+            ->will($this->returnValue(new DataObject()));
+
+        $model = $this->objectManager->getObject(Model::class, [
+            'request' => $request,
+            'resultFactory' => $resultFactory,
+            'imageUploader' => $uploader
+        ]);
+
+        $uploader->expects($this->once())
+            ->method('saveFileToTmpDir')
+            ->with($savedName)
+            ->will($this->returnValue([]));
+
+        $request->setParam('param_name', $name);
+
+        $model->execute();
+    }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php
index 51d99f7219575c205b61de6e5d93727633874f79..745d46710053a7c877e1bf05db47a715175b2bcb 100644
--- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Category/SaveTest.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Category;
 
+use \Magento\Catalog\Controller\Adminhtml\Category\Save as Model;
+
 /**
  * Class SaveTest
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -14,67 +16,47 @@ class SaveTest extends \PHPUnit_Framework_TestCase
     /**
      * @var \Magento\Backend\Model\View\Result\RedirectFactory|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $resultRedirectFactoryMock;
-
-    /**
-     * @var \Magento\Framework\Controller\Result\RawFactory|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $resultRawFactoryMock;
+    private $resultRedirectFactoryMock;
 
     /**
      * @var \Magento\Framework\Controller\Result\JsonFactory|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $resultJsonFactoryMock;
+    private $resultJsonFactoryMock;
 
     /**
      * @var \Magento\Framework\View\LayoutFactory|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $layoutFactoryMock;
-
-    /**
-     * @var \Magento\Backend\App\Action\Context|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $contextMock;
-
-    /**
-     * @var \Magento\Framework\View\Page\Title|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $titleMock;
+    private $layoutFactoryMock;
 
     /**
      * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $requestMock;
+    private $requestMock;
 
     /**
      * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $objectManagerMock;
+    private $objectManagerMock;
 
     /**
      * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $eventManagerMock;
-
-    /**
-     * @var \Magento\Framework\App\ResponseInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $responseMock;
+    private $eventManagerMock;
 
     /**
      * @var \Magento\Framework\Message\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $messageManagerMock;
+    private $messageManagerMock;
 
     /**
      * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
      */
-    protected $objectManager;
+    private $objectManager;
 
     /**
      * @var \Magento\Catalog\Controller\Adminhtml\Category\Save
      */
-    protected $save;
+    private $save;
 
     /**
      * Set up
@@ -84,24 +66,7 @@ class SaveTest extends \PHPUnit_Framework_TestCase
      */
     protected function setUp()
     {
-        $this->markTestSkipped('Due to MAGETWO-48956');
         $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-
-        $this->contextMock = $this->getMock(
-            \Magento\Backend\App\Action\Context::class,
-            [
-                'getTitle',
-                'getRequest',
-                'getObjectManager',
-                'getEventManager',
-                'getResponse',
-                'getMessageManager',
-                'getResultRedirectFactory'
-            ],
-            [],
-            '',
-            false
-        );
         $this->resultRedirectFactoryMock = $this->getMock(
             \Magento\Backend\Model\View\Result\RedirectFactory::class,
             ['create'],
@@ -109,13 +74,6 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $this->resultRawFactoryMock = $this->getMock(
-            \Magento\Framework\Controller\Result\RawFactory::class,
-            [],
-            [],
-            '',
-            false
-        );
         $this->resultJsonFactoryMock = $this->getMock(
             \Magento\Framework\Controller\Result\JsonFactory::class,
             ['create'],
@@ -151,12 +109,6 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             true,
             ['dispatch']
         );
-        $this->responseMock = $this->getMockForAbstractClass(
-            \Magento\Framework\App\ResponseInterface::class,
-            [],
-            '',
-            false
-        );
         $this->messageManagerMock = $this->getMockForAbstractClass(
             \Magento\Framework\Message\ManagerInterface::class,
             [],
@@ -167,23 +119,15 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ['addSuccess', 'getMessages']
         );
 
-        $this->contextMock->expects($this->any())->method('getTitle')->willReturn($this->titleMock);
-        $this->contextMock->expects($this->any())->method('getRequest')->willReturn($this->requestMock);
-        $this->contextMock->expects($this->any())->method('getObjectManager')->willReturn($this->objectManagerMock);
-        $this->contextMock->expects($this->any())->method('getEventManager')->willReturn($this->eventManagerMock);
-        $this->contextMock->expects($this->any())->method('getResponse')->willReturn($this->responseMock);
-        $this->contextMock->expects($this->any())->method('getMessageManager')->willReturn($this->messageManagerMock);
-        $this->contextMock->expects($this->any())
-            ->method('getResultRedirectFactory')
-            ->willReturn($this->resultRedirectFactoryMock);
-
         $this->save = $this->objectManager->getObject(
             \Magento\Catalog\Controller\Adminhtml\Category\Save::class,
             [
-                'context' => $this->contextMock,
-                'resultRawFactory' => $this->resultRawFactoryMock,
+                'request' => $this->requestMock,
+                'eventManager' => $this->eventManagerMock,
+                'messageManager' => $this->messageManagerMock,
                 'resultJsonFactory' => $this->resultJsonFactoryMock,
-                'layoutFactory' => $this->layoutFactoryMock
+                'layoutFactory' => $this->layoutFactoryMock,
+                'resultRedirectFactory' => $this->resultRedirectFactoryMock
             ]
         );
     }
@@ -201,6 +145,8 @@ class SaveTest extends \PHPUnit_Framework_TestCase
      */
     public function testExecute($categoryId, $storeId, $parentId)
     {
+        $this->markTestSkipped('Due to MAGETWO-48956');
+
         $rootCategoryId = \Magento\Catalog\Model\Category::TREE_ROOT_ID;
         $products = [['any_product']];
         $postData = [
@@ -577,4 +523,95 @@ class SaveTest extends \PHPUnit_Framework_TestCase
             ]
         ];
     }
+
+    /**
+     * @return array
+     */
+    public function imagePreprocessingDataProvider()
+    {
+        return [
+            [['attribute1' => null, 'attribute2' => 123]],
+            [['attribute2' => 123]]
+        ];
+    }
+
+    /**
+     * @dataProvider imagePreprocessingDataProvider
+     *
+     * @param array $data
+     */
+    public function testImagePreprocessingWithoutValue($data)
+    {
+        $eavConfig = $this->getMock(\Magento\Eav\Model\Config::class, ['getEntityType'], [], '', false);
+
+        $imageBackendModel = $this->objectManager->getObject(
+            \Magento\Catalog\Model\Category\Attribute\Backend\Image::class
+        );
+
+        $collection = new \Magento\Framework\DataObject(['attribute_collection' => [
+            new \Magento\Framework\DataObject([
+                'attribute_code' => 'attribute1',
+                'backend' => $imageBackendModel
+            ]),
+            new \Magento\Framework\DataObject([
+                'attribute_code' => 'attribute2',
+                'backend' => new \Magento\Framework\DataObject()
+            ])
+        ]]);
+
+        $eavConfig->expects($this->once())
+            ->method('getEntityType')
+            ->with(\Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE)
+            ->will($this->returnValue($collection));
+
+        $model = $this->objectManager->getObject(\Magento\Catalog\Controller\Adminhtml\Category\Save::class, [
+            'eavConfig' => $eavConfig
+        ]);
+
+        $result = $model->imagePreprocessing($data);
+
+        $this->assertEquals([
+            'attribute1' => false,
+            'attribute2' => 123
+        ], $result);
+    }
+
+    public function testImagePreprocessingWithValue()
+    {
+        $eavConfig = $this->getMock(\Magento\Eav\Model\Config::class, ['getEntityType'], [], '', false);
+
+        $imageBackendModel = $this->objectManager->getObject(
+            \Magento\Catalog\Model\Category\Attribute\Backend\Image::class
+        );
+
+        $collection = new \Magento\Framework\DataObject(['attribute_collection' => [
+            new \Magento\Framework\DataObject([
+                'attribute_code' => 'attribute1',
+                'backend' => $imageBackendModel
+            ]),
+            new \Magento\Framework\DataObject([
+                'attribute_code' => 'attribute2',
+                'backend' => new \Magento\Framework\DataObject()
+            ])
+        ]]);
+
+        $eavConfig->expects($this->once())
+            ->method('getEntityType')
+            ->with(\Magento\Catalog\Api\Data\CategoryAttributeInterface::ENTITY_TYPE_CODE)
+            ->will($this->returnValue($collection));
+
+        $model = $this->objectManager->getObject(Model::class, [
+            'eavConfig' => $eavConfig
+        ]);
+
+        $result = $model->imagePreprocessing([
+            'attribute1' => 'somevalue',
+            'attribute2' => null
+        ]);
+
+        $this->assertEquals([
+            'attribute1' => 'somevalue',
+            'attribute2' => null
+        ], $result);
+    }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php
index a4218e92b3486db76afc61254553b914610d99c3..c67ed25d9c6665901beaeae6d7c2835b3bb20bc1 100644
--- a/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Controller/Adminhtml/Product/Initialization/HelperTest.php
@@ -5,18 +5,14 @@
  */
 namespace Magento\Catalog\Test\Unit\Controller\Adminhtml\Product\Initialization;
 
-use Magento\Catalog\Api\Data\ProductLinkInterfaceFactory;
 use Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper;
 use Magento\Catalog\Controller\Adminhtml\Product\Initialization\StockDataFilter;
 use Magento\Catalog\Model\Product;
 use Magento\Catalog\Model\Product\Option;
-use Magento\Catalog\Model\ProductRepository;
 use Magento\Framework\App\RequestInterface;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
-use Magento\Store\Api\Data\StoreInterface;
 use Magento\Store\Api\Data\WebsiteInterface;
 use Magento\Store\Model\StoreManagerInterface;
-use Magento\Framework\Stdlib\DateTime\Filter\Date as DateFilter;
 use Magento\Catalog\Api\Data\ProductCustomOptionInterfaceFactory;
 use Magento\Catalog\Model\Product\Initialization\Helper\ProductLinks;
 
@@ -34,11 +30,6 @@ class HelperTest extends \PHPUnit_Framework_TestCase
      */
     protected $objectManager;
 
-    /**
-     * @var int
-     */
-    protected $websiteId = 1;
-
     /**
      * @var Helper
      */
@@ -64,106 +55,54 @@ class HelperTest extends \PHPUnit_Framework_TestCase
      */
     protected $productMock;
 
-    /**
-     * @var StoreInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $storeMock;
-
-    /**
-     * @var WebsiteInterface|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $websiteMock;
-
-    /**
-     * @var DateFilter|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $dateFilterMock;
-
-    /**
-     * @var ProductLinkInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $productLinkFactoryMock;
-
-    /**
-     * @var ProductRepository|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $productRepositoryMock;
-
     /**
      * @var ProductCustomOptionInterfaceFactory|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $customOptionFactoryMock;
 
     /**
-     * @var Option|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $customOptionMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Catalog\Model\Product\Link\Resolver|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $linkResolverMock;
 
     /**
-     * @var ProductLinks
+     * @var ProductLinks|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $productLinksMock;
 
     protected function setUp()
     {
         $this->objectManager = new ObjectManager($this);
-        $this->productLinkFactoryMock = $this->getMockBuilder(ProductLinkInterfaceFactory::class)
-            ->disableOriginalConstructor()
-            ->getMock();
-        $this->productRepositoryMock = $this->getMockBuilder(ProductRepository::class)
-            ->disableOriginalConstructor()
-            ->getMock();
         $this->requestMock = $this->getMockBuilder(RequestInterface::class)
             ->setMethods(['getPost'])
             ->getMockForAbstractClass();
-        $this->storeMock = $this->getMockBuilder(StoreInterface::class)
-            ->setMethods(['getWebsite'])
-            ->getMockForAbstractClass();
-        $this->websiteMock = $this->getMockBuilder(WebsiteInterface::class)
-            ->getMockForAbstractClass();
         $this->storeManagerMock = $this->getMockBuilder(StoreManagerInterface::class)
             ->getMockForAbstractClass();
-        $this->dateFilterMock = $this->getMockBuilder(DateFilter::class)
-            ->disableOriginalConstructor()
-            ->getMock();
         $this->stockFilterMock = $this->getMockBuilder(StockDataFilter::class)
             ->disableOriginalConstructor()
             ->getMock();
         $this->productMock = $this->getMockBuilder(Product::class)
-            ->setMethods([
-                'getId',
-                'setWebsiteIds',
-                'isLockedAttribute',
-                'lockAttribute',
-                'getAttributes',
-                'unlockAttribute',
-                'getOptionsReadOnly',
-                'setCanSaveCustomOptions',
-                '__sleep',
-                '__wakeup',
-                'getSku',
-                'getProductLinks',
-                'getWebsiteIds'
-            ])
+            ->setMethods(
+                [
+                    'getId',
+                    'isLockedAttribute',
+                    'lockAttribute',
+                    'getAttributes',
+                    'unlockAttribute',
+                    'getOptionsReadOnly',
+                    'getSku',
+                    'getProductLinks',
+                ]
+            )
             ->disableOriginalConstructor()
-            ->getMock();
+            ->getMockForAbstractClass();
         $this->customOptionFactoryMock = $this->getMockBuilder(ProductCustomOptionInterfaceFactory::class)
             ->disableOriginalConstructor()
             ->setMethods(['create'])
             ->getMock();
-        $this->customOptionMock = $this->getMockBuilder(Option::class)
-            ->disableOriginalConstructor()
-            ->setMethods(null)
-            ->getMock();
         $this->productLinksMock = $this->getMockBuilder(ProductLinks::class)
             ->disableOriginalConstructor()
             ->getMock();
-
         $this->productLinksMock->expects($this->any())
             ->method('initializeLinks')
             ->willReturn($this->productMock);
@@ -173,10 +112,7 @@ class HelperTest extends \PHPUnit_Framework_TestCase
             'storeManager' => $this->storeManagerMock,
             'stockFilter' => $this->stockFilterMock,
             'productLinks' => $this->productLinksMock,
-            'dateFilter' => $this->dateFilterMock,
             'customOptionFactory' => $this->customOptionFactoryMock,
-            'productLinkFactory' => $this->productLinkFactoryMock,
-            'productRepository' => $this->productRepositoryMock,
         ]);
 
         $this->linkResolverMock = $this->getMockBuilder(\Magento\Catalog\Model\Product\Link\Resolver::class)
@@ -190,9 +126,13 @@ class HelperTest extends \PHPUnit_Framework_TestCase
 
     /**
      * @covers \Magento\Catalog\Controller\Adminhtml\Product\Initialization\Helper::initialize
-     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @param bool $isSingleStore
+     * @param array $websiteIds
+     * @param array $expWebsiteIds
+     *
+     * @dataProvider initializeDataProvider
      */
-    public function testInitialize()
+    public function testInitialize($isSingleStore, $websiteIds, $expWebsiteIds)
     {
         $optionsData = [
             'option1' => ['is_delete' => true, 'name' => 'name1', 'price' => 'price1', 'option_id' => ''],
@@ -202,6 +142,7 @@ class HelperTest extends \PHPUnit_Framework_TestCase
         $productData = [
             'stock_data' => ['stock_data'],
             'options' => $optionsData,
+            'website_ids' => $websiteIds
         ];
         $attributeNonDate = $this->getMockBuilder(\Magento\Catalog\Model\ResourceModel\Eav\Attribute::class)
             ->disableOriginalConstructor()
@@ -218,69 +159,39 @@ class HelperTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $attributeNonDate->expects($this->any())
-            ->method('getBackend')
-            ->willReturn($attributeNonDateBackEnd);
-        $attributeDate->expects($this->any())
-            ->method('getBackend')
-            ->willReturn($attributeDateBackEnd);
-        $this->productMock->expects($this->any())
-            ->method('getProductLinks')
-            ->willReturn([]);
-        $attributeNonDateBackEnd->expects($this->any())
-            ->method('getType')
-            ->willReturn('non-datetime');
-        $attributeDateBackEnd->expects($this->any())
-            ->method('getType')
-            ->willReturn('datetime');
-
-        $attributesArray = [
-            $attributeNonDate,
-            $attributeDate
-        ];
+        $attributeNonDate->expects($this->any())->method('getBackend')->willReturn($attributeNonDateBackEnd);
+        $attributeDate->expects($this->any())->method('getBackend')->willReturn($attributeDateBackEnd);
+        $this->productMock->expects($this->any())->method('getProductLinks')->willReturn([]);
+        $attributeNonDateBackEnd->expects($this->any())->method('getType')->willReturn('non-datetime');
+        $attributeDateBackEnd->expects($this->any())->method('getType')->willReturn('datetime');
 
         $useDefaults = ['attributeCode1', 'attributeCode2'];
 
-        $this->requestMock->expects($this->at(0))
-            ->method('getPost')
-            ->with('product')
-            ->willReturn($productData);
-        $this->requestMock->expects($this->at(1))
-            ->method('getPost')
-            ->with('use_default')
-            ->willReturn($useDefaults);
+        $this->requestMock->expects($this->any())->method('getPost')->willReturnMap(
+            [
+                ['product', [], $productData],
+                ['use_default', null, $useDefaults]
+            ]
+        );
         $this->linkResolverMock->expects($this->once())->method('getLinks')->willReturn([]);
-        $this->stockFilterMock->expects($this->once())
-            ->method('filter')
-            ->with(['stock_data'])
+        $this->stockFilterMock->expects($this->once())->method('filter')->with(['stock_data'])
             ->willReturn(['stock_data']);
-        $this->productMock->expects($this->once())
-            ->method('isLockedAttribute')
-            ->with('media')
-            ->willReturn(true);
-        $this->productMock->expects($this->once())
-            ->method('unlockAttribute')
-            ->with('media');
-        $this->productMock->expects($this->any())
-            ->method('getProductLinks')
-            ->willReturn([]);
-        $this->productMock->expects($this->once())
-            ->method('lockAttribute')
-            ->with('media');
-        $this->productMock->expects($this->once())
-            ->method('getAttributes')
-            ->willReturn($attributesArray);
-
-        $this->productMock->expects($this->any())
-            ->method('getSku')
-            ->willReturn('sku');
-        $this->productMock->expects($this->any())
-            ->method('getOptionsReadOnly')
-            ->willReturn(false);
-
-        $firstExpectedCustomOption = clone $this->customOptionMock;
+        $this->productMock->expects($this->once())->method('isLockedAttribute')->with('media')->willReturn(true);
+        $this->productMock->expects($this->once())->method('unlockAttribute')->with('media');
+        $this->productMock->expects($this->any())->method('getProductLinks')->willReturn([]);
+        $this->productMock->expects($this->once())->method('lockAttribute')->with('media');
+        $this->productMock->expects($this->once())->method('getAttributes')
+            ->willReturn([$attributeNonDate, $attributeDate]);
+        $this->productMock->expects($this->any())->method('getSku')->willReturn('sku');
+        $this->productMock->expects($this->any())->method('getOptionsReadOnly')->willReturn(false);
+
+        $customOptionMock = $this->getMockBuilder(Option::class)
+            ->disableOriginalConstructor()
+            ->setMethods(null)
+            ->getMock();
+        $firstExpectedCustomOption = clone $customOptionMock;
         $firstExpectedCustomOption->setData($optionsData['option2']);
-        $secondExpectedCustomOption = clone $this->customOptionMock;
+        $secondExpectedCustomOption = clone $customOptionMock;
         $secondExpectedCustomOption->setData($optionsData['option3']);
         $this->customOptionFactoryMock->expects($this->any())
             ->method('create')
@@ -293,8 +204,13 @@ class HelperTest extends \PHPUnit_Framework_TestCase
                     $secondExpectedCustomOption
                 ]
             ]);
+        $website = $this->getMockBuilder(WebsiteInterface::class)->getMockForAbstractClass();
+        $website->expects($this->any())->method('getId')->willReturn(1);
+        $this->storeManagerMock->expects($this->once())->method('isSingleStoreMode')->willReturn($isSingleStore);
+        $this->storeManagerMock->expects($this->any())->method('getWebsite')->willReturn($website);
 
         $this->assertEquals($this->productMock, $this->helper->initialize($this->productMock));
+        $this->assertEquals($expWebsiteIds, $this->productMock->getDataByKey('website_ids'));
 
         $productOptions = $this->productMock->getOptions();
         $this->assertTrue(2 == count($productOptions));
@@ -305,6 +221,35 @@ class HelperTest extends \PHPUnit_Framework_TestCase
         $this->assertTrue('sku' == $option2->getData('product_sku'));
     }
 
+    /**
+     * @return array
+     */
+    public function initializeDataProvider()
+    {
+        return [
+            [
+                'single_store' => false,
+                'website_ids' => ['1' => 1, '2' => 1],
+                'expected_website_ids' => ['1' => 1, '2' => 1]
+            ],
+            [
+                'single_store' => false,
+                'website_ids' => ['1' => 1, '2' => 0],
+                'expected_website_ids' => ['1' => 1]
+            ],
+            [
+                'single_store' => false,
+                'website_ids' => ['1' => 0, '2' => 0],
+                'expected_website_ids' => []
+            ],
+            [
+                'single_store' => true,
+                'website_ids' => [],
+                'expected_website_ids' => ['1' => 1]
+            ],
+        ];
+    }
+
     /**
      * Data provider for testMergeProductOptions
      *
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..aa78fea89668773a2864741526d07c3e76aae1d1
--- /dev/null
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Category/Attribute/Backend/ImageTest.php
@@ -0,0 +1,293 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Catalog\Test\Unit\Model\Category\Attribute\Backend;
+
+class ImageTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Eav\Model\Entity\Attribute\AbstractAttribute
+     */
+    private $attribute;
+
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Catalog\Model\ImageUploader
+     */
+    private $imageUploader;
+
+    /**
+     * @var \Psr\Log\LoggerInterface
+     */
+    private $logger;
+
+    protected function setUp()
+    {
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->attribute = $this->getMockForAbstractClass(
+            \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class,
+            [],
+            'TestAttribute',
+            false,
+            false,
+            true,
+            ['getName']
+        );
+
+        $this->attribute->expects($this->once())
+            ->method('getName')
+            ->will($this->returnValue('test_attribute'));
+
+        $this->logger = $this->getMockForAbstractClass(
+            \Psr\Log\LoggerInterface::class,
+            [],
+            'TestLogger',
+            false,
+            false,
+            true,
+            ['critical']
+        );
+
+        $this->imageUploader = $this->getMock(
+            \Magento\Catalog\Model\ImageUploader::class,
+            ['moveFileFromTmp'],
+            [],
+            '',
+            false
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function deletedValueDataProvider()
+    {
+        return [
+            [false],
+            [['delete' => true]]
+        ];
+    }
+
+    /**
+     * @dataProvider deletedValueDataProvider
+     *
+     * @param array $value
+     */
+    public function testBeforeSaveValueDeletion($value)
+    {
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class);
+        $model->setAttribute($this->attribute);
+
+        $object = new \Magento\Framework\DataObject([
+            'test_attribute' => $value
+        ]);
+
+        $model->beforeSave($object);
+
+        $this->assertEquals('', $object->getTestAttribute());
+    }
+
+    /**
+     * @return array
+     */
+    public function invalidValueDataProvider()
+    {
+        $closure = function () {
+            return false;
+        };
+
+        return [
+            [1234],
+            [true],
+            [new \stdClass()],
+            [$closure],
+            [['a' => 1, 'b' => 2]]
+        ];
+    }
+
+    /**
+     * @dataProvider invalidValueDataProvider
+     *
+     * @param array $value
+     */
+    public function testBeforeSaveValueInvalid($value)
+    {
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class);
+        $model->setAttribute($this->attribute);
+
+        $object = new \Magento\Framework\DataObject([
+            'test_attribute' => $value
+        ]);
+
+        $model->beforeSave($object);
+
+        $this->assertEquals('', $object->getTestAttribute());
+    }
+
+    public function testBeforeSaveAttributeFileName()
+    {
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class);
+        $model->setAttribute($this->attribute);
+
+        $object = new \Magento\Framework\DataObject([
+            'test_attribute' => [
+                ['name' => 'test123.jpg']
+            ]
+        ]);
+
+        $model->beforeSave($object);
+
+        $this->assertEquals('test123.jpg', $object->getTestAttribute());
+    }
+
+    public function testBeforeSaveTemporaryAttribute()
+    {
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class);
+        $model->setAttribute($this->attribute);
+
+        $object = new \Magento\Framework\DataObject([
+            'test_attribute' => [
+                ['name' => 'test123.jpg', 'tmp_name' => 'abc123', 'url' => 'http://www.example.com/test123.jpg']
+            ]
+        ]);
+
+        $model->beforeSave($object);
+
+        $this->assertEquals([
+            ['name' => 'test123.jpg', 'tmp_name' => 'abc123', 'url' => 'http://www.example.com/test123.jpg']
+        ], $object->getData('_additional_data_test_attribute'));
+    }
+
+    public function testBeforeSaveAttributeStringValue()
+    {
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class);
+        $model->setAttribute($this->attribute);
+
+        $object = new \Magento\Framework\DataObject([
+            'test_attribute' => 'test123.jpg'
+        ]);
+
+        $model->beforeSave($object);
+
+        $this->assertEquals('test123.jpg', $object->getTestAttribute());
+        $this->assertNull($object->getData('_additional_data_test_attribute'));
+    }
+
+    /**
+     * @return \Magento\Catalog\Model\Category\Attribute\Backend\Image
+     */
+    private function setUpModelForAfterSave()
+    {
+        $objectManagerMock = $this->getMock(
+            \Magento\Framework\App\ObjectManager::class,
+            ['get'],
+            [],
+            '',
+            false
+        );
+
+        $imageUploaderMock = $this->imageUploader;
+
+        $objectManagerMock->expects($this->any())
+            ->method('get')
+            ->will($this->returnCallback(function ($class, $params = []) use ($imageUploaderMock) {
+                if ($class == \Magento\Catalog\CategoryImageUpload::class) {
+                    return $imageUploaderMock;
+                }
+
+                return $this->objectManager->get($class, $params);
+            }));
+
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category\Attribute\Backend\Image::class, [
+            'objectManager' => $objectManagerMock,
+            'logger' => $this->logger
+        ]);
+        $this->objectManager->setBackwardCompatibleProperty($model, 'imageUploader', $this->imageUploader);
+
+        return $model->setAttribute($this->attribute);
+    }
+
+    public function attributeValueDataProvider()
+    {
+        return [
+            [[['name' => 'test1234.jpg']]],
+            ['test1234.jpg'],
+            [''],
+            [false]
+        ];
+    }
+
+    /**
+     * @dataProvider attributeValueDataProvider
+     *
+     * @param array $value
+     */
+    public function testAfterSaveWithAdditionalData($value)
+    {
+        $model = $this->setUpModelForAfterSave();
+
+        $this->imageUploader->expects($this->once())
+            ->method('moveFileFromTmp')
+            ->with($this->equalTo('test1234.jpg'));
+
+        $object = new \Magento\Framework\DataObject(
+            [
+                'test_attribute' => $value,
+                '_additional_data_test_attribute' => [['name' => 'test1234.jpg']]
+            ]
+        );
+
+        $model->afterSave($object);
+    }
+
+    /**
+     * @dataProvider attributeValueDataProvider
+     *
+     * @param array $value
+     */
+    public function testAfterSaveWithoutAdditionalData($value)
+    {
+        $model = $this->setUpModelForAfterSave();
+
+        $this->imageUploader->expects($this->never())
+            ->method('moveFileFromTmp');
+
+        $object = new \Magento\Framework\DataObject(
+            [
+                'test_attribute' => $value
+            ]
+        );
+
+        $model->afterSave($object);
+    }
+
+    public function testAfterSaveWithExceptions()
+    {
+        $model = $this->setUpModelForAfterSave();
+
+        $exception = new \Exception();
+
+        $this->imageUploader->expects($this->any())
+            ->method('moveFileFromTmp')
+            ->will($this->throwException($exception));
+
+        $this->logger->expects($this->once())
+            ->method('critical')
+            ->with($this->equalTo($exception));
+
+        $object = new \Magento\Framework\DataObject(
+            [
+                '_additional_data_test_attribute' => [['name' => 'test1234.jpg']]
+            ]
+        );
+
+        $model->afterSave($object);
+    }
+}
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php
index 471037f1d3f450c1b2281e06f823222e7f7e28b6..37d0751a81bc06cfb4672874fff20dfefab6cb72 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/CategoryTest.php
@@ -9,6 +9,7 @@
 namespace Magento\Catalog\Test\Unit\Model;
 
 use Magento\Catalog\Model\Indexer;
+use Magento\Catalog\Model\Category;
 
 /**
  * @SuppressWarnings(PHPMD.TooManyFields)
@@ -16,113 +17,131 @@ use Magento\Catalog\Model\Indexer;
  */
 class CategoryTest extends \PHPUnit_Framework_TestCase
 {
-    /** @var \Magento\Catalog\Model\Category */
-    protected $category;
-
-    /** @var \Magento\Framework\Model\Context|\PHPUnit_Framework_MockObject_MockObject */
-    protected $context;
-
-    /** @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $eventManager;
+    /**
+     * @var \Magento\Catalog\Model\Category
+     */
+    private $category;
 
-    /** @var \Magento\Framework\App\CacheInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $cacheManager;
+    /**
+     * @var \Magento\Framework\Registry|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $registry;
 
-    /** @var \Magento\Framework\Registry|\PHPUnit_Framework_MockObject_MockObject */
-    protected $registry;
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeManager;
 
-    /** @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $storeManager;
+    /**
+     * @var \Magento\Catalog\Model\ResourceModel\Category\Tree|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $categoryTreeResource;
 
-    /** @var \Magento\Catalog\Model\ResourceModel\Category\Tree|\PHPUnit_Framework_MockObject_MockObject */
-    protected $categoryTreeResource;
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $categoryTreeFactory;
 
-    /** @var \PHPUnit_Framework_MockObject_MockObject */
-    protected $categoryTreeFactory;
+    /**
+     * @var \Magento\Catalog\Api\CategoryRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $categoryRepository;
 
-    /** @var \Magento\Catalog\Api\CategoryRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $categoryRepository;
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeCollectionFactory;
 
-    /** @var \PHPUnit_Framework_MockObject_MockObject */
-    protected $storeCollectionFactory;
+    /**
+     * @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $url;
 
-    /** @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $url;
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $productCollectionFactory;
 
-    /** @var \PHPUnit_Framework_MockObject_MockObject */
-    protected $productCollectionFactory;
+    /**
+     * @var \Magento\Catalog\Model\Config|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $catalogConfig;
 
-    /** @var \Magento\Catalog\Model\Config|\PHPUnit_Framework_MockObject_MockObject */
-    protected $catalogConfig;
+    /**
+     * @var \Magento\Framework\Filter\FilterManager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filterManager;
 
-    /** @var \Magento\Framework\Filter\FilterManager|\PHPUnit_Framework_MockObject_MockObject */
-    protected $filterManager;
+    /**
+     * @var \Magento\Catalog\Model\Indexer\Category\Flat\State|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $flatState;
 
-    /** @var \Magento\Catalog\Model\Indexer\Category\Flat\State|\PHPUnit_Framework_MockObject_MockObject */
-    protected $flatState;
+    /**
+     * @var \Magento\Framework\Indexer\IndexerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $flatIndexer;
 
-    /** @var \Magento\Framework\Indexer\IndexerInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $flatIndexer;
+    /**
+     * @var \Magento\Framework\Indexer\IndexerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $productIndexer;
 
-    /** @var \Magento\Framework\Indexer\IndexerInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $productIndexer;
+    /**
+     * @var \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $categoryUrlPathGenerator;
 
-    /** @var \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator|\PHPUnit_Framework_MockObject_MockObject */
-    protected $categoryUrlPathGenerator;
+    /**
+     * @var \Magento\UrlRewrite\Model\UrlFinderInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $urlFinder;
 
-    /** @var \Magento\UrlRewrite\Model\UrlFinderInterface|\PHPUnit_Framework_MockObject_MockObject */
-    protected $urlFinder;
+    /**
+     * @var \Magento\Framework\Model\ResourceModel\AbstractResource|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resource;
 
-    /** @var \Magento\Framework\Model\ResourceModel\AbstractResource|\PHPUnit_Framework_MockObject_MockObject */
-    protected $resource;
+    /**
+     * @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $indexerRegistry;
 
-    /** @var \Magento\Framework\Indexer\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject */
-    protected $indexerRegistry;
+    /**
+     * @var \Magento\Catalog\Api\CategoryAttributeRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $metadataServiceMock;
 
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
-    protected $metadataServiceMock;
+    private $attributeValueFactory;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
      */
-    protected $attributeValueFactory;
+    private $objectManager;
 
     protected function setUp()
     {
-        $this->context = $this->getMock(
-            \Magento\Framework\Model\Context::class,
-            ['getEventDispatcher', 'getCacheManager'],
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->registry = $this->getMock(\Magento\Framework\Registry::class);
+        $this->storeManager = $this->getMock(\Magento\Store\Model\StoreManagerInterface::class);
+        $this->categoryTreeResource = $this->getMock(
+            \Magento\Catalog\Model\ResourceModel\Category\Tree::class,
+            [],
             [],
             '',
             false
         );
-
-        $this->eventManager = $this->getMock(\Magento\Framework\Event\ManagerInterface::class);
-        $this->context->expects($this->any())->method('getEventDispatcher')
-            ->will($this->returnValue($this->eventManager));
-        $this->cacheManager = $this->getMock(\Magento\Framework\App\CacheInterface::class);
-        $this->context->expects($this->any())->method('getCacheManager')
-            ->will($this->returnValue($this->cacheManager));
-
-        $this->registry = $this->getMock(\Magento\Framework\Registry::class);
-        $this->storeManager = $this->getMock(\Magento\Store\Model\StoreManagerInterface::class);
-        $this->categoryTreeResource = $this->getMock(
-            \Magento\Catalog\Model\ResourceModel\Category\Tree::class,
-            [],
-            [],
-            '',
-            false
-        );
-        $this->categoryTreeFactory = $this->getMock(
+        $this->categoryTreeFactory = $this->getMock(
             \Magento\Catalog\Model\ResourceModel\Category\TreeFactory::class,
             ['create'],
             [],
             '',
             false);
         $this->categoryRepository = $this->getMock(\Magento\Catalog\Api\CategoryRepositoryInterface::class);
-        $this->storeCollectionFactory = $this->getMock(
+        $this->storeCollectionFactory = $this->getMock(
             \Magento\Store\Model\ResourceModel\Store\CollectionFactory::class,
             ['create'],
             [],
@@ -130,7 +149,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->url = $this->getMock(\Magento\Framework\UrlInterface::class);
-        $this->productCollectionFactory = $this->getMock(
+        $this->productCollectionFactory = $this->getMock(
             \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory::class,
             ['create'],
             [],
@@ -138,7 +157,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->catalogConfig = $this->getMock(\Magento\Catalog\Model\Config::class, [], [], '', false);
-        $this->filterManager = $this->getMock(
+        $this->filterManager = $this->getMock(
             \Magento\Framework\Filter\FilterManager::class,
             ['translitUrl'],
             [],
@@ -148,7 +167,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
         $this->flatState = $this->getMock(\Magento\Catalog\Model\Indexer\Category\Flat\State::class, [], [], '', false);
         $this->flatIndexer = $this->getMock(\Magento\Framework\Indexer\IndexerInterface::class);
         $this->productIndexer = $this->getMock(\Magento\Framework\Indexer\IndexerInterface::class);
-        $this->categoryUrlPathGenerator = $this->getMock(
+        $this->categoryUrlPathGenerator = $this->getMock(
             \Magento\CatalogUrlRewrite\Model\CategoryUrlPathGenerator::class,
             [],
             [],
@@ -156,19 +175,19 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->urlFinder = $this->getMock(\Magento\UrlRewrite\Model\UrlFinderInterface::class);
-        $this->resource = $this->getMock(
+        $this->resource = $this->getMock(
             \Magento\Catalog\Model\ResourceModel\Category::class,
             [],
             [],
             '',
             false
         );
-        $this->indexerRegistry = $this->getMock(
-            \Magento\Framework\Indexer\IndexerRegistry::class,
-            ['get'],
-            [],
-            '',
-            false
+        $this->indexerRegistry = $this->getMock(
+            \Magento\Framework\Indexer\IndexerRegistry::class,
+            ['get'],
+            [],
+            '',
+            false
         );
 
         $this->metadataServiceMock = $this->getMock(\Magento\Catalog\Api\CategoryAttributeRepositoryInterface::class);
@@ -198,7 +217,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
     public function testMoveWhenCannotFindParentCategory()
     {
         $this->markTestIncomplete('MAGETWO-31165');
-        $parentCategory = $this->getMock(
+        $parentCategory = $this->getMock(
             \Magento\Catalog\Model\Category::class,
             ['getId', 'setStoreId', 'load'],
             [],
@@ -223,7 +242,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
      */
     public function testMoveWhenCannotFindNewCategory()
     {
-        $parentCategory = $this->getMock(
+        $parentCategory = $this->getMock(
             \Magento\Catalog\Model\Category::class,
             ['getId', 'setStoreId', 'load'],
             [],
@@ -250,7 +269,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
     public function testMoveWhenParentCategoryIsSameAsChildCategory()
     {
         $this->markTestIncomplete('MAGETWO-31165');
-        $parentCategory = $this->getMock(
+        $parentCategory = $this->getMock(
             \Magento\Catalog\Model\Category::class,
             ['getId', 'setStoreId', 'load'],
             [],
@@ -277,7 +296,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             ->method('get')
             ->with('catalog_category_product')
             ->will($this->returnValue($indexer));
-        $parentCategory = $this->getMock(
+        $parentCategory = $this->getMock(
             \Magento\Catalog\Model\Category::class,
             ['getId', 'setStoreId', 'load'],
             [],
@@ -313,10 +332,9 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
 
     protected function getCategoryModel()
     {
-        return (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject(
+        return $this->objectManager->getObject(
             \Magento\Catalog\Model\Category::class,
             [
-                'context' => $this->context,
                 'registry' => $this->registry,
                 'storeManager' => $this->storeManager,
                 'categoryTreeResource' => $this->categoryTreeResource,
@@ -487,4 +505,76 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             $this->category->getCustomAttribute($descriptionAttributeCode)->getValue()
         );
     }
+
+    /**
+     * @return array
+     */
+    public function getImageWithAttributeCodeDataProvider()
+    {
+        return [
+            ['testimage', 'http://www.example.com/catalog/category/testimage'],
+            [false, false]
+        ];
+    }
+
+    /**
+     * @param string|bool $value
+     * @param string|bool $url
+     *
+     * @dataProvider getImageWithAttributeCodeDataProvider
+     */
+    public function testGetImageWithAttributeCode($value, $url)
+    {
+        $storeManager = $this->getMock(\Magento\Store\Model\StoreManager::class, ['getStore'], [], '', false);
+        $store = $this->getMock(\Magento\Store\Model\Store::class, ['getBaseUrl'], [], '', false);
+
+        $storeManager->expects($this->any())
+            ->method('getStore')
+            ->will($this->returnValue($store));
+
+        $store->expects($this->any())
+            ->method('getBaseUrl')
+            ->with(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA)
+            ->will($this->returnValue('http://www.example.com/'));
+
+        /** @var \Magento\Catalog\Model\Category $model */
+        $model = $this->objectManager->getObject(
+            \Magento\Catalog\Model\Category::class,
+            [
+                'storeManager' => $storeManager
+            ]
+        );
+
+        $model->setData('attribute1', $value);
+
+        $result = $model->getImageUrl('attribute1');
+
+        $this->assertEquals($url, $result);
+    }
+
+    public function testGetImageWithoutAttributeCode()
+    {
+        $storeManager = $this->getMock(\Magento\Store\Model\StoreManager::class, ['getStore'], [], '', false);
+        $store = $this->getMock(\Magento\Store\Model\Store::class, ['getBaseUrl'], [], '', false);
+
+        $storeManager->expects($this->any())
+            ->method('getStore')
+            ->will($this->returnValue($store));
+
+        $store->expects($this->any())
+            ->method('getBaseUrl')
+            ->with(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA)
+            ->will($this->returnValue('http://www.example.com/'));
+
+        /** @var \Magento\Catalog\Model\Category $model */
+        $model = $this->objectManager->getObject(\Magento\Catalog\Model\Category::class, [
+            'storeManager' => $storeManager
+        ]);
+
+        $model->setData('image', 'myimage');
+
+        $result = $model->getImageUrl();
+
+        $this->assertEquals('http://www.example.com/catalog/category/myimage', $result);
+    }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php
index 332e775b019b238b9ba1aec83f0f42302aafa68a..b97b7d2f9842355af1195b7b0ce7ed1d4aa7e4e8 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ResourceModel/Product/CollectionTest.php
@@ -30,6 +30,26 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
      */
     protected $collection;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $galleryResourceMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $entityMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $metadataPoolMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $galleryReadHandlerMock;
+
     /**
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
@@ -100,24 +120,49 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
 
-        $entityMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\AbstractEntity::class)
+        $this->entityMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\AbstractEntity::class)
             ->disableOriginalConstructor()
             ->getMock();
 
+        $this->galleryResourceMock = $this->getMockBuilder(
+            \Magento\Catalog\Model\ResourceModel\Product\Gallery::class
+        )->disableOriginalConstructor()->getMock();
+
+        $this->metadataPoolMock = $this->getMockBuilder(
+            \Magento\Framework\EntityManager\MetadataPool::class
+        )->disableOriginalConstructor()->getMock();
+
+        $this->galleryReadHandlerMock = $this->getMockBuilder(
+            \Magento\Catalog\Model\Product\Gallery\ReadHandler::class
+        )->disableOriginalConstructor()->getMock();
+
         $storeManager->expects($this->any())->method('getId')->willReturn(1);
         $storeManager->expects($this->any())->method('getStore')->willReturnSelf();
         $universalFactory->expects($this->exactly(1))->method('create')->willReturnOnConsecutiveCalls(
-            $entityMock
+            $this->entityMock
         );
-        $entityMock->expects($this->once())->method('getConnection')->willReturn($this->connectionMock);
-        $entityMock->expects($this->once())->method('getDefaultAttributes')->willReturn([]);
-        $entityMock->expects($this->any())->method('getTable')->willReturnArgument(0);
+        $this->entityMock->expects($this->once())->method('getConnection')->willReturn($this->connectionMock);
+        $this->entityMock->expects($this->once())->method('getDefaultAttributes')->willReturn([]);
+        $this->entityMock->expects($this->any())->method('getTable')->willReturnArgument(0);
         $this->connectionMock->expects($this->atLeastOnce())->method('select')->willReturn($this->selectMock);
         $helper = new ObjectManager($this);
 
         $this->prepareObjectManager([
-            [\Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class,
+            [
+                \Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class,
                 $this->getMock(\Magento\Catalog\Model\ResourceModel\Product\Collection\ProductLimitation::class)
+            ],
+            [
+                \Magento\Catalog\Model\ResourceModel\Product\Gallery::class,
+                $this->galleryResourceMock
+            ],
+            [
+                \Magento\Framework\EntityManager\MetadataPool::class,
+                $this->metadataPoolMock
+            ],
+            [
+                \Magento\Catalog\Model\Product\Gallery\ReadHandler::class,
+                $this->galleryReadHandlerMock
             ]
         ]);
         $this->collection = $helper->getObject(
@@ -150,8 +195,8 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
 
     public function testAddProductCategoriesFilter()
     {
-        $condition = ['in' => [1,2]];
-        $values = [1,2];
+        $condition = ['in' => [1, 2]];
+        $values = [1, 2];
         $conditionType = 'nin';
         $preparedSql = "category_id IN(1,2)";
         $tableName = "catalog_category_product";
@@ -174,6 +219,47 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
         $this->collection->addCategoriesFilter([$conditionType => $values]);
     }
 
+    public function testAddMediaGalleryData()
+    {
+        $attributeId = 42;
+        $itemId = 4242;
+        $linkField = 'entity_id';
+        $mediaGalleriesMock = [[$linkField => $itemId]];
+        $itemMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $attributeMock = $this->getMockBuilder(\Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $selectMock = $this->getMockBuilder(\Magento\Framework\DB\Select::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $metadataMock = $this->getMockBuilder(\Magento\Framework\EntityManager\EntityMetadataInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->collection->addItem($itemMock);
+        $reflection = new \ReflectionClass(get_class($this->collection));
+        $reflectionProperty = $reflection->getProperty('_isCollectionLoaded');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($this->collection, true);
+
+        $this->galleryResourceMock->expects($this->once())->method('createBatchBaseSelect')->willReturn($selectMock);
+        $attributeMock->expects($this->once())->method('getAttributeId')->willReturn($attributeId);
+        $this->entityMock->expects($this->once())->method('getAttribute')->willReturn($attributeMock);
+        $itemMock->expects($this->atLeastOnce())->method('getId')->willReturn($itemId);
+        $selectMock->expects($this->once())->method('where')->with('entity.' . $linkField . ' IN (?)', [$itemId]);
+        $this->metadataPoolMock->expects($this->once())->method('getMetadata')->willReturn($metadataMock);
+        $metadataMock->expects($this->once())->method('getLinkField')->willReturn($linkField);
+
+        $this->connectionMock->expects($this->once())->method('fetchAll')->with($selectMock)->willReturn(
+            [['entity_id' => $itemId]]
+        );
+        $this->galleryReadHandlerMock->expects($this->once())->method('addMediaDataToProduct')
+            ->with($itemMock, $mediaGalleriesMock);
+
+        $this->assertSame($this->collection, $this->collection->addMediaGalleryData());
+    }
+
     /**
      * @param $map
      */
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html
index f45115181fe4c628c88d3b5a26129629c21415b5..da625c51d4b7734ccc4808fd9161502e15acf1a9 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/billing-address/details.html
@@ -13,6 +13,11 @@
     <!-- ko if: (currentBillingAddress().telephone) -->
     <a data-bind="text: currentBillingAddress().telephone, attr: {'href': 'tel:' + currentBillingAddress().telephone}"></a>
     <!-- /ko --><br/>
+    <!-- ko foreach: { data: currentBillingAddress().customAttributes, as: 'element' } -->
+        <!-- ko foreach: { data: Object.keys(element), as: 'attribute' } -->
+            <!-- ko text: element[attribute].value --><!-- /ko -->
+        <!-- /ko -->
+    <!-- /ko -->
     <button type="button"
             class="action action-edit-address"
             data-bind="visible: !isAddressSameAsShipping(), click: editAddress">
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html
index eeecbf346636613366db1f9d3fa33c4c7835b681..a2b83ead6b354451b99a4a1003a0f04df905dbbc 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-address/address-renderer/default.html
@@ -13,6 +13,11 @@
     <!-- ko if: (address().telephone) -->
     <a data-bind="text: address().telephone, attr: {'href': 'tel:' + address().telephone}"></a>
     <!-- /ko --><br/>
+    <!-- ko foreach: { data: address().customAttributes, as: 'element' } -->
+        <!-- ko foreach: { data: Object.keys(element), as: 'attribute' } -->
+            <!-- ko text: element[attribute].value --><!-- /ko -->
+        <!-- /ko -->
+    <!-- /ko -->
     <!-- ko if: (address().isEditable()) -->
     <button type="button"
             class="action edit-address-link"
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html
index f02eef5ded99ab86bb3a445f7de3355f810e94e8..440a2c7fc468fc493d10eb0cb57320c5593e1bf8 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/shipping-information/address-renderer/default.html
@@ -13,4 +13,9 @@
     <!-- ko if: (address().telephone) -->
     <a data-bind="text: address().telephone, attr: {'href': 'tel:' + address().telephone}"></a>
     <!-- /ko --><br/>
+    <!-- ko foreach: { data: address().customAttributes, as: 'element' } -->
+        <!-- ko foreach: { data: Object.keys(element), as: 'attribute' } -->
+            <!-- ko text: element[attribute].value --><!-- /ko -->
+        <!-- /ko -->
+    <!-- /ko -->
 <!-- /ko -->
diff --git a/app/code/Magento/PageCache/etc/events.xml b/app/code/Magento/PageCache/etc/events.xml
index 7ac67a931c7ac8bbbe3b5e397a7ade7b3a039633..8d88feeab18bca0ef4101933f54335d51eed2129 100644
--- a/app/code/Magento/PageCache/etc/events.xml
+++ b/app/code/Magento/PageCache/etc/events.xml
@@ -48,11 +48,6 @@
     <event name="model_save_commit_after">
         <observer name="flush_cache_after_model_save" instance="Magento\PageCache\Observer\FlushCacheByTags" />
     </event>
-    <event name="controller_action_predispatch">
-        <observer name="register_form_key"
-                  instance="Magento\PageCache\Observer\RegisterFormKeyFromCookie"
-                  />
-    </event>
     <event name="customer_logout">
         <observer name="FlushFormKeyOnLogout" instance="Magento\PageCache\Observer\FlushFormKeyOnLogout"/>
     </event>
diff --git a/app/code/Magento/PageCache/etc/frontend/events.xml b/app/code/Magento/PageCache/etc/frontend/events.xml
new file mode 100644
index 0000000000000000000000000000000000000000..10ef2eee02804fea57163ea4103cede60a01d220
--- /dev/null
+++ b/app/code/Magento/PageCache/etc/frontend/events.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
+    <event name="controller_action_predispatch">
+        <observer name="register_form_key" instance="Magento\PageCache\Observer\RegisterFormKeyFromCookie" />
+    </event>
+</config>
diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js b/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js
index 1805dcd2f004ec91e5d3d1a96d2b0086e4b69e8c..917dc62f9f49b148d58ad62c671eb6fbeeff8beb 100644
--- a/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js
+++ b/app/code/Magento/Ui/view/base/web/js/form/element/file-uploader.js
@@ -294,15 +294,20 @@ define([
         /**
          * Handler which is invoked prior to the start of a file upload.
          *
-         * @param {Event} e - Event obejct.
+         * @param {Event} e - Event object.
          * @param {Object} data - File data that will be uploaded.
          */
         onBeforeFileUpload: function (e, data) {
             var file     = data.files[0],
-                allowed  = this.isFileAllowed(file);
+                allowed  = this.isFileAllowed(file),
+                target   = $(e.target);
 
             if (allowed.passed) {
-                $(e.target).fileupload('process', data).done(function () {
+                target.on('fileuploadsend', function (event, postData) {
+                    postData.data.set('param_name', this.paramName);
+                }.bind(data));
+
+                target.fileupload('process', data).done(function () {
                     data.submit();
                 });
             } else {
diff --git a/app/code/Magento/User/Block/User/Edit.php b/app/code/Magento/User/Block/User/Edit.php
index f6c5b484861de36850d848e0eba2382d9688dade..116acd132a8487dbe56d933f307c40e62327bf6e 100644
--- a/app/code/Magento/User/Block/User/Edit.php
+++ b/app/code/Magento/User/Block/User/Edit.php
@@ -50,7 +50,7 @@ class Edit extends \Magento\Backend\Block\Widget\Form\Container
         $this->buttonList->update('save', 'label', __('Save User'));
         $this->buttonList->remove('delete');
 
-        $objId = $this->getRequest()->getParam($this->_objectId);
+        $objId = (int)$this->getRequest()->getParam($this->_objectId);
 
         if (!empty($objId)) {
             $this->addButton(
@@ -58,12 +58,9 @@ class Edit extends \Magento\Backend\Block\Widget\Form\Container
                 [
                     'label' => __('Delete User'),
                     'class' => 'delete',
-                    'onclick' => sprintf(
-                        'deleteConfirm("%s", "%s", %s)',
-                        __('Are you sure you want to do this?'),
-                        $this->getUrl('adminhtml/*/delete'),
-                        json_encode(['data' => ['user_id' => $objId]])
-                    ),
+                    'data_attribute' => [
+                        'role' => 'delete-user'
+                    ]
                 ]
             );
 
@@ -79,6 +76,44 @@ class Edit extends \Magento\Backend\Block\Widget\Form\Container
         }
     }
 
+    /**
+     * Returns message that is displayed for admin when he deletes user from the system.
+     * To see this message admin must do the following:
+     * - open user's account for editing;
+     * - type current user's password in the "Current User Identity Verification" field
+     * - click "Delete User" at top left part of the page;
+     *
+     * @return \Magento\Framework\Phrase
+     */
+    public function getDeleteMessage()
+    {
+        return __('Are you sure you want to do this?');
+    }
+
+    /**
+     * Returns the URL that is used for user deletion.
+     * The following Action is executed if admin navigates to returned url
+     * Magento\User\Controller\Adminhtml\User\Delete
+     *
+     * @return string
+     */
+    public function getDeleteUrl()
+    {
+        return $this->getUrl('adminhtml/*/delete');
+    }
+
+    /**
+     * This method is used to get the ID of the user who's account the Admin is editing.
+     * It can be used to determine the reason Admin opens the page:
+     * to create a new user account OR to edit the previously created user account
+     *
+     * @return int
+     */
+    public function getObjectId()
+    {
+        return (int)$this->getRequest()->getParam($this->_objectId);
+    }
+
     /**
      * @return \Magento\Framework\Phrase
      */
diff --git a/app/code/Magento/User/Controller/Adminhtml/User/Delete.php b/app/code/Magento/User/Controller/Adminhtml/User/Delete.php
index d892c8533a29716b1206ba8ee8dbeaccfc3defce..3ff336eeecff87361e79f260f30f0b77cd2c1a03 100644
--- a/app/code/Magento/User/Controller/Adminhtml/User/Delete.php
+++ b/app/code/Magento/User/Controller/Adminhtml/User/Delete.php
@@ -6,6 +6,9 @@
  */
 namespace Magento\User\Controller\Adminhtml\User;
 
+use Magento\User\Block\User\Edit\Tab\Main as UserEdit;
+use Magento\Framework\Exception\AuthenticationException;
+
 class Delete extends \Magento\User\Controller\Adminhtml\User
 {
     /**
@@ -13,8 +16,10 @@ class Delete extends \Magento\User\Controller\Adminhtml\User
      */
     public function execute()
     {
+        /** @var \Magento\User\Model\User */
         $currentUser = $this->_objectManager->get(\Magento\Backend\Model\Auth\Session::class)->getUser();
         $userId = (int)$this->getRequest()->getPost('user_id');
+
         if ($userId) {
             if ($currentUser->getId() == $userId) {
                 $this->messageManager->addError(__('You cannot delete your own account.'));
@@ -22,6 +27,11 @@ class Delete extends \Magento\User\Controller\Adminhtml\User
                 return;
             }
             try {
+                $currentUserPassword = (string)$this->getRequest()->getPost(UserEdit::CURRENT_USER_PASSWORD_FIELD);
+                if (empty($currentUserPassword)) {
+                    throw new AuthenticationException(__('You have entered an invalid password for current user.'));
+                }
+                $currentUser->performIdentityCheck($currentUserPassword);
                 /** @var \Magento\User\Model\User $model */
                 $model = $this->_userFactory->create();
                 $model->setId($userId);
diff --git a/app/code/Magento/User/Test/Unit/Controller/Adminhtml/User/DeleteTest.php b/app/code/Magento/User/Test/Unit/Controller/Adminhtml/User/DeleteTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b88b28f0016964288bca46f793f0f5adb349dd39
--- /dev/null
+++ b/app/code/Magento/User/Test/Unit/Controller/Adminhtml/User/DeleteTest.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\User\Test\Unit\Controller\Adminhtml\User;
+
+use Magento\Backend\Model\Auth\Session;
+use Magento\Framework\Exception\AuthenticationException;
+
+/**
+ * Test class for \Magento\User\Controller\Adminhtml\User\Delete testing
+ */
+class DeleteTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\User\Controller\Adminhtml\User\Delete
+     */
+    private $controller;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\RequestInterface
+     */
+    private $requestMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\App\ResponseInterface
+     */
+    private $responseMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|Session
+     */
+    private $authSessionMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\ObjectManagerInterface
+     */
+    private $objectManagerMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\User\Model\UserFactory
+     */
+    private $userFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\User\Model\User
+     */
+    private $userMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\Message\ManagerInterface
+     */
+    private $messageManagerMock;
+
+    /**
+     * @return void
+     */
+    protected function setUp()
+    {
+        $this->objectManagerMock = $this->getMockBuilder(\Magento\Framework\ObjectManager\ObjectManager::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['get', 'create'])
+            ->getMock();
+
+        $this->responseMock = $this->getMockBuilder(\Magento\Framework\App\ResponseInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['setRedirect'])
+            ->getMockForAbstractClass();
+
+        $this->requestMock = $this->getMockBuilder(\Magento\Framework\App\RequestInterface::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getPost'])
+            ->getMockForAbstractClass();
+
+        $this->authSessionMock = $this->getMockBuilder(Session::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getUser'])
+            ->getMock();
+
+        $this->userMock = $this->getMockBuilder(\Magento\User\Model\User::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['getId', 'performIdentityCheck', 'delete'])
+            ->getMock();
+
+        $this->userFactoryMock = $this->getMockBuilder(\Magento\User\Model\UserFactory::class)
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->messageManagerMock = $this->getMockBuilder(\Magento\Framework\Message\ManagerInterface::class)
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->controller = $objectManager->getObject(
+            \Magento\User\Controller\Adminhtml\User\Delete::class,
+            [
+                'request'        => $this->requestMock,
+                'response'       => $this->responseMock,
+                'objectManager'  => $this->objectManagerMock,
+                'messageManager' => $this->messageManagerMock,
+                'userFactory'  => $this->userFactoryMock,
+            ]
+        );
+    }
+
+    /**
+     * Test method \Magento\User\Controller\Adminhtml\User\Delete::execute
+     *
+     * @param string $currentUserPassword
+     * @param int    $userId
+     * @param int    $currentUserId
+     * @param string $resultMethod
+     *
+     * @dataProvider executeDataProvider
+     * @return void
+     *
+     */
+    public function testExecute($currentUserPassword, $userId, $currentUserId, $resultMethod)
+    {
+        $currentUserMock = $this->userMock;
+        $this->authSessionMock->expects($this->any())->method('getUser')->will($this->returnValue($currentUserMock));
+
+        $currentUserMock->expects($this->any())->method('getId')->willReturn($currentUserId);
+
+        $this->objectManagerMock
+            ->expects($this->any())
+            ->method('get')
+            ->with(Session::class)
+            ->willReturn($this->authSessionMock);
+
+        $this->requestMock->expects($this->any())
+            ->method('getPost')
+            ->willReturnMap([
+                ['user_id', $userId],
+                [\Magento\User\Block\User\Edit\Tab\Main::CURRENT_USER_PASSWORD_FIELD, $currentUserPassword],
+            ]);
+
+        $userMock = clone $currentUserMock;
+
+        $this->userFactoryMock->expects($this->any())->method('create')->will($this->returnValue($userMock));
+        $this->responseMock->expects($this->any())->method('setRedirect')->willReturnSelf();
+        $this->userMock->expects($this->any())->method('delete')->willReturnSelf();
+        $this->messageManagerMock->expects($this->once())->method($resultMethod);
+
+        $this->controller->execute();
+    }
+
+    /**
+     * @return void
+     */
+    public function testEmptyPasswordThrowsException()
+    {
+        try {
+            $currentUserId = 1;
+            $userId = 2;
+
+            $currentUserMock = $this->userMock;
+            $this->authSessionMock->expects($this->any())
+                ->method('getUser')
+                ->will($this->returnValue($currentUserMock));
+
+            $currentUserMock->expects($this->any())->method('getId')->willReturn($currentUserId);
+
+            $this->objectManagerMock
+                ->expects($this->any())
+                ->method('get')
+                ->with(Session::class)
+                ->willReturn($this->authSessionMock);
+
+            $this->requestMock->expects($this->any())
+                ->method('getPost')
+                ->willReturnMap([
+                    ['user_id', $userId],
+                    [\Magento\User\Block\User\Edit\Tab\Main::CURRENT_USER_PASSWORD_FIELD, ''],
+                ]);
+
+            $this->controller->execute();
+        } catch (AuthenticationException $e) {
+            $this->assertEquals($e->getMessage(), 'You have entered an invalid password for current user.');
+        }
+    }
+
+    /**
+     * Data Provider for execute method
+     *
+     * @return array
+     */
+    public function executeDataProvider()
+    {
+        return [
+            [
+                'currentUserPassword' => '123123q',
+                'userId'              => 1,
+                'currentUserId'       => 2,
+                'resultMethod'        => 'addSuccess',
+            ],
+            [
+                'currentUserPassword' => '123123q',
+                'userId'              => 0,
+                'currentUserId'       => 2,
+                'resultMethod'        => 'addError',
+            ],
+            [
+                'currentUserPassword' => '123123q',
+                'userId'              => 1,
+                'currentUserId'       => 1,
+                'resultMethod'        => 'addError',
+            ],
+        ];
+    }
+}
diff --git a/app/code/Magento/User/view/adminhtml/requirejs-config.js b/app/code/Magento/User/view/adminhtml/requirejs-config.js
index 0424073c4d3db45d39394a95a99b9c697c88367d..44a5b331689bb6573c97da7f1d724e26bbea13ae 100644
--- a/app/code/Magento/User/view/adminhtml/requirejs-config.js
+++ b/app/code/Magento/User/view/adminhtml/requirejs-config.js
@@ -6,7 +6,8 @@
 var config = {
     map: {
         '*': {
-            rolesTree: 'Magento_User/js/roles-tree'
+            rolesTree: 'Magento_User/js/roles-tree',
+            deleteUserAccount: 'Magento_User/js/delete-user-account'
         }
     } 
-};
\ No newline at end of file
+};
diff --git a/app/code/Magento/User/view/adminhtml/templates/user/roles_grid_js.phtml b/app/code/Magento/User/view/adminhtml/templates/user/roles_grid_js.phtml
index bac0dd0b3f869bd33ad5d7e12886f47daded00c2..40287595b937b5426c439e0c688adbf286b36d4e 100644
--- a/app/code/Magento/User/view/adminhtml/templates/user/roles_grid_js.phtml
+++ b/app/code/Magento/User/view/adminhtml/templates/user/roles_grid_js.phtml
@@ -71,3 +71,18 @@ require([
 
 });
 </script>
+
+<?php $editBlock = $block->getLayout()->getBlock('adminhtml.user.edit'); ?>
+<?php if (is_object($editBlock)): ?>
+    <script type="text/x-magento-init">
+        {
+            "[data-role=delete-user]" : {
+                "deleteUserAccount" : {
+                    "message": "<?php echo $editBlock->escapeHtml($editBlock->getDeleteMessage()) ?>",
+                    "url": "<?php /* @noEscape */ echo $editBlock->getDeleteUrl(); ?>",
+                    "objId": "<?php echo $editBlock->escapeHtml($editBlock->getObjectId()) ?>"
+                }
+            }
+        }
+    </script>
+<?php endif; ?>
diff --git a/app/code/Magento/User/view/adminhtml/web/js/delete-user-account.js b/app/code/Magento/User/view/adminhtml/web/js/delete-user-account.js
new file mode 100644
index 0000000000000000000000000000000000000000..b326c7aeb20d06953baf406ecf339d40f5be8bc4
--- /dev/null
+++ b/app/code/Magento/User/view/adminhtml/web/js/delete-user-account.js
@@ -0,0 +1,28 @@
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+define([
+    'jquery'
+], function ($) {
+    'use strict';
+
+    var postData;
+
+    return function (params, elem) {
+
+        elem.on('click', function () {
+
+            postData = {
+                'data': {
+                    'user_id': params.objId,
+                    'current_password': $('[name="current_password"]').val()
+                }
+            };
+
+            if ($.validator.validateElement($('[name="current_password"]'))) {
+                window.deleteConfirm(params.message, params.url, postData);
+            }
+        });
+    };
+});
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 25b812bf77665d09877835e676fc5d11fdd1434a..dbb7a4aeb53bb667bf22e99e0198d1b0e3cab25c 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
@@ -41,5 +41,9 @@
             <field name="current_password" xsi:type="string">%current_password%</field>
             <field name="is_active" xsi:type="string">Active</field>
         </dataset>
+
+        <dataset name="system_admin">
+            <field name="current_password" xsi:type="string">123123q</field>
+        </dataset>
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php
index 57de56c7f56f7397282e1863ec43a3f42c6a9ec2..67ede3855e7a77b7da397a42c4de161289387b8f 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.php
@@ -101,11 +101,13 @@ class DeleteAdminUserEntityTest extends Injectable
      *
      * @param User $user
      * @param string $isDefaultUser
+     * @param User $systemAdmin
      * @return void
      */
     public function testDeleteAdminUserEntity(
         User $user,
-        $isDefaultUser
+        $isDefaultUser,
+        User $systemAdmin = null
     ) {
         $filter = [
             'username' => $user->getUsername(),
@@ -118,6 +120,7 @@ class DeleteAdminUserEntityTest extends Injectable
         }
         $this->userIndex->open();
         $this->userIndex->getUserGrid()->searchAndOpen($filter);
+        $this->userEdit->getUserForm()->fill($systemAdmin);
         $this->userEdit->getPageActions()->delete();
         $this->userEdit->getModalBlock()->acceptAlert();
     }
diff --git a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml
index 782c3243eaa6be76578a9fc9f8b670fb6920c4da..fd10c53dfd53393dfcf122888a4d7b9e1003228a 100644
--- a/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml
+++ b/dev/tests/functional/tests/app/Magento/User/Test/TestCase/DeleteAdminUserEntityTest.xml
@@ -9,11 +9,13 @@
     <testCase name="Magento\User\Test\TestCase\DeleteAdminUserEntityTest" summary="Delete Admin User" ticketId="MAGETWO-23416">
         <variation name="DeleteAdminUserEntityTestVariation1">
             <data name="isDefaultUser" xsi:type="string">0</data>
+            <data name="systemAdmin/dataset" xsi:type="string">system_admin</data>
             <constraint name="Magento\User\Test\Constraint\AssertImpossibleDeleteYourOwnAccount" />
             <constraint name="Magento\User\Test\Constraint\AssertUserInGrid" />
         </variation>
         <variation name="DeleteAdminUserEntityTestVariation2">
             <data name="isDefaultUser" xsi:type="string">1</data>
+            <data name="systemAdmin/dataset" xsi:type="string">system_admin</data>
             <constraint name="Magento\User\Test\Constraint\AssertUserSuccessDeleteMessage" />
             <constraint name="Magento\User\Test\Constraint\AssertUserNotInGrid" />
         </variation>
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php
index a3e90819912f03a9413311600c7cd5cbcfddff60..49787c94038a1d9b1c3991c7f6261c0b7ef1453e 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/CategoryTest.php
@@ -293,7 +293,7 @@ class CategoryTest extends \PHPUnit_Framework_TestCase
             ->isObjectNew(true);
 
         $repository->save($model);
-        $this->assertNull($model->getImage());
+        $this->assertEmpty($model->getImage());
     }
 
     /**
diff --git a/dev/tests/static/get_github_changes.php b/dev/tests/static/get_github_changes.php
index c142aae18d8ecd5a4ab3fa895e32e5510b71683b..f332208cd17d0861dd1b28bd7096a0b3fe0066a5 100644
--- a/dev/tests/static/get_github_changes.php
+++ b/dev/tests/static/get_github_changes.php
@@ -12,9 +12,9 @@
 // @codingStandardsIgnoreFile
 
 define(
-'USAGE',
-<<<USAGE
-    php -f get_github_changes.php --
+    'USAGE',
+    <<<USAGE
+        php -f get_github_changes.php --
     --output-file="<output_file>"
     --base-path="<base_path>"
     --repo="<main_repo>"
@@ -36,6 +36,8 @@ $fileExtensions = explode(',', isset($options['file-extensions']) ? $options['fi
 
 $mainline = 'mainline_' . (string)rand(0, 9999);
 $repo = getRepo($options, $mainline);
+$branches = $repo->getBranches('--remotes');
+generateBranchesList($options['output-file'], $branches, $options['branch']);
 $changes = retrieveChangesAcrossForks($mainline, $repo, $options['branch']);
 $changedFiles = getChangedFiles($changes, $fileExtensions);
 generateChangedFilesList($options['output-file'], $changedFiles);
@@ -57,6 +59,25 @@ function generateChangedFilesList($outputFile, $changedFiles)
     fclose($changedFilesList);
 }
 
+/**
+ * Generates a file containing origin branches
+ *
+ * @param string $outputFile
+ * @param array $branches
+ * @param string $branchName
+ * @return void
+ */
+function generateBranchesList($outputFile, $branches, $branchName)
+{
+    $branchOutputFile = str_replace('changed_files', 'branches', $outputFile);
+    $branchesList = fopen($branchOutputFile, 'w');
+    fwrite($branchesList, $branchName . PHP_EOL);
+    foreach ($branches as $branch) {
+        fwrite($branchesList, substr(strrchr($branch, '/'), 1) . PHP_EOL);
+    }
+    fclose($branchesList);
+}
+
 /**
  * Gets list of changed files
  *
@@ -84,7 +105,7 @@ function getChangedFiles(array $changes, array $fileExtensions)
  *
  * @param array $options
  * @param string $mainline
- * @return array
+ * @return GitRepo
  * @throws Exception
  */
 function getRepo($options, $mainline)
@@ -203,6 +224,19 @@ class GitRepo
         $this->call(sprintf('fetch %s', $remoteAlias));
     }
 
+    /**
+     * Returns branches
+     *
+     * @param string $source
+     * @return array|mixed
+     */
+    public function getBranches($source = '--all')
+    {
+        $result = $this->call(sprintf('branch ' . $source));
+
+        return is_array($result) ? $result : [];
+    }
+
     /**
      * Returns files changes between branch and HEAD
      *
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php
index 87bd329ef3b5611475c6ee9486cdc9f27c4ea5fe..2f3d312fb41ffba1287bafd324a64ac751316d5c 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/ModuleDBChangeTest.php
@@ -15,38 +15,49 @@ class ModuleDBChangeTest extends \PHPUnit_Framework_TestCase
     /**
      * @var string
      */
-    protected static $changedFilesPattern = __DIR__ . '/../_files/changed_files*';
+    private static $branchesFilesPattern = __DIR__ . '/../_files/branches*';
 
     /**
      * @var string
      */
-    protected static $changedFileList = '';
+    private static $changedFilesPattern = __DIR__ . '/../_files/changed_files*';
 
     /**
-     * @var string Path for Magento's composer.json
+     * @var string
      */
-    protected static $composerFilePath = BP . '/composer.json';
+    private static $changedFileList = '';
 
     /**
-     * @var bool Is tests executes on develop branch
+     * @var bool
      */
-    protected static $isOnDevVersion = false;
+    private static $actualBranch = false;
 
     /**
      *  Set changed files paths and list for all projects
      */
     public static function setUpBeforeClass()
     {
-        foreach (glob(self::$changedFilesPattern) as $changedFile) {
-            self::$changedFileList .= file_get_contents($changedFile) . PHP_EOL;
-        }
+        foreach (glob(self::$branchesFilesPattern) as $branchesFile) {
+            //get the current branchname from the first line
+            $branchName = trim(file($branchesFile)[0]);
+            if ($branchName === 'develop') {
+                self::$actualBranch = true;
+            } else {
+                //get current minor branch name
+                preg_match('|^(\d+\.\d+)|', $branchName, $minorBranch);
+                $branchName = $minorBranch[0];
+
+                //get all version branches
+                preg_match_all('|^(\d+\.\d+)|m', file_get_contents($branchesFile), $matches);
 
-        if (file_exists(self::$composerFilePath)) {
-            $jsonData = json_decode(file_get_contents(self::$composerFilePath));
-            if (substr((string) $jsonData->version, -4) == '-dev') {
-                self::$isOnDevVersion = true;
+                //check is this a latest release branch
+                self::$actualBranch = ($branchName == max($matches[0]));
             }
         }
+
+        foreach (glob(self::$changedFilesPattern) as $changedFile) {
+            self::$changedFileList .= file_get_contents($changedFile) . PHP_EOL;
+        }
     }
 
     /**
@@ -54,15 +65,14 @@ class ModuleDBChangeTest extends \PHPUnit_Framework_TestCase
      */
     public function testModuleXmlFiles()
     {
-        if (self::$isOnDevVersion) {
-            $this->markTestSkipped('This test isn\'t applicable to the developer version of Magento');
+        if (!self::$actualBranch) {
+            preg_match_all('|etc/module\.xml$|mi', self::$changedFileList, $matches);
+            $this->assertEmpty(
+                reset($matches),
+                'module.xml changes for patch releases in non-actual branches are not allowed:' . PHP_EOL .
+                implode(PHP_EOL, array_values(reset($matches)))
+            );
         }
-        preg_match_all('|etc/module\.xml$|mi', self::$changedFileList, $matches);
-        $this->assertEmpty(
-            reset($matches),
-            'module.xml changes for patch releases in non-actual branches are not allowed:' . PHP_EOL .
-            implode(PHP_EOL, array_values(reset($matches)))
-        );
     }
 
     /**
@@ -70,14 +80,13 @@ class ModuleDBChangeTest extends \PHPUnit_Framework_TestCase
      */
     public function testModuleSetupFiles()
     {
-        if (self::$isOnDevVersion) {
-            $this->markTestSkipped('This test isn\'t applicable to the developer version of Magento');
+        if (!self::$actualBranch) {
+            preg_match_all('|app/code/Magento/[^/]+/Setup/[^/]+$|mi', self::$changedFileList, $matches);
+            $this->assertEmpty(
+                reset($matches),
+                'Code with changes for DB schema or data in non-actual branches are not allowed:' . PHP_EOL .
+                implode(PHP_EOL, array_values(reset($matches)))
+            );
         }
-        preg_match_all('|app/code/Magento/[^/]+/Setup/[^/]+$|mi', self::$changedFileList, $matches);
-        $this->assertEmpty(
-            reset($matches),
-            'Code with changes for DB schema or data in non-actual branches are not allowed:' . PHP_EOL .
-            implode(PHP_EOL, array_values(reset($matches)))
-        );
     }
 }
diff --git a/setup/performance-toolkit/profiles/ce/attributeSets.xml b/setup/performance-toolkit/config/attributeSets.xml
similarity index 100%
rename from setup/performance-toolkit/profiles/ce/attributeSets.xml
rename to setup/performance-toolkit/config/attributeSets.xml
diff --git a/setup/performance-toolkit/profiles/ce/searchConfig.xml b/setup/performance-toolkit/config/searchConfig.xml
similarity index 100%
rename from setup/performance-toolkit/profiles/ce/searchConfig.xml
rename to setup/performance-toolkit/config/searchConfig.xml
diff --git a/setup/performance-toolkit/profiles/ce/searchTerms.xml b/setup/performance-toolkit/config/searchTerms.xml
similarity index 100%
rename from setup/performance-toolkit/profiles/ce/searchTerms.xml
rename to setup/performance-toolkit/config/searchTerms.xml
diff --git a/setup/performance-toolkit/profiles/ce/extra_large.xml b/setup/performance-toolkit/profiles/ce/extra_large.xml
index c9bf96ad4f4cab4cb8a6c1aacbe6e89a673e842c..fd1da116bc92b39fa23a3a4821daec93889fbad4 100644
--- a/setup/performance-toolkit/profiles/ce/extra_large.xml
+++ b/setup/performance-toolkit/profiles/ce/extra_large.xml
@@ -68,8 +68,8 @@
                 <set_scheduled>true</set_scheduled>
             </indexer>
         </indexers>
-        <xi:include href="searchTerms.xml" />
-        <xi:include href="searchConfig.xml" />
-        <xi:include href="attributeSets.xml" />
+        <xi:include href="../../config/searchTerms.xml" />
+        <xi:include href="../../config/searchConfig.xml" />
+        <xi:include href="../../config/attributeSets.xml" />
     </profile>
 </config>
diff --git a/setup/performance-toolkit/profiles/ce/large.xml b/setup/performance-toolkit/profiles/ce/large.xml
index 07e7ac33023b17d5d626986b76d84e88b3f7314b..d5d381fe059c95316d43ef88f56280c27494b197 100644
--- a/setup/performance-toolkit/profiles/ce/large.xml
+++ b/setup/performance-toolkit/profiles/ce/large.xml
@@ -68,8 +68,8 @@
                 <set_scheduled>true</set_scheduled>
             </indexer>
         </indexers>
-        <xi:include href="searchTerms.xml" />
-        <xi:include href="searchConfig.xml" />
-        <xi:include href="attributeSets.xml" />
+        <xi:include href="../../config/searchTerms.xml" />
+        <xi:include href="../../config/searchConfig.xml" />
+        <xi:include href="../../config/attributeSets.xml" />
     </profile>
 </config>
diff --git a/setup/performance-toolkit/profiles/ce/medium.xml b/setup/performance-toolkit/profiles/ce/medium.xml
index 6b1b289e823bab41a6d637350037b64c39e96935..95cd062fa74b6b94233066a6f0d0d3b296480b6b 100644
--- a/setup/performance-toolkit/profiles/ce/medium.xml
+++ b/setup/performance-toolkit/profiles/ce/medium.xml
@@ -68,8 +68,8 @@
                 <set_scheduled>false</set_scheduled>
             </indexer>
         </indexers>
-        <xi:include href="searchTerms.xml" />
-        <xi:include href="searchConfig.xml" />
-        <xi:include href="attributeSets.xml" />
+        <xi:include href="../../config/searchTerms.xml" />
+        <xi:include href="../../config/searchConfig.xml" />
+        <xi:include href="../../config/attributeSets.xml" />
     </profile>
 </config>
diff --git a/setup/performance-toolkit/profiles/ce/small.xml b/setup/performance-toolkit/profiles/ce/small.xml
index 4f9b436666f8c743c0fd0058c6fc747944506c9d..1949bb2a53f9aa69237b544ade511f4dd39815e0 100644
--- a/setup/performance-toolkit/profiles/ce/small.xml
+++ b/setup/performance-toolkit/profiles/ce/small.xml
@@ -68,8 +68,8 @@
                 <set_scheduled>false</set_scheduled>
             </indexer>
         </indexers>
-        <xi:include href="searchTerms.xml" />
-        <xi:include href="searchConfig.xml" />
-        <xi:include href="attributeSets.xml" />
+        <xi:include href="../../config/searchTerms.xml" />
+        <xi:include href="../../config/searchConfig.xml" />
+        <xi:include href="../../config/attributeSets.xml" />
     </profile>
 </config>
diff --git a/setup/src/Magento/Setup/Fixtures/FixtureModel.php b/setup/src/Magento/Setup/Fixtures/FixtureModel.php
index 44173a32c3e771ec2c43480a73c380ad2a2691ab..997244f5508933d05ae731255b81779f2528a101 100644
--- a/setup/src/Magento/Setup/Fixtures/FixtureModel.php
+++ b/setup/src/Magento/Setup/Fixtures/FixtureModel.php
@@ -221,6 +221,12 @@ class FixtureModel
      */
     public function getValue($key, $default = null)
     {
-        return isset($this->config['config']['profile'][$key]) ? $this->config['config']['profile'][$key] : $default;
+        return isset($this->config['config']['profile'][$key]) ?
+            (
+                // Work around for how attributes are handled in the XML parser when injected via xinclude due to the
+                // files existing outside of the current working directory.
+                isset($this->config['config']['profile'][$key]['_value']) ?
+                    $this->config['config']['profile'][$key]['_value'] : $this->config['config']['profile'][$key]
+            ) : $default;
     }
 }