diff --git a/app/code/Magento/Catalog/Block/Product/View.php b/app/code/Magento/Catalog/Block/Product/View.php
index 8157ab4de07f2a10c9bc5e34541944698f0ab71c..964a444a0aef8b924819598634a0eea36f7ba247 100644
--- a/app/code/Magento/Catalog/Block/Product/View.php
+++ b/app/code/Magento/Catalog/Block/Product/View.php
@@ -7,7 +7,6 @@ namespace Magento\Catalog\Block\Product;
 
 use Magento\Catalog\Api\ProductRepositoryInterface;
 use Magento\Catalog\Model\Category;
-use Magento\Catalog\Model\Product;
 
 /**
  * Product View block
@@ -29,6 +28,7 @@ class View extends AbstractProduct implements \Magento\Framework\DataObject\Iden
 
     /**
      * @var \Magento\Framework\Pricing\PriceCurrencyInterface
+     * @deprecated
      */
     protected $priceCurrency;
 
@@ -225,40 +225,34 @@ class View extends AbstractProduct implements \Magento\Framework\DataObject\Iden
             $config = [
                 'productId' => $product->getId(),
                 'priceFormat' => $this->_localeFormat->getPriceFormat()
-                ];
+            ];
             return $this->_jsonEncoder->encode($config);
         }
 
         $tierPrices = [];
         $tierPricesList = $product->getPriceInfo()->getPrice('tier_price')->getTierPriceList();
         foreach ($tierPricesList as $tierPrice) {
-            $tierPrices[] = $this->priceCurrency->convert($tierPrice['price']->getValue());
+            $tierPrices[] = $tierPrice['price']->getValue();
         }
         $config = [
-            'productId' => $product->getId(),
+            'productId'   => $product->getId(),
             'priceFormat' => $this->_localeFormat->getPriceFormat(),
-            'prices' => [
-                'oldPrice' => [
-                    'amount' => $this->priceCurrency->convert(
-                        $product->getPriceInfo()->getPrice('regular_price')->getAmount()->getValue()
-                    ),
+            'prices'      => [
+                'oldPrice'   => [
+                    'amount'      => $product->getPriceInfo()->getPrice('regular_price')->getAmount()->getValue(),
                     'adjustments' => []
                 ],
-                'basePrice' => [
-                    'amount' => $this->priceCurrency->convert(
-                        $product->getPriceInfo()->getPrice('final_price')->getAmount()->getBaseAmount()
-                    ),
+                'basePrice'  => [
+                    'amount'      => $product->getPriceInfo()->getPrice('final_price')->getAmount()->getBaseAmount(),
                     'adjustments' => []
                 ],
                 'finalPrice' => [
-                    'amount' => $this->priceCurrency->convert(
-                        $product->getPriceInfo()->getPrice('final_price')->getAmount()->getValue()
-                    ),
+                    'amount'      => $product->getPriceInfo()->getPrice('final_price')->getAmount()->getValue(),
                     'adjustments' => []
                 ]
             ],
-            'idSuffix' => '_clone',
-            'tierPrices' => $tierPrices
+            'idSuffix'    => '_clone',
+            'tierPrices'  => $tierPrices
         ];
 
         $responseObject = new \Magento\Framework\DataObject();
diff --git a/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml b/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml
index eacc039255caf98525625e3a18f6dd7e43376e70..ea3e8077d0dc195f42e4cddb78135b6a0d0f9470 100644
--- a/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml
+++ b/app/code/Magento/Catalog/view/frontend/templates/product/view/addtocart.phtml
@@ -20,9 +20,9 @@
                 <input type="number"
                        name="qty"
                        id="qty"
-                       maxlength="12"
                        value="<?php /* @escapeNotVerified */ echo $block->getProductDefaultQty() * 1 ?>"
-                       title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" class="input-text qty"
+                       title="<?php /* @escapeNotVerified */ echo __('Qty') ?>"
+                       class="input-text qty"
                        data-validate="<?php echo $block->escapeHtml(json_encode($block->getQuantityValidators())) ?>"
                        />
             </div>
@@ -58,4 +58,4 @@
         }
     }
 </script>
-<?php endif; ?>
\ No newline at end of file
+<?php endif; ?>
diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml
index 0f221a393f5eb181f31a778ce4d01da1b0cc109b..ebe8f4570b02f39ca9acb39986d72b5c402b496d 100644
--- a/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml
+++ b/app/code/Magento/Checkout/view/frontend/templates/cart/item/configure/updatecart.phtml
@@ -17,7 +17,13 @@
             <div class="field qty">
                 <label class="label" for="qty"><span><?php /* @escapeNotVerified */ echo __('Qty') ?></span></label>
                 <div class="control">
-                    <input type="number" name="qty" id="qty" maxlength="12" value="" title="<?php /* @escapeNotVerified */ echo __('Qty') ?>" class="input-text qty" data-validate="{'required-number':true,digits:true}"/>
+                    <input type="number"
+                           name="qty"
+                           id="qty"
+                           value=""
+                           title="<?php /* @escapeNotVerified */ echo __('Qty') ?>"
+                           class="input-text qty"
+                           data-validate="{'required-number':true,digits:true}"/>
                 </div>
             </div>
             <?php endif; ?>
diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml
index d83b552b05cd4be4e55262bfb4c56a86039113c6..21fafe4d37f1b2496f421026c410e974972bc59d 100644
--- a/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml
+++ b/app/code/Magento/Checkout/view/frontend/templates/cart/item/default.phtml
@@ -96,7 +96,6 @@ $canApplyMsrp = $helper->isShowBeforeOrderConfirm($product) && $helper->isMinima
                            size="4"
                            title="<?php echo $block->escapeHtml(__('Qty')); ?>"
                            class="input-text qty"
-                           maxlength="12"
                            data-validate="{required:true,'validate-greater-than-zero':true}"
                            data-role="cart-item-qty"/>
                 </div>
diff --git a/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html b/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html
index 89789996e5248bb8ffec2ac9db18b52eec315d56..8796152eb60315266d870682924f44789c2f5dc7 100644
--- a/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html
+++ b/app/code/Magento/Checkout/view/frontend/web/template/minicart/item/default.html
@@ -79,8 +79,7 @@
                            }, value: qty"
                            type="number"
                            size="4"
-                           class="item-qty cart-item-qty"
-                           maxlength="12"/>
+                           class="item-qty cart-item-qty">
                     <button data-bind="attr: {
                            id: 'update-cart-item-'+item_id,
                            'data-cart-item': item_id,
diff --git a/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php
index 1cc1cceefb39972cfc09d2c7f70463d2f3f76da7..51c68145b24cf5e72061a51647d4b311f39e60bf 100644
--- a/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Block/Product/View/Type/Configurable.php
@@ -92,6 +92,18 @@ class Configurable extends \Magento\Catalog\Block\Product\View\AbstractView
         );
     }
 
+    /**
+     * Get cache key informative items.
+     *
+     * @return array
+     */
+    public function getCacheKeyInfo()
+    {
+        $parentData = parent::getCacheKeyInfo();
+        $parentData[] = $this->priceCurrency->getCurrencySymbol();
+        return $parentData;
+    }
+
     /**
      * Get allowed attributes
      *
diff --git a/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js b/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js
index f6740550efca6556490481a9c6c0516d21b9b4e2..a96dca0002d69d30fd0aab7372020e787383512e 100644
--- a/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js
+++ b/app/code/Magento/Customer/view/frontend/web/js/model/customer-addresses.js
@@ -11,11 +11,13 @@ define(
     ],
     function($, ko, address) {
         "use strict";
+
         var isLoggedIn = ko.observable(window.isCustomerLoggedIn);
+
         return {
             getAddressItems: function() {
                 var items = [];
-                if (isLoggedIn) {
+                if (isLoggedIn()) {
                     var customerData = window.customerData;
                     if (Object.keys(customerData).length) {
                         $.each(customerData.addresses, function (key, item) {
@@ -23,8 +25,9 @@ define(
                         });
                     }
                 }
+
                 return items;
             }
         }
     }
-);
\ No newline at end of file
+);
diff --git a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php
index 0d8d18df223767b2812f58356de3b7904090d8f7..1841a9efb6cf8424ebc7ef0b289495388da31db2 100644
--- a/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php
+++ b/app/code/Magento/Eav/Model/Entity/Attribute/AbstractAttribute.php
@@ -8,6 +8,7 @@ namespace Magento\Eav\Model\Entity\Attribute;
 
 use Magento\Framework\Api\AttributeValueFactory;
 use Magento\Framework\Exception\LocalizedException;
+use Magento\Framework\Serialize\SerializerInterface;
 
 /**
  * Entity/Attribute/Model - attribute abstract
@@ -22,6 +23,11 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
 {
     const TYPE_STATIC = 'static';
 
+    /**
+     * Const for empty string value.
+     */
+    const EMPTY_STRING = '';
+
     /**
      * Attribute name
      *
@@ -111,6 +117,27 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
      */
     protected $dataObjectHelper;
 
+    /**
+     * Serializer Instance.
+     *
+     * @var SerializerInterface
+     */
+    private $serializer;
+
+    /**
+     * Array of attribute types that have empty string as a possible value.
+     *
+     * @var array
+     */
+    private $emptyStringTypes = [
+        'int',
+        'decimal',
+        'datetime',
+        'varchar',
+        'text',
+        'static',
+    ];
+
     /**
      * @param \Magento\Framework\Model\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -166,6 +193,21 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
         $this->dataObjectHelper = $dataObjectHelper;
     }
 
+    /**
+     * Get Serializer instance.
+     * @deprecated
+     *
+     * @return SerializerInterface
+     */
+    private function getSerializer()
+    {
+        if ($this->serializer === null) {
+            $this->serializer = \Magento\Framework\App\ObjectManager::getInstance()->create(SerializerInterface::class);
+        }
+
+        return $this->serializer;
+    }
+
     /**
      * Initialize resource model
      *
@@ -202,6 +244,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
         $this->_getResource()->loadByCode($this, $entityTypeId, $code);
         $this->_afterLoad();
         \Magento\Framework\Profiler::stop('load_by_code');
+
         return $this;
     }
 
@@ -226,6 +269,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
     public function setAttributeId($data)
     {
         $this->_data['attribute_id'] = $data;
+
         return $this;
     }
 
@@ -372,6 +416,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
     public function setAttributeSetId($id)
     {
         $this->_data['attribute_set_id'] = $id;
+
         return $this;
     }
 
@@ -392,6 +437,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
     public function setEntityTypeId($id)
     {
         $this->_data['entity_type_id'] = $id;
+
         return $this;
     }
 
@@ -403,6 +449,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
     public function setEntityType($type)
     {
         $this->setData('entity_type', $type);
+
         return $this;
     }
 
@@ -456,6 +503,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
     public function setEntity($entity)
     {
         $this->_entity = $entity;
+
         return $this;
     }
 
@@ -469,6 +517,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
         if (!$this->_entity) {
             $this->_entity = $this->getEntityType();
         }
+
         return $this->_entity;
     }
 
@@ -546,6 +595,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
             }
             $this->_source = $source->setAttribute($this);
         }
+
         return $this->_source;
     }
 
@@ -557,6 +607,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
     public function usesSource()
     {
         $input = $this->getFrontendInput();
+
         return $input === 'select' || $input === 'multiselect' || $this->_getData('source_model') != '';
     }
 
@@ -588,17 +639,38 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
     }
 
     /**
+     * Check if Value is empty.
+     *
      * @param array|null|bool|int|float|string $value
      * @return bool
      */
     public function isValueEmpty($value)
     {
-        /** @var array $emptyStringTypes list of attribute types that treat empty string as a possible value */
-        $emptyStringTypes = ['int', 'decimal', 'datetime', 'varchar', 'text', 'static'];
         return (is_array($value) && count($value) == 0)
             || $value === null
             || ($value === false && $this->getBackend()->getType() != 'int')
-            || ($value === '' && in_array($this->getBackend()->getType(), $emptyStringTypes));
+            || ($value === self::EMPTY_STRING && $this->isInEmptyStringTypes());
+    }
+
+    /**
+     * Check if attribute empty value is valid.
+     *
+     * @param array|null|bool|int|float|string $value
+     * @return bool
+     */
+    public function isAllowedEmptyTextValue($value)
+    {
+        return $this->isInEmptyStringTypes() && $value === self::EMPTY_STRING;
+    }
+
+    /**
+     * Check is attribute type in allowed empty string types.
+     *
+     * @return bool
+     */
+    private function isInEmptyStringTypes()
+    {
+        return in_array($this->getBackend()->getType(), $this->emptyStringTypes);
     }
 
     /**
@@ -654,6 +726,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
         if (!isset($this->_attributeIdCache[$cacheKey])) {
             $this->_attributeIdCache[$cacheKey] = $this->getResource()->getIdByCode($entityType, $code);
         }
+
         return $this->_attributeIdCache[$cacheKey];
     }
 
@@ -686,6 +759,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
                 $this->_dataTable = $backendTable;
             }
         }
+
         return $this->_dataTable;
     }
 
@@ -700,6 +774,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
         if ($this->usesSource() && $this->getBackendType() != self::TYPE_STATIC) {
             return $this->getSource()->getFlatColumns();
         }
+
         return $this->_getFlatColumnsDdlDefinition();
     }
 
@@ -723,60 +798,60 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
                 $size = $prop['LENGTH'] ? $prop['LENGTH'] : null;
 
                 $columns[$this->getAttributeCode()] = [
-                    'type' => $this->_resourceHelper->getDdlTypeByColumnType($type),
-                    'length' => $size,
+                    'type'     => $this->_resourceHelper->getDdlTypeByColumnType($type),
+                    'length'   => $size,
                     'unsigned' => $prop['UNSIGNED'] ? true : false,
                     'nullable' => $prop['NULLABLE'],
-                    'default' => $prop['DEFAULT'],
-                    'extra' => null,
+                    'default'  => $prop['DEFAULT'],
+                    'extra'    => null,
                 ];
                 break;
             case 'datetime':
                 $columns[$this->getAttributeCode()] = [
-                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_DATETIME,
+                    'type'     => \Magento\Framework\DB\Ddl\Table::TYPE_DATETIME,
                     'unsigned' => false,
                     'nullable' => true,
-                    'default' => null,
-                    'extra' => null,
+                    'default'  => null,
+                    'extra'    => null,
                 ];
                 break;
             case 'decimal':
                 $columns[$this->getAttributeCode()] = [
-                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL,
-                    'length' => '12,4',
+                    'type'     => \Magento\Framework\DB\Ddl\Table::TYPE_DECIMAL,
+                    'length'   => '12,4',
                     'unsigned' => false,
                     'nullable' => true,
-                    'default' => null,
-                    'extra' => null,
+                    'default'  => null,
+                    'extra'    => null,
                 ];
                 break;
             case 'int':
                 $columns[$this->getAttributeCode()] = [
-                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
+                    'type'     => \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
                     'unsigned' => false,
                     'nullable' => true,
-                    'default' => null,
-                    'extra' => null,
+                    'default'  => null,
+                    'extra'    => null,
                 ];
                 break;
             case 'text':
                 $columns[$this->getAttributeCode()] = [
-                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
+                    'type'     => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
                     'unsigned' => false,
                     'nullable' => true,
-                    'default' => null,
-                    'extra' => null,
-                    'length' => \Magento\Framework\DB\Ddl\Table::MAX_TEXT_SIZE,
+                    'default'  => null,
+                    'extra'    => null,
+                    'length'   => \Magento\Framework\DB\Ddl\Table::MAX_TEXT_SIZE,
                 ];
                 break;
             case 'varchar':
                 $columns[$this->getAttributeCode()] = [
-                    'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
-                    'length' => '255',
+                    'type'     => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
+                    'length'   => '255',
                     'unsigned' => false,
                     'nullable' => true,
-                    'default' => null,
-                    'extra' => null,
+                    'default'  => null,
+                    'extra'    => null,
                 ];
                 break;
             default:
@@ -804,61 +879,62 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
                 }
                 $prop = $describe[$this->getAttributeCode()];
                 $columns[$this->getAttributeCode()] = [
-                    'type' => $prop['DATA_TYPE'] . ($prop['LENGTH'] ? "({$prop['LENGTH']})" : ""),
+                    'type'     => $prop['DATA_TYPE'] . ($prop['LENGTH'] ? "({$prop['LENGTH']})" : ""),
                     'unsigned' => $prop['UNSIGNED'] ? true : false,
-                    'is_null' => $prop['NULLABLE'],
-                    'default' => $prop['DEFAULT'],
-                    'extra' => null,
+                    'is_null'  => $prop['NULLABLE'],
+                    'default'  => $prop['DEFAULT'],
+                    'extra'    => null,
                 ];
                 break;
             case 'datetime':
                 $columns[$this->getAttributeCode()] = [
-                    'type' => 'datetime',
+                    'type'     => 'datetime',
                     'unsigned' => false,
-                    'is_null' => true,
-                    'default' => null,
-                    'extra' => null,
+                    'is_null'  => true,
+                    'default'  => null,
+                    'extra'    => null,
                 ];
                 break;
             case 'decimal':
                 $columns[$this->getAttributeCode()] = [
-                    'type' => 'decimal(12,4)',
+                    'type'     => 'decimal(12,4)',
                     'unsigned' => false,
-                    'is_null' => true,
-                    'default' => null,
-                    'extra' => null,
+                    'is_null'  => true,
+                    'default'  => null,
+                    'extra'    => null,
                 ];
                 break;
             case 'int':
                 $columns[$this->getAttributeCode()] = [
-                    'type' => 'int',
+                    'type'     => 'int',
                     'unsigned' => false,
-                    'is_null' => true,
-                    'default' => null,
-                    'extra' => null,
+                    'is_null'  => true,
+                    'default'  => null,
+                    'extra'    => null,
                 ];
                 break;
             case 'text':
                 $columns[$this->getAttributeCode()] = [
-                    'type' => 'text',
+                    'type'     => 'text',
                     'unsigned' => false,
-                    'is_null' => true,
-                    'default' => null,
-                    'extra' => null,
+                    'is_null'  => true,
+                    'default'  => null,
+                    'extra'    => null,
                 ];
                 break;
             case 'varchar':
                 $columns[$this->getAttributeCode()] = [
-                    'type' => 'varchar(255)',
+                    'type'     => 'varchar(255)',
                     'unsigned' => false,
-                    'is_null' => true,
-                    'default' => null,
-                    'extra' => null,
+                    'is_null'  => true,
+                    'default'  => null,
+                    'extra'    => null,
                 ];
                 break;
             default:
                 break;
         }
+
         return $columns;
     }
 
@@ -945,6 +1021,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
             foreach ($this->_storeManager->getStores() as $store) {
                 $this->getFlatUpdateSelect($store->getId());
             }
+
             return $this;
         }
 
@@ -955,6 +1032,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
         if ($this->usesSource()) {
             return $this->getSource()->getFlatUpdateSelect($store);
         }
+
         return $this->_getResource()->getFlatUpdateSelect($this, $store);
     }
 
@@ -1064,6 +1142,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
         } else {
             $this->setData(self::OPTIONS, $options);
         }
+
         return $this;
     }
 
@@ -1086,6 +1165,7 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
             );
             $dataObjects[] = $optionDataObject;
         }
+
         return $dataObjects;
     }
 
@@ -1195,8 +1275,9 @@ abstract class AbstractAttribute extends \Magento\Framework\Model\AbstractExtens
         if (is_array($rules)) {
             return $rules;
         } elseif (!empty($rules)) {
-            return unserialize($rules);
+            return $this->getSerializer()->unserialize($rules);
         }
+
         return [];
     }
 
diff --git a/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php b/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php
index c775a24a03c465dad45640a7f634823cb8b43ef8..bcaf11aaf5532be296fe19ac6d0bb451b6a20b13 100644
--- a/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php
+++ b/app/code/Magento/Eav/Model/ResourceModel/UpdateHandler.php
@@ -125,55 +125,65 @@ class UpdateHandler implements AttributeInterface
                 : null; // @todo verify is it normal to not have attributer_set_id
             $snapshot = $this->readSnapshot->execute($entityType, $entityDataForSnapshot);
             foreach ($this->getAttributes($entityType, $attributeSetId) as $attribute) {
-                if ($attribute->isStatic()) {
-                    continue;
-                }
-                /**
-                 * Only scalar values can be stored in generic tables
-                 */
-                if (isset($entityData[$attribute->getAttributeCode()])
-                    && !is_scalar($entityData[$attribute->getAttributeCode()])) {
+                $code = $attribute->getAttributeCode();
+                $isAllowedValueType = array_key_exists($code, $entityData)
+                    && (is_scalar($entityData[$code]) || $entityData[$code] === null);
+
+                if ($attribute->isStatic() || !$isAllowedValueType) {
                     continue;
                 }
-                if (isset($snapshot[$attribute->getAttributeCode()])
-                    && $snapshot[$attribute->getAttributeCode()] !== false
-                    && (array_key_exists($attribute->getAttributeCode(), $entityData)
-                        && $attribute->isValueEmpty($entityData[$attribute->getAttributeCode()]))
-                ) {
-                    $this->attributePersistor->registerDelete(
-                        $entityType,
-                        $entityData[$metadata->getLinkField()],
-                        $attribute->getAttributeCode()
-                    );
-                }
-                if ((!array_key_exists($attribute->getAttributeCode(), $snapshot)
-                        || $snapshot[$attribute->getAttributeCode()] === false)
-                    && array_key_exists($attribute->getAttributeCode(), $entityData)
-                    && !$attribute->isValueEmpty($entityData[$attribute->getAttributeCode()])
-                ) {
-                    $this->attributePersistor->registerInsert(
-                        $entityType,
-                        $entityData[$metadata->getLinkField()],
-                        $attribute->getAttributeCode(),
-                        $entityData[$attribute->getAttributeCode()]
-                    );
-                }
-                if (array_key_exists($attribute->getAttributeCode(), $snapshot)
-                    && $snapshot[$attribute->getAttributeCode()] !== false
-                    && array_key_exists($attribute->getAttributeCode(), $entityData)
-                    && $snapshot[$attribute->getAttributeCode()] != $entityData[$attribute->getAttributeCode()]
-                    && !$attribute->isValueEmpty($entityData[$attribute->getAttributeCode()])
-                ) {
-                    $this->attributePersistor->registerUpdate(
-                        $entityType,
-                        $entityData[$metadata->getLinkField()],
-                        $attribute->getAttributeCode(),
-                        $entityData[$attribute->getAttributeCode()]
-                    );
+
+                $newValue = $entityData[$code];
+                $isValueEmpty = $attribute->isValueEmpty($newValue);
+                $isAllowedEmptyStringValue = $attribute->isAllowedEmptyTextValue($newValue);
+
+                if (array_key_exists($code, $snapshot)) {
+                    $snapshotValue = $snapshot[$code];
+                    /**
+                     * 'FALSE' value for attributes can't be update or delete
+                     */
+                    if ($snapshotValue === false) {
+                        continue;
+                    }
+
+                    if (!$isValueEmpty || $isAllowedEmptyStringValue) {
+                        /**
+                         * NOT Updated value for attributes not need to update
+                         */
+                        if ($snapshotValue === $newValue) {
+                            continue;
+                        }
+
+                        $this->attributePersistor->registerUpdate(
+                            $entityType,
+                            $entityData[$metadata->getLinkField()],
+                            $code,
+                            $newValue
+                        );
+                    } else {
+                        $this->attributePersistor->registerDelete(
+                            $entityType,
+                            $entityData[$metadata->getLinkField()],
+                            $code
+                        );
+                    }
+                } else {
+                    /**
+                     * Only not empty value of attribute is insertable
+                     */
+                    if (!$isValueEmpty || $isAllowedEmptyStringValue) {
+                        $this->attributePersistor->registerInsert(
+                            $entityType,
+                            $entityData[$metadata->getLinkField()],
+                            $code,
+                            $newValue
+                        );
+                    }
                 }
             }
             $this->attributePersistor->flush($entityType, $context);
         }
+
         return $this->getReadHandler()->execute($entityType, $entityData, $arguments);
     }
 
@@ -189,6 +199,7 @@ class UpdateHandler implements AttributeInterface
         if (!$this->readHandler) {
             $this->readHandler = ObjectManager::getInstance()->get(ReadHandler::class);
         }
+
         return $this->readHandler;
     }
 }
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php
index a10bafacda42dc2b72fcc285307a0250cae3074b..3c0e77408ba2dfbbe68651107cfa1a1d7a885588 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Attribute/AbstractAttributeTest.php
@@ -144,19 +144,33 @@ class AbstractAttributeTest extends \PHPUnit_Framework_TestCase
 
     public function testGetValidationRulesWhenRuleIsSerialized()
     {
-        $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $rule = 'some value';
-        $model = $objectManagerHelper->getObject(
-            \Magento\Catalog\Model\Entity\Attribute::class,
-            [
-                'data' => [
-                    \Magento\Eav\Api\Data\AttributeInterface::VALIDATE_RULES => serialize($rule)
-                ]
+        $rule = serialize('some value');
+        $expected = 'some test result';
 
-            ]
-        );
+        $modelClassName = \Magento\Eav\Model\Entity\Attribute\AbstractAttribute::class;
+        $model = $this->getMockForAbstractClass($modelClassName, [], '', false);
 
-        $this->assertEquals($rule, $model->getValidationRules());
+        $serializerMock = $this->getMock(\Magento\Framework\Serialize\SerializerInterface::class);
+
+        $reflection = new \ReflectionClass($modelClassName);
+        $reflectionProperty = $reflection->getProperty('serializer');
+        $reflectionProperty->setAccessible(true);
+        $reflectionProperty->setValue($model, $serializerMock);
+
+        $model->setData(\Magento\Eav\Api\Data\AttributeInterface::VALIDATE_RULES, $rule);
+
+        $serializerMock->method('unserialize')
+            ->with($rule)
+            ->willReturn($expected);
+
+        $this->assertEquals($expected, $model->getValidationRules());
+
+        $data = ['test array'];
+        $model->setData(\Magento\Eav\Api\Data\AttributeInterface::VALIDATE_RULES, $data);
+        $this->assertEquals($data, $model->getValidationRules());
+
+        $model->setData(\Magento\Eav\Api\Data\AttributeInterface::VALIDATE_RULES, null);
+        $this->assertEquals([], $model->getValidationRules());
     }
 
     public function testGetValidationRulesWhenRuleIsEmpty()
diff --git a/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml b/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml
index 58fbb4511e54ca06afdf0d3f8c864bb9e1a8bee4..05428e248b69c996af9c0863e9d48ca261777538 100644
--- a/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml
+++ b/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml
@@ -46,9 +46,9 @@
                 <td data-th="<?php echo $block->escapeHtml(__('Qty')); ?>" class="col qty">
                 <?php if ($_item->isSaleable()) : ?>
                     <div class="control qty">
-                        <input type="number" name="super_group[<?php /* @escapeNotVerified */ echo $_item->getId() ?>]"
+                        <input type="number"
+                               name="super_group[<?php /* @escapeNotVerified */ echo $_item->getId() ?>]"
                                data-selector="super_group[<?php /* @escapeNotVerified */ echo $_item->getId() ?>]"
-                               maxlength="12"
                                value="<?php /* @escapeNotVerified */ echo $_item->getQty() * 1 ?>"
                                title="<?php /* @escapeNotVerified */ echo __('Qty') ?>"
                                class="input-text qty"
diff --git a/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail.php b/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail.php
index 70eb41e8fcbdf6f8b55c00a8bd291a2ceef68df1..e97a1a2f9d64c9d60c82869ed2ff882dcecd5979 100644
--- a/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail.php
+++ b/app/code/Magento/Sales/Block/Adminhtml/Transactions/Detail.php
@@ -131,7 +131,7 @@ class Detail extends \Magento\Backend\Block\Widget\Container
 
         $this->setOrderIncrementIdHtml($this->escapeHtml($this->_txn->getOrder()->getIncrementId()));
 
-        $this->setTxnTypeHtml($this->escapeHtml($this->_txn->getTxnType()));
+        $this->setTxnTypeHtml($this->escapeHtml(__($this->_txn->getTxnType())));
 
         $this->setOrderIdUrlHtml(
             $this->escapeHtml($this->getUrl('sales/order/view', ['order_id' => $this->_txn->getOrderId()]))
diff --git a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js
index 01c8ef29029a9ef34f82885e3efbada75774a88b..209b05773a497b8e02d36cdd4adba10eab107779 100644
--- a/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js
+++ b/app/code/Magento/Ui/view/base/web/js/form/element/wysiwyg.js
@@ -93,7 +93,7 @@ define([
             /* eslint-disable no-undef */
             if (tinyMCE) {
                 _.each(tinyMCE.activeEditor.controlManager.controls, function (property, index, controls) {
-                    controls[property].setDisabled(status);
+                    controls[property.id].setDisabled(status);
                 });
 
                 tinyMCE.activeEditor.getBody().setAttribute('contenteditable', !status);
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml
index ae9c2238c9e008ac8086d365a1b1547d3309762b..b977e23166f45ec9c471ea08c5e7dc7516a728c0 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/CustomOptions.xml
@@ -382,5 +382,22 @@
                 </item>
             </field>
         </dataset>
+
+        <dataset name="not_required_text_option">
+            <field name="0" xsi:type="array">
+                <item name="title" xsi:type="string">Test1 option %isolation%</item>
+                <item name="is_require" xsi:type="string">No</item>
+                <item name="type" xsi:type="string">Text/Field</item>
+                <item name="options" xsi:type="array">
+                    <item name="0" xsi:type="array">
+                        <item name="price" xsi:type="string">10</item>
+                        <item name="price_type" xsi:type="string">Fixed</item>
+                        <item name="sku" xsi:type="string">sku1_%isolation%</item>
+                        <item name="max_characters" xsi:type="string">45</item>
+                    </item>
+                </item>
+            </field>
+        </dataset>
+
     </repository>
 </config>
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php
new file mode 100644
index 0000000000000000000000000000000000000000..6f3cfc48cdd553fea81ef9681f24e5799273af5e
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Test\Constraint;
+
+use Magento\Catalog\Test\Page\Product\CatalogProductView;
+use Magento\Cms\Test\Page\CmsIndex;
+use Magento\CurrencySymbol\Test\Fixture\CurrencySymbolEntity;
+use Magento\Mtf\Client\BrowserInterface;
+use Magento\Mtf\Constraint\AbstractConstraint;
+use Magento\Mtf\Fixture\InjectableFixture;
+
+/**
+ * Assert currency rate applied on configurable product page.
+ */
+class AssertCurrencyRateAppliedOnProductPage extends AbstractConstraint
+{
+    /**
+     * Assert currency rate applied on configurable product page.
+     *
+     * @param BrowserInterface $browser
+     * @param InjectableFixture $product
+     * @param CatalogProductView $view
+     * @param CmsIndex $cmsIndex
+     * @param CurrencySymbolEntity $baseCurrency
+     * @param array $configuredPrices
+     * @param string $basePrice
+     */
+    public function processAssert(
+        BrowserInterface $browser,
+        InjectableFixture $product,
+        CatalogProductView $view,
+        CmsIndex $cmsIndex,
+        CurrencySymbolEntity $baseCurrency,
+        array $configuredPrices,
+        $basePrice
+    ) {
+        $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html');
+        $this->assertPrice($view, $basePrice);
+
+        $view->getViewBlock()->configure($product);
+        $this->assertPrice($view, $configuredPrices['custom_currency']);
+
+        $cmsIndex->getCurrencyBlock()->switchCurrency($baseCurrency);
+        $view->getViewBlock()->configure($product);
+        $this->assertPrice($view, $configuredPrices['base_currency']);
+    }
+
+    /**
+     * Assert price.
+     *
+     * @param CatalogProductView $view
+     * @param string $price
+     * @param string $currency [optional]
+     */
+    public function assertPrice(CatalogProductView $view, $price, $currency = '')
+    {
+        \PHPUnit_Framework_Assert::assertEquals(
+            $price,
+            $view->getViewBlock()->getPriceBlock()->getPrice($currency),
+            'Wrong price is displayed on Product page.'
+        );
+    }
+
+    /**
+     * Returns a string representation of successful assertion.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return "Currency rate has been applied correctly on Configurable Product page.";
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCurrencyRateTest.xml b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCurrencyRateTest.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6ba7729120ae909591f0703c36b83b51f2ea8aa0
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/TestCase/CreateCurrencyRateTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+ -->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../vendor/magento/mtf/etc/variations.xsd">
+    <testCase name="Magento\Directory\Test\TestCase\CreateCurrencyRateTest" summary="Create Currency Rate" ticketId="MAGETWO-36824">
+        <variation name="CreateCurrencyRateTestVariation3">
+            <data name="currencyRate/data/currency_from" xsi:type="string">USD</data>
+            <data name="currencyRate/data/currency_to" xsi:type="string">UAH</data>
+            <data name="currencyRate/data/rate" xsi:type="number">2.000</data>
+            <data name="currencySymbol/dataSet" xsi:type="string">currency_symbols_uah</data>
+            <data name="product" xsi:type="string">configurableProduct::default</data>
+            <data name="config/dataset" xsi:type="string">config_base_currency_us_display_currency_uah</data>
+            <data name="baseCurrency/data/code" xsi:type="string">USD</data>
+            <data name="basePrice" xsi:type="string">â‚´80.00</data>
+            <data name="configuredPrices" xsi:type="array">
+                <item name="custom_currency" xsi:type="string">â‚´80.00</item>
+                <item name="base_currency" xsi:type="string">$40.00</item>
+            </data>
+            <data name="tag" xsi:type="string">test_type:acceptance_test</data>
+            <constraint name="Magento\Directory\Test\Constraint\AssertCurrencyRateSuccessSaveMessage" />
+            <constraint name="Magento\ConfigurableProduct\Test\Constraint\AssertCurrencyRateAppliedOnProductPage" />
+        </variation>
+    </testCase>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml
index 9df42574840d692ced41a85979d63de6bf7c467f..3a099d79d370a97b9d75afb419bd36860e559a1a 100644
--- a/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml
+++ b/dev/tests/functional/tests/app/Magento/CurrencySymbol/Test/Repository/ConfigData.xml
@@ -48,6 +48,18 @@
                     <item name="US Dollar" xsi:type="string">USD</item>
                 </item>
             </field>
+            <field name="currency/options/base" xsi:type="array">
+                <item name="scope" xsi:type="string">currency</item>
+                <item name="label" xsi:type="string">US Dollar</item>
+                <item name="scope_id" xsi:type="number">1</item>
+                <item name="value" xsi:type="string">USD</item>
+            </field>
+            <field name="currency/options/default" xsi:type="array">
+                <item name="scope" xsi:type="string">currency</item>
+                <item name="label" xsi:type="string">US Dollar</item>
+                <item name="scope_id" xsi:type="number">1</item>
+                <item name="value" xsi:type="string">USD</item>
+            </field>
         </dataset>
 
         <dataset name="config_base_currency_ch">
diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php
new file mode 100644
index 0000000000000000000000000000000000000000..4b8f3825df8bab870a272e3db20864118db25079
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Constraint/AssertCurrencyRateAppliedOnProductPage.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Directory\Test\Constraint;
+
+use Magento\Catalog\Test\Page\Product\CatalogProductView;
+use Magento\Mtf\Client\BrowserInterface;
+use Magento\Mtf\Constraint\AbstractConstraint;
+use Magento\Mtf\Fixture\InjectableFixture;
+
+/**
+ * Assert currency rate applied on product page.
+ */
+class AssertCurrencyRateAppliedOnProductPage extends AbstractConstraint
+{
+    /**
+     * Assert currency rate applied on product page.
+     *
+     * @param BrowserInterface $browser
+     * @param InjectableFixture $product
+     * @param CatalogProductView $view
+     * @param string $basePrice
+     */
+    public function processAssert(
+        BrowserInterface $browser,
+        InjectableFixture $product,
+        CatalogProductView $view,
+        $basePrice
+    ) {
+        $browser->open($_ENV['app_frontend_url'] . $product->getUrlKey() . '.html');
+        $this->assertPrice($view, $basePrice);
+    }
+
+    /**
+     * Assert price.
+     *
+     * @param CatalogProductView $view
+     * @param string $price
+     * @param string $currency [optional]
+     */
+    public function assertPrice(CatalogProductView $view, $price, $currency = '')
+    {
+        \PHPUnit_Framework_Assert::assertEquals(
+            $price,
+            $view->getViewBlock()->getPriceBlock()->getPrice($currency),
+            'Wrong price is displayed on Product page.'
+        );
+    }
+
+    /**
+     * Returns a string representation of successful assertion.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return "Currency rate has been applied correctly on Product page.";
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/Repository/ConfigData.xml b/dev/tests/functional/tests/app/Magento/Directory/Test/Repository/ConfigData.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7046437a0f4e2916aaa21e7eca1b902794aa8b9d
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Directory/Test/Repository/ConfigData.xml
@@ -0,0 +1,33 @@
+<?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="../../../../../../vendor/magento/mtf/Magento/Mtf/Repository/etc/repository.xsd">
+    <repository class="Magento\Config\Test\Repository\ConfigData">
+        <dataset name="config_base_currency_us_display_currency_uah">
+            <field name="currency/options/allow" xsi:type="array">
+                <item name="scope" xsi:type="string">currency</item>
+                <item name="scope_id" xsi:type="number">1</item>
+                <item name="value" xsi:type="array">
+                    <item name="Ukrainian Hryvnia" xsi:type="string">UAH</item>
+                    <item name="US Dollar" xsi:type="string">USD</item>
+                </item>
+            </field>
+            <field name="currency/options/base" xsi:type="array">
+                <item name="scope" xsi:type="string">currency</item>
+                <item name="label" xsi:type="string">US Dollar</item>
+                <item name="scope_id" xsi:type="number">1</item>
+                <item name="value" xsi:type="string">USD</item>
+            </field>
+            <field name="currency/options/default" xsi:type="array">
+                <item name="scope" xsi:type="string">currency</item>
+                <item name="label" xsi:type="string">Ukrainian Hryvnia</item>
+                <item name="scope_id" xsi:type="number">1</item>
+                <item name="value" xsi:type="string">UAH</item>
+            </field>
+        </dataset>
+    </repository>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.php b/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.php
index bc40a2ab98f6d913b80736346c7c06ef6f1c7f9e..c7841934035cadcf40b55931f748948427504652 100644
--- a/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.php
+++ b/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.php
@@ -6,11 +6,12 @@
 
 namespace Magento\Directory\Test\TestCase;
 
+use Magento\Catalog\Test\TestStep\CreateProductsStep;
 use Magento\Config\Test\Fixture\ConfigData;
 use Magento\Mtf\TestCase\Injectable;
 use Magento\Directory\Test\Fixture\CurrencyRate;
-use Magento\Catalog\Test\Fixture\CatalogProductSimple;
 use Magento\CurrencySymbol\Test\Page\Adminhtml\SystemCurrencyIndex;
+use Magento\Mtf\TestStep\TestStepFactory;
 
 /**
  * Preconditions:
@@ -41,35 +42,48 @@ class CreateCurrencyRateTest extends Injectable
      */
     protected $currencyIndexPage;
 
+    /**
+     * Test step factory.
+     *
+     * @var TestStepFactory
+     */
+    private $stepFactory;
+
     /**
      * Inject data.
      *
      * @param SystemCurrencyIndex $currencyIndexPage
-     * @return void
+     * @param TestStepFactory $stepFactory
      */
-    public function __inject(SystemCurrencyIndex $currencyIndexPage)
+    public function __inject(SystemCurrencyIndex $currencyIndexPage, TestStepFactory $stepFactory)
     {
         $this->currencyIndexPage = $currencyIndexPage;
+        $this->stepFactory = $stepFactory;
     }
 
     /**
      * Create currency rate test.
      *
      * @param CurrencyRate $currencyRate
-     * @param CatalogProductSimple $product
-     * @param $config
-     * @return void
+     * @param ConfigData $config
+     * @param string $product
+     * @param array $productData [optional]
+     * @return array
      */
-    public function test(CurrencyRate $currencyRate, CatalogProductSimple $product, ConfigData $config)
+    public function test(CurrencyRate $currencyRate, ConfigData $config, $product, array $productData = [])
     {
         // Preconditions:
-        $product->persist();
+        $product = $this->stepFactory
+            ->create(CreateProductsStep::class, ['products' => [$product], 'data' => $productData])
+            ->run()['products'][0];
         $config->persist();
 
         // Steps:
         $this->currencyIndexPage->open();
         $this->currencyIndexPage->getCurrencyRateForm()->fill($currencyRate);
         $this->currencyIndexPage->getFormPageActions()->save();
+
+        return ['product' => $product];
     }
 
     /**
diff --git a/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.xml b/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.xml
index dd42950c18a78175ce51fb7cfce85fe7fbc85a0c..e984cad9ca327aa2a0896e44fc85e365e9f24503 100644
--- a/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.xml
+++ b/dev/tests/functional/tests/app/Magento/Directory/Test/TestCase/CreateCurrencyRateTest.xml
@@ -13,12 +13,25 @@
             <data name="currencyRate/data/currency_to" xsi:type="string">EUR</data>
             <data name="currencyRate/data/rate" xsi:type="number">0.8</data>
             <data name="currencySymbol/dataset" xsi:type="string">currency_symbols_eur</data>
-            <data name="product/dataset" xsi:type="string">simple_10_dollar</data>
+            <data name="product" xsi:type="string">catalogProductSimple::simple_10_dollar</data>
             <data name="config/dataset" xsi:type="string">config_currency_symbols_usd_and_eur</data>
             <data name="basePrice" xsi:type="string">$10.00</data>
             <data name="convertedPrice" xsi:type="string">€8.00</data>
             <constraint name="Magento\Directory\Test\Constraint\AssertCurrencyRateSuccessSaveMessage" />
             <constraint name="Magento\Directory\Test\Constraint\AssertCurrencyRateAppliedOnCatalogPage" />
         </variation>
+        <variation name="CreateCurrencyRateTestVariation2">
+            <data name="currencyRate/data/currency_from" xsi:type="string">USD</data>
+            <data name="currencyRate/data/currency_to" xsi:type="string">UAH</data>
+            <data name="currencyRate/data/rate" xsi:type="number">2.000</data>
+            <data name="currencySymbol/dataSet" xsi:type="string">currency_symbols_uah</data>
+            <data name="product" xsi:type="string">catalogProductSimple::simple_10_dollar</data>
+            <data name="productData/0/custom_options/dataset" xsi:type="string">not_required_text_option</data>
+            <data name="config/dataset" xsi:type="string">config_base_currency_us_display_currency_uah</data>
+            <data name="basePrice" xsi:type="string">â‚´20.00</data>
+            <data name="tag" xsi:type="string">test_type:acceptance_test</data>
+            <constraint name="Magento\Directory\Test\Constraint\AssertCurrencyRateSuccessSaveMessage" />
+            <constraint name="Magento\Directory\Test\Constraint\AssertCurrencyRateAppliedOnProductPage" />
+        </variation>
     </testCase>
 </config>
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php
index f84c661126b04b9a30ec2ca84ef7d3f570d2a1bb..5db10afdee00284a4faa7249e273bb3d47ab5daf 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Controller/Adminhtml/CategoryTest.php
@@ -233,7 +233,7 @@ class CategoryTest extends \Magento\TestFramework\TestCase\AbstractBackendContro
                     'display_mode' => true,
                     'meta_title' => true,
                     'custom_design' => true,
-                    'page_layout' => false,
+                    'page_layout' => true,
                     'is_active' => true,
                     'include_in_menu' => true,
                     'landing_page' => true,
@@ -242,7 +242,7 @@ class CategoryTest extends \Magento\TestFramework\TestCase\AbstractBackendContro
                     'description' => true,
                     'meta_keywords' => true,
                     'meta_description' => true,
-                    'custom_layout_update' => false,
+                    'custom_layout_update' => true,
                     'custom_design_from' => true,
                     'custom_design_to' => true,
                     'filter_price_range' => false
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/dropdown_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/dropdown_attribute.php
new file mode 100644
index 0000000000000000000000000000000000000000..56e84046b255bf89c5f6aa6c1cb75cb7c7d584ba
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/dropdown_attribute.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/* Create attribute */
+/** @var $attribute \Magento\Catalog\Model\ResourceModel\Eav\Attribute */
+$attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+    \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class
+);
+
+if (!$attribute->loadByCode(4, 'dropdown_attribute')->getId()) {
+    /** @var $installer \Magento\Catalog\Setup\CategorySetup */
+    $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+        \Magento\Catalog\Setup\CategorySetup::class
+    );
+
+    $attribute->setData(
+        [
+            'attribute_code'                => 'dropdown_attribute',
+            'entity_type_id'                => $installer->getEntityTypeId('catalog_product'),
+            'is_global'                     => 0,
+            'is_user_defined'               => 1,
+            'frontend_input'                => 'select',
+            'is_unique'                     => 0,
+            'is_required'                   => 0,
+            'is_searchable'                 => 0,
+            'is_visible_in_advanced_search' => 0,
+            'is_comparable'                 => 0,
+            'is_filterable'                 => 0,
+            'is_filterable_in_search'       => 0,
+            'is_used_for_promo_rules'       => 0,
+            'is_html_allowed_on_front'      => 1,
+            'is_visible_on_front'           => 0,
+            'used_in_product_listing'       => 0,
+            'used_for_sort_by'              => 0,
+            'frontend_label'                => ['Drop-Down Attribute'],
+            'backend_type'                  => 'varchar',
+            'backend_model'                 => \Magento\Eav\Model\Entity\Attribute\Backend\ArrayBackend::class,
+            'option'                        => [
+                'value' => [
+                    'option_1' => ['Option 1'],
+                    'option_2' => ['Option 2'],
+                    'option_3' => ['Option 3'],
+                ],
+                'order' => [
+                    'option_1' => 1,
+                    'option_2' => 2,
+                    'option_3' => 3,
+                ],
+            ],
+        ]
+    );
+    $attribute->save();
+
+    /* Assign attribute to attribute set */
+    $installer->addAttributeToGroup('catalog_product', 'Default', 'Attributes', $attribute->getId());
+}
diff --git a/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/UpdateHandlerTest.php b/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/UpdateHandlerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1f8b20b7b041119a0394e0d3d8b83de3aeb727c4
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Eav/Model/ResourceModel/UpdateHandlerTest.php
@@ -0,0 +1,256 @@
+<?php
+/**
+ * Copyright © 2016 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Eav\Model\ResourceModel;
+
+use Magento\TestFramework\Helper\Bootstrap;
+
+/**
+ * @magentoAppArea adminhtml
+ * @magentoAppIsolation enabled
+ */
+class UpdateHandlerTest extends \Magento\TestFramework\Indexer\TestCase
+{
+    /**
+     * @covers       \Magento\Eav\Model\ResourceModel\UpdateHandler::execute
+     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+     * @dataProvider getAllStoresDataProvider
+     * @param $code
+     * @param $snapshotValue
+     * @param $newValue
+     * @param $expected
+     */
+    public function testExecuteProcessForAllStores($code, $snapshotValue, $newValue, $expected)
+    {
+        if ($snapshotValue !== '-') {
+            $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+            $entity->setStoreId(0);
+            $entity->load(1);
+            $entity->setData($code, $snapshotValue);
+            $entity->save();
+        }
+
+        $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+        $entity->setStoreId(0);
+        $entity->load(1);
+
+        $updateHandler = Bootstrap::getObjectManager()->create(UpdateHandler::class);
+        $entityData = array_merge($entity->getData(), [$code => $newValue]);
+        $updateHandler->execute(\Magento\Catalog\Api\Data\ProductInterface::class, $entityData);
+
+        $resultEntity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+        $resultEntity->setStoreId(0);
+        $resultEntity->load(1);
+
+        $this->assertSame($expected, $resultEntity->getData($code));
+    }
+
+    /**
+     * @covers       \Magento\Eav\Model\ResourceModel\UpdateHandlerTest::execute
+     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+     * @magentoDataFixture Magento/Store/_files/second_store.php
+     * @dataProvider getCustomStoreDataProvider
+     * @param $code
+     * @param $snapshotValue
+     * @param $newValue
+     * @param $expected
+     */
+    public function testExecuteProcessForCustomStore($code, $snapshotValue, $newValue, $expected)
+    {
+        $store = Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class);
+        $store->load('fixture_second_store', 'code');
+
+        Bootstrap::getObjectManager()
+            ->create(\Magento\CatalogSearch\Model\Indexer\Fulltext\Processor::class)
+            ->reindexAll();
+
+        if ($snapshotValue !== '-') {
+            $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+            $entity->setStoreId($store->getId());
+            $entity->load(1);
+            $entity->setData($code, $snapshotValue);
+            $entity->save();
+        }
+
+        $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+        $entity->setStoreId($store->getId());
+        $entity->load(1);
+
+        $updateHandler = Bootstrap::getObjectManager()->create(UpdateHandler::class);
+        $entityData = array_merge($entity->getData(), [$code => $newValue]);
+        $updateHandler->execute(\Magento\Catalog\Api\Data\ProductInterface::class, $entityData);
+
+        $resultEntity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+        $resultEntity->setStoreId($store->getId());
+        $resultEntity->load(1);
+
+        $this->assertSame($expected, $resultEntity->getData($code));
+    }
+
+    /**
+     * @covers       \Magento\Eav\Model\ResourceModel\UpdateHandlerTest::execute
+     * @magentoDataFixture Magento/Catalog/_files/product_simple.php
+     * @magentoDataFixture Magento/Catalog/_files/dropdown_attribute.php
+     * @magentoDataFixture Magento/Store/_files/second_store.php
+     * @dataProvider getCustomAttributeDataProvider
+     * @param $code
+     * @param $defaultStoreValue
+     * @param $snapshotValue
+     * @param $newValue
+     * @param $expected
+     */
+    public function testExecuteProcessForCustomAttributeInCustomStore(
+        $code,
+        $defaultStoreValue,
+        $snapshotValue,
+        $newValue,
+        $expected
+    ) {
+        $store = Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class);
+        $store->load('fixture_second_store', 'code');
+
+        Bootstrap::getObjectManager()
+            ->create(\Magento\CatalogSearch\Model\Indexer\Fulltext\Processor::class)
+            ->reindexAll();
+
+        $attribute = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+            \Magento\Catalog\Model\ResourceModel\Eav\Attribute::class
+        );
+        $attribute->loadByCode(4, $code);
+
+        $options = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
+            \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection::class
+        );
+        $options->setAttributeFilter($attribute->getId());
+        $optionIds = $options->getAllIds();
+
+        $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+        $entity->setStoreId(0);
+        $entity->load(1);
+        $entity->setData($code, $optionIds[$defaultStoreValue]);
+        $entity->save();
+
+        if ($snapshotValue !== '-') {
+            /** @var $options \Magento\Eav\Model\ResourceModel\Entity\Attribute\Option\Collection */
+            $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+            $entity->setStoreId($store->getId());
+            $entity->load(1);
+
+            if ($snapshotValue) {
+                $snapshotValue = $optionIds[$snapshotValue];
+            }
+
+            $entity->setData($code, $snapshotValue);
+            $entity->save();
+        }
+
+        $entity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+        $entity->setStoreId($store->getId());
+        $entity->load(1);
+
+        $updateHandler = Bootstrap::getObjectManager()->create(UpdateHandler::class);
+
+        if ($newValue) {
+            $newValue = $optionIds[$newValue];
+        }
+
+        $entityData = array_merge($entity->getData(), [$code => $newValue]);
+        $updateHandler->execute(\Magento\Catalog\Api\Data\ProductInterface::class, $entityData);
+
+        $resultEntity = Bootstrap::getObjectManager()->create(\Magento\Catalog\Model\Product::class);
+        $resultEntity->setStoreId($store->getId());
+        $resultEntity->load(1);
+
+        if ($expected !== null) {
+            $expected = $optionIds[$expected];
+        }
+
+        $this->assertSame($expected, $resultEntity->getData($code));
+    }
+
+    /**
+     * @return array
+     */
+    public function getAllStoresDataProvider()
+    {
+        return [
+            ['description', '', 'not_empty_value', 'not_empty_value'],                  //0
+            ['description', '', '', null],                                              //1
+            ['description', '', null, null],                                            //2
+            ['description', '', false, null],                                           //3
+
+            ['description', 'not_empty_value', 'not_empty_value2', 'not_empty_value2'], //4
+            ['description', 'not_empty_value', '', null],                               //5
+            ['description', 'not_empty_value', null, null],                             //6
+            ['description', 'not_empty_value', false, null],                            //7
+
+            ['description', null, 'not_empty_value', 'not_empty_value'],                //8
+            ['description', null, '', null],                                            //9
+            ['description', null, false, null],                                         //10
+
+            ['description', false, 'not_empty_value', 'not_empty_value'],               //11
+            ['description', false, '', null],                                           //12
+            ['description', false, null, null],                                         //13
+        ];
+    }
+
+    /**
+     * @return array
+     */
+    public function getCustomStoreDataProvider()
+    {
+        return [
+            ['description', '', 'not_empty_value', 'not_empty_value'],                  //0
+            ['description', '', '', null],                                              //1
+            ['description', '', null, 'Description with <b>html tag</b>'],              //2
+            ['description', '', false, 'Description with <b>html tag</b>'],             //3
+
+            ['description', 'not_empty_value', 'not_empty_value2', 'not_empty_value2'], //4
+            ['description', 'not_empty_value', '', null],                               //5
+            ['description', 'not_empty_value', null, 'Description with <b>html tag</b>'], //6
+            ['description', 'not_empty_value', false, 'Description with <b>html tag</b>'], //7
+
+            ['description', null, 'not_empty_value', 'not_empty_value'],                 //8
+            ['description', null, '', null],                                             //9
+            ['description', null, false, 'Description with <b>html tag</b>'],            //10
+
+            ['description', false, 'not_empty_value', 'not_empty_value'],                //11
+            ['description', false, '', null],                                            //12
+            ['description', false, null, 'Description with <b>html tag</b>'],            //13
+        ];
+    }
+
+    /**
+     * @return array
+     */
+    public function getCustomAttributeDataProvider()
+    {
+        return [
+            ['dropdown_attribute', 0, '', 1, 1],        //0
+            ['dropdown_attribute', 0, '', '', null],    //1
+            ['dropdown_attribute', 0, '', null, 0],     //2
+            ['dropdown_attribute', 0, '', false, 0],    //3
+
+            ['dropdown_attribute', 0, 1, 2, 2],         //4
+            ['dropdown_attribute', 0, 1, '', null],     //5
+            ['dropdown_attribute', 0, 1, null, 0],      //6
+            ['dropdown_attribute', 0, 1, false, 0],     //7
+
+            ['dropdown_attribute', 0, null, 1, 1],      //8
+            ['dropdown_attribute', 0, null, '', null],  //9
+            ['dropdown_attribute', 0, null, false, 0],  //10
+
+            ['dropdown_attribute', 0, false, 1, 1],     //11
+            ['dropdown_attribute', 0, false, '', null], //12
+            ['dropdown_attribute', 0, false, null, 0],  //13
+
+            ['dropdown_attribute', 0, '-', 1, 1],       //14
+            ['dropdown_attribute', 0, '-', '', null],   //15
+            ['dropdown_attribute', 0, '-', null, 0],    //16
+            ['dropdown_attribute', 0, '-', false, 0],   //17
+        ];
+    }
+}