diff --git a/app/code/Magento/Backend/App/Config.php b/app/code/Magento/Backend/App/Config.php
index d8eaa7af14254bd16dd3c8f7ae3cc9a549e75cde..0ac5211b41d9f58308d4f57977e0c8054c15e4c7 100644
--- a/app/code/Magento/Backend/App/Config.php
+++ b/app/code/Magento/Backend/App/Config.php
@@ -10,6 +10,8 @@
 
 namespace Magento\Backend\App;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 /**
  * Backend config accessor
  */
@@ -36,7 +38,7 @@ class Config implements ConfigInterface
      */
     public function getValue($path)
     {
-        return $this->_scopePool->getScope(\Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, null)->getValue($path);
+        return $this->_scopePool->getScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null)->getValue($path);
     }
 
     /**
@@ -48,7 +50,7 @@ class Config implements ConfigInterface
      */
     public function setValue($path, $value)
     {
-        $this->_scopePool->getScope(\Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, null)->setValue($path, $value);
+        $this->_scopePool->getScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null)->setValue($path, $value);
     }
 
     /**
@@ -59,6 +61,6 @@ class Config implements ConfigInterface
      */
     public function isSetFlag($path)
     {
-        return !!$this->_scopePool->getScope(\Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, null)->getValue($path);
+        return !!$this->_scopePool->getScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT, null)->getValue($path);
     }
 }
diff --git a/app/code/Magento/Backend/Block/Page/System/Config/Robots/Reset.php b/app/code/Magento/Backend/Block/Page/System/Config/Robots/Reset.php
index d32e99a00d814b5a134e9e3060526e7586f9043e..827ae18b0b8e1f908653597bc1816a6c73d9b148 100644
--- a/app/code/Magento/Backend/Block/Page/System/Config/Robots/Reset.php
+++ b/app/code/Magento/Backend/Block/Page/System/Config/Robots/Reset.php
@@ -8,6 +8,8 @@
 
 namespace Magento\Backend\Block\Page\System\Config\Robots;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 /**
  * "Reset to Defaults" button renderer
  *
@@ -50,7 +52,7 @@ class Reset extends \Magento\Config\Block\System\Config\Form\Field
     public function getRobotsDefaultCustomInstructions()
     {
         return trim((string)$this->_scopeConfig->getValue(
-            self::XML_PATH_ROBOTS_DEFAULT_CUSTOM_INSTRUCTIONS, \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+            self::XML_PATH_ROBOTS_DEFAULT_CUSTOM_INSTRUCTIONS, ScopeConfigInterface::SCOPE_TYPE_DEFAULT
         ));
     }
 
diff --git a/app/code/Magento/Backend/Console/Command/AbstractCacheCommand.php b/app/code/Magento/Backend/Console/Command/AbstractCacheCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..55cecac162335817125de204e9657bf4be3868fc
--- /dev/null
+++ b/app/code/Magento/Backend/Console/Command/AbstractCacheCommand.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Console\Command;
+
+use Magento\Framework\App\Cache\Manager;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputOption;
+
+abstract class AbstractCacheCommand extends Command
+{
+    /**
+     * Input option bootsrap
+     */
+    const INPUT_KEY_BOOTSTRAP = 'bootstrap';
+
+    /**
+     * CacheManager
+     *
+     * @var Manager
+     */
+    protected $cacheManager;
+
+    /**
+     * Constructor
+     *
+     * @param Manager $cacheManager
+     */
+    public function __construct(Manager $cacheManager)
+    {
+        $this->cacheManager = $cacheManager;
+        parent::__construct();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->addOption(
+            self::INPUT_KEY_BOOTSTRAP,
+            null,
+            InputOption::VALUE_REQUIRED,
+            'add or override parameters of the bootstrap'
+        );
+    }
+}
diff --git a/app/code/Magento/Backend/Console/Command/AbstractCacheManageCommand.php b/app/code/Magento/Backend/Console/Command/AbstractCacheManageCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..0644e7d41de44aee1d95449a8bc68eb63363b7fd
--- /dev/null
+++ b/app/code/Magento/Backend/Console/Command/AbstractCacheManageCommand.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Console\Command;
+
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+
+abstract class AbstractCacheManageCommand extends AbstractCacheCommand
+{
+    /**
+     * Input argument types
+     */
+    const INPUT_KEY_TYPES = 'types';
+
+    /**
+     * Input key all
+     */
+    const INPUT_KEY_ALL = 'all';
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->addArgument(
+            self::INPUT_KEY_TYPES,
+            InputArgument::IS_ARRAY,
+            'List of cache types, space separated. If omitted, all caches will be affected'
+        );
+        $this->addOption(
+            self::INPUT_KEY_ALL,
+            null,
+            InputOption::VALUE_NONE,
+            'All cache types'
+        );
+        parent::configure();
+    }
+
+
+    /**
+     * Get requested cache types
+     *
+     * @param InputInterface $input
+     * @return array
+     */
+    protected function getRequestedTypes(InputInterface $input)
+    {
+        $requestedTypes = [];
+        if ($input->getArgument(self::INPUT_KEY_TYPES)) {
+            $requestedTypes = $input->getArgument(self::INPUT_KEY_TYPES);
+            $requestedTypes = array_filter(array_map('trim', $requestedTypes), 'strlen');
+        }
+        if (empty($requestedTypes)) {
+            return [];
+        } else {
+            $availableTypes = $this->cacheManager->getAvailableTypes();
+            $unsupportedTypes = array_diff($requestedTypes, $availableTypes);
+            if ($unsupportedTypes) {
+                throw new \InvalidArgumentException(
+                    "The following requested cache types are not supported: '" . join("', '", $unsupportedTypes)
+                    . "'." . PHP_EOL . 'Supported types: ' . join(", ", $availableTypes)
+                );
+            }
+            return array_values(array_intersect($availableTypes, $requestedTypes));
+        }
+    }
+}
diff --git a/app/code/Magento/Backend/Console/Command/AbstractCacheSetCommand.php b/app/code/Magento/Backend/Console/Command/AbstractCacheSetCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..b1330c0de2d05f840c84c3b7f0135d1489cd5847
--- /dev/null
+++ b/app/code/Magento/Backend/Console/Command/AbstractCacheSetCommand.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+abstract class AbstractCacheSetCommand extends AbstractCacheManageCommand
+{
+    /**
+     * Is enable cache or not
+     *
+     * @return bool
+     */
+    abstract protected function isEnable();
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $isEnable = $this->isEnable();
+        if ($input->getOption(self::INPUT_KEY_ALL)) {
+            $types = $this->cacheManager->getAvailableTypes();
+        } else {
+            $types = $this->getRequestedTypes($input);
+        }
+        $changedTypes = $this->cacheManager->setEnabled($types, $isEnable);
+        if ($changedTypes) {
+            $output->writeln('Changed cache status:');
+            foreach ($changedTypes as $type) {
+                $output->writeln(sprintf('%30s: %d -> %d', $type, !$isEnable, $isEnable));
+            }
+        } else {
+            $output->writeln('There is nothing to change in cache status');
+        }
+        if (!empty($changedTypes) && $isEnable) {
+            $this->cacheManager->clean($changedTypes);
+            $output->writeln('Cleaned cache types:');
+            $output->writeln(join(PHP_EOL, $changedTypes));
+        }
+    }
+}
diff --git a/app/code/Magento/Backend/Console/Command/AbstractCacheTypeManageCommand.php b/app/code/Magento/Backend/Console/Command/AbstractCacheTypeManageCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..79583c2f08a2a6bcd62a0619192d179316bf8fb0
--- /dev/null
+++ b/app/code/Magento/Backend/Console/Command/AbstractCacheTypeManageCommand.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+abstract class AbstractCacheTypeManageCommand extends AbstractCacheManageCommand
+{
+    /**
+     * Perform a cache management action on cache types
+     *
+     * @param array $cacheTypes
+     * @return void
+     */
+    abstract protected function performAction(array $cacheTypes);
+
+    /**
+     * Get display message
+     *
+     * @return string
+     */
+    abstract protected function getDisplayMessage();
+
+    /**
+     * Perform cache management action
+     *
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @return void
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        if ($input->getOption(self::INPUT_KEY_ALL)) {
+            $types = $this->cacheManager->getAvailableTypes();
+        } else {
+            $types = $this->getRequestedTypes($input);
+        }
+        $this->performAction($types);
+        $output->writeln($this->getDisplayMessage());
+        $output->writeln(join(PHP_EOL, $types));
+    }
+}
diff --git a/app/code/Magento/Backend/Console/Command/CacheCleanCommand.php b/app/code/Magento/Backend/Console/Command/CacheCleanCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..ab57f0ff7b578611ee3a64402650aa07ba52219e
--- /dev/null
+++ b/app/code/Magento/Backend/Console/Command/CacheCleanCommand.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Console\Command;
+
+/**
+ * Command for cleaning cache
+ */
+class CacheCleanCommand extends AbstractCacheTypeManageCommand
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('cache:clean');
+        $this->setDescription('Cleans cache type(s)');
+        parent::configure();
+    }
+
+    /**
+     * Cleans cache types
+     *
+     * @param array $cacheTypes
+     * @return void
+     */
+    protected function performAction(array $cacheTypes)
+    {
+        $this->cacheManager->clean($cacheTypes);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getDisplayMessage()
+    {
+        return 'Cleaned cache types:';
+    }
+}
diff --git a/app/code/Magento/Backend/Console/Command/CacheDisableCommand.php b/app/code/Magento/Backend/Console/Command/CacheDisableCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..a3d94e0b44cc3871d29a24537e427f59ed0bbaef
--- /dev/null
+++ b/app/code/Magento/Backend/Console/Command/CacheDisableCommand.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Console\Command;
+
+/**
+ * Command for disabling cache
+ */
+class CacheDisableCommand extends AbstractCacheSetCommand
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('cache:disable');
+        $this->setDescription('Disables cache type(s)');
+        parent::configure();
+    }
+
+    /**
+     * Is Disable cache
+     *
+     * @return bool
+     */
+    protected function isEnable()
+    {
+        return false;
+    }
+}
diff --git a/app/code/Magento/Backend/Console/Command/CacheEnableCommand.php b/app/code/Magento/Backend/Console/Command/CacheEnableCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..3109cd650e793e23d04992d6836c6078d2bf015a
--- /dev/null
+++ b/app/code/Magento/Backend/Console/Command/CacheEnableCommand.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Console\Command;
+
+/**
+ * Command for enabling cache
+ */
+class CacheEnableCommand extends AbstractCacheSetCommand
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('cache:enable');
+        $this->setDescription('Enables cache type(s)');
+        parent::configure();
+    }
+
+    /**
+     * Is enable cache
+     *
+     * @return bool
+     */
+    protected function isEnable()
+    {
+        return true;
+    }
+}
diff --git a/app/code/Magento/Backend/Console/Command/CacheFlushCommand.php b/app/code/Magento/Backend/Console/Command/CacheFlushCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..c847204de9043e84ded25607e890273441ec0e4e
--- /dev/null
+++ b/app/code/Magento/Backend/Console/Command/CacheFlushCommand.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Console\Command;
+
+/**
+ * Command for flushing cache
+ */
+class CacheFlushCommand extends AbstractCacheTypeManageCommand
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('cache:flush');
+        $this->setDescription('Flushes cache storage used by cache type(s)');
+        parent::configure();
+    }
+
+    /**
+     * Flushes cache types
+     *
+     * @param array $cacheTypes
+     * @return void
+     */
+    protected function performAction(array $cacheTypes)
+    {
+        $this->cacheManager->flush($cacheTypes);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function getDisplayMessage()
+    {
+        return 'Flushed cache types:';
+    }
+}
diff --git a/app/code/Magento/Backend/Console/Command/CacheStatusCommand.php b/app/code/Magento/Backend/Console/Command/CacheStatusCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..445cf42a4cd016cb0d8924e6fdf47fd8aa1c153c
--- /dev/null
+++ b/app/code/Magento/Backend/Console/Command/CacheStatusCommand.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Command for checking cache status
+ */
+class CacheStatusCommand extends AbstractCacheCommand
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('cache:status');
+        $this->setDescription('Checks cache status');
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $output->writeln('Current status:');
+        foreach ($this->cacheManager->getStatus() as $cache => $status) {
+            $output->writeln(sprintf('%30s: %d', $cache, $status));
+        }
+    }
+}
diff --git a/app/code/Magento/Backend/Model/Auth/Session.php b/app/code/Magento/Backend/Model/Auth/Session.php
index fec438f70c744d7b7cc9999d8574f3e4deef862c..d5cf7e86c4b8ae8c301a2993893a9d31d615e7e5 100644
--- a/app/code/Magento/Backend/Model/Auth/Session.php
+++ b/app/code/Magento/Backend/Model/Auth/Session.php
@@ -61,9 +61,11 @@ class Session extends \Magento\Framework\Session\SessionManager implements \Mage
      * @param \Magento\Framework\Session\StorageInterface $storage
      * @param CookieManagerInterface $cookieManager
      * @param CookieMetadataFactory $cookieMetadataFactory
+     * @param \Magento\Framework\App\State $appState
      * @param \Magento\Framework\Acl\Builder $aclBuilder
      * @param \Magento\Backend\Model\UrlInterface $backendUrl
      * @param \Magento\Backend\App\ConfigInterface $config
+     * @throws \Magento\Framework\Exception\SessionException
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -75,6 +77,7 @@ class Session extends \Magento\Framework\Session\SessionManager implements \Mage
         \Magento\Framework\Session\StorageInterface $storage,
         CookieManagerInterface $cookieManager,
         CookieMetadataFactory $cookieMetadataFactory,
+        \Magento\Framework\App\State $appState,
         \Magento\Framework\Acl\Builder $aclBuilder,
         \Magento\Backend\Model\UrlInterface $backendUrl,
         \Magento\Backend\App\ConfigInterface $config
@@ -90,9 +93,9 @@ class Session extends \Magento\Framework\Session\SessionManager implements \Mage
             $validator,
             $storage,
             $cookieManager,
-            $cookieMetadataFactory
+            $cookieMetadataFactory,
+            $appState
         );
-        $this->start();
     }
 
     /**
diff --git a/app/code/Magento/Backend/Model/Locale/Manager.php b/app/code/Magento/Backend/Model/Locale/Manager.php
index 76a327f1364d1b42a05f3ea000474049d5b87068..4f9584c96a81706b0eaefafd3137a27d75291fc3 100644
--- a/app/code/Magento/Backend/Model/Locale/Manager.php
+++ b/app/code/Magento/Backend/Model/Locale/Manager.php
@@ -68,7 +68,7 @@ class Manager
      */
     public function getUserInterfaceLocale()
     {
-        $interfaceLocale = \Magento\Framework\Locale\ResolverInterface::DEFAULT_LOCALE;
+        $interfaceLocale = \Magento\Framework\Locale\Resolver::DEFAULT_LOCALE;
 
         $userData = $this->_authSession->getUser();
         if ($userData && $userData->getInterfaceLocale()) {
diff --git a/app/code/Magento/Backend/Model/Session.php b/app/code/Magento/Backend/Model/Session.php
index c0719bb2ecf9ef98084a0ecba7e11630732eddbf..6dd5af4a3c54830029f8372e214009a4e3b04bef 100644
--- a/app/code/Magento/Backend/Model/Session.php
+++ b/app/code/Magento/Backend/Model/Session.php
@@ -9,39 +9,6 @@ namespace Magento\Backend\Model;
 
 class Session extends \Magento\Framework\Session\SessionManager
 {
-    /**
-     * @param \Magento\Framework\App\Request\Http $request
-     * @param \Magento\Framework\Session\SidResolverInterface $sidResolver
-     * @param \Magento\Framework\Session\Config\ConfigInterface $sessionConfig
-     * @param \Magento\Framework\Session\SaveHandlerInterface $saveHandler
-     * @param \Magento\Framework\Session\ValidatorInterface $validator
-     * @param \Magento\Framework\Session\StorageInterface $storage
-     * @param \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager
-     * @param \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory
-     */
-    public function __construct(
-        \Magento\Framework\App\Request\Http $request,
-        \Magento\Framework\Session\SidResolverInterface $sidResolver,
-        \Magento\Framework\Session\Config\ConfigInterface $sessionConfig,
-        \Magento\Framework\Session\SaveHandlerInterface $saveHandler,
-        \Magento\Framework\Session\ValidatorInterface $validator,
-        \Magento\Framework\Session\StorageInterface $storage,
-        \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager,
-        \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory
-    ) {
-        parent::__construct(
-            $request,
-            $sidResolver,
-            $sessionConfig,
-            $saveHandler,
-            $validator,
-            $storage,
-            $cookieManager,
-            $cookieMetadataFactory
-        );
-        $this->start();
-    }
-
     /**
      * Skip path validation in backend area
      *
diff --git a/app/code/Magento/Backend/Model/Session/Quote.php b/app/code/Magento/Backend/Model/Session/Quote.php
index 2f1f75ab07e9201d03ec0706fc3a0fb20f42ddc1..1427e1ad5ad570d5ea93c0f5cef3c5cdfd71c4cb 100644
--- a/app/code/Magento/Backend/Model/Session/Quote.php
+++ b/app/code/Magento/Backend/Model/Session/Quote.php
@@ -83,11 +83,13 @@ class Quote extends \Magento\Framework\Session\SessionManager
      * @param \Magento\Framework\Session\StorageInterface $storage
      * @param \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager
      * @param \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory
+     * @param \Magento\Framework\App\State $appState
      * @param CustomerRepositoryInterface $customerRepository
      * @param \Magento\Quote\Model\QuoteRepository $quoteRepository
      * @param \Magento\Sales\Model\OrderFactory $orderFactory
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param GroupManagementInterface $groupManagement
+     * @throws \Magento\Framework\Exception\SessionException
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -99,6 +101,7 @@ class Quote extends \Magento\Framework\Session\SessionManager
         \Magento\Framework\Session\StorageInterface $storage,
         \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager,
         \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory,
+        \Magento\Framework\App\State $appState,
         CustomerRepositoryInterface $customerRepository,
         \Magento\Quote\Model\QuoteRepository $quoteRepository,
         \Magento\Sales\Model\OrderFactory $orderFactory,
@@ -118,9 +121,9 @@ class Quote extends \Magento\Framework\Session\SessionManager
             $validator,
             $storage,
             $cookieManager,
-            $cookieMetadataFactory
+            $cookieMetadataFactory,
+            $appState
         );
-        $this->start();
         if ($this->_storeManager->hasSingleStore()) {
             $this->setStoreId($this->_storeManager->getStore(true)->getId());
         }
@@ -147,7 +150,7 @@ class Quote extends \Magento\Framework\Session\SessionManager
                     $this->_quote->setStoreId($this->getStoreId());
                 }
 
-                if ($this->getCustomerId()) {
+                if ($this->getCustomerId() && $this->getCustomerId() != $this->_quote->getCustomerId()) {
                     $customer = $this->customerRepository->getById($this->getCustomerId());
                     $this->_quote->assignCustomer($customer);
                 }
diff --git a/app/code/Magento/Backend/Model/Url.php b/app/code/Magento/Backend/Model/Url.php
index 265a7237ed37e1713fb17d97a3674c633d406341..36fbfafe66974d236c0bc90c2d7133fc3bcf128b 100644
--- a/app/code/Magento/Backend/Model/Url.php
+++ b/app/code/Magento/Backend/Model/Url.php
@@ -83,7 +83,7 @@ class Url extends \Magento\Framework\Url implements \Magento\Backend\Model\UrlIn
      * @param \Magento\Framework\Url\ScopeResolverInterface $scopeResolver
      * @param \Magento\Framework\Session\Generic $session
      * @param \Magento\Framework\Session\SidResolverInterface $sidResolver
-     * @param \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolver
+     * @param \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory
      * @param \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param string $scopeType
@@ -105,7 +105,7 @@ class Url extends \Magento\Framework\Url implements \Magento\Backend\Model\UrlIn
         \Magento\Framework\Url\ScopeResolverInterface $scopeResolver,
         \Magento\Framework\Session\Generic $session,
         \Magento\Framework\Session\SidResolverInterface $sidResolver,
-        \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolver,
+        \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory,
         \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         $scopeType,
@@ -126,7 +126,7 @@ class Url extends \Magento\Framework\Url implements \Magento\Backend\Model\UrlIn
             $scopeResolver,
             $session,
             $sidResolver,
-            $routeParamsResolver,
+            $routeParamsResolverFactory,
             $queryParamsResolver,
             $scopeConfig,
             $scopeType,
diff --git a/app/code/Magento/Backend/Test/Unit/Console/Command/CacheCleanCommandTest.php b/app/code/Magento/Backend/Test/Unit/Console/Command/CacheCleanCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..5177df7711e43ef9a90f1072ebfe5b482abe0e1c
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Console/Command/CacheCleanCommandTest.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Test\Unit\Console\Command;
+
+use Magento\Backend\Console\Command\CacheCleanCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class CacheCleanCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\Cache\Manager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $cacheManager;
+
+    /**
+     * @var CacheCleanCommand
+     */
+    private $command;
+
+    public function setUp()
+    {
+        $this->cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false);
+        $this->command = new CacheCleanCommand($this->cacheManager);
+    }
+
+    public function testExecute()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $this->cacheManager->expects($this->once())->method('clean')->with(['A', 'B']);
+        $param = ['types' => ['A', 'B']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+        $expect = 'Cleaned cache types:' . PHP_EOL . 'A' . PHP_EOL . 'B' . PHP_EOL;
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage The following requested cache types are not supported:
+     */
+    public function testExecuteInvalidCacheType()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $param = ['types' => ['A', 'D']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+    }
+
+    public function testExecuteAllCacheType()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $this->cacheManager->expects($this->once())->method('clean')->with(['A', 'B', 'C']);
+        $param = ['--all' => true];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+        $expect = 'Cleaned cache types:' . PHP_EOL . 'A' . PHP_EOL . 'B' . PHP_EOL . 'C' . PHP_EOL;
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+}
diff --git a/app/code/Magento/Backend/Test/Unit/Console/Command/CacheDisableCommandTest.php b/app/code/Magento/Backend/Test/Unit/Console/Command/CacheDisableCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..82a477ad924571be565534cc9976e80e0ce2b1ab
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Console/Command/CacheDisableCommandTest.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Test\Unit\Console\Command;
+
+use Magento\Backend\Console\Command\CacheDisableCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class CacheDisableCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\Cache\Manager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $cacheManager;
+
+    /**
+     * @var CacheDisableCommand
+     */
+    private $command;
+
+    public function setUp()
+    {
+        $this->cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false);
+        $this->command = new CacheDisableCommand($this->cacheManager);
+    }
+
+    public function testExecute()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $this->cacheManager
+            ->expects($this->once())
+            ->method('setEnabled')
+            ->with(['A', 'B'], false)
+            ->willReturn(['A', 'B']);
+        $param = ['types' => ['A', 'B']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+
+        $expect = 'Changed cache status:' . PHP_EOL;
+        foreach (['A', 'B'] as $cacheType) {
+            $expect .= sprintf('%30s: %d -> %d', $cacheType, true, false) . PHP_EOL;
+        }
+
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+
+    public function testExecuteAll()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $this->cacheManager
+            ->expects($this->once())
+            ->method('setEnabled')
+            ->with(['A', 'B', 'C'], false)
+            ->willReturn(['A', 'B', 'C']);
+        $param = ['--all' => true];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+
+        $expect = 'Changed cache status:' . PHP_EOL;
+        foreach (['A', 'B', 'C'] as $cacheType) {
+            $expect .= sprintf('%30s: %d -> %d', $cacheType, true, false) . PHP_EOL;
+        }
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+
+    public function testExecuteNoChanges()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $this->cacheManager
+            ->expects($this->once())
+            ->method('setEnabled')
+            ->with(['A', 'B'], false)
+            ->willReturn([]);
+        $this->cacheManager->expects($this->never())->method('clean');
+        $param = ['types' => ['A', 'B']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+
+        $expect = 'There is nothing to change in cache status' . PHP_EOL;
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage The following requested cache types are not supported:
+     */
+    public function testExecuteInvalidCacheType()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $param = ['types' => ['A', 'D']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+    }
+}
diff --git a/app/code/Magento/Backend/Test/Unit/Console/Command/CacheEnableCommandTest.php b/app/code/Magento/Backend/Test/Unit/Console/Command/CacheEnableCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..f5b9ea8e8ec4fa5a88b2aa6a6a7a9fb51b219308
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Console/Command/CacheEnableCommandTest.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Test\Unit\Console\Command;
+
+use Magento\Backend\Console\Command\CacheEnableCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class CacheEnableCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\Cache\Manager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $cacheManager;
+
+    /**
+     * @var CacheEnableCommand
+     */
+    private $command;
+
+    public function setUp()
+    {
+        $this->cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false);
+        $this->command = new CacheEnableCommand($this->cacheManager);
+    }
+
+    public function testExecute()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $this->cacheManager
+            ->expects($this->once())
+            ->method('setEnabled')
+            ->with(['A', 'B'], true)
+            ->willReturn(['A', 'B']);
+        $this->cacheManager->expects($this->once())->method('clean')->with(['A', 'B']);
+        $param = ['types' => ['A', 'B']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+
+        $expect = 'Changed cache status:' . PHP_EOL;
+        foreach (['A', 'B'] as $cacheType) {
+            $expect .= sprintf('%30s: %d -> %d', $cacheType, false, true) . PHP_EOL;
+        }
+        $expect .= 'Cleaned cache types:' . PHP_EOL;
+        $expect .= 'A' . PHP_EOL . 'B' . PHP_EOL;
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+
+    public function testExecuteAll()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $this->cacheManager
+            ->expects($this->once())
+            ->method('setEnabled')
+            ->with(['A', 'B', 'C'], true)
+            ->willReturn(['A', 'B', 'C']);
+        $this->cacheManager->expects($this->once())->method('clean')->with(['A', 'B', 'C']);
+        $param = ['--all' => true];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+
+        $expect = 'Changed cache status:' . PHP_EOL;
+        foreach (['A', 'B', 'C'] as $cacheType) {
+            $expect .= sprintf('%30s: %d -> %d', $cacheType, false, true) . PHP_EOL;
+        }
+        $expect .= 'Cleaned cache types:' . PHP_EOL;
+        $expect .= 'A' . PHP_EOL . 'B' . PHP_EOL . 'C' . PHP_EOL;
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+
+    public function testExecuteNoChanges()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $this->cacheManager
+            ->expects($this->once())
+            ->method('setEnabled')
+            ->with(['A', 'B'], true)
+            ->willReturn([]);
+        $this->cacheManager->expects($this->never())->method('clean');
+        $param = ['types' => ['A', 'B']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+
+        $expect = 'There is nothing to change in cache status' . PHP_EOL;
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage The following requested cache types are not supported:
+     */
+    public function testExecuteInvalidCacheType()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $param = ['types' => ['A', 'D']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+    }
+}
diff --git a/app/code/Magento/Backend/Test/Unit/Console/Command/CacheFlushCommandTest.php b/app/code/Magento/Backend/Test/Unit/Console/Command/CacheFlushCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b443efd1a93e0c07eeb9e8ea526e4d0812e7e913
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Console/Command/CacheFlushCommandTest.php
@@ -0,0 +1,63 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Test\Unit\Console\Command;
+
+use Magento\Backend\Console\Command\CacheFlushCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class CacheFlushCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\Cache\Manager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $cacheManager;
+
+    /**
+     * @var CacheFlushCommand
+     */
+    private $command;
+
+    public function setUp()
+    {
+        $this->cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false);
+        $this->command = new CacheFlushCommand($this->cacheManager);
+    }
+
+    public function testExecute()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $this->cacheManager->expects($this->once())->method('flush')->with(['A', 'B']);
+        $param = ['types' => ['A', 'B']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+        $expect = 'Flushed cache types:' . PHP_EOL . 'A' . PHP_EOL . 'B' . PHP_EOL;
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage The following requested cache types are not supported:
+     */
+    public function testExecuteInvalidCacheType()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $param = ['types' => ['A', 'D']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+    }
+
+    public function testExecuteAllCacheType()
+    {
+        $this->cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['A', 'B', 'C']);
+        $this->cacheManager->expects($this->once())->method('flush')->with(['A', 'B', 'C']);
+        $param = ['--all' => true];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($param);
+        $expect = 'Flushed cache types:' . PHP_EOL . 'A' . PHP_EOL . 'B' . PHP_EOL . 'C' . PHP_EOL;
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+}
diff --git a/app/code/Magento/Backend/Test/Unit/Console/Command/CacheStatusCommandTest.php b/app/code/Magento/Backend/Test/Unit/Console/Command/CacheStatusCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..158c2a7783c906bc0ec6181e91985cbd18cc9b6f
--- /dev/null
+++ b/app/code/Magento/Backend/Test/Unit/Console/Command/CacheStatusCommandTest.php
@@ -0,0 +1,42 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Backend\Test\Unit\Console\Command;
+
+use Magento\Backend\Console\Command\CacheStatusCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class CacheStatusCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\Cache\Manager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $cacheManager;
+
+    /**
+     * @var CacheStatusCommand
+     */
+    private $command;
+
+    public function setUp()
+    {
+        $this->cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false);
+        $this->command = new CacheStatusCommand($this->cacheManager);
+    }
+
+    public function testExecute()
+    {
+        $cacheTypes = ['A' => 0, 'B' => 1, 'C' => 1];
+        $this->cacheManager->expects($this->once())->method('getStatus')->willReturn($cacheTypes);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute([]);
+        $expect = 'Current status:' . PHP_EOL;
+        foreach ($cacheTypes as $cacheType => $status) {
+            $expect .= sprintf('%30s: %d', $cacheType, $status) . PHP_EOL;
+        }
+        $this->assertEquals($expect, $commandTester->getDisplay());
+    }
+}
diff --git a/app/code/Magento/Backend/Test/Unit/Model/Locale/ManagerTest.php b/app/code/Magento/Backend/Test/Unit/Model/Locale/ManagerTest.php
index 000c861f11d8eba4c098f8427df867287de61c2d..a624a526d5dbffd7dcd06460a11872fb1f4328c2 100644
--- a/app/code/Magento/Backend/Test/Unit/Model/Locale/ManagerTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Model/Locale/ManagerTest.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Backend\Test\Unit\Model\Locale;
 
+use Magento\Framework\Locale\Resolver;
+
 class ManagerTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -87,7 +89,7 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
     {
         $locale = $this->_model->getUserInterfaceLocale();
 
-        $this->assertEquals($locale, \Magento\Framework\Locale\ResolverInterface::DEFAULT_LOCALE);
+        $this->assertEquals($locale, Resolver::DEFAULT_LOCALE);
     }
 
     /**
diff --git a/app/code/Magento/Backend/Test/Unit/Model/Session/QuoteTest.php b/app/code/Magento/Backend/Test/Unit/Model/Session/QuoteTest.php
index 13f906bee346b45c02399d3f2cdc59602f9dec3f..fd3af3380023396c31f53ac97a41a1a631154993 100644
--- a/app/code/Magento/Backend/Test/Unit/Model/Session/QuoteTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Model/Session/QuoteTest.php
@@ -182,6 +182,13 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $appStateMock = $this->getMock(
+            'Magento\Framework\App\State',
+            [],
+            [],
+            '',
+            false
+        );
         $this->storeManagerMock = $this->getMockForAbstractClass(
             'Magento\Store\Model\StoreManagerInterface',
             [],
@@ -201,11 +208,12 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
                 'storage' => $this->storageMock,
                 'cookieManager' => $this->cookieManagerMock,
                 'cookieMetadataFactory' => $this->cookieMetadataFactoryMock,
+                'appState' => $appStateMock,
                 'customerRepository' => $this->customerRepositoryMock,
                 'quoteRepository' => $this->quoteRepositoryMock,
                 'orderFactory' => $this->orderFactoryMock,
                 'storeManager' => $this->storeManagerMock,
-                'groupManagement' => $this->groupManagementMock
+                'groupManagement' => $this->groupManagementMock,
             ],
             '',
             true
@@ -217,12 +225,42 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
      *
      * @return void
      */
-    public function testGetQuote()
+    public function testGetQuoteWithoutQuoteId()
     {
-        $storeId = 10;
         $quoteId = 22;
-        $customerGroupId = 77;
+        $storeId = 10;
         $customerId = 66;
+        $customerGroupId = 77;
+
+        $this->quote->expects($this->any())
+            ->method('getQuoteId')
+            ->will($this->returnValue(null));
+        $this->quote->expects($this->any())
+            ->method('setQuoteId')
+            ->with($quoteId);
+        $this->quote->expects($this->any())
+            ->method('getStoreId')
+            ->will($this->returnValue($storeId));
+        $this->quote->expects($this->any())
+            ->method('getCustomerId')
+            ->will($this->returnValue($customerId));
+
+        $defaultGroup = $this->getMockBuilder('Magento\Customer\Api\Data\GroupInterface')
+            ->getMock();
+        $defaultGroup->expects($this->any())
+            ->method('getId')
+            ->will($this->returnValue($customerGroupId));
+        $this->groupManagementMock->expects($this->any())
+            ->method('getDefaultGroup')
+            ->will($this->returnValue($defaultGroup));
+
+        $dataCustomerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->customerRepositoryMock->expects($this->once())
+            ->method('getById')
+            ->with($customerId)
+            ->willReturn($dataCustomerMock);
 
         $quoteMock = $this->getMock(
             'Magento\Quote\Model\Quote',
@@ -240,28 +278,9 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-
-        $defaultGroup = $this->getMockBuilder('Magento\Customer\Api\Data\GroupInterface')
-            ->getMock();
-        $defaultGroup->expects($this->any())
-            ->method('getId')
-            ->will($this->returnValue($customerGroupId));
-        $this->groupManagementMock->expects($this->any())
-            ->method('getDefaultGroup')
-            ->will($this->returnValue($defaultGroup));
-
-        $this->quoteRepositoryMock->expects($this->once())
-            ->method('create')
-            ->will($this->returnValue($quoteMock));
-        $this->quote->expects($this->any())
-            ->method('getStoreId')
-            ->will($this->returnValue($storeId));
         $quoteMock->expects($this->once())
             ->method('setStoreId')
             ->with($storeId);
-        $this->quote->expects($this->any())
-            ->method('getQuoteId')
-            ->will($this->returnValue(null));
         $quoteMock->expects($this->once())
             ->method('setCustomerGroupId')
             ->with($customerGroupId)
@@ -270,25 +289,9 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
             ->method('setIsActive')
             ->with(false)
             ->will($this->returnSelf());
-        $this->quoteRepositoryMock->expects($this->once())
-            ->method('save')
-            ->with($quoteMock);
         $quoteMock->expects($this->once())
             ->method('getId')
             ->will($this->returnValue($quoteId));
-        $this->quote->expects($this->any())
-            ->method('setQuoteId')
-            ->with($quoteId);
-        $this->quote->expects($this->any())
-            ->method('getCustomerId')
-            ->will($this->returnValue($customerId));
-        $dataCustomerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
-            ->disableOriginalConstructor()
-            ->getMock();
-        $this->customerRepositoryMock->expects($this->once())
-            ->method('getById')
-            ->with($customerId)
-            ->willReturn($dataCustomerMock);
         $quoteMock->expects($this->once())
             ->method('assignCustomer')
             ->with($dataCustomerMock);
@@ -299,6 +302,13 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
             ->method('setIsSuperMode')
             ->with(true);
 
+        $this->quoteRepositoryMock->expects($this->once())
+            ->method('create')
+            ->will($this->returnValue($quoteMock));
+        $this->quoteRepositoryMock->expects($this->once())
+            ->method('save')
+            ->with($quoteMock);
+
         $this->assertEquals($quoteMock, $this->quote->getQuote());
     }
 
@@ -306,12 +316,33 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
      * Run test getQuote method
      *
      * @return void
+     * @dataProvider getQuoteDataProvider
      */
-    public function testGetQuoteGet()
+    public function testGetQuoteWithQuoteId($customerId, $quoteCustomerId, $expectedNumberOfInvokes)
     {
-        $storeId = 10;
         $quoteId = 22;
-        $customerId = 66;
+        $storeId = 10;
+
+        $this->quote->expects($this->any())
+            ->method('getQuoteId')
+            ->will($this->returnValue($quoteId));
+        $this->quote->expects($this->any())
+            ->method('setQuoteId')
+            ->with($quoteId);
+        $this->quote->expects($this->any())
+            ->method('getStoreId')
+            ->will($this->returnValue($storeId));
+        $this->quote->expects($this->any())
+            ->method('getCustomerId')
+            ->will($this->returnValue($customerId));
+
+        $dataCustomerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->customerRepositoryMock->expects($this->$expectedNumberOfInvokes())
+            ->method('getById')
+            ->with($customerId)
+            ->willReturn($dataCustomerMock);
 
         $quoteMock = $this->getMock(
             'Magento\Quote\Model\Quote',
@@ -323,43 +354,17 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
                 'assignCustomer',
                 'setIgnoreOldQty',
                 'setIsSuperMode',
+                'getCustomerId',
                 '__wakeup'
             ],
             [],
             '',
             false
         );
-
-        $this->quoteRepositoryMock->expects($this->once())
-            ->method('create')
-            ->will($this->returnValue($quoteMock));
-        $this->quote->expects($this->any())
-            ->method('getStoreId')
-            ->will($this->returnValue($storeId));
         $quoteMock->expects($this->once())
             ->method('setStoreId')
             ->with($storeId);
-        $this->quote->expects($this->any())
-            ->method('getQuoteId')
-            ->will($this->returnValue($quoteId));
-        $this->quoteRepositoryMock->expects($this->once())
-            ->method('get')
-            ->with($quoteId)
-            ->willReturn($quoteMock);
-        $this->quote->expects($this->any())
-            ->method('setQuoteId')
-            ->with($quoteId);
-        $this->quote->expects($this->any())
-            ->method('getCustomerId')
-            ->will($this->returnValue($customerId));
-        $dataCustomerMock = $this->getMockBuilder('Magento\Customer\Api\Data\CustomerInterface')
-            ->disableOriginalConstructor()
-            ->getMock();
-        $this->customerRepositoryMock->expects($this->once())
-            ->method('getById')
-            ->with($customerId)
-            ->willReturn($dataCustomerMock);
-        $quoteMock->expects($this->once())
+        $quoteMock->expects($this->$expectedNumberOfInvokes())
             ->method('assignCustomer')
             ->with($dataCustomerMock);
         $quoteMock->expects($this->once())
@@ -368,7 +373,29 @@ class QuoteTest extends \PHPUnit_Framework_TestCase
         $quoteMock->expects($this->once())
             ->method('setIsSuperMode')
             ->with(true);
+        $quoteMock->expects($this->once())
+            ->method('getCustomerId')
+            ->will($this->returnValue($quoteCustomerId));
+
+        $this->quoteRepositoryMock->expects($this->once())
+            ->method('create')
+            ->will($this->returnValue($quoteMock));
+        $this->quoteRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($quoteId)
+            ->willReturn($quoteMock);
 
         $this->assertEquals($quoteMock, $this->quote->getQuote());
     }
+
+    /**
+     * @return array
+     */
+    public function getQuoteDataProvider()
+    {
+        return [
+            'customer ids different' => [66, null, 'once'],
+            'customer ids same' => [66, 66, 'never'],
+        ];
+    }
 }
diff --git a/app/code/Magento/Backend/Test/Unit/Model/UrlTest.php b/app/code/Magento/Backend/Test/Unit/Model/UrlTest.php
index a53b891a17be5e100f0916cf04e6b2a4f3469c71..b833fe25752a09ecd9af87a7147f4debf493affe 100644
--- a/app/code/Magento/Backend/Test/Unit/Model/UrlTest.php
+++ b/app/code/Magento/Backend/Test/Unit/Model/UrlTest.php
@@ -165,7 +165,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
                 'menuConfig' => $this->_menuConfigMock,
                 'authSession' => $this->_authSessionMock,
                 'encryptor' => $this->_encryptor,
-                'routeParamsResolver' => $this->_paramsResolverMock
+                'routeParamsResolverFactory' => $this->_paramsResolverMock
             ]
         );
         $this->_paramsResolverMock->expects(
@@ -186,7 +186,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
                 'menuConfig' => $this->_menuConfigMock,
                 'authSession' => $this->_authSessionMock,
                 'encryptor' => $this->_encryptor,
-                'routeParamsResolver' => $this->_paramsResolverMock
+                'routeParamsResolverFactory' => $this->_paramsResolverMock
             ]
         );
 
@@ -259,7 +259,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
             [
                 'backendHelper' => $helperMock,
                 'authSession' => $this->_authSessionMock,
-                'routeParamsResolver' => $this->_paramsResolverMock
+                'routeParamsResolverFactory' => $this->_paramsResolverMock
             ]
         );
         $urlModel->getAreaFrontName();
diff --git a/app/code/Magento/Backend/etc/di.xml b/app/code/Magento/Backend/etc/di.xml
index 7660919372b99c4f6b1b7128a8faac43d07b2a1a..a0617b8e645a4ac8bbcfadba57fcb8e139d5a639 100644
--- a/app/code/Magento/Backend/etc/di.xml
+++ b/app/code/Magento/Backend/etc/di.xml
@@ -149,4 +149,15 @@
             <argument name="storage" xsi:type="object">Magento\Backend\Model\Session\Quote\Storage</argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\Console\CommandList">
+        <arguments>
+            <argument name="commands" xsi:type="array">
+                <item name="cacheEnableCommand" xsi:type="object">Magento\Backend\Console\Command\CacheEnableCommand</item>
+                <item name="cacheDisableCommand" xsi:type="object">Magento\Backend\Console\Command\CacheDisableCommand</item>
+                <item name="cacheFlushCommand" xsi:type="object">Magento\Backend\Console\Command\CacheFlushCommand</item>
+                <item name="cacheCleanCommand" xsi:type="object">Magento\Backend\Console\Command\CacheCleanCommand</item>
+                <item name="cacheStatusCommand" xsi:type="object">Magento\Backend\Console\Command\CacheStatusCommand</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Backup/README.md b/app/code/Magento/Backup/README.md
index 661f8a5d6ddd86f23772c9f595526420ae51dd9e..59688ea3e716e162e8efa9421de0ffe004ec3cee 100644
--- a/app/code/Magento/Backup/README.md
+++ b/app/code/Magento/Backup/README.md
@@ -1,3 +1,3 @@
 The Backup module allows administrators to perform backups and rollbacks. Types of backups include system, database and media backups. This module relies on the Cron module to schedule backups.
 
-This module does not effect the storefront.
\ No newline at end of file
+This module does not affect the storefront.
diff --git a/app/code/Magento/Backup/view/adminhtml/layout/backup_index_block.xml b/app/code/Magento/Backup/view/adminhtml/layout/backup_index_block.xml
index 861bc2050e44a61e3cf1daf950dcad8fc05d0997..1553a783f6356dca8510044813cd919312ff5fdb 100644
--- a/app/code/Magento/Backup/view/adminhtml/layout/backup_index_block.xml
+++ b/app/code/Magento/Backup/view/adminhtml/layout/backup_index_block.xml
@@ -46,7 +46,6 @@
                         <arguments>
                             <argument name="header" xsi:type="string" translate="true">Name</argument>
                             <argument name="index" xsi:type="string">display_name</argument>
-                            <argument name="filter" xsi:type="string">0</argument>
                             <argument name="sortable" xsi:type="string">1</argument>
                             <argument name="column_css_class" xsi:type="string">col-name</argument>
                             <argument name="header_css_class" xsi:type="string">col-name</argument>
diff --git a/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php b/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php
index f4948588c6d8336a83690ff7b1ac3dd0e95381d4..ecf2459e85fc638b49c97fbbacac7860d52acbcf 100644
--- a/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php
+++ b/app/code/Magento/Bundle/Block/Adminhtml/Catalog/Product/Edit/Tab/Attributes/Extend.php
@@ -13,6 +13,11 @@ namespace Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes;
 
 class Extend extends \Magento\Catalog\Block\Adminhtml\Form\Renderer\Fieldset\Element
 {
+    /**
+     * Initialize block template
+     */
+    private $template = 'Magento_Bundle::catalog/product/edit/tab/attributes/extend.phtml';
+
     const DYNAMIC = 0;
 
     const FIXED = 1;
@@ -24,18 +29,26 @@ class Extend extends \Magento\Catalog\Block\Adminhtml\Form\Renderer\Fieldset\Ele
      */
     protected $_coreRegistry = null;
 
+    /**
+     * @var \Magento\Framework\Data\FormFactory
+     */
+    private $formFactory;
+
     /**
      * @param \Magento\Backend\Block\Template\Context $context
      * @param \Magento\Framework\Registry $registry
+     * @param \Magento\Framework\Data\FormFactory $formFactory
      * @param array $data
      */
     public function __construct(
         \Magento\Backend\Block\Template\Context $context,
         \Magento\Framework\Registry $registry,
+        \Magento\Framework\Data\FormFactory $formFactory,
         array $data = []
     ) {
         $this->_coreRegistry = $registry;
         parent::__construct($context, $data);
+        $this->formFactory = $formFactory;
     }
 
     /**
@@ -54,112 +67,52 @@ class Extend extends \Magento\Catalog\Block\Adminhtml\Form\Renderer\Fieldset\Ele
      * Get Element Html
      *
      * @return string
-     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
-     * @SuppressWarnings(PHPMD.NPathComplexity)
-     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
     public function getElementHtml()
     {
-        $elementHtml = parent::getElementHtml();
-
-        $switchAttributeCode = $this->getAttribute()->getAttributeCode() . '_type';
-        $switchAttributeValue = $this->getProduct()->getData($switchAttributeCode);
-
-        $html = '<select name="product[' .
-            $switchAttributeCode .
-            ']" id="' .
-            $switchAttributeCode .
-            '" type="select" class="required-entry select next-toinput"' .
-            ($this->getProduct()->getId() &&
-            $this->getAttribute()->getAttributeCode() == 'price' ||
-            $this->getElement()->getReadonly() ? ' disabled="disabled"' : '') . '>
-            <option value="">' . __('-- Select --') . '</option>
-            <option ' . ($switchAttributeValue ==
-            self::DYNAMIC ? 'selected' : '') . ' value="' . self::DYNAMIC . '">' . __('Dynamic') . '</option>
-            <option ' . ($switchAttributeValue ==
-            self::FIXED ? 'selected' : '') . ' value="' . self::FIXED . '">' . __('Fixed') . '</option>
-        </select>';
-
-        if (!($this->getAttribute()->getAttributeCode() == 'price' && $this->getCanReadPrice() === false)) {
-            $html = '<div class="' .
-                $this->getAttribute()->getAttributeCode() .
-                ' ">' .
-                $elementHtml .
-                '</div>' .
-                $html;
-        }
-        if ($this->getDisableChild() && !$this->getElement()->getReadonly()) {
-            $html .= "<script>
-            require(['prototype'], function(){
-                function " .
-                $switchAttributeCode .
-                "_change() {
-                    if ($('" .
-                $switchAttributeCode .
-                "').value == '" .
-                self::DYNAMIC .
-                "') {
-                        if ($('" .
-                $this->getAttribute()->getAttributeCode() .
-                "')) {
-                            $('" .
-                $this->getAttribute()->getAttributeCode() .
-                "').disabled = true;
-                            $('" .
-                $this->getAttribute()->getAttributeCode() .
-                "').value = '';
-                            $('" .
-                $this->getAttribute()->getAttributeCode() .
-                "').removeClassName('required-entry');
-                        }
-
-                        if ($('dynamic-price-warning')) {
-                            $('dynamic-price-warning').show();
-                        }
-                    } else {
-                        if ($('" .
-                $this->getAttribute()->getAttributeCode() .
-                "')) {";
-
-            if ($this->getAttribute()->getAttributeCode() == 'price' &&
-                $this->getCanEditPrice() === false &&
-                $this->getCanReadPrice() === true &&
-                $this->getProduct()->isObjectNew()
-            ) {
-                $defaultProductPrice = $this->getDefaultProductPrice() ? $this->getDefaultProductPrice() : "''";
-                $html .= "$('" .
-                    $this->getAttribute()->getAttributeCode() .
-                    "').value = " .
-                    $defaultProductPrice .
-                    ";";
-            } else {
-                $html .= "$('" .
-                    $this->getAttribute()->getAttributeCode() .
-                    "').disabled = false;
-                          $('" .
-                    $this->getAttribute()->getAttributeCode() .
-                    "').addClassName('required-entry');";
-            }
+        $templateFile = $this->getTemplateFile($this->template);
+        return $this->fetchView($templateFile);
+    }
 
-            $html .= "}
+    /**
+     * Execute method getElementHtml from parrent class
+     *
+     * @return string
+     */
+    public function getParentElementHtml()
+    {
+        return parent::getElementHtml();
+    }
 
-                        if ($('dynamic-price-warning')) {
-                            $('dynamic-price-warning').hide();
-                        }
-                    }
-                }" . "\n";
+    /**
+     * @return array
+     */
+    public function getOptions()
+    {
+        return [
+            [
+                'value' => '',
+                'label' => __('-- Select --')
+            ],
+            [
+                'value' => self::DYNAMIC,
+                'label' => __('Dynamic')
+            ],
+            [
+                'value' => self::FIXED,
+                'label' => __('Fixed')
+            ]
+        ];
+    }
 
-            if (!($this->getAttribute()->getAttributeCode() == 'price' &&
-                !$this->getCanEditPrice() &&
-                !$this->getProduct()->isObjectNew())
-            ) {
-                $html .= "$('" . $switchAttributeCode . "').observe('change', " . $switchAttributeCode . "_change);";
-            }
-            $html .= $switchAttributeCode . "_change();
-            });
-            </script>";
-        }
-        return $html;
+    /**
+     * @return bool
+     */
+    public function isDisabledField()
+    {
+        return $this->getProduct()->getId() &&
+            $this->getAttribute()->getAttributeCode() === 'price' ||
+            $this->getElement()->getReadonly();
     }
 
     /**
@@ -172,4 +125,25 @@ class Extend extends \Magento\Catalog\Block\Adminhtml\Form\Renderer\Fieldset\Ele
         }
         return $this->getData('product');
     }
+
+    /**
+     * @param string $switchAttributeCode
+     * @return \Magento\Framework\Data\Form\Element\Select
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    public function getExtendedElement($switchAttributeCode)
+    {
+        $form = $this->formFactory->create();
+        return $form->addField(
+            $switchAttributeCode,
+            'select',
+            [
+                'name' => "product[{$switchAttributeCode}]",
+                'values' => $this->getOptions(),
+                'value' => $switchAttributeCode,
+                'class' => 'required-entry next-toinput',
+                'disabled' => $this->isDisabledField()
+            ]
+        );
+    }
 }
diff --git a/app/code/Magento/Bundle/view/adminhtml/templates/catalog/product/edit/tab/attributes/extend.phtml b/app/code/Magento/Bundle/view/adminhtml/templates/catalog/product/edit/tab/attributes/extend.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..166ae943859bd839bfdaa4dfa767429562f61305
--- /dev/null
+++ b/app/code/Magento/Bundle/view/adminhtml/templates/catalog/product/edit/tab/attributes/extend.phtml
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+/** @var $block \Magento\Bundle\Block\Adminhtml\Catalog\Product\Edit\Tab\Attributes\Extend */
+$elementHtml = $block->getParentElementHtml();
+
+$attributeCode = $block->getAttribute()
+    ->getAttributeCode();
+
+$switchAttributeCode = "{$attributeCode}_type";
+$switchAttributeValue = $block->getProduct()
+    ->getData($switchAttributeCode);
+
+$isElementReadonly = $block->getElement()
+    ->getReadonly();
+?>
+
+<?php if (!($attributeCode === 'price' && $block->getCanReadPrice() === false)) { ?>
+    <div class="<?= $attributeCode ?> "><?= $elementHtml ?></div>
+<?php } ?>
+
+<?=$block->getExtendedElement($switchAttributeCode)->toHtml(); ?>
+
+<?php if (!$isElementReadonly && $block->getDisableChild()) { ?>
+    <script>
+        require(['prototype'], function () {
+            function <?=$switchAttributeCode?>_change() {
+                var $attribute = $('<?=$attributeCode?>');
+                if ($('<?=$switchAttributeCode?>').value == '<?=$block::DYNAMIC?>') {
+                    if ($attribute) {
+                        $attribute.disabled = true;
+                        $attribute.value = '';
+                        $attribute.removeClassName('required-entry');
+                    }
+                    if ($('dynamic-price-warning')) {
+                        $('dynamic-price-warning').show();
+                    }
+                } else {
+                    if ($attribute) {
+                        <?php if ($attributeCode === 'price' && !$block->getCanEditPrice() && $block->getCanReadPrice()
+                                && $block->getProduct()->isObjectNew()) { ?>
+                            <?php $defaultProductPrice = $block->getDefaultProductPrice() ?: "''"; ?>
+                            $attribute.value = <?=$defaultProductPrice?>;
+                        <?php } else { ?>
+                            $attribute.disabled = false;
+                            $attribute.addClassName('required-entry');
+                        <?php } ?>
+                    }
+                    if ($('dynamic-price-warning')) {
+                        $('dynamic-price-warning').hide();
+                    }
+                }
+            }
+
+            <?php if (!($attributeCode === 'price' && !$block->getCanEditPrice()
+                    && !$block->getProduct()->isObjectNew())) { ?>
+                $('<?=$switchAttributeCode?>').observe('change', <?=$switchAttributeCode?>_change);
+            <?php } ?>
+            <?=$switchAttributeCode?>_change();
+        });
+    </script>
+<?php } ?>
diff --git a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php
index a79466c6007bfb13a619d59a922c29d99d947968..29be0868558ee450d152d492091f5cb5b9bbaef8 100644
--- a/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php
+++ b/app/code/Magento/Catalog/Block/Product/ProductList/Toolbar.php
@@ -29,7 +29,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template
      *
      * @var array
      */
-    protected $_availableOrder = [];
+    protected $_availableOrder = null;
 
     /**
      * List of available view types
@@ -146,19 +146,6 @@ class Toolbar extends \Magento\Framework\View\Element\Template
         parent::__construct($context, $data);
     }
 
-    /**
-     * Init Toolbar
-     *
-     * @return null
-     */
-    protected function _construct()
-    {
-        parent::_construct();
-        $this->_orderField = $this->_productListHelper->getDefaultSortField();
-        $this->_availableOrder = $this->_catalogConfig->getAttributeUsedForSortByArray();
-        $this->_availableMode = $this->_productListHelper->getAvailableViewMode();
-    }
-
     /**
      * Disable list state params memorizing
      *
@@ -241,7 +228,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template
         }
 
         $orders = $this->getAvailableOrders();
-        $defaultOrder = $this->_orderField;
+        $defaultOrder = $this->getOrderField();
 
         if (!isset($orders[$defaultOrder])) {
             $keys = array_keys($orders);
@@ -295,6 +282,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template
      */
     public function setDefaultOrder($field)
     {
+        $this->loadAvailableOrders();
         if (isset($this->_availableOrder[$field])) {
             $this->_orderField = $field;
         }
@@ -322,6 +310,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template
      */
     public function getAvailableOrders()
     {
+        $this->loadAvailableOrders();
         return $this->_availableOrder;
     }
 
@@ -346,6 +335,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template
      */
     public function addOrderToAvailableOrders($order, $value)
     {
+        $this->loadAvailableOrders();
         $this->_availableOrder[$order] = $value;
         return $this;
     }
@@ -358,6 +348,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template
      */
     public function removeOrderFromAvailableOrders($order)
     {
+        $this->loadAvailableOrders();
         if (isset($this->_availableOrder[$order])) {
             unset($this->_availableOrder[$order]);
         }
@@ -411,7 +402,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template
         if ($mode) {
             return $mode;
         }
-        $defaultMode = $this->_productListHelper->getDefaultViewMode($this->_availableMode);
+        $defaultMode = $this->_productListHelper->getDefaultViewMode($this->getModes());
         $mode = $this->_toolbarModel->getMode();
         if (!$mode || !isset($this->_availableMode[$mode])) {
             $mode = $defaultMode;
@@ -439,6 +430,9 @@ class Toolbar extends \Magento\Framework\View\Element\Template
      */
     public function getModes()
     {
+        if ($this->_availableMode === []) {
+            $this->_availableMode = $this->_productListHelper->getAvailableViewMode();
+        }
         return $this->_availableMode;
     }
 
@@ -450,6 +444,7 @@ class Toolbar extends \Magento\Framework\View\Element\Template
      */
     public function setModes($modes)
     {
+        $this->getModes();
         if (!isset($this->_availableMode)) {
             $this->_availableMode = $modes;
         }
@@ -691,4 +686,30 @@ class Toolbar extends \Magento\Framework\View\Element\Template
         $options = array_replace_recursive($options, $customOptions);
         return json_encode(['productListToolbarForm' => $options]);
     }
+
+    /**
+     * Get order field
+     *
+     * @return null|string
+     */
+    protected function getOrderField()
+    {
+        if ($this->_orderField === null) {
+            $this->_orderField = $this->_productListHelper->getDefaultSortField();
+        }
+        return $this->_orderField;
+    }
+
+    /**
+     * Load Available Orders
+     *
+     * @return $this
+     */
+    private function loadAvailableOrders()
+    {
+        if ($this->_availableOrder === null) {
+            $this->_availableOrder = $this->_catalogConfig->getAttributeUsedForSortByArray();
+        }
+        return $this;
+    }
 }
diff --git a/app/code/Magento/Catalog/Block/Product/View/Options.php b/app/code/Magento/Catalog/Block/Product/View/Options.php
index f80bdede71af34f4440d8cce9ff14da2ebfdf9f0..db3d2a911038295fbcb8942d7c61f0041a2637a5 100644
--- a/app/code/Magento/Catalog/Block/Product/View/Options.php
+++ b/app/code/Magento/Catalog/Block/Product/View/Options.php
@@ -206,19 +206,30 @@ class Options extends \Magento\Framework\View\Element\Template
             /* @var $option \Magento\Catalog\Model\Product\Option */
             $priceValue = 0;
             if ($option->getGroupByType() == \Magento\Catalog\Model\Product\Option::OPTION_GROUP_SELECT) {
-                $_tmpPriceValues = [];
+                $tmpPriceValues = [];
                 foreach ($option->getValues() as $value) {
                     /* @var $value \Magento\Catalog\Model\Product\Option\Value */
                     $id = $value->getId();
-                    $_tmpPriceValues[$id] = $this->_getPriceConfiguration($value);
+                    $tmpPriceValues[$id] = $this->_getPriceConfiguration($value);
                 }
-                $priceValue = $_tmpPriceValues;
+                $priceValue = $tmpPriceValues;
             } else {
                 $priceValue = $this->_getPriceConfiguration($option);
             }
             $config[$option->getId()] = $priceValue;
         }
 
+        $configObj = new \Magento\Framework\Object(
+            [
+                'config' => $config,
+            ]
+        );
+
+        //pass the return array encapsulated in an object for the other modules to be able to alter it eg: weee
+        $this->_eventManager->dispatch('catalog_product_option_price_configuration_after', ['configObj' => $configObj]);
+
+        $config=$configObj->getConfig();
+
         return $this->_jsonEncoder->encode($config);
     }
 
diff --git a/app/code/Magento/Catalog/Model/Observer.php b/app/code/Magento/Catalog/Model/Observer.php
index 39e72883f68add9d3672497199eb7c744480a7db..417a4f61811c99663538fd72e3c790ddc0753f3c 100644
--- a/app/code/Magento/Catalog/Model/Observer.php
+++ b/app/code/Magento/Catalog/Model/Observer.php
@@ -34,7 +34,14 @@ class Observer
      *
      * @var \Magento\Catalog\Model\Layer
      */
-    protected $_catalogLayer;
+    private $_catalogLayer = null;
+
+    /**
+     * Catalog layer resolver
+     *
+     * @var \Magento\Catalog\Model\Layer\Resolver
+     */
+    protected $layerResolver;
 
     /**
      * Store manager
@@ -95,7 +102,7 @@ class Observer
         $this->_categoryResource = $categoryResource;
         $this->_catalogProduct = $catalogProduct;
         $this->_storeManager = $storeManager;
-        $this->_catalogLayer = $layerResolver->get();
+        $this->layerResolver = $layerResolver;
         $this->_catalogCategory = $catalogCategory;
         $this->_catalogData = $catalogData;
         $this->categoryFlatConfig = $categoryFlatState;
@@ -184,11 +191,12 @@ class Observer
      */
     protected function hasActive($category)
     {
-        if (!$this->_catalogLayer) {
+        $catalogLayer = $this->getCatalogLayer();
+        if (!$catalogLayer) {
             return false;
         }
 
-        $currentCategory = $this->_catalogLayer->getCurrentCategory();
+        $currentCategory = $catalogLayer->getCurrentCategory();
         if (!$currentCategory) {
             return false;
         }
@@ -196,4 +204,16 @@ class Observer
         $categoryPathIds = explode(',', $currentCategory->getPathInStore());
         return in_array($category->getId(), $categoryPathIds);
     }
+
+    /**
+     * Get catalog layer
+     * @return \Magento\Catalog\Model\Layer
+     */
+    private function getCatalogLayer()
+    {
+        if ($this->_catalogLayer === null) {
+            $this->_catalogLayer = $this->layerResolver->get();
+        }
+        return $this->_catalogLayer;
+    }
 }
diff --git a/app/code/Magento/Catalog/Model/Product.php b/app/code/Magento/Catalog/Model/Product.php
index ebd9494fe1f842f7e42eba21cdb0c3da4cbd1325..d012f23de3df22b5e130abe2454fe2dc8f030c25 100644
--- a/app/code/Magento/Catalog/Model/Product.php
+++ b/app/code/Magento/Catalog/Model/Product.php
@@ -250,15 +250,25 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
     protected $metadataService;
 
     /*
-     * @param \Magento\Catalog\Model\ProductLink\ProductLinkManagementInterface
+     * @param \Magento\Catalog\Model\ProductLink\CollectionProvider
      */
-    protected $linkManagement;
+    protected $entityCollectionProvider;
 
     /*
-     * @param \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory $productLinkFactory
+     * @param \Magento\Catalog\Model\Product\LinkTypeProvider
+     */
+    protected $linkProvider;
+
+    /*
+     * @param \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory
      */
     protected $productLinkFactory;
 
+    /*
+     * @param \Magento\Catalog\Api\Data\ProductLinkExtensionFactory
+     */
+    protected $productLinkExtensionFactory;
+
     /**
      * @var \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterfaceFactory
      */
@@ -318,8 +328,10 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
      * @param Indexer\Product\Eav\Processor $productEavIndexerProcessor
      * @param CategoryRepositoryInterface $categoryRepository
      * @param Product\Image\CacheFactory $imageCacheFactory
-     * @param \Magento\Catalog\Model\ProductLink\Management $linkManagement
-     * @param \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory $productLinkFactory,
+     * @param \Magento\Catalog\Model\ProductLink\CollectionProvider $entityCollectionProvider
+     * @param \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider
+     * @param \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory $productLinkFactory
+     * @param \Magento\Catalog\Api\Data\ProductLinkExtensionFactory $productLinkExtensionFactory
      * @param \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterfaceFactory $mediaGalleryEntryFactory
      * @param \Magento\Framework\Api\DataObjectHelper $dataObjectHelper
      * @param array $data
@@ -354,8 +366,10 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
         \Magento\Catalog\Model\Indexer\Product\Eav\Processor $productEavIndexerProcessor,
         CategoryRepositoryInterface $categoryRepository,
         Product\Image\CacheFactory $imageCacheFactory,
-        \Magento\Catalog\Model\ProductLink\Management $linkManagement,
+        \Magento\Catalog\Model\ProductLink\CollectionProvider $entityCollectionProvider,
+        \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider,
         \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory $productLinkFactory,
+        \Magento\Catalog\Api\Data\ProductLinkExtensionFactory $productLinkExtensionFactory,
         \Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterfaceFactory $mediaGalleryEntryFactory,
         \Magento\Framework\Api\DataObjectHelper $dataObjectHelper,
         array $data = []
@@ -380,8 +394,10 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
         $this->_productEavIndexerProcessor = $productEavIndexerProcessor;
         $this->categoryRepository = $categoryRepository;
         $this->imageCacheFactory = $imageCacheFactory;
-        $this->linkManagement = $linkManagement;
+        $this->entityCollectionProvider = $entityCollectionProvider;
+        $this->linkTypeProvider = $linkTypeProvider;
         $this->productLinkFactory = $productLinkFactory;
+        $this->productLinkExtensionFactory = $productLinkExtensionFactory;
         $this->mediaGalleryEntryFactory = $mediaGalleryEntryFactory;
         $this->dataObjectHelper = $dataObjectHelper;
         parent::__construct(
@@ -1352,23 +1368,34 @@ class Product extends \Magento\Catalog\Model\AbstractModel implements
     public function getProductLinks()
     {
         if (empty($this->_links)) {
-            $productLinks = [];
-
-            $productLinks['related'] = $this->getRelatedProducts();
-            $productLinks['upsell'] = $this->getUpSellProducts();
-            $productLinks['crosssell'] = $this->getCrossSellProducts();
-
             $output = [];
-            foreach ($productLinks as $type => $linkTypeArray) {
-                foreach ($linkTypeArray as $link) {
+            $linkTypes = $this->linkTypeProvider->getLinkTypes();
+            foreach (array_keys($linkTypes) as $linkTypeName) {
+                $collection = $this->entityCollectionProvider->getCollection($this, $linkTypeName);
+                foreach ($collection as $item) {
                     /** @var \Magento\Catalog\Api\Data\ProductLinkInterface $productLink */
                     $productLink = $this->productLinkFactory->create();
                     $productLink->setProductSku($this->getSku())
-                        ->setLinkType($type)
-                        ->setLinkedProductSku($link['sku'])
-                        ->setLinkedProductType($link['type_id'])
-                        ->setPosition($link['position']);
-
+                        ->setLinkType($linkTypeName)
+                        ->setLinkedProductSku($item['sku'])
+                        ->setLinkedProductType($item['type'])
+                        ->setPosition($item['position']);
+                    if (isset($item['custom_attributes'])) {
+                        $productLinkExtension = $productLink->getExtensionAttributes();
+                        if ($productLinkExtension === null) {
+                            $productLinkExtension = $this->productLinkExtensionFactory->create();
+                        }
+                        foreach ($item['custom_attributes'] as $option) {
+                            $name = $option['attribute_code'];
+                            $value = $option['value'];
+                            $setterName = 'set' . ucfirst($name);
+                            // Check if setter exists
+                            if (method_exists($productLinkExtension, $setterName)) {
+                                call_user_func([$productLinkExtension, $setterName], $value);
+                            }
+                        }
+                        $productLink->setExtensionAttributes($productLinkExtension);
+                    }
                     $output[] = $productLink;
                 }
             }
diff --git a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php
index 94612dbf200a5f95fc003342e0c114d273366be1..b40b91d5b08b8efa59ff0534e04600c1bfcc33d7 100644
--- a/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php
+++ b/app/code/Magento/Catalog/Model/Product/Type/AbstractType.php
@@ -100,6 +100,13 @@ abstract class AbstractType
      */
     protected $_fileStorageDb;
 
+    /**
+     * Cache key for Product Attributes
+     *
+     * @var string
+     */
+    protected $_cacheProductSetAttributes = '_cache_instance_product_set_attributes';
+
     /**
      * Delete data specific for this product type
      *
@@ -249,9 +256,13 @@ abstract class AbstractType
      */
     public function getSetAttributes($product)
     {
-        return $product->getResource()
-            ->loadAllAttributes($product)
-            ->getSortedAttributes($product->getAttributeSetId());
+        if (!$product->hasData($this->_cacheProductSetAttributes)) {
+            $setAttributes = $product->getResource()
+                ->loadAllAttributes($product)
+                ->getSortedAttributes($product->getAttributeSetId());
+            $product->setData($this->_cacheProductSetAttributes, $setAttributes);
+        }
+        return $product->getData($this->_cacheProductSetAttributes);
     }
 
     /**
diff --git a/app/code/Magento/Catalog/Model/ProductLink/Management.php b/app/code/Magento/Catalog/Model/ProductLink/Management.php
index 558561d22de50af6f402f9201a6138aaba441496..e702a6cde0e41f1a8e3316d5a30be821c620fa0b 100644
--- a/app/code/Magento/Catalog/Model/ProductLink/Management.php
+++ b/app/code/Magento/Catalog/Model/ProductLink/Management.php
@@ -7,7 +7,6 @@
 namespace Magento\Catalog\Model\ProductLink;
 
 use Magento\Catalog\Api\Data;
-use Magento\Catalog\Model\Product\Initialization\Helper\ProductLinks as LinksInitializer;
 use Magento\Framework\Exception\CouldNotSaveException;
 use Magento\Framework\Exception\NoSuchEntityException;
 
@@ -18,26 +17,6 @@ class Management implements \Magento\Catalog\Api\ProductLinkManagementInterface
      */
     protected $productRepository;
 
-    /**
-     * @var CollectionProvider
-     */
-    protected $entityCollectionProvider;
-
-    /**
-     * @var LinksInitializer
-     */
-    protected $linkInitializer;
-
-    /**
-     * @var \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory
-     */
-    protected $productLinkFactory;
-
-    /**
-     * @var \Magento\Catalog\Model\Resource\Product
-     */
-    protected $productResource;
-
     /**
      * @var \Magento\Catalog\Model\Product\LinkTypeProvider
      */
@@ -45,25 +24,13 @@ class Management implements \Magento\Catalog\Api\ProductLinkManagementInterface
 
     /**
      * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository
-     * @param CollectionProvider $collectionProvider
-     * @param \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory $productLinkFactory
-     * @param LinksInitializer $linkInitializer
-     * @param \Magento\Catalog\Model\Resource\Product $productResource
      * @param \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider
      */
     public function __construct(
         \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
-        CollectionProvider $collectionProvider,
-        \Magento\Catalog\Api\Data\ProductLinkInterfaceFactory $productLinkFactory,
-        LinksInitializer $linkInitializer,
-        \Magento\Catalog\Model\Resource\Product $productResource,
         \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider
     ) {
         $this->productRepository = $productRepository;
-        $this->entityCollectionProvider = $collectionProvider;
-        $this->productLinkFactory = $productLinkFactory;
-        $this->productResource = $productResource;
-        $this->linkInitializer = $linkInitializer;
         $this->linkTypeProvider = $linkTypeProvider;
     }
 
@@ -73,27 +40,22 @@ class Management implements \Magento\Catalog\Api\ProductLinkManagementInterface
     public function getLinkedItemsByType($sku, $type)
     {
         $output = [];
-        $product = $this->productRepository->get($sku);
-        try {
-            $collection = $this->entityCollectionProvider->getCollection($product, $type);
-        } catch (NoSuchEntityException $e) {
+
+        $linkTypes = $this->linkTypeProvider->getLinkTypes();
+
+        if (!isset($linkTypes[$type])) {
             throw new NoSuchEntityException(__('Unknown link type: %1', (string)$type));
         }
-        foreach ($collection as $item) {
-            /** @var \Magento\Catalog\Api\Data\ProductLinkInterface $productLink */
-            $productLink = $this->productLinkFactory->create();
-            $productLink->setProductSku($product->getSku())
-                ->setLinkType($type)
-                ->setLinkedProductSku($item['sku'])
-                ->setLinkedProductType($item['type'])
-                ->setPosition($item['position']);
-            if (isset($item['custom_attributes'])) {
-                foreach ($item['custom_attributes'] as $option) {
-                    $productLink->getExtensionAttributes()->setQty($option['value']);
-                }
+        $product = $this->productRepository->get($sku);
+        $links = $product->getProductLinks();
+
+        // Only return the links of type specified
+        foreach ($links as $link) {
+            if ($link->getLinkType() == $type) {
+                $output[] = $link;
             }
-            $output[] = $productLink;
         }
+
         return $output;
     }
 
@@ -111,32 +73,27 @@ class Management implements \Magento\Catalog\Api\ProductLinkManagementInterface
         }
 
         $product = $this->productRepository->get($sku);
-        $assignedSkuList = [];
-        /** @var \Magento\Catalog\Api\Data\ProductLinkInterface $link */
-        foreach ($items as $link) {
-            $assignedSkuList[] = $link->getLinkedProductSku();
-        }
-        $linkedProductIds = $this->productResource->getProductsIdsBySkus($assignedSkuList);
 
-        $links = [];
-        /** @var \Magento\Catalog\Api\Data\ProductLinkInterface[] $items*/
-        foreach ($items as $link) {
-            $data = $link->__toArray();
-            $linkedSku = $link->getLinkedProductSku();
-            if (!isset($linkedProductIds[$linkedSku])) {
-                throw new NoSuchEntityException(
-                    __('Product with SKU "%1" does not exist', $linkedSku)
-                );
+        // Replace only links of the specified type
+        $existingLinks = $product->getProductLinks();
+        $newLinks = [];
+        if (!empty($existingLinks)) {
+            foreach ($existingLinks as $link) {
+                if ($link->getLinkType() != $type) {
+                    $newLinks[] = $link;
+                }
             }
-            $data['product_id'] = $linkedProductIds[$linkedSku];
-            $links[$linkedProductIds[$linkedSku]] = $data;
+            $newLinks = array_merge($newLinks, $items);
+        } else {
+            $newLinks = $items;
         }
-        $this->linkInitializer->initializeLinks($product, [$type => $links]);
+        $product->setProductLinks($newLinks);
         try {
-            $product->save();
+            $this->productRepository->save($product);
         } catch (\Exception $exception) {
             throw new CouldNotSaveException(__('Invalid data provided for linked products'));
         }
+
         return true;
     }
 }
diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php
index 40ecc5d2cb3419101374a9d563b52ada19cd9967..8f2e7664c4e3df2c3ebf963cd4122e22a0e730cb 100644
--- a/app/code/Magento/Catalog/Model/ProductRepository.php
+++ b/app/code/Magento/Catalog/Model/ProductRepository.php
@@ -75,6 +75,16 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
      */
     protected $linkInitializer;
 
+    /*
+     * @param \Magento\Catalog\Model\Product\LinkTypeProvider
+     */
+    protected $linkTypeProvider;
+
+    /*
+     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
+     */
+    protected $storeManager;
+
     /**
      * @var \Magento\Catalog\Api\ProductAttributeRepositoryInterface
      */
@@ -129,6 +139,8 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
      * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository
      * @param Resource\Product $resourceModel
      * @param \Magento\Catalog\Model\Product\Initialization\Helper\ProductLinks $linkInitializer
+     * @param \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider
+     * @param \Magento\Store\Model\StoreManagerInterface $storeManager,
      * @param \Magento\Framework\Api\FilterBuilder $filterBuilder
      * @param \Magento\Catalog\Api\ProductAttributeRepositoryInterface $metadataServiceInterface
      * @param \Magento\Framework\Api\ExtensibleDataObjectConverter $extensibleDataObjectConverter
@@ -149,6 +161,8 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
         \Magento\Catalog\Api\ProductAttributeRepositoryInterface $attributeRepository,
         \Magento\Catalog\Model\Resource\Product $resourceModel,
         \Magento\Catalog\Model\Product\Initialization\Helper\ProductLinks $linkInitializer,
+        \Magento\Catalog\Model\Product\LinkTypeProvider $linkTypeProvider,
+        \Magento\Store\Model\StoreManagerInterface $storeManager,
         \Magento\Framework\Api\FilterBuilder $filterBuilder,
         \Magento\Catalog\Api\ProductAttributeRepositoryInterface $metadataServiceInterface,
         \Magento\Framework\Api\ExtensibleDataObjectConverter $extensibleDataObjectConverter,
@@ -166,6 +180,8 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
         $this->searchCriteriaBuilder = $searchCriteriaBuilder;
         $this->resourceModel = $resourceModel;
         $this->linkInitializer = $linkInitializer;
+        $this->linkTypeProvider = $linkTypeProvider;
+        $this->storeManager = $storeManager;
         $this->attributeRepository = $attributeRepository;
         $this->filterBuilder = $filterBuilder;
         $this->metadataService = $metadataServiceInterface;
@@ -260,6 +276,9 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
     {
         if ($createNew) {
             $product = $this->productFactory->create();
+            if ($this->storeManager->hasSingleStore()) {
+                $product->setWebsiteIds([$this->storeManager->getStore(true)->getWebsite()->getId()]);
+            }
         } else {
             unset($this->instances[$productData['sku']]);
             $product = $this->get($productData['sku']);
@@ -353,11 +372,12 @@ class ProductRepository implements \Magento\Catalog\Api\ProductRepositoryInterfa
         }
 
         // Clear all existing product links and then set the ones we want
-        $this->linkInitializer->initializeLinks($product, ['related' => []]);
-        $this->linkInitializer->initializeLinks($product, ['upsell' => []]);
-        $this->linkInitializer->initializeLinks($product, ['crosssell' => []]);
+        $linkTypes = $this->linkTypeProvider->getLinkTypes();
+        foreach (array_keys($linkTypes) as $typeName) {
+            $this->linkInitializer->initializeLinks($product, [$typeName => []]);
+        }
 
-        // Gather each linktype info
+        // Set each linktype info
         if (!empty($newLinks)) {
             $productLinks = [];
             foreach ($newLinks as $link) {
diff --git a/app/code/Magento/Catalog/Model/Resource/Category.php b/app/code/Magento/Catalog/Model/Resource/Category.php
index f99d1b9ee9d2c15cdca6c883cc7ded953973afc7..27d7f8b801df56c735259f20150e53aa1a5d7af4 100644
--- a/app/code/Magento/Catalog/Model/Resource/Category.php
+++ b/app/code/Magento/Catalog/Model/Resource/Category.php
@@ -92,13 +92,36 @@ class Category extends AbstractResource
         $this->_categoryTreeFactory = $categoryTreeFactory;
         $this->_categoryCollectionFactory = $categoryCollectionFactory;
         $this->_eventManager = $eventManager;
-        $this->setType(
-            \Magento\Catalog\Model\Category::ENTITY
-        )->setConnection(
-            $this->_resource->getConnection('catalog_read'),
-            $this->_resource->getConnection('catalog_write')
-        );
-        $this->_categoryProductTable = $this->getTable('catalog_category_product');
+
+        $this->_read  = 'catalog_read';
+        $this->_write = 'catalog_write';
+    }
+
+    /**
+     * Entity type getter and lazy loader
+     *
+     * @return \Magento\Eav\Model\Entity\Type
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    public function getEntityType()
+    {
+        if (empty($this->_type)) {
+            $this->setType(\Magento\Catalog\Model\Category::ENTITY);
+        }
+        return parent::getEntityType();
+    }
+
+    /**
+     * Category product table name getter
+     *
+     * @return string
+     */
+    public function getCategoryProductTable()
+    {
+        if (!$this->_categoryProductTable) {
+            $this->_categoryProductTable = $this->getTable('catalog_category_product');
+        }
+        return $this->_categoryProductTable;
     }
 
     /**
@@ -359,7 +382,7 @@ class Category extends AbstractResource
          */
         if (!empty($delete)) {
             $cond = ['product_id IN(?)' => array_keys($delete), 'category_id=?' => $id];
-            $adapter->delete($this->_categoryProductTable, $cond);
+            $adapter->delete($this->getCategoryProductTable(), $cond);
         }
 
         /**
@@ -374,7 +397,7 @@ class Category extends AbstractResource
                     'position' => (int)$position,
                 ];
             }
-            $adapter->insertMultiple($this->_categoryProductTable, $data);
+            $adapter->insertMultiple($this->getCategoryProductTable(), $data);
         }
 
         /**
@@ -384,7 +407,7 @@ class Category extends AbstractResource
             foreach ($update as $productId => $position) {
                 $where = ['category_id = ?' => (int)$id, 'product_id = ?' => (int)$productId];
                 $bind = ['position' => (int)$position];
-                $adapter->update($this->_categoryProductTable, $bind, $where);
+                $adapter->update($this->getCategoryProductTable(), $bind, $where);
             }
         }
 
@@ -417,7 +440,7 @@ class Category extends AbstractResource
     public function getProductsPosition($category)
     {
         $select = $this->_getWriteAdapter()->select()->from(
-            $this->_categoryProductTable,
+            $this->getCategoryProductTable(),
             ['product_id', 'position']
         )->where(
             'category_id = :category_id'
diff --git a/app/code/Magento/Catalog/Model/Resource/Category/Collection.php b/app/code/Magento/Catalog/Model/Resource/Category/Collection.php
index 2abc203eccbcada147503ce7f5be4400deb898e8..f21ce9f363b51f01a7555d79e3ba39aa89598b53 100644
--- a/app/code/Magento/Catalog/Model/Resource/Category/Collection.php
+++ b/app/code/Magento/Catalog/Model/Resource/Category/Collection.php
@@ -33,7 +33,7 @@ class Collection extends \Magento\Catalog\Model\Resource\Collection\AbstractColl
      *
      * @var string
      */
-    protected $_productTable;
+    private $_productTable;
 
     /**
      * Store id, that we should count products on
@@ -47,7 +47,7 @@ class Collection extends \Magento\Catalog\Model\Resource\Collection\AbstractColl
      *
      * @var string
      */
-    protected $_productWebsiteTable;
+    private $_productWebsiteTable;
 
     /**
      * Load with product count flag
@@ -64,9 +64,6 @@ class Collection extends \Magento\Catalog\Model\Resource\Collection\AbstractColl
     protected function _construct()
     {
         $this->_init('Magento\Catalog\Model\Category', 'Magento\Catalog\Model\Resource\Category');
-
-        $this->_productWebsiteTable = $this->getTable('catalog_product_website');
-        $this->_productTable = $this->getTable('catalog_category_product');
     }
 
     /**
@@ -224,7 +221,7 @@ class Collection extends \Magento\Catalog\Model\Resource\Collection\AbstractColl
             if (!empty($regularIds)) {
                 $select = $this->_conn->select();
                 $select->from(
-                    ['main_table' => $this->_productTable],
+                    ['main_table' => $this->getProductTable()],
                     ['category_id', new \Zend_Db_Expr('COUNT(main_table.product_id)')]
                 )->where(
                     $this->_conn->quoteInto('main_table.category_id IN(?)', $regularIds)
@@ -233,7 +230,7 @@ class Collection extends \Magento\Catalog\Model\Resource\Collection\AbstractColl
                 );
                 if ($websiteId) {
                     $select->join(
-                        ['w' => $this->_productWebsiteTable],
+                        ['w' => $this->getProductWebsiteTable()],
                         'main_table.product_id = w.product_id',
                         []
                     )->where(
@@ -259,7 +256,7 @@ class Collection extends \Magento\Catalog\Model\Resource\Collection\AbstractColl
                     $bind = ['entity_id' => $item->getId(), 'c_path' => $item->getPath() . '/%'];
                     $select = $this->_conn->select();
                     $select->from(
-                        ['main_table' => $this->_productTable],
+                        ['main_table' => $this->getProductTable()],
                         new \Zend_Db_Expr('COUNT(DISTINCT main_table.product_id)')
                     )->joinInner(
                         ['e' => $this->getTable('catalog_category_entity')],
@@ -272,7 +269,7 @@ class Collection extends \Magento\Catalog\Model\Resource\Collection\AbstractColl
                     );
                     if ($websiteId) {
                         $select->join(
-                            ['w' => $this->_productWebsiteTable],
+                            ['w' => $this->getProductWebsiteTable()],
                             'main_table.product_id = w.product_id',
                             []
                         )->where(
@@ -416,4 +413,30 @@ class Collection extends \Magento\Catalog\Model\Resource\Collection\AbstractColl
         $this->setOrder($field, self::SORT_ORDER_ASC);
         return $this;
     }
+
+    /**
+     * Getter for _productWebsiteTable
+     *
+     * @return string
+     */
+    public function getProductWebsiteTable()
+    {
+        if (empty($this->_productWebsiteTable)) {
+            $this->_productWebsiteTable = $this->getTable('catalog_product_website');
+        }
+        return $this->_productWebsiteTable;
+    }
+
+    /**
+     * Getter for _productTable
+     *
+     * @return string
+     */
+    public function getProductTable()
+    {
+        if (empty($this->_productTable)) {
+            $this->_productTable = $this->getTable('catalog_category_product');
+        }
+        return $this->_productTable;
+    }
 }
diff --git a/app/code/Magento/Catalog/Model/Resource/Product.php b/app/code/Magento/Catalog/Model/Resource/Product.php
index 336d8f796577ecabad0284932cc213cabcfb5f28..6f02829d2bc2a7dff4e95b39b7cd20181d5d1903 100644
--- a/app/code/Magento/Catalog/Model/Resource/Product.php
+++ b/app/code/Magento/Catalog/Model/Resource/Product.php
@@ -91,9 +91,48 @@ class Product extends AbstractResource
             $modelFactory,
             $data
         );
-        $this->setType(\Magento\Catalog\Model\Product::ENTITY)->setConnection('catalog_read', 'catalog_write');
-        $this->_productWebsiteTable = $this->getTable('catalog_product_website');
-        $this->_productCategoryTable = $this->getTable('catalog_category_product');
+        $this->_read  = 'catalog_read';
+        $this->_write = 'catalog_write';
+    }
+
+    /**
+     * Entity type getter and lazy loader
+     *
+     * @return \Magento\Eav\Model\Entity\Type
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    public function getEntityType()
+    {
+        if (empty($this->_type)) {
+            $this->setType(\Magento\Catalog\Model\Product::ENTITY);
+        }
+        return parent::getEntityType();
+    }
+
+    /**
+     * Product Website table name getter
+     *
+     * @return string
+     */
+    public function getProductWebsiteTable()
+    {
+        if (!$this->_productWebsiteTable) {
+            $this->_productWebsiteTable = $this->getTable('catalog_product_website');
+        }
+        return $this->_productWebsiteTable;
+    }
+
+    /**
+     * Product Category table name getter
+     *
+     * @return string
+     */
+    public function getProductCategoryTable()
+    {
+        if (!$this->_productCategoryTable) {
+            $this->_productCategoryTable = $this->getTable('catalog_category_product');
+        }
+        return $this->_productCategoryTable;
     }
 
     /**
@@ -123,7 +162,7 @@ class Product extends AbstractResource
         }
 
         $select = $adapter->select()->from(
-            $this->_productWebsiteTable,
+            $this->getProductWebsiteTable(),
             'website_id'
         )->where(
             'product_id = ?',
@@ -142,7 +181,7 @@ class Product extends AbstractResource
     public function getWebsiteIdsByProductIds($productIds)
     {
         $select = $this->_getWriteAdapter()->select()->from(
-            $this->_productWebsiteTable,
+            $this->getProductWebsiteTable(),
             ['product_id', 'website_id']
         )->where(
             'product_id IN (?)',
@@ -171,7 +210,7 @@ class Product extends AbstractResource
         $adapter = $this->_getReadAdapter();
 
         $select = $adapter->select()->from(
-            $this->_productCategoryTable,
+            $this->getProductCategoryTable(),
             'category_id'
         )->where(
             'product_id = ?',
@@ -274,14 +313,14 @@ class Product extends AbstractResource
             foreach ($insert as $websiteId) {
                 $data[] = ['product_id' => (int)$product->getId(), 'website_id' => (int)$websiteId];
             }
-            $adapter->insertMultiple($this->_productWebsiteTable, $data);
+            $adapter->insertMultiple($this->getProductWebsiteTable(), $data);
         }
 
         if (!empty($delete)) {
             foreach ($delete as $websiteId) {
                 $condition = ['product_id = ?' => (int)$product->getId(), 'website_id = ?' => (int)$websiteId];
 
-                $adapter->delete($this->_productWebsiteTable, $condition);
+                $adapter->delete($this->getProductWebsiteTable(), $condition);
             }
         }
 
@@ -329,7 +368,7 @@ class Product extends AbstractResource
                 ];
             }
             if ($data) {
-                $write->insertMultiple($this->_productCategoryTable, $data);
+                $write->insertMultiple($this->getProductCategoryTable(), $data);
             }
         }
 
@@ -337,7 +376,7 @@ class Product extends AbstractResource
             foreach ($delete as $categoryId) {
                 $where = ['product_id = ?' => (int)$object->getId(), 'category_id = ?' => (int)$categoryId];
 
-                $write->delete($this->_productCategoryTable, $where);
+                $write->delete($this->getProductCategoryTable(), $where);
             }
         }
 
diff --git a/app/code/Magento/Catalog/Model/Session.php b/app/code/Magento/Catalog/Model/Session.php
index b61175b11e7da3ff879834074f303590b664b72b..d7a3748c2810bd82a6b856e4d7dfe814cd0401ab 100644
--- a/app/code/Magento/Catalog/Model/Session.php
+++ b/app/code/Magento/Catalog/Model/Session.php
@@ -8,6 +8,6 @@ namespace Magento\Catalog\Model;
 /**
  * Catalog session model
  */
-class Session extends \Magento\Framework\Session\Generic
+class Session extends \Magento\Framework\Session\SessionManager
 {
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php
index df66448c160372d82452ebe45b9ac68b7bb08749..d4501bd7d04393062a693c3491482132a7565d7d 100644
--- a/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/ProductList/ToolbarTest.php
@@ -106,9 +106,6 @@ class ToolbarTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $this->catalogConfig->expects($this->any())
-            ->method('getAttributeUsedForSortByArray')
-            ->will($this->returnValue(['name' => [], 'price' => []]));
 
         $context = $this->getMock(
             'Magento\Framework\View\Element\Template\Context',
@@ -133,9 +130,6 @@ class ToolbarTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $this->productListHelper->expects($this->any())
-            ->method('getAvailableViewMode')
-            ->will($this->returnValue(['list' => 'List']));
 
         $this->urlEncoder = $this->getMock('Magento\Framework\Url\EncoderInterface', ['encode'], [], '', false);
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
@@ -187,6 +181,9 @@ class ToolbarTest extends \PHPUnit_Framework_TestCase
         $this->model->expects($this->once())
             ->method('getOrder')
             ->will($this->returnValue($order));
+        $this->catalogConfig->expects($this->once())
+            ->method('getAttributeUsedForSortByArray')
+            ->will($this->returnValue(['name' => [], 'price' => []]));
 
         $this->assertEquals($order, $this->block->getCurrentOrder());
     }
@@ -206,6 +203,9 @@ class ToolbarTest extends \PHPUnit_Framework_TestCase
     {
         $mode = 'list';
 
+        $this->productListHelper->expects($this->once())
+            ->method('getAvailableViewMode')
+            ->will($this->returnValue(['list' => 'List']));
         $this->model->expects($this->once())
             ->method('getMode')
             ->will($this->returnValue($mode));
@@ -213,6 +213,40 @@ class ToolbarTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($mode, $this->block->getCurrentMode());
     }
 
+    public function testGetModes()
+    {
+        $mode = ['list' => 'List'];
+        $this->productListHelper->expects($this->once())
+            ->method('getAvailableViewMode')
+            ->will($this->returnValue($mode));
+
+        $this->assertEquals($mode, $this->block->getModes());
+        $this->assertEquals($mode, $this->block->getModes());
+    }
+
+    /**
+     * @param string[] $mode
+     * @param string[] $expected
+     * @dataProvider setModesDataProvider
+     */
+    public function testSetModes($mode, $expected)
+    {
+        $this->productListHelper->expects($this->once())
+            ->method('getAvailableViewMode')
+            ->will($this->returnValue($mode));
+
+        $block = $this->block->setModes(['mode' => 'mode']);
+        $this->assertEquals($expected, $block->getModes());
+    }
+
+    public function setModesDataProvider()
+    {
+        return [
+            [['list' => 'List'], ['list' => 'List']],
+            [null, ['mode' => 'mode']],
+        ];
+    }
+
     public function testGetLimit()
     {
         $mode = 'list';
@@ -232,6 +266,9 @@ class ToolbarTest extends \PHPUnit_Framework_TestCase
             ->method('getDefaultLimitPerPageValue')
             ->with($this->equalTo('list'))
             ->will($this->returnValue(10));
+        $this->productListHelper->expects($this->any())
+            ->method('getAvailableViewMode')
+            ->will($this->returnValue(['list' => 'List']));
 
         $this->assertEquals($limit, $this->block->getLimit());
     }
@@ -280,4 +317,48 @@ class ToolbarTest extends \PHPUnit_Framework_TestCase
 
         $this->assertTrue($this->block->getPagerHtml());
     }
+
+    public function testSetDefaultOrder()
+    {
+        $this->catalogConfig->expects($this->atLeastOnce())
+            ->method('getAttributeUsedForSortByArray')
+            ->will($this->returnValue(['name' => [], 'price' => []]));
+
+        $this->block->setDefaultOrder('field');
+    }
+
+    public function testGetAvailableOrders()
+    {
+        $data = ['name' => [], 'price' => []];
+        $this->catalogConfig->expects($this->once())
+            ->method('getAttributeUsedForSortByArray')
+            ->will($this->returnValue($data));
+
+        $this->assertEquals($data, $this->block->getAvailableOrders());
+        $this->assertEquals($data, $this->block->getAvailableOrders());
+    }
+
+    public function testAddOrderToAvailableOrders()
+    {
+        $data = ['name' => [], 'price' => []];
+        $this->catalogConfig->expects($this->once())
+            ->method('getAttributeUsedForSortByArray')
+            ->will($this->returnValue($data));
+        $expected = $data;
+        $expected['order'] = 'value';
+        $toolbar = $this->block->addOrderToAvailableOrders('order', 'value');
+        $this->assertEquals($expected, $toolbar->getAvailableOrders());
+    }
+
+    public function testRemoveOrderFromAvailableOrders()
+    {
+        $data = ['name' => [], 'price' => []];
+        $this->catalogConfig->expects($this->once())
+            ->method('getAttributeUsedForSortByArray')
+            ->will($this->returnValue($data));
+        $toolbar = $this->block->removeOrderFromAvailableOrders('order', 'value');
+        $this->assertEquals($data, $toolbar->getAvailableOrders());
+        $toolbar2 = $this->block->removeOrderFromAvailableOrders('name');
+        $this->assertEquals(['price' => []], $toolbar2->getAvailableOrders());
+    }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/AbstractTypeTest.php b/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/AbstractTypeTest.php
index 75149c26c8d001cf51956b2ca893ecb326f801d4..0ce39e12fbdc93ee8f2e1d38eff837c5a9b25514 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/AbstractTypeTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/Product/Type/AbstractTypeTest.php
@@ -119,11 +119,12 @@ class AbstractTypeTest extends \PHPUnit_Framework_TestCase
 
     public function testGetSetAttributes()
     {
-        $this->productResource->expects($this->any())->method('loadAllAttributes')->will(
+        $this->productResource->expects($this->once())->method('loadAllAttributes')->will(
             $this->returnValue($this->productResource)
         );
-        $this->productResource->expects($this->any())->method('getSortedAttributes')->will($this->returnValue(5));
-        $this->model->getSetAttributes($this->product);
+        $this->productResource->expects($this->once())->method('getSortedAttributes')->will($this->returnValue(5));
+        $this->assertEquals(5, $this->model->getSetAttributes($this->product));
+        //Call the method for a second time, the cached copy should be used
         $this->assertEquals(5, $this->model->getSetAttributes($this->product));
     }
 
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductLink/ManagementTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductLink/ManagementTest.php
index ed28dc6fda78135af0e50f4e57d7db7c656dac67..92c2026f8961c258516299ba309da2cb811c145c 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ProductLink/ManagementTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductLink/ManagementTest.php
@@ -26,58 +26,21 @@ class ManagementTest extends \PHPUnit_Framework_TestCase
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
-    protected $collectionProviderMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $linkInitializerMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $productLinkFactoryMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $productResourceMock;
+    protected $productMock;
 
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
-    protected $productMock;
+    protected $linkTypeProviderMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\ObjectManager
      */
-    protected $linkTypeProviderMock;
+    protected $objectManager;
 
     protected function setUp()
     {
         $this->productRepositoryMock = $this->getMock('\Magento\Catalog\Model\ProductRepository', [], [], '', false);
-        $this->productResourceMock = $this->getMock('\Magento\Catalog\Model\Resource\Product', [], [], '', false);
-        $this->collectionProviderMock = $this->getMock(
-            '\Magento\Catalog\Model\ProductLink\CollectionProvider',
-            [],
-            [],
-            '',
-            false
-        );
-        $this->linkInitializerMock = $this->getMock(
-            '\Magento\Catalog\Model\Product\Initialization\Helper\ProductLinks',
-            [],
-            [],
-            '',
-            false
-        );
-        $this->productLinkFactoryMock = $this->getMock(
-            '\Magento\Catalog\Api\Data\ProductLinkInterfaceFactory',
-            ['create'],
-            [],
-            '',
-            false
-        );
         $this->productMock = $this->getMock('Magento\Catalog\Model\Product', [], [], '', false);
 
         $this->linkTypeProviderMock = $this->getMock(
@@ -88,15 +51,11 @@ class ManagementTest extends \PHPUnit_Framework_TestCase
             false
         );
 
-        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->model = $objectManager->getObject(
+        $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->model = $this->objectManager->getObject(
             'Magento\Catalog\Model\ProductLink\Management',
             [
                 'productRepository' => $this->productRepositoryMock,
-                'collectionProvider' => $this->collectionProviderMock,
-                'productLinkFactory' => $this->productLinkFactoryMock,
-                'linkInitializer' => $this->linkInitializerMock,
-                'productResource' => $this->productResourceMock,
                 'linkTypeProvider' => $this->linkTypeProviderMock
             ]
         );
@@ -104,163 +63,135 @@ class ManagementTest extends \PHPUnit_Framework_TestCase
 
     public function testGetLinkedItemsByType()
     {
-        $productSku = 'product';
-        $linkType = 'link';
+        $productSku = 'Simple Product 1';
+        $linkType = 'related';
         $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku)
             ->willReturn($this->productMock);
-        $item = [
-            'sku' => 'product1',
-            'type' => 'type1',
-            'position' => 'pos1',
-        ];
-        $itemCollection = [$item];
-        $this->collectionProviderMock->expects($this->once())
-            ->method('getCollection')
-            ->with($this->productMock, $linkType)
-            ->willReturn($itemCollection);
-        $this->productMock->expects($this->once())->method('getSku')->willReturn($productSku);
-        $productLinkMock = $this->getMock('\Magento\Catalog\Api\Data\ProductLinkInterface');
-        $productLinkMock->expects($this->once())
-            ->method('setProductSku')
-            ->with($productSku)
-            ->willReturnSelf();
-        $productLinkMock->expects($this->once())
-            ->method('setLinkType')
-            ->with($linkType)
-            ->willReturnSelf();
-        $productLinkMock->expects($this->once())
-            ->method('setLinkedProductSku')
-            ->with($item['sku'])
-            ->willReturnSelf();
-        $productLinkMock->expects($this->once())
-            ->method('setLinkedProductType')
-            ->with($item['type'])
-            ->willReturnSelf();
-        $productLinkMock->expects($this->once())
-            ->method('setPosition')
-            ->with($item['position'])
-            ->willReturnSelf();
-        $this->productLinkFactoryMock->expects($this->once())->method('create')->willReturn($productLinkMock);
-        $this->assertEquals([$productLinkMock], $this->model->getLinkedItemsByType($productSku, $linkType));
+
+        $inputRelatedLink = $this->objectManager->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $inputRelatedLink->setProductSku($productSku);
+        $inputRelatedLink->setLinkType($linkType);
+        $inputRelatedLink->setData("sku", "Simple Product 2");
+        $inputRelatedLink->setData("type_id", "simple");
+        $inputRelatedLink->setPosition(0);
+        $links = [$inputRelatedLink];
+
+        $linkTypes = ['related' => 1, 'upsell' => 4, 'crosssell' => 5, 'associated' => 3];
+        $this->linkTypeProviderMock->expects($this->once())
+            ->method('getLinkTypes')
+            ->willReturn($linkTypes);
+
+        $this->productMock->expects($this->once())->method('getProductLinks')->willReturn($links);
+        $this->assertEquals($links, $this->model->getLinkedItemsByType($productSku, $linkType));
     }
 
     /**
      * @expectedException \Magento\Framework\Exception\NoSuchEntityException
-     * @expectedExceptionMessage Unknown link type: wrong_type
+     * @expectedExceptionMessage Unknown link type: bad type
      */
     public function testGetLinkedItemsByTypeWithWrongType()
     {
-        $productSku = 'product';
-        $linkType = 'wrong_type';
-
-        $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku)
+        $productSku = 'Simple Product 1';
+        $linkType = 'bad type';
+        $this->productRepositoryMock->expects($this->never())->method('get')->with($productSku)
             ->willReturn($this->productMock);
-        $this->collectionProviderMock->expects($this->once())
-            ->method('getCollection')
-            ->with($this->productMock, $linkType)
-            ->willThrowException(new NoSuchEntityException(__('Collection provider is not registered')));
 
+        $inputRelatedLink = $this->objectManager->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $inputRelatedLink->setProductSku($productSku);
+        $inputRelatedLink->setLinkType($linkType);
+        $inputRelatedLink->setData("sku", "Simple Product 2");
+        $inputRelatedLink->setData("type_id", "simple");
+        $inputRelatedLink->setPosition(0);
+        $links = [$inputRelatedLink];
+
+        $linkTypes = ['related' => 1, 'upsell' => 4, 'crosssell' => 5, 'associated' => 3];
+        $this->linkTypeProviderMock->expects($this->once())
+            ->method('getLinkTypes')
+            ->willReturn($linkTypes);
+
+        $this->productMock->expects($this->never())->method('getProductLinks')->willReturn($links);
         $this->model->getLinkedItemsByType($productSku, $linkType);
     }
 
     public function testSetProductLinks()
     {
-        $type = 'type';
-        $linkedProductsMock = [];
-        $linksData = [];
-
-        $this->linkTypeProviderMock->expects($this->once())->method('getLinkTypes')->willReturn([$type => 'link']);
-        for ($i = 0; $i < 2; $i++) {
-            $linkMock = $this->getMockForAbstractClass(
-                '\Magento\Catalog\Api\Data\ProductLinkInterface',
-                [],
-                '',
-                false,
-                false,
-                true,
-                ['getLinkedProductSku', '__toArray']
-            );
-            $linkMock->expects($this->exactly(2))
-                ->method('getLinkedProductSku')
-                ->willReturn('linkedProduct' . $i . 'Sku');
-            $linkMock->expects($this->once())->method('__toArray');
-            $linkedProductsMock[$i] = $linkMock;
-            $linksData['productSku']['link'][] = $linkMock;
-        }
-        $linkedSkuList = ['linkedProduct0Sku', 'linkedProduct1Sku'];
-        $linkedProductIds = ['linkedProduct0Sku' => 1, 'linkedProduct1Sku' => 2];
-
-        $this->productResourceMock->expects($this->once())->method('getProductsIdsBySkus')->with($linkedSkuList)
-            ->willReturn($linkedProductIds);
-        $this->productRepositoryMock->expects($this->once())->method('get')->willReturn($this->productMock);
-        $this->linkInitializerMock->expects($this->once())->method('initializeLinks')
-            ->with($this->productMock, [$type => [
-                1 => ['product_id' => 1],
-                2 => ['product_id' => 2],
-            ]]);
-        $this->productMock->expects($this->once())->method('save');
-        $this->assertTrue($this->model->setProductLinks('', $type, $linkedProductsMock));
+        $productSku = 'Simple Product 1';
+        $linkType = 'related';
+        $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku)
+            ->willReturn($this->productMock);
+
+        $inputRelatedLink = $this->objectManager->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $inputRelatedLink->setProductSku($productSku);
+        $inputRelatedLink->setLinkType($linkType);
+        $inputRelatedLink->setData("sku", "Simple Product 1");
+        $inputRelatedLink->setData("type_id", "related");
+        $inputRelatedLink->setPosition(0);
+        $links = [$inputRelatedLink];
+
+        $linkTypes = ['related' => 1, 'upsell' => 4, 'crosssell' => 5, 'associated' => 3];
+        $this->linkTypeProviderMock->expects($this->once())
+            ->method('getLinkTypes')
+            ->willReturn($linkTypes);
+
+        $this->productMock->expects($this->once())->method('getProductLinks')->willReturn([]);
+        $this->productMock->expects($this->once())->method('setProductLinks')->with($links);
+        $this->assertTrue($this->model->setProductLinks($productSku, $linkType, $links));
     }
 
     /**
      * @expectedException \Magento\Framework\Exception\NoSuchEntityException
-     * @expectedExceptionMessage Provided link type "type2" does not exist
+     * @expectedExceptionMessage Provided link type "bad type" does not exist
      */
     public function testSetProductLinksThrowExceptionIfProductLinkTypeDoesNotExist()
     {
-        $type = 'type';
-        $linkedProductsMock = [];
+        $productSku = 'Simple Product 1';
+        $linkType = 'bad type';
+        $this->productRepositoryMock->expects($this->never())->method('get')->with($productSku)
+            ->willReturn($this->productMock);
+
+        $inputRelatedLink = $this->objectManager->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $inputRelatedLink->setProductSku($productSku);
+        $inputRelatedLink->setLinkType($linkType);
+        $inputRelatedLink->setData("sku", "Simple Product 2");
+        $inputRelatedLink->setData("type_id", "simple");
+        $inputRelatedLink->setPosition(0);
+        $links = [$inputRelatedLink];
 
-        $this->linkTypeProviderMock->expects($this->once())->method('getLinkTypes')->willReturn([$type => 'link']);
-        $this->assertTrue($this->model->setProductLinks('', 'type2', $linkedProductsMock));
+        $linkTypes = ['related' => 1, 'upsell' => 4, 'crosssell' => 5, 'associated' => 3];
+        $this->linkTypeProviderMock->expects($this->once())
+            ->method('getLinkTypes')
+            ->willReturn($linkTypes);
+
+        $this->assertTrue($this->model->setProductLinks('', $linkType, $links));
     }
 
     /**
-     * @dataProvider setProductLinksNoProductExceptionDataProvider
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedExceptionMessage Requested product doesn't exist
      */
-    public function testSetProductLinksNoProductException($exceptionName, $exceptionMessage, $linkedProductIds)
+    public function testSetProductLinksNoProductException()
     {
-        $this->setExpectedException($exceptionName, $exceptionMessage);
-        $linkedProductsMock = [];
-        $type = 'type';
-        $this->linkTypeProviderMock->expects($this->once())->method('getLinkTypes')->willReturn([$type => 'link']);
-        for ($i = 0; $i < 2; $i++) {
-            $productLinkMock = $this->getMock(
-                '\Magento\Catalog\Api\Data\ProductLinkInterface',
-                [
-                    'getLinkedProductSku', 'getProductSku', 'getLinkType',
-                    '__toArray', 'getLinkedProductType', 'getPosition', 'getCustomAttribute', 'getCustomAttributes',
-                    'setCustomAttribute', 'setCustomAttributes', 'getMetadataServiceInterface',
-                    'getExtensionAttributes', 'setExtensionAttributes',
-                    'setLinkedProductSku', 'setProductSku', 'setLinkType', 'setLinkedProductType', 'setPosition'
-                ]
-            );
-            $productLinkMock->expects($this->any())
-                ->method('getLinkedProductSku')
-                ->willReturn('linkedProduct' . $i . 'Sku');
-            $productLinkMock->expects($this->any())->method('getProductSku')->willReturn('productSku');
-            $productLinkMock->expects($this->any())->method('getLinkType')->willReturn('link');
-            $linkedProductsMock[$i] = $productLinkMock;
-        }
-        $linkedSkuList = ['linkedProduct0Sku', 'linkedProduct1Sku'];
-        $this->productResourceMock->expects($this->any())->method('getProductsIdsBySkus')->with($linkedSkuList)
-            ->willReturn($linkedProductIds);
-        $this->model->setProductLinks('', $type, $linkedProductsMock);
-    }
-
-    public function setProductLinksNoProductExceptionDataProvider()
-    {
-        return [
-            [
-                '\Magento\Framework\Exception\NoSuchEntityException',
-                'Product with SKU "linkedProduct0Sku" does not exist',
-                ['linkedProduct1Sku' => 2],
-            ], [
-                '\Magento\Framework\Exception\NoSuchEntityException',
-                'Product with SKU "linkedProduct1Sku" does not exist',
-                ['linkedProduct0Sku' => 1]
-            ]
-        ];
+        $productSku = 'Simple Product 1';
+        $linkType = 'related';
+
+        $inputRelatedLink = $this->objectManager->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $inputRelatedLink->setProductSku($productSku);
+        $inputRelatedLink->setLinkType($linkType);
+        $inputRelatedLink->setData("sku", "Simple Product 2");
+        $inputRelatedLink->setData("type_id", "simple");
+        $inputRelatedLink->setPosition(0);
+        $links = [$inputRelatedLink];
+
+        $linkTypes = ['related' => 1, 'upsell' => 4, 'crosssell' => 5, 'associated' => 3];
+        $this->linkTypeProviderMock->expects($this->once())
+            ->method('getLinkTypes')
+            ->willReturn($linkTypes);
+
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->will($this->throwException(
+                new \Magento\Framework\Exception\NoSuchEntityException(__('Requested product doesn\'t exist'))));
+        $this->model->setProductLinks($productSku, $linkType, $links);
     }
 
     /**
@@ -269,39 +200,27 @@ class ManagementTest extends \PHPUnit_Framework_TestCase
      */
     public function testSetProductLinksInvalidDataException()
     {
-        $type = 'type';
-        $linkedProductsMock = [];
-        $linksData = [];
-        $this->linkTypeProviderMock->expects($this->once())->method('getLinkTypes')->willReturn([$type => 'link']);
-        for ($i = 0; $i < 2; $i++) {
-            $linkMock = $this->getMockForAbstractClass(
-                '\Magento\Catalog\Api\Data\ProductLinkInterface',
-                [],
-                '',
-                false,
-                false,
-                true,
-                ['getLinkedProductSku', '__toArray']
-            );
-            $linkMock->expects($this->exactly(2))
-                ->method('getLinkedProductSku')
-                ->willReturn('linkedProduct' . $i . 'Sku');
-            $linkMock->expects($this->once())->method('__toArray');
-            $linkedProductsMock[$i] = $linkMock;
-            $linksData['productSku']['link'][] = $linkMock;
-        }
-        $linkedSkuList = ['linkedProduct0Sku', 'linkedProduct1Sku'];
-        $linkedProductIds = ['linkedProduct0Sku' => 1, 'linkedProduct1Sku' => 2];
-
-        $this->productResourceMock->expects($this->once())->method('getProductsIdsBySkus')->with($linkedSkuList)
-            ->willReturn($linkedProductIds);
-        $this->productRepositoryMock->expects($this->once())->method('get')->willReturn($this->productMock);
-        $this->linkInitializerMock->expects($this->once())->method('initializeLinks')
-            ->with($this->productMock, [$type => [
-                1 => ['product_id' => 1],
-                2 => ['product_id' => 2],
-            ]]);
-        $this->productMock->expects($this->once())->method('save')->willThrowException(new \Exception());
-        $this->model->setProductLinks('', $type, $linkedProductsMock);
+        $productSku = 'Simple Product 1';
+        $linkType = 'related';
+        $this->productRepositoryMock->expects($this->once())->method('get')->with($productSku)
+            ->willReturn($this->productMock);
+
+        $inputRelatedLink = $this->objectManager->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $inputRelatedLink->setProductSku($productSku);
+        $inputRelatedLink->setLinkType($linkType);
+        $inputRelatedLink->setData("sku", "bad sku");
+        $inputRelatedLink->setData("type_id", "bad type");
+        $inputRelatedLink->setPosition(0);
+        $links = [$inputRelatedLink];
+
+        $linkTypes = ['related' => 1, 'upsell' => 4, 'crosssell' => 5, 'associated' => 3];
+        $this->linkTypeProviderMock->expects($this->once())
+            ->method('getLinkTypes')
+            ->willReturn($linkTypes);
+
+        $this->productMock->expects($this->once())->method('getProductLinks')->willReturn([]);
+
+        $this->productRepositoryMock->expects($this->once())->method('save')->willThrowException(new \Exception());
+        $this->model->setProductLinks($productSku, $linkType, $links);
     }
 }
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
index a8ba184519d797718c4613f9e5f4c4c8690764bf..35b260532553ee98240c049b12e1116449fbc9d9 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductRepositoryTest.php
@@ -111,11 +111,19 @@ class ProductRepositoryTest extends \PHPUnit_Framework_TestCase
      */
     protected $contentValidatorMock;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $linkTypeProviderMock;
+
     /**
      * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
      */
     protected $objectManager;
 
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
     protected function setUp()
     {
         $this->productFactoryMock = $this->getMock('Magento\Catalog\Model\ProductFactory', ['create'], [], '', false);
@@ -194,6 +202,8 @@ class ProductRepositoryTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
         $optionConverter = $this->objectManager->getObject('Magento\Catalog\Model\Product\Option\Converter');
+        $this->linkTypeProviderMock = $this->getMock('Magento\Catalog\Model\Product\LinkTypeProvider',
+            ['getLinkTypes'], [], '', false);
         $this->model = $this->objectManager->getObject(
             'Magento\Catalog\Model\ProductRepository',
             [
@@ -212,6 +222,7 @@ class ProductRepositoryTest extends \PHPUnit_Framework_TestCase
                 'fileSystem' => $this->fileSystemMock,
                 'contentFactory' => $this->contentFactoryMock,
                 'mimeTypeExtensionMap' => $this->mimeTypeExtensionMapMock,
+                'linkTypeProvider' => $this->linkTypeProviderMock
             ]
         );
     }
@@ -847,6 +858,11 @@ class ProductRepositoryTest extends \PHPUnit_Framework_TestCase
         $this->initializedProductMock->setData("product_links", $existingLinks);
 
         if (!empty($newLinks)) {
+            $linkTypes = ['related' => 1, 'upsell' => 4, 'crosssell' => 5, 'associated' => 3];
+            $this->linkTypeProviderMock->expects($this->once())
+                ->method('getLinkTypes')
+                ->willReturn($linkTypes);
+
             $this->initializedProductMock->setData("ignore_links_flag", false);
             $this->resourceModelMock
                 ->expects($this->any())->method('getProductsIdsBySkus')
@@ -859,6 +875,10 @@ class ProductRepositoryTest extends \PHPUnit_Framework_TestCase
             $inputLink->setLinkedProductType($newLinks['linked_product_type']);
             $inputLink->setPosition($newLinks['position']);
 
+            if (isset($newLinks['qty'])) {
+                $inputLink->setQty($newLinks['qty']);
+            }
+
             $this->productData['product_links'] = [$inputLink];
 
             $this->initializedProductMock->expects($this->any())
@@ -898,6 +918,9 @@ class ProductRepositoryTest extends \PHPUnit_Framework_TestCase
                 $outputLink->setLinkedProductSku($link['linked_product_sku']);
                 $outputLink->setLinkedProductType($link['linked_product_type']);
                 $outputLink->setPosition($link['position']);
+                if (isset($link['qty'])) {
+                    $outputLink->setQty($link['qty']);
+                }
 
                 $outputLinks[] = $outputLink;
             }
@@ -913,11 +936,11 @@ class ProductRepositoryTest extends \PHPUnit_Framework_TestCase
         // Scenario 1
         // No existing, new links
         $data['scenario_1'] = [
-            'newLinks' => ["product_sku" => "Simple Product 1", "link_type" => "related", "linked_product_sku" =>
-                "Simple Product 2", "linked_product_type" => "simple", "position" => 0],
+            'newLinks' => ["product_sku" => "Simple Product 1", "link_type" => "associated", "linked_product_sku" =>
+                "Simple Product 2", "linked_product_type" => "simple", "position" => 0, "qty" => 1],
             'existingLinks' => [],
-            'expectedData' => [["product_sku" => "Simple Product 1", "link_type" => "related", "linked_product_sku" =>
-                "Simple Product 2", "linked_product_type" => "simple", "position" => 0]]
+            'expectedData' => [["product_sku" => "Simple Product 1", "link_type" => "associated", "linked_product_sku" =>
+                "Simple Product 2", "linked_product_type" => "simple", "position" => 0, "qty" => 1]]
             ];
 
         // Scenario 2
diff --git a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php
index 4dcd067721f5bc239c97b1aa0141e694fb8a7f07..4cc87c7011c705075f1cb321657748006efc6aa6 100644
--- a/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Model/ProductTest.php
@@ -146,6 +146,16 @@ class ProductTest extends \PHPUnit_Framework_TestCase
      */
     protected $attributeValueFactory;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $linkTypeProviderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $entityCollectionProviderMock;
+
     /**
      * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
      */
@@ -283,6 +293,11 @@ class ProductTest extends \PHPUnit_Framework_TestCase
         $this->metadataServiceMock = $this->getMock('\Magento\Catalog\Api\ProductAttributeRepositoryInterface');
         $this->attributeValueFactory = $this->getMockBuilder('Magento\Framework\Api\AttributeValueFactory')
             ->disableOriginalConstructor()->getMock();
+        $this->linkTypeProviderMock = $this->getMock('Magento\Catalog\Model\Product\LinkTypeProvider',
+            ['getLinkTypes'], [], '', false);
+        $this->entityCollectionProviderMock = $this->getMock('Magento\Catalog\Model\ProductLink\CollectionProvider',
+            ['getCollection'], [], '', false);
+
         $this->objectManagerHelper = new ObjectManagerHelper($this);
         $this->model = $this->objectManagerHelper->getObject(
             'Magento\Catalog\Model\Product',
@@ -306,6 +321,8 @@ class ProductTest extends \PHPUnit_Framework_TestCase
                 'mediaGalleryEntryFactory' => $this->mediaGalleryEntryFactoryMock,
                 'metadataService' => $this->metadataServiceMock,
                 'customAttributeFactory' => $this->attributeValueFactory,
+                'entityCollectionProvider' => $this->entityCollectionProviderMock,
+                'linkTypeProvider' => $this->linkTypeProviderMock,
                 'data' => ['id' => 1]
             ]
         );
@@ -737,37 +754,43 @@ class ProductTest extends \PHPUnit_Framework_TestCase
      */
     public function testGetProductLinks()
     {
-        $inputLink = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
-        $inputLink->setProductSku("Simple Product 1");
-        $inputLink->setLinkType("related");
-        $inputLink->setData("sku", "Simple Product 2");
-        $inputLink->setData("type_id", "simple");
-        $inputLink->setPosition(0);
-
-        $outputLink = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
-        $outputLink->setProductSku("Simple Product 1");
-        $outputLink->setLinkType("related");
-        $outputLink->setLinkedProductSku("Simple Product 2");
-        $outputLink->setLinkedProductType("simple");
-        $outputLink->setPosition(0);
-
-        $productLinks = [];
-        $this->model->setData('related_products', [$inputLink]);
-        $productLinks[] = $outputLink;
-        $outputLink->setLinkType("upsell");
-        $inputLink->setLinkType("upsell");
-        $this->model->setData('up_sell_products', [$inputLink]);
-        $productLinks[] = $outputLink;
-        $outputLink->setLinkType("crosssell");
-        $inputLink->setLinkType("crosssell");
-        $this->model->setData('cross_sell_products', [$inputLink]);
-        $productLinks[] = $outputLink;
-
-        $productLink = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
-        $this->productLinkFactory->expects($this->atLeastOnce())
-            ->method('create')
-            ->willReturn($productLink);
-
+        $linkTypes = ['related' => 1, 'upsell' => 4, 'crosssell' => 5, 'associated' => 3];
+        $this->linkTypeProviderMock->expects($this->once())
+            ->method('getLinkTypes')
+            ->willReturn($linkTypes);
+
+        $inputRelatedLink = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $inputRelatedLink->setProductSku("Simple Product 1");
+        $inputRelatedLink->setLinkType("related");
+        $inputRelatedLink->setData("sku", "Simple Product 2");
+        $inputRelatedLink->setData("type", "simple");
+        $inputRelatedLink->setPosition(0);
+
+        $outputRelatedLink = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $outputRelatedLink->setProductSku("Simple Product 1");
+        $outputRelatedLink->setLinkType("related");
+        $outputRelatedLink->setLinkedProductSku("Simple Product 2");
+        $outputRelatedLink->setLinkedProductType("simple");
+        $outputRelatedLink->setPosition(0);
+
+        $this->entityCollectionProviderMock->expects($this->at(0))
+            ->method('getCollection')
+            ->with($this->model, 'related')
+            ->willReturn([$inputRelatedLink]);
+        $this->entityCollectionProviderMock->expects($this->at(1))
+            ->method('getCollection')
+            ->with($this->model, 'upsell')
+            ->willReturn([]);
+        $this->entityCollectionProviderMock->expects($this->at(2))
+            ->method('getCollection')
+            ->with($this->model, 'crosssell')
+            ->willReturn([]);
+        $this->entityCollectionProviderMock->expects($this->at(3))
+            ->method('getCollection')
+            ->with($this->model, 'associated')
+            ->willReturn([]);
+
+        $expectedOutput = [$outputRelatedLink];
         $typeInstanceMock = $this->getMock(
             'Magento\ConfigurableProduct\Model\Product\Type\Simple', ["getSku"], [], '', false);
         $typeInstanceMock
@@ -776,8 +799,13 @@ class ProductTest extends \PHPUnit_Framework_TestCase
             ->willReturn("Simple Product 1");
         $this->model->setTypeInstance($typeInstanceMock);
 
+        $productLink1 = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $this->productLinkFactory->expects($this->at(0))
+            ->method('create')
+            ->willReturn($productLink1);
+
         $links = $this->model->getProductLinks();
-        $this->assertEquals($links, $productLinks);
+        $this->assertEquals($links, $expectedOutput);
     }
 
     /**
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml
index acd741fdbbe66d5c107a3d24ce3d99a5ec716b52..6f7a28ce683603769fabd81c833237ca3956bd0b 100644
--- a/app/code/Magento/Catalog/etc/di.xml
+++ b/app/code/Magento/Catalog/etc/di.xml
@@ -88,6 +88,7 @@
                     <item name="category_ids" xsi:type="string">category_ids</item>
                     <item name="entity_id" xsi:type="string">entity_id</item>
                     <item name="store_id" xsi:type="string">store_id</item>
+                    <item name="website_ids" xsi:type="string">website_ids</item>
                     <item name="visibility" xsi:type="string">visibility</item>
                     <item name="status" xsi:type="string">status</item>
                 </item>
@@ -98,6 +99,7 @@
     <type name="Magento\Catalog\Model\Product">
         <arguments>
             <argument name="catalogProductStatus" xsi:type="object">Magento\Catalog\Model\Product\Attribute\Source\Status\Proxy</argument>
+            <argument name="productLink" xsi:type="object">Magento\Catalog\Model\Product\Link\Proxy</argument>
         </arguments>
     </type>
     <type name="Magento\Catalog\Model\Resource\Product\Collection">
@@ -398,6 +400,11 @@
             <argument name="validatorFile" xsi:type="object">Magento\Catalog\Model\Product\Option\Type\File\ValidatorFile\Proxy</argument>
         </arguments>
     </type>
+    <type name="Magento\Catalog\Model\Attribute\Config">
+        <arguments>
+            <argument name="dataStorage" xsi:type="object">Magento\Catalog\Model\Attribute\Config\Data\Proxy</argument>
+        </arguments>
+    </type>
     <virtualType name="Magento\Catalog\Model\Layer\Search\Context" type="Magento\Catalog\Model\Layer\Context">
         <arguments>
             <argument name="collectionProvider" xsi:type="object">Magento\Catalog\Model\Layer\Search\ItemCollectionProvider</argument>
@@ -464,4 +471,9 @@
     <type name="Magento\Catalog\Api\ProductRepositoryInterface">
         <plugin name="transactionWrapper" type="\Magento\Catalog\Model\Plugin\ProductRepository\TransactionWrapper" sortOrder="-1"/>
     </type>
+    <type name="Magento\Catalog\Model\CategoryRepository">
+        <arguments>
+            <argument name="categoryResource" xsi:type="object">Magento\Catalog\Model\Resource\Category\Proxy</argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Catalog/view/base/web/js/price-box.js b/app/code/Magento/Catalog/view/base/web/js/price-box.js
index 667a30836e529533ce04c77b9f5605668852b04b..eed8ac4b9752c2eabcf80175699cc778d7d491c0 100644
--- a/app/code/Magento/Catalog/view/base/web/js/price-box.js
+++ b/app/code/Magento/Catalog/view/base/web/js/price-box.js
@@ -190,7 +190,7 @@ define([
             if (_.isEmpty(prices)) {
                 priceHolders.each(function (index, element) {
                     var type = $(element).data('priceType'),
-                        amount = $(element).data('priceAmount');
+                        amount = parseFloat($(element).data('priceAmount'));
 
                     if (type && amount) {
                         prices[type] = {
diff --git a/app/code/Magento/CatalogImportExport/Model/Import/Proxy/Product/Resource.php b/app/code/Magento/CatalogImportExport/Model/Import/Proxy/Product/Resource.php
index a71fe9dcc496215b69d7573c094c6762a8be4c4d..0f68ad9e99503a7932d2407dd79bd15d55c870f5 100644
--- a/app/code/Magento/CatalogImportExport/Model/Import/Proxy/Product/Resource.php
+++ b/app/code/Magento/CatalogImportExport/Model/Import/Proxy/Product/Resource.php
@@ -13,23 +13,4 @@ namespace Magento\CatalogImportExport\Model\Import\Proxy\Product;
 
 class Resource extends \Magento\Catalog\Model\Resource\Product
 {
-    /**
-     * Product to category table.
-     *
-     * @return string
-     */
-    public function getProductCategoryTable()
-    {
-        return $this->_productCategoryTable;
-    }
-
-    /**
-     * Product to website table.
-     *
-     * @return string
-     */
-    public function getProductWebsiteTable()
-    {
-        return $this->_productWebsiteTable;
-    }
 }
diff --git a/app/code/Magento/CatalogInventory/Api/Data/StockItemInterface.php b/app/code/Magento/CatalogInventory/Api/Data/StockItemInterface.php
index 46163c26be6d3df33831a35e9344333ffeaef7ef..0a620ce1562d529959ce09af000bc2f3b9923b7a 100644
--- a/app/code/Magento/CatalogInventory/Api/Data/StockItemInterface.php
+++ b/app/code/Magento/CatalogInventory/Api/Data/StockItemInterface.php
@@ -55,7 +55,7 @@ interface StockItemInterface extends ExtensibleDataInterface
     const CUSTOMER_GROUP_ID = 'customer_group_id';
 
     /**
-     * @return int
+     * @return int|null
      */
     public function getItemId();
 
@@ -66,7 +66,7 @@ interface StockItemInterface extends ExtensibleDataInterface
     public function setItemId($itemId);
 
     /**
-     * @return int
+     * @return int|null
      */
     public function getProductId();
 
@@ -79,7 +79,7 @@ interface StockItemInterface extends ExtensibleDataInterface
     /**
      * Retrieve Website Id
      *
-     * @return int
+     * @return int|null
      */
     public function getWebsiteId();
 
@@ -94,7 +94,7 @@ interface StockItemInterface extends ExtensibleDataInterface
     /**
      * Retrieve stock identifier
      *
-     * @return int
+     * @return int|null
      */
     public function getStockId();
 
diff --git a/app/code/Magento/CatalogInventory/Model/Configuration.php b/app/code/Magento/CatalogInventory/Model/Configuration.php
index 2d4d0189a63c565b9bca8f97fb3b016e328220b6..8cb377e1a4dc7fc577bb9b0cf52789c706eeb84d 100644
--- a/app/code/Magento/CatalogInventory/Model/Configuration.php
+++ b/app/code/Magento/CatalogInventory/Model/Configuration.php
@@ -150,7 +150,7 @@ class Configuration implements StockConfigurationInterface
      */
     public function getDefaultWebsiteId()
     {
-        return (int) $this->storeManager->getWebsite(true)->getId();
+        return (int) $this->storeManager->getWebsite()->getId();
     }
 
     /**
diff --git a/app/code/Magento/CatalogInventory/Model/Plugin/AfterProductLoad.php b/app/code/Magento/CatalogInventory/Model/Plugin/AfterProductLoad.php
new file mode 100644
index 0000000000000000000000000000000000000000..3d6c9d404afe0e0e4594ef8f467c630575c69fab
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Model/Plugin/AfterProductLoad.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogInventory\Model\Plugin;
+
+class AfterProductLoad
+{
+    /**
+     * @var \Magento\CatalogInventory\Api\StockRegistryInterface
+     */
+    protected $stockRegistry;
+
+    /**
+     * @var \Magento\Catalog\Api\Data\ProductExtensionFactory
+     */
+    protected $productExtensionFactory;
+
+    /**
+     * @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
+     * @param \Magento\Catalog\Api\Data\ProductExtensionFactory $productExtensionFactory
+     */
+    public function __construct(
+        \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
+        \Magento\Catalog\Api\Data\ProductExtensionFactory $productExtensionFactory
+    ) {
+        $this->stockRegistry = $stockRegistry;
+        $this->productExtensionFactory = $productExtensionFactory;
+    }
+
+    /**
+     * Add stock item information to the product's extension attributes
+     *
+     * @param \Magento\Catalog\Model\Product $product
+     * @return \Magento\Catalog\Model\Product
+     */
+    public function afterLoad(\Magento\Catalog\Model\Product $product)
+    {
+        $productExtension = $product->getExtensionAttributes();
+        if ($productExtension === null) {
+            $productExtension = $this->productExtensionFactory->create();
+        }
+        // stockItem := \Magento\CatalogInventory\Api\Data\StockItemInterface
+        $productExtension->setStockItem($this->stockRegistry->getStockItem($product->getId()));
+        $product->setExtensionAttributes($productExtension);
+        return $product;
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Model/Plugin/AroundProductRepositorySave.php b/app/code/Magento/CatalogInventory/Model/Plugin/AroundProductRepositorySave.php
new file mode 100644
index 0000000000000000000000000000000000000000..0b222de117c9e84cb9aea4c009889f57ccbb8c80
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Model/Plugin/AroundProductRepositorySave.php
@@ -0,0 +1,95 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogInventory\Model\Plugin;
+
+class AroundProductRepositorySave
+{
+    /**
+     * @var \Magento\CatalogInventory\Api\StockRegistryInterface
+     */
+    protected $stockRegistry;
+
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface
+     */
+    protected $storeManager;
+
+    /**
+     * @param \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry
+     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
+     */
+    public function __construct(
+        \Magento\CatalogInventory\Api\StockRegistryInterface $stockRegistry,
+        \Magento\Store\Model\StoreManagerInterface $storeManager
+    ) {
+        $this->stockRegistry = $stockRegistry;
+        $this->storeManager = $storeManager;
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\ProductRepositoryInterface $subject
+     * @param callable $proceed
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param bool $saveOptions
+     * @return \Magento\Catalog\Api\Data\ProductInterface
+     * @throws \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function aroundSave(
+        \Magento\Catalog\Api\ProductRepositoryInterface $subject,
+        \Closure $proceed,
+        \Magento\Catalog\Api\Data\ProductInterface $product,
+        $saveOptions = false
+    ) {
+        /** @var \Magento\Catalog\Api\Data\ProductInterface $result */
+        $result = $proceed($product, $saveOptions);
+
+        /* @var \Magento\CatalogInventory\Api\Data\StockItemInterface $stockItem */
+        $stockItem = $this->getStockItemToBeUpdated($product);
+        if ($stockItem == null) {
+            return $result;
+        }
+
+        // set fields that the customer should not care about
+        $stockItem->setProductId($result->getId());
+        $stockItem->setWebsiteId($this->storeManager->getStore($result->getStoreId())->getWebsiteId());
+
+        $this->stockRegistry->updateStockItemBySku($result->getSku(), $stockItem);
+
+        // since we just saved a portion of the product, force a reload of it before returning it
+        return $subject->get($result->getSku(), false, $result->getStoreId(), true);
+    }
+
+    /**
+     * Return the stock item that needs to be updated.
+     * If the stock item does not need to be updated, return null.
+     *
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @return \Magento\CatalogInventory\Api\Data\StockItemInterface|null
+     */
+    protected function getStockItemToBeUpdated($product)
+    {
+        // from the API, all the data we care about will exist as extension attributes of the original product
+        $extendedAttributes = $product->getExtensionAttributes();
+        if ($extendedAttributes !== null) {
+            $stockItem = $extendedAttributes->getStockItem();
+            if ($stockItem != null) {
+                return $stockItem;
+            }
+        }
+
+        // we have no new stock item information to update, however we need to ensure that the product does have some
+        // stock item information present.  On a newly created product, it will not have any stock item info.
+        $stockItem = $this->stockRegistry->getStockItem($product->getId());
+        if ($stockItem->getItemId() != null) {
+            // we already have stock item info, so we return null since nothing more needs to be updated
+            return null;
+        }
+
+        return $stockItem;
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Model/Stock/Item.php b/app/code/Magento/CatalogInventory/Model/Stock/Item.php
index cb622e904c6bbab1838275d66a5f9129e6640a24..15fb84875aafeac95108233e7f4ea482fc295a26 100644
--- a/app/code/Magento/CatalogInventory/Model/Stock/Item.php
+++ b/app/code/Magento/CatalogInventory/Model/Stock/Item.php
@@ -239,11 +239,11 @@ class Item extends AbstractExtensibleModel implements StockItemInterface
     }
 
     /**
-     * @return int Timestamp
+     * @return string Timestamp
      */
     public function getLowStockDate()
     {
-        return (int) $this->_getData(static::LOW_STOCK_DATE);
+        return $this->_getData(static::LOW_STOCK_DATE);
     }
 
     /**
diff --git a/app/code/Magento/CatalogInventory/Model/StockManagement.php b/app/code/Magento/CatalogInventory/Model/StockManagement.php
index 1f50b8b5dceaa3b64ff14c83044ac6e62f7e85cb..3d5fee6d9cef90eb8bfcf98d78b6c45e68c0bca2 100644
--- a/app/code/Magento/CatalogInventory/Model/StockManagement.php
+++ b/app/code/Magento/CatalogInventory/Model/StockManagement.php
@@ -84,7 +84,7 @@ class StockManagement implements StockManagementInterface
             $orderedQty = $items[$productId];
             $stockItem = $this->stockRegistryProvider->getStockItem($productId, $websiteId);
             $canSubtractQty = $stockItem->getItemId() && $this->canSubtractQty($stockItem);
-            if (!$canSubtractQty || !$this->stockConfiguration->isQty($this->getProductType($productId))) {
+            if (!$canSubtractQty || !$this->stockConfiguration->isQty($lockedItemRecord['type_id'])) {
                 continue;
             }
             if (!$stockItem->hasAdminArea()
diff --git a/app/code/Magento/CatalogInventory/Model/StockRegistry.php b/app/code/Magento/CatalogInventory/Model/StockRegistry.php
index fefbf9f34899f031a374d551e390b24235d3f9c0..f32aeb2104b686091e06120271c462ec33542f08 100644
--- a/app/code/Magento/CatalogInventory/Model/StockRegistry.php
+++ b/app/code/Magento/CatalogInventory/Model/StockRegistry.php
@@ -15,6 +15,8 @@ use Magento\CatalogInventory\Model\Spi\StockRegistryProviderInterface;
 
 /**
  * Class StockRegistry
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class StockRegistry implements StockRegistryInterface
 {
@@ -185,9 +187,7 @@ class StockRegistry implements StockRegistryInterface
         $origStockItem = $this->getStockItem($productId, $websiteId);
         $data = $stockItem->getData();
         if ($origStockItem->getItemId()) {
-            if (isset($data['item_id'])) {
-                unset($data['item_id']);
-            }
+            unset($data['item_id']);
         }
         $origStockItem->addData($data);
         $origStockItem->setProductId($productId);
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/ConfigurationTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/ConfigurationTest.php
index 34e93d5bd730082c2f67ab408ab83773f65a18be..6de9c01656aecb292c061550e65c69bc000ee0c1 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Model/ConfigurationTest.php
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/ConfigurationTest.php
@@ -70,7 +70,6 @@ class ConfigurationTest extends \PHPUnit_Framework_TestCase
             ->willReturn($id);
         $this->storeManagerMock->expects($this->once())
             ->method('getWebsite')
-            ->with(true)
             ->willReturn($websiteMock);
         $this->assertEquals($id, $this->model->getDefaultWebsiteId());
     }
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AfterProductLoadTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AfterProductLoadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..77b8985cac84c3d21bb9eeb7a598ea9138c366d6
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AfterProductLoadTest.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+namespace Magento\CatalogInventory\Test\Unit\Model\Plugin;
+
+class AfterProductLoadTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogInventory\Model\Plugin\AfterProductLoad
+     */
+    protected $plugin;
+
+    /**
+     * @var \Magento\Catalog\Api\Data\ProductInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var \Magento\Catalog\Api\Data\ProductExtensionFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productExtensionFactoryMock;
+
+    /**
+     * @var \Magento\Catalog\Api\Data\ProductExtension|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productExtensionMock;
+
+    protected function setUp()
+    {
+        $stockRegistryMock = $this->getMock('\Magento\CatalogInventory\Api\StockRegistryInterface');
+        $this->productExtensionFactoryMock = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtensionFactory')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->plugin = new \Magento\CatalogInventory\Model\Plugin\AfterProductLoad(
+            $stockRegistryMock,
+            $this->productExtensionFactoryMock
+        );
+
+        $productId = 5494;
+        $stockItemMock = $this->getMock('\Magento\CatalogInventory\Api\Data\StockItemInterface');
+
+        $stockRegistryMock->expects($this->once())
+            ->method('getStockItem')
+            ->with($productId)
+            ->willReturn($stockItemMock);
+
+        $this->productExtensionMock = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtension')
+            ->setMethods(['setStockItem'])
+            ->getMock();
+        $this->productExtensionMock->expects($this->once())
+            ->method('setStockItem')
+            ->with($stockItemMock)
+            ->willReturnSelf();
+
+        $this->productMock = $this->getMockBuilder('\Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->productMock->expects($this->once())
+            ->method('setExtensionAttributes')
+            ->with($this->productExtensionMock)
+            ->willReturnSelf();
+        $this->productMock->expects(($this->once()))
+            ->method('getId')
+            ->will($this->returnValue($productId));
+    }
+
+    public function testAfterLoad()
+    {
+        // test when extension attributes are not (yet) present in the product
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn(null);
+        $this->productExtensionFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($this->productExtensionMock);
+
+        $this->assertEquals(
+            $this->productMock,
+            $this->plugin->afterLoad($this->productMock)
+        );
+    }
+
+    public function testAfterLoadWithExistingExtensionAttributes()
+    {
+        // test when extension attributes already exist
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $this->productExtensionFactoryMock->expects($this->never())
+            ->method('create');
+
+        $this->assertEquals(
+            $this->productMock,
+            $this->plugin->afterLoad($this->productMock)
+        );
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..95560e7ce7be3144937120e89eb40f41484b7586
--- /dev/null
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+namespace Magento\CatalogInventory\Test\Unit\Model\Plugin;
+
+class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogInventory\Model\Plugin\AroundProductRepositorySave
+     */
+    protected $plugin;
+
+    /**
+     * @var \Magento\CatalogInventory\Api\Data\StockItemInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemMock;
+
+    /**
+     * @var \Magento\Catalog\Api\Data\ProductInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var \Magento\Catalog\Api\Data\ProductInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $savedProductMock;
+
+    /**
+     * @var \Magento\CatalogInventory\Api\StockRegistryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockRegistry;
+
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $storeManager;
+
+    /**
+     * @var \Magento\Catalog\Api\Data\ProductExtension|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productExtensionMock;
+
+    /**
+     * @var \Magento\Catalog\Api\ProductRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productRepositoryMock;
+
+    /**
+     * @var \Closure
+     */
+    protected $closureMock;
+
+    public function setUp()
+    {
+        $this->stockRegistry = $this->getMock('\Magento\CatalogInventory\Api\StockRegistryInterface');
+        $this->storeManager = $this->getMock('\Magento\Store\Model\StoreManagerInterface');
+
+        $this->plugin = new \Magento\CatalogInventory\Model\Plugin\AroundProductRepositorySave(
+            $this->stockRegistry,
+            $this->storeManager
+        );
+
+        $this->productExtensionMock = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtension')
+            ->setMethods(['getStockItem'])
+            ->getMock();
+        $this->productRepositoryMock = $this->getMock('Magento\Catalog\Api\ProductRepositoryInterface');
+        $this->productMock = $this->getMock('\Magento\Catalog\Api\Data\ProductInterface');
+        $this->savedProductMock = $this->getMock('\Magento\Catalog\Api\Data\ProductInterface');
+        $this->closureMock = function () {
+            return $this->savedProductMock;
+        };
+        $this->stockItemMock = $this->getMock('\Magento\CatalogInventory\Api\Data\StockItemInterface');
+    }
+
+    public function testAroundSaveWhenProductHasNoStockItemNeedingToBeUpdated()
+    {
+        // pretend we have no extension attributes at all
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn(null);
+        $this->productExtensionMock->expects($this->never())->method('getStockItem');
+
+        // pretend that the product already has existing stock item information
+        $this->stockRegistry->expects($this->once())->method('getStockItem')->willReturn($this->stockItemMock);
+        $this->stockItemMock->expects($this->once())->method('getItemId')->willReturn(1);
+        $this->stockItemMock->expects($this->never())->method('setProductId');
+        $this->stockItemMock->expects($this->never())->method('setWebsiteId');
+
+        // expect that there are no changes to the existing stock item information
+        $this->assertEquals(
+            $this->savedProductMock,
+            $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock)
+        );
+    }
+
+    public function testAroundSaveWhenProductHasNoPersistentStockItemInfo()
+    {
+        // pretend we do have extension attributes, but none for 'stock_item'
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getStockItem')
+            ->willReturn(null);
+
+        $storeMock = $this->getMockBuilder('\Magento\Store\Model\Store')
+            ->disableOriginalConstructor()->getMock();
+        $storeMock->expects($this->once())->method('getWebsiteId')->willReturn(1);
+        $this->storeManager->expects($this->once())->method('getStore')->willReturn($storeMock);
+
+        $this->stockRegistry->expects($this->once())->method('getStockItem')->willReturn($this->stockItemMock);
+        $this->stockRegistry->expects($this->once())->method('updateStockItemBySku');
+
+        $this->stockItemMock->expects($this->once())->method('getItemId')->willReturn(null);
+        $this->stockItemMock->expects($this->once())->method('setProductId');
+        $this->stockItemMock->expects($this->once())->method('setWebsiteId');
+
+        $newProductMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductInterface')
+            ->disableOriginalConstructor()->getMock();
+        $this->productRepositoryMock->expects($this->once())->method('get')->willReturn($newProductMock);
+
+        $this->assertEquals(
+            $newProductMock,
+            $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock)
+        );
+    }
+
+    public function testAroundSave()
+    {
+        $productId = 5494;
+        $websiteId = 1;
+        $storeId = 2;
+        $sku = 'my product that needs saving';
+
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getStockItem')
+            ->willReturn($this->stockItemMock);
+
+        $storeMock = $this->getMockBuilder('\Magento\Store\Model\Store')
+            ->disableOriginalConstructor()->getMock();
+        $storeMock->expects($this->once())->method('getWebsiteId')->willReturn($websiteId);
+        $this->storeManager->expects($this->once())->method('getStore')->with($storeId)->willReturn($storeMock);
+
+        $this->savedProductMock->expects(($this->once()))->method('getId')->willReturn($productId);
+        $this->savedProductMock->expects(($this->atLeastOnce()))->method('getStoreId')->willReturn($storeId);
+        $this->savedProductMock->expects($this->atLeastOnce())->method('getSku')->willReturn($sku);
+
+        $this->stockItemMock->expects($this->once())->method('setProductId')->with($productId);
+        $this->stockItemMock->expects($this->once())->method('setWebsiteId')->with($websiteId);
+
+        $this->stockRegistry->expects($this->once())
+            ->method('updateStockItemBySku')
+            ->with($sku, $this->stockItemMock);
+
+        $newProductMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductInterface')
+            ->disableOriginalConstructor()->getMock();
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($sku, false, $storeId, true)
+            ->willReturn($newProductMock);
+
+        $this->assertEquals(
+            $newProductMock,
+            $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock)
+        );
+    }
+}
diff --git a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/ItemTest.php b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/ItemTest.php
index 20de61fbf3ba19c6851e47bc016e3ee38e82d9eb..f6cfa8b4e7e6643d3b4df80ae83fe79bd57dd0fc 100644
--- a/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/ItemTest.php
+++ b/app/code/Magento/CatalogInventory/Test/Unit/Model/Stock/ItemTest.php
@@ -395,4 +395,12 @@ class ItemTest extends \PHPUnit_Framework_TestCase
             [0, $this->storeId],
         ];
     }
+
+    public function testGetLowStockDate()
+    {
+        // ensure we do *not* return '2015' due to casting to an int
+        $date = '2015-4-17';
+        $this->item->setLowStockDate($date);
+        $this->assertEquals($date, $this->item->getLowStockDate());
+    }
 }
diff --git a/app/code/Magento/CatalogInventory/etc/di.xml b/app/code/Magento/CatalogInventory/etc/di.xml
index 11c98534f732718a84bb3cde28379c3f76137b61..b1ad4a03847bbd997e93dc255b0d7de325f11f9d 100644
--- a/app/code/Magento/CatalogInventory/etc/di.xml
+++ b/app/code/Magento/CatalogInventory/etc/di.xml
@@ -52,4 +52,15 @@
     <type name="Magento\Catalog\Block\Product\View">
         <plugin name="quantityValidators" type="Magento\CatalogInventory\Block\Plugin\ProductView" />
     </type>
+    <type name="Magento\CatalogInventory\Model\Configuration">
+        <arguments>
+            <argument name="config" xsi:type="object">Magento\Catalog\Model\ProductTypes\Config\Proxy</argument>
+        </arguments>
+    </type>
+    <type name="Magento\Catalog\Model\Product">
+        <plugin name="catalogInventoryAfterLoad" type="\Magento\CatalogInventory\Model\Plugin\AfterProductLoad"/>
+    </type>
+    <type name="Magento\Catalog\Api\ProductRepositoryInterface">
+        <plugin name="catalogInventoryAroundSave" type="\Magento\CatalogInventory\Model\Plugin\AroundProductRepositorySave"/>
+    </type>
 </config>
diff --git a/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml b/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml
index 577b4678c42e99ad5d250f34409c2c5e51654848..587b98b401a0981d8ca14b75242f0adac67312a2 100644
--- a/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml
+++ b/app/code/Magento/CatalogInventory/etc/service_data_attributes.xml
@@ -7,14 +7,10 @@
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
     <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
-    <!--
-        Once this is merged with the branch with the CatalogInventory integration, need to make sure the permission
-        below is actually used.
         <attribute code="stock_item" type="Magento\CatalogInventory\Api\Data\StockItemInterface">
             <resources>
                 <resource ref="Magento_CatalogInventory::cataloginventory"/>
             </resources>
         </attribute>
-    -->
     </extension_attributes>
 </config>
diff --git a/app/code/Magento/CatalogSearch/Model/Advanced/Request/Builder.php b/app/code/Magento/CatalogSearch/Model/Advanced/Request/Builder.php
new file mode 100644
index 0000000000000000000000000000000000000000..5e0eb83f4ebabdfd6b28b4aadbf063e39b9ae51a
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Model/Advanced/Request/Builder.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogSearch\Model\Advanced\Request;
+
+use Magento\Framework\Search\Request\Builder as RequestBuilder;
+
+class Builder extends RequestBuilder
+{
+    /**
+     * @param string $attributeCode
+     * @param array|string $attributeValue
+     * @return void
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    public function bindRequestValue($attributeCode, $attributeValue)
+    {
+        if (isset($attributeValue['from']) || isset($attributeValue['to'])) {
+            if (isset($attributeValue['from']) && '' !== $attributeValue['from']) {
+                $this->bind("{$attributeCode}.from", $attributeValue['from']);
+            }
+            if (isset($attributeValue['to']) && '' !== $attributeValue['to']) {
+                $this->bind("{$attributeCode}.to", $attributeValue['to']);
+            }
+        } elseif (!is_array($attributeValue)) {
+            $this->bind($attributeCode, $attributeValue);
+        } elseif (isset($attributeValue['like'])) {
+            $this->bind($attributeCode, trim($attributeValue['like'], '%'));
+        } elseif (isset($attributeValue['in'])) {
+            $this->bind($attributeCode, $attributeValue['in']);
+        } elseif (isset($attributeValue['in_set'])) {
+            $this->bind($attributeCode, $attributeValue['in_set']);
+        }
+    }
+}
diff --git a/app/code/Magento/CatalogSearch/Model/Resource/Advanced/Collection.php b/app/code/Magento/CatalogSearch/Model/Resource/Advanced/Collection.php
index b6f38b5b7a540608a4278f51465ce7a85d814dee..2d04b203536acb6fb3e661f3a8701931fd436510 100644
--- a/app/code/Magento/CatalogSearch/Model/Resource/Advanced/Collection.php
+++ b/app/code/Magento/CatalogSearch/Model/Resource/Advanced/Collection.php
@@ -22,7 +22,7 @@ class Collection extends \Magento\Catalog\Model\Resource\Product\Collection
     private $filters = [];
 
     /**
-     * @var \Magento\Framework\Search\Request\Builder
+     * @var \Magento\CatalogSearch\Model\Advanced\Request\Builder
      */
     private $requestBuilder;
 
@@ -51,7 +51,7 @@ class Collection extends \Magento\Catalog\Model\Resource\Product\Collection
      * @param \Magento\Customer\Model\Session $customerSession
      * @param \Magento\Framework\Stdlib\DateTime $dateTime
      * @param \Magento\Customer\Api\GroupManagementInterface $groupManagement
-     * @param \Magento\Framework\Search\Request\Builder $requestBuilder
+     * @param \Magento\CatalogSearch\Model\Advanced\Request\Builder $requestBuilder
      * @param \Magento\Search\Model\SearchEngine $searchEngine
      * @param \Zend_Db_Adapter_Abstract $connection
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
@@ -76,7 +76,7 @@ class Collection extends \Magento\Catalog\Model\Resource\Product\Collection
         \Magento\Customer\Model\Session $customerSession,
         \Magento\Framework\Stdlib\DateTime $dateTime,
         \Magento\Customer\Api\GroupManagementInterface $groupManagement,
-        \Magento\Framework\Search\Request\Builder $requestBuilder,
+        \Magento\CatalogSearch\Model\Advanced\Request\Builder $requestBuilder,
         \Magento\Search\Model\SearchEngine $searchEngine,
         $connection = null
     ) {
@@ -123,7 +123,6 @@ class Collection extends \Magento\Catalog\Model\Resource\Product\Collection
 
     /**
      * @inheritdoc
-     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     protected function _renderFiltersBefore()
     {
@@ -132,39 +131,45 @@ class Collection extends \Magento\Catalog\Model\Resource\Product\Collection
             $this->requestBuilder->setRequestName('advanced_search_container');
             foreach ($this->filters as $attributes) {
                 foreach ($attributes as $attributeCode => $attributeValue) {
-                    if (is_numeric($attributeCode)) {
-                        $attributeCode = $this->_eavConfig->getAttribute(Product::ENTITY, $attributeCode)
-                            ->getAttributeCode();
-                    }
-                    if (isset($attributeValue['from']) || isset($attributeValue['to'])) {
-                        if (isset($attributeValue['from']) && '' !== $attributeValue['from']) {
-                            $this->requestBuilder->bind("{$attributeCode}.from", $attributeValue['from']);
-                        }
-                        if (isset($attributeValue['to']) && '' !== $attributeValue['to']) {
-                            $this->requestBuilder->bind("{$attributeCode}.to", $attributeValue['to']);
-                        }
-                    } elseif (!is_array($attributeValue)) {
-                        $this->requestBuilder->bind($attributeCode, $attributeValue);
-                    } elseif (isset($attributeValue['like'])) {
-                        $this->requestBuilder->bind($attributeCode, trim($attributeValue['like'], '%'));
-                    } elseif (isset($attributeValue['in'])) {
-                        $this->requestBuilder->bind($attributeCode, $attributeValue['in']);
-                    } elseif (isset($attributeValue['in_set'])) {
-                        $this->requestBuilder->bind($attributeCode, $attributeValue['in_set']);
-                    }
+                    $attributeCode = $this->getAttributeCode($attributeCode);
+                    $this->requestBuilder->bindRequestValue($attributeCode, $attributeValue);
                 }
             }
             $queryRequest = $this->requestBuilder->create();
             $queryResponse = $this->searchEngine->search($queryRequest);
 
-            $ids = [0];
-            /** @var \Magento\Framework\Search\Document $document */
-            foreach ($queryResponse as $document) {
-                $ids[] = $document->getId();
-            }
+            $ids = $this->getResponseIds($queryResponse);
 
             $this->addIdFilter($ids);
         }
         return parent::_renderFiltersBefore();
     }
+
+    /**
+     * @param string $attributeCode
+     * @return string
+     */
+    private function getAttributeCode($attributeCode)
+    {
+        if (is_numeric($attributeCode)) {
+            $attributeCode = $this->_eavConfig->getAttribute(Product::ENTITY, $attributeCode)
+                ->getAttributeCode();
+        }
+
+        return $attributeCode;
+    }
+
+    /**
+     * @param \Magento\Framework\Search\Document[] $queryResponse
+     * @return int[]
+     */
+    private function getResponseIds($queryResponse)
+    {
+        $ids = [0];
+        foreach ($queryResponse as $document) {
+            $ids[] = $document->getId();
+        }
+
+        return $ids;
+    }
 }
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Advanced/Request/BuilderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Advanced/Request/BuilderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2b7788e245be3bd6aaafb3aa145b4cd9f55150cb
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Advanced/Request/BuilderTest.php
@@ -0,0 +1,215 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogSearch\Test\Unit\Model\Advanced\Request;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class BuilderTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\CatalogSearch\Model\Advanced\Request\Builder
+     */
+    private $requestBuilder;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Framework\Search\Request\Config|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $config;
+
+    /**
+     * @var \Magento\Framework\Search\Request\Mapper|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $requestMapper;
+
+    /**
+     * @var \Magento\Framework\Search\Request|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $request;
+
+    /**
+     * @var \Magento\Framework\Search\Request\Binder|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $binder;
+
+    /**
+     * @var \Magento\Framework\Search\Request\Cleaner|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $cleaner;
+
+    protected function setUp()
+    {
+        $helper = new ObjectManager($this);
+
+        $this->config = $this->getMockBuilder('Magento\Framework\Search\Request\Config')
+            ->setMethods(['get'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->objectManager = $this->getMock('Magento\Framework\ObjectManagerInterface');
+
+        $this->requestMapper = $this->getMockBuilder('Magento\Framework\Search\Request\Mapper')
+            ->setMethods(['getRootQuery', 'getBuckets'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->request = $this->getMockBuilder('Magento\Framework\Search\Request')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->binder = $this->getMockBuilder('Magento\Framework\Search\Request\Binder')
+            ->setMethods(['bind'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->cleaner = $this->getMockBuilder('Magento\Framework\Search\Request\Cleaner')
+            ->setMethods(['clean'])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->requestBuilder = $helper->getObject(
+            'Magento\CatalogSearch\Model\Advanced\Request\Builder',
+            [
+                'config' => $this->config,
+                'objectManager' => $this->objectManager,
+                'binder' => $this->binder,
+                'cleaner' => $this->cleaner
+            ]
+        );
+    }
+
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testCreate()
+    {
+        $data = [
+            'dimensions' => [
+                'scope' => [
+                    'name' => 'scope',
+                    'value' => 'default',
+                ],
+            ],
+            'queries' => [
+                'filter_search_query' => [
+                    'name' => 'filter_search_query',
+                    'filterReference' => [
+                        [
+                            'ref' => 'boolFilter',
+                        ],
+                    ],
+                    'type' => 'filteredQuery',
+                ],
+            ],
+            'filters' => [
+                'boolFilter' => [
+                    'name' => 'boolFilter',
+                    'filterReference' => [
+                        [
+                            'clause' => 'should',
+                            'ref' => 'from_to',
+                        ],
+                        [
+                            'clause' => 'should',
+                            'ref' => 'not_array',
+                        ],
+                        [
+                            'clause' => 'should',
+                            'ref' => 'like',
+                        ],
+                    ],
+                    'type' => 'boolFilter',
+                ],
+                'from_to' => [
+                    'name' => 'from_to',
+                    'field' => 'product_id',
+                    'type' => 'rangeFilter',
+                    'from' => '$from_to.from$',
+                    'to' => '$from_to.to$',
+                ],
+                'not_array' => [
+                    'name' => 'not_array',
+                    'field' => 'product_id',
+                    'type' => 'termFilter',
+                    'value' => '$not_array$',
+                ],
+                'like' => [
+                    'name' => 'like',
+                    'field' => 'product_id',
+                    'type' => 'wildcardFilter',
+                    'value' => '$like$',
+                ],
+                'in' => [
+                    'name' => 'in',
+                    'field' => 'product_id',
+                    'type' => 'termFilter',
+                    'value' => '$in$',
+                ],
+                'in_set' => [
+                    'name' => 'in_set',
+                    'field' => 'product_id',
+                    'type' => 'termFilter',
+                    'value' => '$in_set$',
+                ],
+            ],
+            'from' => '10',
+            'size' => '10',
+            'query' => 'one_match_filters',
+            'index' => 'catalogsearch_fulltext',
+            'aggregations' => [],
+        ];
+        $requestName = 'rn';
+        $bindData = [
+            'dimensions' => ['scope' => 'default'],
+            'placeholder' => [
+                '$from_to.from$' => 10,
+                '$from_to.to$' => 20,
+                '$not_array$' => 130,
+                '$like$' => 'search_text',
+                '$in$' => 23,
+                '$in_set$' => [12, 23, 34, 45],
+            ],
+            'requestName' => $requestName,
+            'from' => 10,
+            'size' => 10
+        ];
+        $this->requestBuilder->bindRequestValue('from_to', ['from' => 10, 'to' => 20]);
+        $this->requestBuilder->bindRequestValue('not_array', 130);
+        $this->requestBuilder->bindRequestValue('like', ['like' => '%search_text%']);
+        $this->requestBuilder->bindRequestValue('in', ['in' => 23]);
+        $this->requestBuilder->bindRequestValue('in_set', ['in_set' => [12, 23, 34, 45]]);
+        $this->requestBuilder->setRequestName($requestName);
+        $this->requestBuilder->setSize(10);
+        $this->requestBuilder->setFrom(10);
+        $this->requestBuilder->bindDimension('scope', 'default');
+        $this->binder->expects($this->once())
+            ->method('bind')
+            ->withConsecutive([$data, $bindData])
+            ->willReturn($data);
+        $this->cleaner->expects($this->once())
+            ->method('clean')
+            ->willReturn($data);
+        $this->requestMapper->expects($this->once())
+            ->method('getRootQuery')
+            ->willReturn([]);
+        $this->objectManager->expects($this->at(0))
+            ->method('create')
+            ->willReturn($this->requestMapper);
+        $this->objectManager->expects($this->at(2))
+            ->method('create')
+            ->willReturn($this->request);
+        $this->config->expects($this->once())
+            ->method('get')
+            ->with($this->equalTo($requestName))
+            ->willReturn($data);
+        $result = $this->requestBuilder->create();
+        $this->assertInstanceOf('\Magento\Framework\Search\Request', $result);
+    }
+}
diff --git a/app/code/Magento/Checkout/Controller/Cart/UpdateItemOptions.php b/app/code/Magento/Checkout/Controller/Cart/UpdateItemOptions.php
index f15ccfdede8694ac96cdd2a991ce179e232474dd..83b569541117f680ff951809eeffe95b288fe7c5 100644
--- a/app/code/Magento/Checkout/Controller/Cart/UpdateItemOptions.php
+++ b/app/code/Magento/Checkout/Controller/Cart/UpdateItemOptions.php
@@ -66,7 +66,7 @@ class UpdateItemOptions extends \Magento\Checkout\Controller\Cart
                     );
                     $this->messageManager->addSuccess($message);
                 }
-                return $this->_goBack();
+                return $this->_goBack($this->_url->getUrl('checkout/cart'));
             }
         } catch (\Magento\Framework\Exception\LocalizedException $e) {
             if ($this->_checkoutSession->getUseNotice(true)) {
diff --git a/app/code/Magento/Checkout/Model/Session.php b/app/code/Magento/Checkout/Model/Session.php
index 0f7d18e41355b5ffbae94f02f0f6272485d59cbd..da634e082756d1e8be81769a6af6dc32a6874fbe 100644
--- a/app/code/Magento/Checkout/Model/Session.php
+++ b/app/code/Magento/Checkout/Model/Session.php
@@ -90,6 +90,7 @@ class Session extends \Magento\Framework\Session\SessionManager
      * @param \Magento\Framework\Session\StorageInterface $storage
      * @param \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager
      * @param \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory
+     * @param \Magento\Framework\App\State $appState
      * @param \Magento\Sales\Model\OrderFactory $orderFactory
      * @param \Magento\Customer\Model\Session $customerSession
      * @param \Magento\Quote\Model\QuoteRepository $quoteRepository
@@ -97,6 +98,7 @@ class Session extends \Magento\Framework\Session\SessionManager
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
      * @param \Magento\Customer\Api\CustomerRepositoryInterface $customerRepository
+     * @throws \Magento\Framework\Exception\SessionException
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -108,6 +110,7 @@ class Session extends \Magento\Framework\Session\SessionManager
         \Magento\Framework\Session\StorageInterface $storage,
         \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager,
         \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory,
+        \Magento\Framework\App\State $appState,
         \Magento\Sales\Model\OrderFactory $orderFactory,
         \Magento\Customer\Model\Session $customerSession,
         \Magento\Quote\Model\QuoteRepository $quoteRepository,
@@ -131,9 +134,9 @@ class Session extends \Magento\Framework\Session\SessionManager
             $validator,
             $storage,
             $cookieManager,
-            $cookieMetadataFactory
+            $cookieMetadataFactory,
+            $appState
         );
-        $this->start();
     }
 
     /**
diff --git a/app/code/Magento/Checkout/view/frontend/templates/cart/form.phtml b/app/code/Magento/Checkout/view/frontend/templates/cart/form.phtml
index 3453edfb0c29f433e751133af006968973356026..d34488d2b6705b02414f638e09e1f318e4e1ee93 100644
--- a/app/code/Magento/Checkout/view/frontend/templates/cart/form.phtml
+++ b/app/code/Magento/Checkout/view/frontend/templates/cart/form.phtml
@@ -57,9 +57,7 @@
                 class="action update">
             <span><?php echo __('Update Shopping Cart'); ?></span>
         </button>
-        <!--[if lt IE 8]>
         <input type="hidden" value="" id="update_cart_action_container" />
-        <![endif]-->
     </div>
 </form>
 <?php echo $block->getChildHtml('shopping.cart.table.after'); ?>
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 f95857919381b183ba4f5706abcd8b808e7bf8a8..7d0ceffcb8b3a16a0178b1cd72c42ed1a4f573d2 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
@@ -99,7 +99,8 @@ $canApplyMsrp = $helper->isShowBeforeOrderConfirm($product) && $helper->isMinima
                            title="<?php echo $block->escapeHtml(__('Qty')); ?>"
                            class="input-text qty"
                            maxlength="12"
-                           data-validate="{required:true,'validate-greater-than-zero':true}" />
+                           data-validate="{required:true,'validate-greater-than-zero':true}"
+                           data-role="cart-item-qty"/>
                 </div>
             </div>
             <?php $cols++; ?>
diff --git a/app/code/Magento/Checkout/view/frontend/web/js/shopping-cart.js b/app/code/Magento/Checkout/view/frontend/web/js/shopping-cart.js
index 0b8ae7b4f8273719832a19115414f7ef79297850..66b55341c815ef5957bc845d304d3e168052d1fe 100644
--- a/app/code/Magento/Checkout/view/frontend/web/js/shopping-cart.js
+++ b/app/code/Magento/Checkout/view/frontend/web/js/shopping-cart.js
@@ -11,11 +11,21 @@ define([
     
     $.widget('mage.shoppingCart', {
         _create: function() {
-            if ($(this.options.updateCartActionContainer).length > 0) { /* <!--[if lt IE 8]> Only */
-                $(this.options.emptyCartButton).on('click', $.proxy(function() {
-                    $(this.options.emptyCartButton).attr('name', 'update_cart_action_temp');
-                    $(this.options.updateCartActionContainer)
-                        .attr('name', 'update_cart_action').attr('value', 'empty_cart');
+            $(this.options.emptyCartButton).on('click', $.proxy(function() {
+                $(this.options.emptyCartButton).attr('name', 'update_cart_action_temp');
+                $(this.options.updateCartActionContainer)
+                    .attr('name', 'update_cart_action').attr('value', 'empty_cart');
+            }, this));
+            var items = $.find("[data-role='cart-item-qty']");
+            for (var i = 0; i < items.length; i++) {
+                $(items[i]).on('keypress', $.proxy(function(event) {
+                    var keyCode = (event.keyCode ? event.keyCode : event.which);
+                    if(keyCode == 13) {
+                        $(this.options.emptyCartButton).attr('name', 'update_cart_action_temp');
+                        $(this.options.updateCartActionContainer)
+                            .attr('name', 'update_cart_action').attr('value', 'update_qty');
+
+                    }
                 }, this));
             }
             $(this.options.continueShoppingButton).on('click', $.proxy(function() {
diff --git a/app/code/Magento/Cms/Block/Adminhtml/Block/Widget/Chooser.php b/app/code/Magento/Cms/Block/Adminhtml/Block/Widget/Chooser.php
index fed2f67da6f177806559e463deb8fda56a2fbb3f..11a83c181d64f504d267524440423a30c90b2970 100644
--- a/app/code/Magento/Cms/Block/Adminhtml/Block/Widget/Chooser.php
+++ b/app/code/Magento/Cms/Block/Adminhtml/Block/Widget/Chooser.php
@@ -81,7 +81,7 @@ class Chooser extends \Magento\Backend\Block\Widget\Grid\Extended
         if ($element->getValue()) {
             $block = $this->_blockFactory->create()->load($element->getValue());
             if ($block->getId()) {
-                $chooser->setLabel($block->getTitle());
+                $chooser->setLabel($this->escapeHtml($block->getTitle()));
             }
         }
 
diff --git a/app/code/Magento/Cms/Block/Adminhtml/Page/Widget/Chooser.php b/app/code/Magento/Cms/Block/Adminhtml/Page/Widget/Chooser.php
index addaf3f4926b8e05f48833b16e540eb73ad295ef..54c169c890a9b8f8901203bff0a9a3a6d4e69275 100644
--- a/app/code/Magento/Cms/Block/Adminhtml/Page/Widget/Chooser.php
+++ b/app/code/Magento/Cms/Block/Adminhtml/Page/Widget/Chooser.php
@@ -98,7 +98,7 @@ class Chooser extends \Magento\Backend\Block\Widget\Grid\Extended
         if ($element->getValue()) {
             $page = $this->_pageFactory->create()->load((int)$element->getValue());
             if ($page->getId()) {
-                $chooser->setLabel($page->getTitle());
+                $chooser->setLabel($this->escapeHtml($page->getTitle()));
             }
         }
 
diff --git a/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Block/Widget/ChooserTest.php b/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Block/Widget/ChooserTest.php
index 0c075194e3330d099d7bb12b2427b971621f8a81..55761dae44ac94230eb126aa182e22394aaf1d32 100644
--- a/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Block/Widget/ChooserTest.php
+++ b/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Block/Widget/ChooserTest.php
@@ -35,6 +35,11 @@ class ChooserTest extends \PHPUnit_Framework_TestCase
      */
     protected $urlBuilderMock;
 
+    /**
+     * @var \Magento\Framework\Escaper|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $escaper;
+
     /**
      * @var \Magento\Cms\Model\BlockFactory|\PHPUnit_Framework_MockObject_MockObject
      */
@@ -66,6 +71,14 @@ class ChooserTest extends \PHPUnit_Framework_TestCase
         $this->urlBuilderMock = $this->getMockBuilder('Magento\Framework\UrlInterface')
             ->disableOriginalConstructor()
             ->getMock();
+        $this->escaper = $this->getMockBuilder('Magento\Framework\Escaper')
+            ->disableOriginalConstructor()
+            ->setMethods(
+                [
+                    'escapeHtml',
+                ]
+            )
+            ->getMock();
         $this->blockFactoryMock = $this->getMockBuilder('Magento\Cms\Model\BlockFactory')
             ->setMethods(
                 [
@@ -90,6 +103,7 @@ class ChooserTest extends \PHPUnit_Framework_TestCase
                 [
                     'getTitle',
                     'load',
+                    'getId',
                 ]
             )
             ->getMock();
@@ -112,15 +126,16 @@ class ChooserTest extends \PHPUnit_Framework_TestCase
         $this->context = $objectManager->getObject(
             'Magento\Backend\Block\Template\Context',
             [
-                'layout' => $this->layoutMock,
+                'layout'     => $this->layoutMock,
                 'mathRandom' => $this->mathRandomMock,
-                'urlBuilder' => $this->urlBuilderMock
+                'urlBuilder' => $this->urlBuilderMock,
+                'escaper'    => $this->escaper,
             ]
         );
         $this->this = $objectManager->getObject(
             'Magento\Cms\Block\Adminhtml\Block\Widget\Chooser',
             [
-                'context' => $this->context,
+                'context'      => $this->context,
                 'blockFactory' => $this->blockFactoryMock
             ]
         );
@@ -135,13 +150,14 @@ class ChooserTest extends \PHPUnit_Framework_TestCase
      */
     public function testPrepareElementHtml($elementValue, $modelBlockId)
     {
-        $elementId = 1;
-        $uniqId = '126hj4h3j73hk7b347jhkl37gb34';
-        $sourceUrl = 'cms/block_widget/chooser/126hj4h3j73hk7b347jhkl37gb34';
-        $config = ['key1' => 'value1'];
-        $fieldsetId = 2;
-        $html = 'some html';
-        $title = 'some title';
+        $elementId    = 1;
+        $uniqId       = '126hj4h3j73hk7b347jhkl37gb34';
+        $sourceUrl    = 'cms/block_widget/chooser/126hj4h3j73hk7b347jhkl37gb34';
+        $config       = ['key1' => 'value1'];
+        $fieldsetId   = 2;
+        $html         = 'some html';
+        $title        = 'some "><img src=y onerror=prompt(document.domain)>; title';
+        $titleEscaped = 'some &quot;&gt;&lt;img src=y onerror=prompt(document.domain)&gt;; title';
 
         $this->this->setConfig($config);
         $this->this->setFieldsetId($fieldsetId);
@@ -197,13 +213,18 @@ class ChooserTest extends \PHPUnit_Framework_TestCase
         $this->modelBlockMock->expects($this->any())
             ->method('getTitle')
             ->willReturn($title);
-        $this->chooserMock->expects($this->any())
-            ->method('setLabel')
-            ->with($title)
-            ->willReturnSelf();
         $this->chooserMock->expects($this->atLeastOnce())
             ->method('toHtml')
             ->willReturn($html);
+        if (!empty($elementValue) && !empty($modelBlockId)) {
+            $this->escaper->expects(($this->atLeastOnce()))
+                ->method('escapeHtml')
+                ->willReturn($titleEscaped);
+            $this->chooserMock->expects($this->atLeastOnce())
+                ->method('setLabel')
+                ->with($titleEscaped)
+                ->willReturnSelf();
+        }
         $this->elementMock->expects($this->atLeastOnce())
             ->method('setData')
             ->with('after_element_html', $html)
diff --git a/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Page/Widget/ChooserTest.php b/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Page/Widget/ChooserTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..75107bcb42de11db287607e49595aa6fecfd637b
--- /dev/null
+++ b/app/code/Magento/Cms/Test/Unit/Block/Adminhtml/Page/Widget/ChooserTest.php
@@ -0,0 +1,271 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Cms\Test\Unit\Block\Adminhtml\Page\Widget;
+
+/**
+ * @covers \Magento\Cms\Block\Adminhtml\Page\Widget\Chooser
+ */
+class ChooserTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Cms\Block\Adminhtml\Page\Widget\Chooser
+     */
+    protected $this;
+
+    /**
+     * @var \Magento\Backend\Block\Template\Context
+     */
+    protected $context;
+
+    /**
+     * @var \Magento\Framework\Math\Random|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $mathRandomMock;
+
+    /**
+     * @var \Magento\Framework\UrlInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $urlBuilderMock;
+
+    /**
+     * @var \Magento\Framework\Escaper|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $escaper;
+
+    /**
+     * @var \Magento\Cms\Model\Page|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $cmsPageMock;
+
+    /**
+     * @var \Magento\Framework\View\LayoutInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $layoutMock;
+
+    /**
+     * @var \Magento\Cms\Model\PageFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $pageFactoryMock;
+
+    /**
+     * @var \Magento\Framework\Data\Form\Element\AbstractElement|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $elementMock;
+
+    /**
+     * @var \Magento\Framework\View\Element\BlockInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $chooserMock;
+
+    protected function setUp()
+    {
+        $this->layoutMock = $this->getMockBuilder('Magento\Framework\View\LayoutInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->mathRandomMock = $this->getMockBuilder('Magento\Framework\Math\Random')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->urlBuilderMock = $this->getMockBuilder('Magento\Framework\UrlInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->escaper = $this->getMockBuilder('Magento\Framework\Escaper')
+            ->disableOriginalConstructor()
+            ->setMethods(
+                [
+                    'escapeHtml',
+                ]
+            )
+            ->getMock();
+        $this->pageFactoryMock = $this->getMockBuilder('Magento\Cms\Model\PageFactory')
+            ->setMethods(
+                [
+                    'create',
+                ]
+            )
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->elementMock = $this->getMockBuilder('Magento\Framework\Data\Form\Element\AbstractElement')
+            ->disableOriginalConstructor()
+            ->setMethods(
+                [
+                    'getId',
+                    'getValue',
+                    'setData',
+                ]
+            )
+            ->getMock();
+        $this->cmsPageMock = $this->getMockBuilder('Magento\Cms\Model\Page')
+            ->disableOriginalConstructor()
+            ->setMethods(
+                [
+                    'getTitle',
+                    'load',
+                    'getId',
+                ]
+            )
+            ->getMock();
+        $this->chooserMock = $this->getMockBuilder('Magento\Framework\View\Element\BlockInterface')
+            ->disableOriginalConstructor()
+            ->setMethods(
+                [
+                    'setElement',
+                    'setConfig',
+                    'setFieldsetId',
+                    'setSourceUrl',
+                    'setUniqId',
+                    'setLabel',
+                    'toHtml',
+                ]
+            )
+            ->getMock();
+
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->context = $objectManager->getObject(
+            'Magento\Backend\Block\Template\Context',
+            [
+                'layout'     => $this->layoutMock,
+                'mathRandom' => $this->mathRandomMock,
+                'urlBuilder' => $this->urlBuilderMock,
+                'escaper'    => $this->escaper,
+            ]
+        );
+        $this->this = $objectManager->getObject(
+            'Magento\Cms\Block\Adminhtml\Page\Widget\Chooser',
+            [
+                'context'     => $this->context,
+                'pageFactory' => $this->pageFactoryMock
+            ]
+        );
+    }
+
+    /**
+     * @covers \Magento\Cms\Block\Adminhtml\Block\Widget\Chooser::prepareElementHtml
+     *
+     * @param string $elementValue
+     * @param integer|null $cmsPageId
+     *
+     * @dataProvider prepareElementHtmlDataProvider
+     */
+    public function testPrepareElementHtml($elementValue, $cmsPageId)
+    {
+        //$elementValue = 12345;
+        //$cmsPageId    = 1;
+        $elementId    = 1;
+        $uniqId       = '126hj4h3j73hk7b347jhkl37gb34';
+        $sourceUrl    = 'cms/page_widget/chooser/126hj4h3j73hk7b347jhkl37gb34';
+        $config       = ['key1' => 'value1'];
+        $fieldsetId   = 2;
+        $html         = 'some html';
+        $title        = 'some "><img src=y onerror=prompt(document.domain)>; title';
+        $titleEscaped = 'some &quot;&gt;&lt;img src=y onerror=prompt(document.domain)&gt;; title';
+
+        $this->this->setConfig($config);
+        $this->this->setFieldsetId($fieldsetId);
+
+        $this->elementMock->expects($this->atLeastOnce())
+            ->method('getId')
+            ->willReturn($elementId);
+        $this->mathRandomMock->expects($this->atLeastOnce())
+            ->method('getUniqueHash')
+            ->with($elementId)
+            ->willReturn($uniqId);
+        $this->urlBuilderMock->expects($this->atLeastOnce())
+            ->method('getUrl')
+            ->with('cms/page_widget/chooser', ['uniq_id' => $uniqId])
+            ->willReturn($sourceUrl);
+        $this->layoutMock->expects($this->atLeastOnce())
+            ->method('createBlock')
+            ->with('Magento\Widget\Block\Adminhtml\Widget\Chooser')
+            ->willReturn($this->chooserMock);
+        $this->chooserMock->expects($this->atLeastOnce())
+            ->method('setElement')
+            ->with($this->elementMock)
+            ->willReturnSelf();
+        $this->chooserMock->expects($this->atLeastOnce())
+            ->method('setConfig')
+            ->with($config)
+            ->willReturnSelf();
+        $this->chooserMock->expects($this->atLeastOnce())
+            ->method('setFieldsetId')
+            ->with($fieldsetId)
+            ->willReturnSelf();
+        $this->chooserMock->expects($this->atLeastOnce())
+            ->method('setSourceUrl')
+            ->with($sourceUrl)
+            ->willReturnSelf();
+        $this->chooserMock->expects($this->atLeastOnce())
+            ->method('setUniqId')
+            ->with($uniqId)
+            ->willReturnSelf();
+        $this->elementMock->expects($this->atLeastOnce())
+            ->method('getValue')
+            ->willReturn($elementValue);
+        $this->pageFactoryMock->expects($this->any())
+            ->method('create')
+            ->willReturn($this->cmsPageMock);
+        $this->cmsPageMock->expects($this->any())
+            ->method('load')
+            ->with((int)$elementValue)
+            ->willReturnSelf();
+        $this->cmsPageMock->expects($this->any())
+            ->method('getId')
+            ->willReturn($cmsPageId);
+        $this->cmsPageMock->expects($this->any())
+            ->method('getTitle')
+            ->willReturn($title);
+        $this->chooserMock->expects($this->atLeastOnce())
+            ->method('toHtml')
+            ->willReturn($html);
+        if (!empty($elementValue) && !empty($cmsPageId)) {
+            $this->escaper->expects(($this->atLeastOnce()))
+                ->method('escapeHtml')
+                ->willReturn($titleEscaped);
+            $this->chooserMock->expects($this->atLeastOnce())
+                ->method('setLabel')
+                ->with($titleEscaped)
+                ->willReturnSelf();
+        }
+        $this->elementMock->expects($this->atLeastOnce())
+            ->method('setData')
+            ->with('after_element_html', $html)
+            ->willReturnSelf();
+
+        $this->assertEquals($this->elementMock, $this->this->prepareElementHtml($this->elementMock));
+    }
+
+    public function prepareElementHtmlDataProvider()
+    {
+        return [
+            'elementValue NOT EMPTY, modelBlockId NOT EMPTY' => [
+                'elementValue' => 'some value',
+                'cmsPageId' => 1,
+            ],
+            'elementValue NOT EMPTY, modelBlockId IS EMPTY' => [
+                'elementValue' => 'some value',
+                'cmsPageId' => null,
+            ],
+            'elementValue IS EMPTY, modelBlockId NEVER REACHED' => [
+                'elementValue' => '',
+                'cmsPageId' => 1,
+            ]
+        ];
+    }
+
+    /**
+     * @covers \Magento\Cms\Block\Adminhtml\Page\Widget\Chooser::getGridUrl
+     */
+    public function testGetGridUrl()
+    {
+        $url = 'some url';
+
+        $this->urlBuilderMock->expects($this->atLeastOnce())
+            ->method('getUrl')
+            ->with('cms/page_widget/chooser', ['_current' => true])
+            ->willReturn($url);
+
+        $this->assertEquals($url, $this->this->getGridUrl());
+    }
+}
diff --git a/app/code/Magento/Config/Model/Config/Backend/File.php b/app/code/Magento/Config/Model/Config/Backend/File.php
index e7a119f79af9f0bf78d8f459ff0d30875abd097b..a08ed7d4f23894640e6592728f9a2c6a8eb1432b 100644
--- a/app/code/Magento/Config/Model/Config/Backend/File.php
+++ b/app/code/Magento/Config/Model/Config/Backend/File.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Config\Model\Config\Backend;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\App\Filesystem\DirectoryList;
 use Magento\Framework\Filesystem;
 
@@ -196,7 +197,7 @@ class File extends \Magento\Framework\App\Config\Value
     protected function _prependScopeInfo($path)
     {
         $scopeInfo = $this->getScope();
-        if (\Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT != $this->getScope()) {
+        if (ScopeConfigInterface::SCOPE_TYPE_DEFAULT != $this->getScope()) {
             $scopeInfo .= '/' . $this->getScopeId();
         }
         return $scopeInfo . '/' . $path;
@@ -213,7 +214,7 @@ class File extends \Magento\Framework\App\Config\Value
     protected function _appendScopeInfo($path)
     {
         $path .= '/' . $this->getScope();
-        if (\Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT != $this->getScope()) {
+        if (ScopeConfigInterface::SCOPE_TYPE_DEFAULT != $this->getScope()) {
             $path .= '/' . $this->getScopeId();
         }
         return $path;
diff --git a/app/code/Magento/Config/Model/Config/Backend/Locale.php b/app/code/Magento/Config/Model/Config/Backend/Locale.php
index 0881afdebfc3839d52d0c27de0052ae6a8bd68b1..3d057fd6df864d23061ba4d1d762e265482eb595 100644
--- a/app/code/Magento/Config/Model/Config/Backend/Locale.php
+++ b/app/code/Magento/Config/Model/Config/Backend/Locale.php
@@ -9,6 +9,8 @@
  */
 namespace Magento\Config\Model\Config\Backend;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 class Locale extends \Magento\Framework\App\Config\Value
 {
     /**
@@ -91,7 +93,7 @@ class Locale extends \Magento\Framework\App\Config\Value
                     }
 
                     switch ($data->getScope()) {
-                        case \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT:
+                        case ScopeConfigInterface::SCOPE_TYPE_DEFAULT:
                             $scopeName = __('Default scope');
                             break;
 
diff --git a/app/code/Magento/Config/Model/Config/ScopeDefiner.php b/app/code/Magento/Config/Model/Config/ScopeDefiner.php
index 893496d874009b9834fc2f1821057283ba01e323..f69e9dd96d2eb820a87a9d1f5905445df9c576df 100644
--- a/app/code/Magento/Config/Model/Config/ScopeDefiner.php
+++ b/app/code/Magento/Config/Model/Config/ScopeDefiner.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Config\Model\Config;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Store\Model\ScopeInterface as StoreScopeInterface;
 
 /**
@@ -38,6 +39,6 @@ class ScopeDefiner
             'store'
         ) ? StoreScopeInterface::SCOPE_STORE : ($this->_request->getParam(
             'website'
-        ) ? StoreScopeInterface::SCOPE_WEBSITE : \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT);
+        ) ? StoreScopeInterface::SCOPE_WEBSITE : ScopeConfigInterface::SCOPE_TYPE_DEFAULT);
     }
 }
diff --git a/app/code/Magento/Config/Model/Config/Structure/AbstractElement.php b/app/code/Magento/Config/Model/Config/Structure/AbstractElement.php
index e10a1a1c3e725333743bea341d6170865f17d119..03ed66f29abec3ebd79735f648aefcd633dc44cc 100644
--- a/app/code/Magento/Config/Model/Config/Structure/AbstractElement.php
+++ b/app/code/Magento/Config/Model/Config/Structure/AbstractElement.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Config\Model\Config\Structure;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Store\Model\StoreManagerInterface;
 
 abstract class AbstractElement implements ElementInterface
@@ -136,7 +137,7 @@ abstract class AbstractElement implements ElementInterface
         $showInScope = [
             \Magento\Store\Model\ScopeInterface::SCOPE_STORE => $this->_hasVisibilityValue('showInStore'),
             \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE => $this->_hasVisibilityValue('showInWebsite'),
-            \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT => $this->_hasVisibilityValue('showInDefault'),
+            ScopeConfigInterface::SCOPE_TYPE_DEFAULT => $this->_hasVisibilityValue('showInDefault'),
         ];
 
         if ($this->_storeManager->isSingleStoreMode()) {
diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/ScopeDefinerTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/ScopeDefinerTest.php
index 23069beec258fa8c6ab4e398c537a4874a9010b7..e0c64a35053ad44c88baa18861e84641a995d17d 100644
--- a/app/code/Magento/Config/Test/Unit/Model/Config/ScopeDefinerTest.php
+++ b/app/code/Magento/Config/Test/Unit/Model/Config/ScopeDefinerTest.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Config\Test\Unit\Model\Config;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 class ScopeDefinerTest extends \PHPUnit_Framework_TestCase
@@ -31,7 +32,7 @@ class ScopeDefinerTest extends \PHPUnit_Framework_TestCase
 
     public function testGetScopeReturnsDefaultScopeIfNoScopeDataIsSpecified()
     {
-        $this->assertEquals(\Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, $this->_model->getScope());
+        $this->assertEquals(ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $this->_model->getScope());
     }
 
     public function testGetScopeReturnsStoreScopeIfStoreIsSpecified()
diff --git a/app/code/Magento/Config/Test/Unit/Model/Config/Structure/AbstractElementTest.php b/app/code/Magento/Config/Test/Unit/Model/Config/Structure/AbstractElementTest.php
index 03e9fd8d2266e5c9256c74a81716e59e4eb40ac0..778141ab2132096aa8d0e750f7175bebdcea935b 100644
--- a/app/code/Magento/Config/Test/Unit/Model/Config/Structure/AbstractElementTest.php
+++ b/app/code/Magento/Config/Test/Unit/Model/Config/Structure/AbstractElementTest.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Config\Test\Unit\Model\Config\Structure;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 class AbstractElementTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -77,7 +79,7 @@ class AbstractElementTest extends \PHPUnit_Framework_TestCase
         $this->_storeManager->expects($this->once())->method('isSingleStoreMode')->will($this->returnValue(true));
         $this->_model->setData(
             ['showInDefault' => 1, 'showInStore' => 0, 'showInWebsite' => 0],
-            \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+            ScopeConfigInterface::SCOPE_TYPE_DEFAULT
         );
         $this->assertTrue($this->_model->isVisible());
     }
@@ -87,7 +89,7 @@ class AbstractElementTest extends \PHPUnit_Framework_TestCase
         $this->_storeManager->expects($this->once())->method('isSingleStoreMode')->will($this->returnValue(true));
         $this->_model->setData(
             ['hide_in_single_store_mode' => 1, 'showInDefault' => 1, 'showInStore' => 0, 'showInWebsite' => 0],
-            \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+            ScopeConfigInterface::SCOPE_TYPE_DEFAULT
         );
         $this->assertFalse($this->_model->isVisible());
     }
@@ -100,7 +102,7 @@ class AbstractElementTest extends \PHPUnit_Framework_TestCase
         $this->_storeManager->expects($this->once())->method('isSingleStoreMode')->will($this->returnValue(true));
         $this->_model->setData(
             ['showInDefault' => 0, 'showInStore' => 0, 'showInWebsite' => 0],
-            \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+            ScopeConfigInterface::SCOPE_TYPE_DEFAULT
         );
         $this->assertFalse($this->_model->isVisible());
     }
@@ -121,7 +123,7 @@ class AbstractElementTest extends \PHPUnit_Framework_TestCase
         return [
             [
                 ['showInDefault' => 1, 'showInStore' => 0, 'showInWebsite' => 0],
-                \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT,
+                ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
             ],
             [
                 ['showInDefault' => 0, 'showInStore' => 1, 'showInWebsite' => 0],
@@ -150,7 +152,7 @@ class AbstractElementTest extends \PHPUnit_Framework_TestCase
         return [
             [
                 ['showInDefault' => 0, 'showInStore' => 1, 'showInWebsite' => 1],
-                \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT,
+                ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
             ],
             [
                 ['showInDefault' => 1, 'showInStore' => 0, 'showInWebsite' => 1],
diff --git a/app/code/Magento/ConfigurableProduct/Api/Data/OptionInterface.php b/app/code/Magento/ConfigurableProduct/Api/Data/OptionInterface.php
index 82e73fe8686e268e1b3701c216fe3bb8a2d4ee95..1c60ed2762efbb9c8e1a4fc6bd62c511dc98f7f1 100644
--- a/app/code/Magento/ConfigurableProduct/Api/Data/OptionInterface.php
+++ b/app/code/Magento/ConfigurableProduct/Api/Data/OptionInterface.php
@@ -41,17 +41,6 @@ interface OptionInterface extends \Magento\Framework\Api\ExtensibleDataInterface
      */
     public function setLabel($label);
 
-    /**
-     * @return string|null
-     */
-    public function getType();
-
-    /**
-     * @param string $type
-     * @return $this
-     */
-    public function setType($type);
-
     /**
      * @return int|null
      */
diff --git a/app/code/Magento/ConfigurableProduct/Api/OptionTypesListInterface.php b/app/code/Magento/ConfigurableProduct/Api/OptionTypesListInterface.php
deleted file mode 100644
index 0978b9c705c4933d3590a69b9454432c4cf3f0d6..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Api/OptionTypesListInterface.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\ConfigurableProduct\Api;
-
-interface OptionTypesListInterface
-{
-    /**
-     * Get all available option types for configurable product
-     *
-     * @return string[]
-     * @throws \Magento\Framework\Exception\NoSuchEntityException
-     * @throws \Magento\Framework\Exception\InputException
-     */
-    public function getItems();
-}
diff --git a/app/code/Magento/ConfigurableProduct/Model/OptionRepository.php b/app/code/Magento/ConfigurableProduct/Model/OptionRepository.php
index 3e18c09648b9f9a6087e3daef9d67c1f4279b0e1..68cdb235bdeb03bd1e15e7b2146d92586236aac0 100644
--- a/app/code/Magento/ConfigurableProduct/Model/OptionRepository.php
+++ b/app/code/Magento/ConfigurableProduct/Model/OptionRepository.php
@@ -87,26 +87,17 @@ class OptionRepository implements \Magento\ConfigurableProduct\Api\OptionReposit
     public function get($sku, $id)
     {
         $product = $this->getProduct($sku);
-        $collection = $this->getConfigurableAttributesCollection($product);
-        $collection->addFieldToFilter($collection->getResource()->getIdFieldName(), $id);
-        /** @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute $configurableAttribute */
-        $configurableAttribute = $collection->getFirstItem();
-        if (!$configurableAttribute->getId()) {
-            throw new NoSuchEntityException(__('Requested option doesn\'t exist: %1', $id));
-        }
-        $prices = $configurableAttribute->getPrices();
-        if (is_array($prices)) {
-            foreach ($prices as $price) {
-                /** @var \Magento\ConfigurableProduct\Api\Data\OptionValueInterface $value */
-                $value = $this->optionValueFactory->create();
-                $value->setValueIndex($price['value_index'])
-                    ->setPricingValue($price['pricing_value'])
-                    ->setIsPercent($price['is_percent']);
-                $values[] = $value;
+
+        $extensionAttribute = $product->getExtensionAttributes();
+        if ($extensionAttribute !== null) {
+            $options = $extensionAttribute->getConfigurableProductOptions();
+            foreach ($options as $option) {
+                if ($option->getId() == $id) {
+                    return $option;
+                }
             }
         }
-        $configurableAttribute->setValues($values);
-        return $configurableAttribute;
+        throw new NoSuchEntityException(__('Requested option doesn\'t exist: %1', $id));
     }
 
     /**
@@ -116,21 +107,10 @@ class OptionRepository implements \Magento\ConfigurableProduct\Api\OptionReposit
     {
         $options = [];
         $product = $this->getProduct($sku);
-        foreach ($this->getConfigurableAttributesCollection($product) as $option) {
-            $values = [];
-            $prices = $option->getPrices();
-            if (is_array($prices)) {
-                foreach ($prices as $price) {
-                    /** @var \Magento\ConfigurableProduct\Api\Data\OptionValueInterface $value */
-                    $value = $this->optionValueFactory->create();
-                    $value->setValueIndex($price['value_index'])
-                        ->setPricingValue($price['pricing_value'])
-                        ->setIsPercent($price['is_percent']);
-                    $values[] = $value;
-                }
-            }
-            $option->setValues($values);
-            $options[] = $option;
+
+        $extensionAttribute = $product->getExtensionAttributes();
+        if ($extensionAttribute !== null) {
+            $options = $extensionAttribute->getConfigurableProductOptions();
         }
         return $options;
     }
@@ -259,17 +239,6 @@ class OptionRepository implements \Magento\ConfigurableProduct\Api\OptionReposit
         return $product;
     }
 
-    /**
-     * Retrieve configurable attribute collection through product object
-     *
-     * @param \Magento\Catalog\Model\Product $product
-     * @return \Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable\Attribute\Collection
-     */
-    private function getConfigurableAttributesCollection(\Magento\Catalog\Model\Product $product)
-    {
-        return $this->configurableType->getConfigurableAttributeCollection($product);
-    }
-
     /**
      * Ensure that all necessary data is available for a new option creation.
      *
@@ -284,9 +253,6 @@ class OptionRepository implements \Magento\ConfigurableProduct\Api\OptionReposit
         if (!$option->getAttributeId()) {
             $inputException->addError(__('Option attribute ID is not specified.'));
         }
-        if (!$option->getType()) {
-            $inputException->addError(__('Option type is not specified.'));
-        }
         if (!$option->getLabel()) {
             $inputException->addError(__('Option label is not specified.'));
         }
diff --git a/app/code/Magento/ConfigurableProduct/Model/OptionTypesList.php b/app/code/Magento/ConfigurableProduct/Model/OptionTypesList.php
deleted file mode 100644
index 23b871b21248166e892ec10b45801cf1184dcf39..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Model/OptionTypesList.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\ConfigurableProduct\Model;
-
-class OptionTypesList implements \Magento\ConfigurableProduct\Api\OptionTypesListInterface
-{
-    /**
-     * @var \Magento\Catalog\Model\System\Config\Source\Inputtype
-     */
-    protected $inputType;
-
-    /**
-     * @param \Magento\Catalog\Model\System\Config\Source\Inputtype $inputType
-     */
-    public function __construct(\Magento\Catalog\Model\System\Config\Source\Inputtype $inputType)
-    {
-        $this->inputType = $inputType;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getItems()
-    {
-        return array_map(
-            function ($inputType) {
-                return $inputType['value'];
-            },
-            $this->inputType->toOptionArray()
-        );
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Model/Plugin/AfterProductLoad.php b/app/code/Magento/ConfigurableProduct/Model/Plugin/AfterProductLoad.php
new file mode 100644
index 0000000000000000000000000000000000000000..6bf640f16735294afeb92a35513ebbbd58e7e5f0
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Model/Plugin/AfterProductLoad.php
@@ -0,0 +1,103 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Model\Plugin;
+
+class AfterProductLoad
+{
+    /**
+     * @var \Magento\Catalog\Api\Data\ProductExtensionFactory
+     */
+    protected $productExtensionFactory;
+
+    /**
+     * @var \Magento\ConfigurableProduct\Api\Data\OptionValueInterfaceFactory
+     */
+    protected $optionValueFactory;
+
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductExtensionFactory $productExtensionFactory
+     * @param \Magento\ConfigurableProduct\Api\Data\OptionValueInterfaceFactory $optionValueFactory
+     */
+    public function __construct(
+        \Magento\Catalog\Api\Data\ProductExtensionFactory $productExtensionFactory,
+        \Magento\ConfigurableProduct\Api\Data\OptionValueInterfaceFactory $optionValueFactory
+    ) {
+        $this->productExtensionFactory = $productExtensionFactory;
+        $this->optionValueFactory = $optionValueFactory;
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $subject
+     * @return \Magento\Catalog\Model\Product
+     */
+    public function afterLoad(\Magento\Catalog\Model\Product $product)
+    {
+        if ($product->getTypeId() != \Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE) {
+            return $product;
+        }
+
+        $productExtension = $product->getExtensionAttributes();
+        if ($productExtension === null) {
+            $productExtension = $this->productExtensionFactory->create();
+        }
+
+        $productExtension->setConfigurableProductOptions($this->getOptions($product));
+        $productExtension->setConfigurableProductLinks($this->getLinkedProducts($product));
+
+        $product->setExtensionAttributes($productExtension);
+
+        return $product;
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $product
+     * @return \Magento\ConfigurableProduct\Api\Data\OptionInterface[]
+     */
+    protected function getOptions(\Magento\Catalog\Model\Product $product)
+    {
+        $options = [];
+        /** @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable $typeInstance */
+        $typeInstance = $product->getTypeInstance();
+        $attributeCollection = $typeInstance->getConfigurableAttributes($product);
+        /** @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute $option */
+        foreach ($attributeCollection as $option) {
+            $values = [];
+            $prices = $option->getPrices();
+            if (is_array($prices)) {
+                foreach ($prices as $price) {
+                    /** @var \Magento\ConfigurableProduct\Api\Data\OptionValueInterface $value */
+                    $value = $this->optionValueFactory->create();
+                    $value->setValueIndex($price['value_index'])
+                        ->setPricingValue($price['pricing_value'])
+                        ->setIsPercent($price['is_percent']);
+                    $values[] = $value;
+                }
+            }
+            $option->setValues($values);
+            $options[] = $option;
+        }
+        return $options;
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $product
+     * @return int[]
+     */
+    protected function getLinkedProducts(\Magento\Catalog\Model\Product $product)
+    {
+        /** @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable $typeInstance */
+        $typeInstance = $product->getTypeInstance();
+        $childrenIds = $typeInstance->getChildrenIds($product->getId());
+
+        if (isset($childrenIds[0])) {
+            return $childrenIds[0];
+        } else {
+            return [];
+        }
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Model/Plugin/AroundProductRepositorySave.php b/app/code/Magento/ConfigurableProduct/Model/Plugin/AroundProductRepositorySave.php
new file mode 100644
index 0000000000000000000000000000000000000000..f0a12b809dcd9c484b63f379c94f1749ff5d6555
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Model/Plugin/AroundProductRepositorySave.php
@@ -0,0 +1,197 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Model\Plugin;
+
+use Magento\Framework\Exception\InputException;
+
+class AroundProductRepositorySave
+{
+    /**
+     * @var \Magento\ConfigurableProduct\Api\OptionRepositoryInterface
+     */
+    protected $optionRepository;
+
+    /**
+     * @var \Magento\Catalog\Model\ProductFactory
+     */
+    protected $productFactory;
+
+    /**
+     * Type configurable factory
+     *
+     * @var \Magento\ConfigurableProduct\Model\Resource\Product\Type\ConfigurableFactory
+     */
+    protected $typeConfigurableFactory;
+
+    /*
+     * @var \Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable\Attribute\Price\Data
+     */
+    protected $priceData;
+
+    /**
+     * @param \Magento\ConfigurableProduct\Api\OptionRepositoryInterface $optionRepository
+     * @param \Magento\Catalog\Model\ProductFactory $productFactory
+     * @param \Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable\Attribute\Price\Data $priceData
+     * @param \Magento\ConfigurableProduct\Model\Resource\Product\Type\ConfigurableFactory $typeConfigurableFactory
+     */
+    public function __construct(
+        \Magento\ConfigurableProduct\Api\OptionRepositoryInterface $optionRepository,
+        \Magento\Catalog\Model\ProductFactory $productFactory,
+        \Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable\Attribute\Price\Data $priceData,
+        \Magento\ConfigurableProduct\Model\Resource\Product\Type\ConfigurableFactory $typeConfigurableFactory
+    ) {
+        $this->optionRepository = $optionRepository;
+        $this->productFactory = $productFactory;
+        $this->priceData = $priceData;
+        $this->typeConfigurableFactory = $typeConfigurableFactory;
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\ProductRepositoryInterface $subject
+     * @param callable $proceed
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param bool $saveOptions
+     * @return \Magento\Catalog\Api\Data\ProductInterface
+     * @throws \Magento\Framework\Exception\CouldNotSaveException
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    public function aroundSave(
+        \Magento\Catalog\Api\ProductRepositoryInterface $subject,
+        \Closure $proceed,
+        \Magento\Catalog\Api\Data\ProductInterface $product,
+        $saveOptions = false
+    ) {
+        /** @var \Magento\Catalog\Api\Data\ProductInterface $result */
+        $result = $proceed($product, $saveOptions);
+
+        if ($product->getTypeId() != \Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE) {
+            return $result;
+        }
+
+        $extendedAttributes = $product->getExtensionAttributes();
+        if ($extendedAttributes === null) {
+            return $result;
+        }
+        $configurableProductOptions = $extendedAttributes->getConfigurableProductOptions();
+        $configurableProductLinks = $extendedAttributes->getConfigurableProductLinks();
+        if ($configurableProductOptions === null && $configurableProductLinks === null) {
+            return $result;
+        }
+        if ($configurableProductOptions !== null) {
+            $this->saveConfigurableProductOptions($result, $configurableProductOptions);
+            $result->getTypeInstance()->resetConfigurableAttributes($result);
+        }
+        if ($configurableProductLinks !== null) {
+            $this->saveConfigurableProductLinks($result, $configurableProductLinks);
+        }
+        $this->priceData->setProductPrice($result->getId(), null);
+        return $subject->get($result->getSku(), false, $result->getStoreId(), true);
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param \Magento\ConfigurableProduct\Api\Data\OptionInterface[] $options
+     * @return $this
+     */
+    protected function saveConfigurableProductOptions(
+        \Magento\Catalog\Api\Data\ProductInterface $product,
+        array $options
+    ) {
+        $existingOptionIds = [];
+        if ($product->getExtensionAttributes() !== null) {
+            $extensionAttributes = $product->getExtensionAttributes();
+            if ($extensionAttributes->getConfigurableProductOptions() !== null) {
+                $existingOptions = $extensionAttributes->getConfigurableProductOptions();
+                foreach ($existingOptions as $option) {
+                    $existingOptionIds[] = $option->getId();
+                }
+            }
+        }
+
+        $updatedOptionIds = [];
+        foreach ($options as $option) {
+            if ($option->getId()) {
+                $updatedOptionIds[] = $option->getId();
+            }
+            $this->optionRepository->save($product->getSku(), $option);
+        }
+
+        $optionIdsToDelete = array_diff($existingOptionIds, $updatedOptionIds);
+        foreach ($optionIdsToDelete as $optionId) {
+            $this->optionRepository->deleteById($product->getSku(), $optionId);
+        }
+        return $this;
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param int[] $linkIds
+     * @return $this
+     */
+    protected function saveConfigurableProductLinks(
+        \Magento\Catalog\Api\Data\ProductInterface $product,
+        array $linkIds
+    ) {
+        $configurableProductTypeResource = $this->typeConfigurableFactory->create();
+        if (!empty($linkIds)) {
+            /** @var \Magento\ConfigurableProduct\Model\Product\Type\Configurable $configurableProductType */
+            $configurableProductType = $product->getTypeInstance();
+            $configurableAttributes = $configurableProductType->getConfigurableAttributes($product);
+            $attributeCodes = [];
+            foreach ($configurableAttributes as $configurableAttribute) {
+                /** @var \Magento\Catalog\Model\Resource\Eav\Attribute $productAttribute */
+                $productAttribute = $configurableAttribute->getProductAttribute();
+                $attributeCode = $productAttribute->getAttributeCode();
+                $attributeCodes[] = $attributeCode;
+            }
+            $this->validateProductLinks($attributeCodes, $linkIds);
+        }
+
+        $configurableProductTypeResource->saveProducts($product, $linkIds);
+        return $this;
+    }
+
+    /**
+     * @param array $attributeCodes
+     * @param array $linkIds
+     * @throws InputException
+     * @return $this
+     */
+    protected function validateProductLinks(array $attributeCodes, array $linkIds)
+    {
+        $valueMap = [];
+        if (empty($attributeCodes) && !empty($linkIds)) {
+            throw new InputException(
+                __('The configurable product does not have any variation attribute.')
+            );
+        }
+
+        foreach ($linkIds as $productId) {
+            $variation = $this->productFactory->create()->load($productId);
+            if (!$variation->getId()) {
+                throw new InputException(__('Product with id "%1" does not exist.', $productId));
+            }
+            $valueKey = '';
+            foreach ($attributeCodes as $attributeCode) {
+                if (!$variation->getData($attributeCode)) {
+                    throw new InputException(
+                        __('Product with id "%1" does not contain required attribute "%2".', $productId, $attributeCode)
+                    );
+                }
+                $valueKey = $valueKey . $attributeCode . ':' . $variation->getData($attributeCode) . ';';
+            }
+            if (isset($valueMap[$valueKey])) {
+                throw new InputException(
+                    __('Products "%1" and %2 have the same set of attribute values.', $productId, $valueMap[$valueKey])
+                );
+            }
+            $valueMap[$valueKey] = $productId;
+        }
+        return $this;
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
index 5922c01bad8a3868bd867b8bd1522d3b2593ef30..c1fb0b41ef427e758954ee9728084e67eb9c5bed 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable.php
@@ -377,6 +377,18 @@ class Configurable extends \Magento\Catalog\Model\Product\Type\AbstractType
         return $product->getData($this->_configurableAttributes);
     }
 
+    /**
+     * Reset the cached configurable attributes of a product
+     *
+     * @param \Magento\Catalog\Model\Product $product
+     * @return $this
+     */
+    public function resetConfigurableAttributes($product)
+    {
+        $product->unsetData($this->_configurableAttributes);
+        return $this;
+    }
+
     /**
      * Retrieve Configurable Attributes as array
      *
diff --git a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Attribute.php b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Attribute.php
index f02e39626d66a7571bea42e1c5b2b1af804caf9c..8cf22a9b6dc3b4127baa3b8e9c8e5a9c0ade4dce 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Attribute.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Product/Type/Configurable/Attribute.php
@@ -24,7 +24,6 @@ class Attribute extends \Magento\Framework\Model\AbstractExtensibleModel impleme
      */
     const KEY_ATTRIBUTE_ID = 'attribute_id';
     const KEY_LABEL = 'label';
-    const KEY_TYPE = 'type';
     const KEY_POSITION = 'position';
     const KEY_IS_USE_DEFAULT = 'is_use_default';
     const KEY_VALUES = 'values';
@@ -119,15 +118,6 @@ class Attribute extends \Magento\Framework\Model\AbstractExtensibleModel impleme
         return $this->getData(self::KEY_ATTRIBUTE_ID);
     }
 
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getType()
-    {
-        return $this->getData(self::KEY_TYPE);
-    }
-
     /**
      * {@inheritdoc}
      * @codeCoverageIgnore
@@ -174,15 +164,6 @@ class Attribute extends \Magento\Framework\Model\AbstractExtensibleModel impleme
         return $this->setData(self::KEY_LABEL, $label);
     }
 
-    /**
-     * @param string $type
-     * @return $this
-     */
-    public function setType($type)
-    {
-        return $this->setData(self::KEY_TYPE, $type);
-    }
-
     /**
      * @param int $position
      * @return $this
diff --git a/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable/Attribute/Collection.php b/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable/Attribute/Collection.php
index 9d2ca8b5414c7920d4fb9235e6c6eaaaf4882368..f10a02db96f2297d1050a322c9bb92eaaa28cb91 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable/Attribute/Collection.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable/Attribute/Collection.php
@@ -263,7 +263,12 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
             $values = $this->getPriceValues();
 
             foreach ($values as $data) {
-                $this->getItemById($data['product_super_attribute_id'])->addPrice($data);
+                $item = $this->getItemById($data['product_super_attribute_id']);
+                //the price values is cached, it could have gotten out of sync with current items
+                //when a filter is added, in that case, we just ignore the data from the cache
+                if ($item) {
+                    $item->addPrice($data);
+                }
             }
         }
         return $this;
diff --git a/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable/Attribute/Price/Data.php b/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable/Attribute/Price/Data.php
index 248ed3ede9f343883132711c056d9966431c763e..3e5c714e425e4d50f4eec11eb6f1a09879c1ec87 100644
--- a/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable/Attribute/Price/Data.php
+++ b/app/code/Magento/ConfigurableProduct/Model/Resource/Product/Type/Configurable/Attribute/Price/Data.php
@@ -24,10 +24,10 @@ class Data
 
     /**
      * @param int $productId
-     * @param array $priceData
+     * @param array|null $priceData
      * @return void
      */
-    public function setProductPrice($productId, array $priceData)
+    public function setProductPrice($productId, array $priceData = null)
     {
         $this->prices[$productId] = $priceData;
     }
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/OptionRepositoryTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/OptionRepositoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..34b66ecb320dc65bed96338f0435a8253b7aca5b
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/OptionRepositoryTest.php
@@ -0,0 +1,210 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Test\Unit\Model;
+
+class OptionRepositoryTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\ConfigurableProduct\Model\OptionRepository
+     */
+    protected $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    protected function setUp()
+    {
+        $this->productRepositoryMock = $this->getMock('\Magento\Catalog\Api\ProductRepositoryInterface');
+        $this->productMock = $this->getMock('\Magento\Catalog\Api\Data\ProductInterface');
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->model = $objectManager->getObject(
+            '\Magento\ConfigurableProduct\Model\OptionRepository',
+            [
+                'productRepository' => $this->productRepositoryMock,
+            ]
+        );
+    }
+
+    public function testGet()
+    {
+        $productSku = "configurable";
+        $optionId = 3;
+
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->willReturn($this->productMock);
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+
+        $optionMock = $this->getMock('\Magento\ConfigurableProduct\Api\Data\OptionInterface');
+        $optionMock->expects($this->once())
+            ->method('getId')
+            ->willReturn($optionId);
+        $productExtensionMock = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtension')
+            ->setMethods(['getConfigurableProductOptions'])
+            ->getMock();
+        $productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductOptions')
+            ->willReturn([$optionMock]);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($productExtensionMock);
+
+        $this->assertEquals($optionMock, $this->model->get($productSku, $optionId));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Only implemented for configurable product: configurable
+     */
+    public function testGetNotConfigurableProduct()
+    {
+        $productSku = "configurable";
+        $optionId = 3;
+
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->willReturn($this->productMock);
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn('simple');
+
+        $this->model->get($productSku, $optionId);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedExceptionMessage Requested option doesn't exist: 3
+     */
+    public function testGetEmptyExtensionAttribute()
+    {
+        $productSku = "configurable";
+        $optionId = 3;
+
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->willReturn($this->productMock);
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn(null);
+
+        $this->model->get($productSku, $optionId);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedExceptionMessage Requested option doesn't exist: 3
+     */
+    public function testGetOptionIdNotFound()
+    {
+        $productSku = "configurable";
+        $optionId = 3;
+
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->willReturn($this->productMock);
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+
+        $optionMock = $this->getMock('\Magento\ConfigurableProduct\Api\Data\OptionInterface');
+        $optionMock->expects($this->once())
+            ->method('getId')
+            ->willReturn(6);
+        $productExtensionMock = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtension')
+            ->setMethods(['getConfigurableProductOptions'])
+            ->getMock();
+        $productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductOptions')
+            ->willReturn([$optionMock]);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($productExtensionMock);
+
+        $this->model->get($productSku, $optionId);
+    }
+
+    public function testGetList()
+    {
+        $productSku = "configurable";
+
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->willReturn($this->productMock);
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+
+        $optionMock = $this->getMock('\Magento\ConfigurableProduct\Api\Data\OptionInterface');
+        $productExtensionMock = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtension')
+            ->setMethods(['getConfigurableProductOptions'])
+            ->getMock();
+        $productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductOptions')
+            ->willReturn([$optionMock]);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($productExtensionMock);
+
+        $this->assertEquals([$optionMock], $this->model->getList($productSku));
+    }
+
+    public function testGetListNullExtensionAttribute()
+    {
+        $productSku = "configurable";
+
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->willReturn($this->productMock);
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn(null);
+
+        $this->assertEquals([], $this->model->getList($productSku));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Only implemented for configurable product: configurable
+     */
+    public function testGetListNotConfigurableProduct()
+    {
+        $productSku = "configurable";
+
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->willReturn($this->productMock);
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn('simple');
+
+        $this->model->getList($productSku);
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/OptionTypesListTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/OptionTypesListTest.php
deleted file mode 100644
index 79867bb302e321ff1da0c4e887a1d2f754bb115b..0000000000000000000000000000000000000000
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/OptionTypesListTest.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\ConfigurableProduct\Test\Unit\Model;
-
-class OptionTypesListTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var OptionTypesList
-     */
-    protected $model;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $sourceMock;
-
-    protected function setUp()
-    {
-        $this->sourceMock = $this->getMock('\Magento\Catalog\Model\System\Config\Source\Inputtype', [], [], '', false);
-        $this->model = new \Magento\ConfigurableProduct\Model\OptionTypesList($this->sourceMock);
-    }
-
-    public function testGetItems()
-    {
-        $data = [
-            ['value' => 'multiselect', 'label' => __('Multiple Select')],
-            ['value' => 'select', 'label' => __('Dropdown')]
-        ];
-        $this->sourceMock->expects($this->once())->method('toOptionArray')->willReturn($data);
-        $expected = ['multiselect', 'select'];
-        $this->assertEquals($expected, $this->model->getItems());
-    }
-}
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Plugin/AfterProductLoadTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Plugin/AfterProductLoadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..af3e73f0b855eeddb16f965f7438d8a16cbcd601
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Plugin/AfterProductLoadTest.php
@@ -0,0 +1,239 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Test\Unit\Model\Plugin;
+
+use Magento\ConfigurableProduct\Model\Plugin\AfterProductLoad;
+
+class AfterProductLoadTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var AfterProductLoad
+     */
+    protected $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionValueFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productExtensionFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|Magento\Catalog\Model\Product
+     */
+    protected $productMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $configurableProductTypeInstanceMock;
+
+    protected function setUp()
+    {
+        $this->optionValueFactory = $this->getMockBuilder(
+            '\Magento\ConfigurableProduct\Api\Data\OptionValueInterfaceFactory'
+        )->disableOriginalConstructor()->getMock();
+        $this->productMock = $this->getMockBuilder('Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->configurableProductTypeInstanceMock = $this->getMock(
+            '\Magento\ConfigurableProduct\Model\Product\Type\Configurable',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->productMock->expects($this->any())
+            ->method('getTypeInstance')
+            ->willReturn($this->configurableProductTypeInstanceMock);
+        $this->productExtensionFactory = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtensionFactory')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->model = new \Magento\ConfigurableProduct\Model\Plugin\AfterProductLoad(
+            $this->productExtensionFactory,
+            $this->optionValueFactory
+        );
+    }
+
+    protected function setupOptions()
+    {
+        $optionValues = [
+            [
+                'value_index' => 5,
+                'pricing_value' => 10,
+                'is_percent' => 0,
+            ],
+            [
+                'value_index' => 6,
+                'pricing_value' => 5,
+                'is_percent' => 1,
+            ],
+        ];
+        $optionMock1 = $this->getMockBuilder('\Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute')
+            ->disableOriginalConstructor()
+            ->setMethods(['getPrices', 'setValues'])
+            ->getMock();
+        $optionMock1->expects($this->once())
+            ->method('getPrices')
+            ->willReturn($optionValues);
+
+        $optionValueMock1 = $this->getMockBuilder('\Magento\ConfigurableProduct\Api\Data\OptionValueInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $optionValueMock1->expects($this->once())
+            ->method('setValueIndex')
+            ->with($optionValues[0]['value_index'])
+            ->willReturnSelf();
+        $optionValueMock1->expects($this->once())
+            ->method('setPricingValue')
+            ->with($optionValues[0]['pricing_value'])
+            ->willReturnSelf();
+        $optionValueMock1->expects($this->once())
+            ->method('setIsPercent')
+            ->with($optionValues[0]['is_percent'])
+            ->willReturnSelf();
+
+        $optionValueMock2 = $this->getMockBuilder('\Magento\ConfigurableProduct\Api\Data\OptionValueInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $optionValueMock2->expects($this->once())
+            ->method('setValueIndex')
+            ->with($optionValues[1]['value_index'])
+            ->willReturnSelf();
+        $optionValueMock2->expects($this->once())
+            ->method('setPricingValue')
+            ->with($optionValues[1]['pricing_value'])
+            ->willReturnSelf();
+        $optionValueMock2->expects($this->once())
+            ->method('setIsPercent')
+            ->with($optionValues[1]['is_percent'])
+            ->willReturnSelf();
+
+        $this->optionValueFactory->expects($this->at(0))
+            ->method('create')
+            ->willReturn($optionValueMock1);
+        $optionMock1->expects($this->once())
+            ->method('setValues')
+            ->with([$optionValueMock1, $optionValueMock2]);
+
+        $optionMock2 = $this->getMockBuilder('\Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute')
+            ->disableOriginalConstructor()
+            ->setMethods(['getPrices', 'setValues'])
+            ->getMock();
+        $optionMock2->expects($this->once())
+            ->method('getPrices')
+            ->willReturn([]);
+        $optionMock2->expects($this->once())
+            ->method('setValues')
+            ->with([]);
+        $this->optionValueFactory->expects($this->at(1))
+            ->method('create')
+            ->willReturn($optionValueMock2);
+
+        $options = [$optionMock1, $optionMock2];
+
+        $this->configurableProductTypeInstanceMock->expects($this->once())
+            ->method('getConfigurableAttributes')
+            ->with($this->productMock)
+            ->willReturn($options);
+        return $options;
+    }
+
+    protected function setupLinks()
+    {
+        $id = 5;
+        $links = [6, 7];
+        $this->productMock->expects($this->once())
+            ->method('getId')
+            ->willReturn($id);
+        $this->configurableProductTypeInstanceMock->expects($this->once())
+            ->method('getChildrenIds')
+            ->with($id)
+            ->willReturn([$links]);
+        return $links;
+    }
+
+    public function testAfterLoad()
+    {
+        $options = $this->setupOptions();
+        $links = $this->setupLinks();
+
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+
+        $extensionAttributeMock = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtension')
+            ->setMethods(['setConfigurableProductOptions', 'setConfigurableProductLinks'])
+            ->getMock();
+
+        $extensionAttributeMock->expects($this->once())->method('setConfigurableProductOptions')
+            ->with($options)
+            ->willReturnSelf();
+        $extensionAttributeMock->expects($this->once())->method('setConfigurableProductLinks')
+            ->with($links)
+            ->willReturnSelf();
+
+        $this->productExtensionFactory->expects($this->once())
+            ->method('create')
+            ->willReturn($extensionAttributeMock);
+
+        $this->productMock->expects($this->once())
+            ->method('setExtensionAttributes')
+            ->with($extensionAttributeMock)
+            ->willReturnSelf();
+
+        $this->assertEquals($this->productMock, $this->model->afterLoad($this->productMock));
+    }
+
+    public function testAfterLoadNotConfigurableProduct()
+    {
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn('simple');
+
+        $this->productMock->expects($this->never())
+            ->method('getExtensionAttributes');
+        $this->productMock->expects($this->never())
+            ->method('setExtensionAttributes');
+        $this->assertEquals($this->productMock, $this->model->afterLoad($this->productMock));
+    }
+
+    public function testAfterLoadNoLinks()
+    {
+        $options = $this->setupOptions();
+
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+
+        $extensionAttributeMock = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtension')
+            ->setMethods(['setConfigurableProductOptions', 'setConfigurableProductLinks'])
+            ->getMock();
+
+        $extensionAttributeMock->expects($this->once())->method('setConfigurableProductOptions')
+            ->with($options)
+            ->willReturnSelf();
+        $extensionAttributeMock->expects($this->once())->method('setConfigurableProductLinks')
+            ->with([])
+            ->willReturnSelf();
+
+        $this->productExtensionFactory->expects($this->once())
+            ->method('create')
+            ->willReturn($extensionAttributeMock);
+
+        $this->productMock->expects($this->once())
+            ->method('setExtensionAttributes')
+            ->with($extensionAttributeMock)
+            ->willReturnSelf();
+
+        $this->assertEquals($this->productMock, $this->model->afterLoad($this->productMock));
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6e750f9e13fcee390a5ae1a4fab496a507816f6c
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php
@@ -0,0 +1,553 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Test\Unit\Model\Plugin;
+
+use Magento\ConfigurableProduct\Model\Plugin\AroundProductRepositorySave;
+
+class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var AroundProductRepositorySave
+     */
+    protected $plugin;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productOptionRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productExtensionMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $configurableTypeFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $priceDataMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productInterfaceMock;
+
+    /**
+     * @var \Closure
+     */
+    protected $closureMock;
+
+    protected function setUp()
+    {
+        $this->productRepositoryMock = $this->getMock('Magento\Catalog\Api\ProductRepositoryInterface');
+        $this->productOptionRepositoryMock = $this->getMock(
+            'Magento\ConfigurableProduct\Api\OptionRepositoryInterface'
+        );
+        $this->configurableTypeFactoryMock = $this->getMockBuilder(
+            '\Magento\ConfigurableProduct\Model\Resource\Product\Type\ConfigurableFactory'
+        )->disableOriginalConstructor()->getMock();
+        $this->priceDataMock = $this->getMockBuilder(
+            '\Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable\Attribute\Price\Data'
+        )->disableOriginalConstructor()->getMock();
+        $this->productInterfaceMock = $this->getMock('\Magento\Catalog\Api\Data\ProductInterface');
+        $this->productMock = $this->getMock(
+            'Magento\Catalog\Model\Product',
+            ['getExtensionAttributes', 'getTypeId', 'getSku', 'getStoreId', 'getId', 'getTypeInstance'],
+            [],
+            '',
+            false
+        );
+        $this->closureMock = function () {
+            return $this->productMock;
+        };
+
+        $this->productFactoryMock = $this->getMockBuilder('\Magento\Catalog\Model\ProductFactory')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->plugin = $objectManager->getObject(
+            'Magento\ConfigurableProduct\Model\Plugin\AroundProductRepositorySave',
+            [
+                'optionRepository' => $this->productOptionRepositoryMock,
+                'productFactory' => $this->productFactoryMock,
+                'priceData' => $this->priceDataMock,
+                'typeConfigurableFactory' => $this->configurableTypeFactoryMock
+            ]
+        );
+
+        $this->productExtensionMock = $this->getMock(
+            'Magento\Catalog\Api\Data\ProductExtension',
+            [
+                'getConfigurableProductOptions',
+                'getConfigurableProductLinks',
+                'setConfigurableProductOptions',
+                'setConfigurableProductLinks',
+            ],
+            [],
+            '',
+            false
+        );
+    }
+
+    public function testAroundSaveWhenProductIsSimple()
+    {
+        $this->productMock->expects($this->once())->method('getTypeId')->willReturn('simple');
+        $this->productMock->expects($this->never())->method('getExtensionAttributes');
+
+        $this->assertEquals(
+            $this->productMock,
+            $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock)
+        );
+    }
+
+    public function testAroundSaveWithoutOptions()
+    {
+        $this->productInterfaceMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+        $this->productInterfaceMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductOptions')
+            ->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductLinks')
+            ->willReturn(null);
+
+        $this->priceDataMock->expects($this->never())
+            ->method('setProductPrice');
+
+        $this->assertEquals(
+            $this->productMock,
+            $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productInterfaceMock)
+        );
+    }
+
+    protected function setupProducts($productIds, $attributeCode, $additionalProductId = null)
+    {
+        $count = 0;
+        $products = [];
+        foreach ($productIds as $productId) {
+            $productMock = $this->getMockBuilder('\Magento\Catalog\Model\Product')
+                ->disableOriginalConstructor()
+                ->getMock();
+            $productMock->expects($this->once())
+                ->method('load')
+                ->with($productId)
+                ->willReturnSelf();
+            $productMock->expects($this->once())
+                ->method('getId')
+                ->willReturn($productId);
+            $productMock->expects($this->any())
+                ->method('getData')
+                ->with($attributeCode)
+                ->willReturn($productId);
+            $this->productFactoryMock->expects($this->at($count))
+                ->method('create')
+                ->willReturn($productMock);
+            $products[] = $productMock;
+            $count++;
+        }
+
+        if ($additionalProductId) {
+            $nonExistingProductMock = $this->getMockBuilder('\Magento\Catalog\Model\Product')
+                ->disableOriginalConstructor()
+                ->getMock();
+            $nonExistingProductMock->expects($this->once())
+                ->method('load')
+                ->with($additionalProductId)
+                ->willReturnSelf();
+            $this->productFactoryMock->expects($this->at($count))
+                ->method('create')
+                ->willReturn($nonExistingProductMock);
+            $products[] = $nonExistingProductMock;
+        }
+        return $products;
+    }
+
+    protected function setupConfigurableProductAttributes($attributeCodes)
+    {
+        $configurableProductTypeMock = $this->getMockBuilder(
+            '\Magento\ConfigurableProduct\Model\Product\Type\Configurable'
+        )->disableOriginalConstructor()->getMock();
+
+        $this->productMock->expects($this->once())
+            ->method('getTypeInstance')
+            ->willReturn($configurableProductTypeMock);
+
+        $configurableAttributes = [];
+        foreach ($attributeCodes as $attributeCode) {
+            $configurableAttribute = $this->getMockBuilder(
+                '\Magento\ConfigurableProduct\Model\Product\Type\Configurable\Attribute'
+            )->setMethods(['getProductAttribute'])
+                ->disableOriginalConstructor()
+                ->getMock();
+            $productAttributeMock = $this->getMockBuilder('\Magento\Catalog\Model\Resource\Eav\Attribute')
+                ->disableOriginalConstructor()
+                ->getMock();
+            $productAttributeMock->expects($this->once())
+                ->method('getAttributeCode')
+                ->willReturn($attributeCode);
+            $configurableAttribute->expects($this->once())
+                ->method('getProductAttribute')
+                ->willReturn($productAttributeMock);
+            $configurableAttributes[] = $configurableAttribute;
+        }
+
+        $configurableProductTypeMock->expects($this->once())
+            ->method('getConfigurableAttributes')
+            ->with($this->productMock)
+            ->willReturn($configurableAttributes);
+
+        return $this;
+    }
+
+    public function testAroundSaveWithLinks()
+    {
+        $links = [4, 5];
+        $configurableAttributeCode = 'color';
+        $this->productMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductOptions')
+            ->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductLinks')
+            ->willReturn($links);
+
+        $this->setupConfigurableProductAttributes([$configurableAttributeCode]);
+        $this->setupProducts($links, $configurableAttributeCode);
+
+        $configurableTypeMock = $this->getMockBuilder(
+            '\Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable'
+        )->disableOriginalConstructor()->getMock();
+        $this->configurableTypeFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($configurableTypeMock);
+        $configurableTypeMock->expects($this->once())
+            ->method('saveProducts')
+            ->with($this->productMock, $links);
+
+        $productId = 3;
+        $this->productMock->expects($this->any())
+            ->method('getId')
+            ->willReturn($productId);
+        $this->priceDataMock->expects($this->once())
+            ->method('setProductPrice')
+            ->with($productId, null);
+
+        $productSku = 'configurable-sku';
+        $this->productMock->expects($this->any())
+            ->method('getSku')
+            ->willReturn($productSku);
+        $newProductMock = $this->setupReload($productSku);
+
+        $this->assertEquals(
+            $newProductMock,
+            $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock)
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Product with id "6" does not exist.
+     */
+    public function testAroundSaveWithNonExistingLinks()
+    {
+        $links = [4, 5];
+        $nonExistingId = 6;
+        $configurableAttributeCode = 'color';
+
+        $this->setupConfigurableProductAttributes([$configurableAttributeCode]);
+        $productMocks = $this->setupProducts($links, $configurableAttributeCode, $nonExistingId);
+        $nonExistingProductMock = $productMocks[2];
+        $nonExistingProductMock->expects($this->once())
+            ->method('getId')
+            ->willReturn(null);
+        $links[] = $nonExistingId;
+
+        $this->productMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductOptions')
+            ->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductLinks')
+            ->willReturn($links);
+
+        $configurableTypeMock = $this->getMockBuilder(
+            '\Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable'
+        )->disableOriginalConstructor()->getMock();
+        $this->configurableTypeFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($configurableTypeMock);
+        $configurableTypeMock->expects($this->never())
+            ->method('saveProducts')
+            ->with($this->productMock, $links);
+
+        $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Product with id "6" does not contain required attribute "color".
+     */
+    public function testAroundSaveWithLinksWithMissingAttribute()
+    {
+        $links = [4, 5];
+        $simpleProductId = 6;
+        $configurableAttributeCode = 'color';
+
+        $this->setupConfigurableProductAttributes([$configurableAttributeCode]);
+        $productMocks = $this->setupProducts($links, $configurableAttributeCode, $simpleProductId);
+        $simpleProductMock = $productMocks[2];
+        $simpleProductMock->expects($this->once())
+            ->method('getId')
+            ->willReturn($simpleProductId);
+        $simpleProductMock->expects($this->any())
+            ->method('getData')
+            ->with($configurableAttributeCode)
+            ->willReturn(null);
+
+        $links[] = $simpleProductId;
+
+        $this->productMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductOptions')
+            ->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductLinks')
+            ->willReturn($links);
+
+        $configurableTypeMock = $this->getMockBuilder(
+            '\Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable'
+        )->disableOriginalConstructor()->getMock();
+        $this->configurableTypeFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($configurableTypeMock);
+        $configurableTypeMock->expects($this->never())
+            ->method('saveProducts')
+            ->with($this->productMock, $links);
+
+        $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Products "6" and 4 have the same set of attribute values.
+     */
+    public function testAroundSaveWithLinksWithDuplicateAttributes()
+    {
+        $links = [4, 5];
+        $simpleProductId = 6;
+        $configurableAttributeCode = 'color';
+
+        $this->setupConfigurableProductAttributes([$configurableAttributeCode]);
+        $productMocks = $this->setupProducts($links, $configurableAttributeCode, $simpleProductId);
+        $simpleProductMock = $productMocks[2];
+        $simpleProductMock->expects($this->once())
+            ->method('getId')
+            ->willReturn($simpleProductId);
+        $simpleProductMock->expects($this->any())
+            ->method('getData')
+            ->with($configurableAttributeCode)
+            ->willReturn(4);
+
+        $links[] = $simpleProductId;
+
+        $this->productMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductOptions')
+            ->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductLinks')
+            ->willReturn($links);
+
+        $configurableTypeMock = $this->getMockBuilder(
+            '\Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable'
+        )->disableOriginalConstructor()->getMock();
+        $this->configurableTypeFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($configurableTypeMock);
+        $configurableTypeMock->expects($this->never())
+            ->method('saveProducts')
+            ->with($this->productMock, $links);
+
+        $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage The configurable product does not have any variation attribute.
+     */
+    public function testAroundSaveWithLinksWithoutVariationAttributes()
+    {
+        $links = [4, 5];
+
+        $this->setupConfigurableProductAttributes([]);
+
+        $this->productMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductOptions')
+            ->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getConfigurableProductLinks')
+            ->willReturn($links);
+
+        $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock);
+    }
+
+    public function testAroundSaveWithOptions()
+    {
+        $productSku = "configurable_sku";
+        $this->productInterfaceMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\ConfigurableProduct\Model\Product\Type\Configurable::TYPE_CODE);
+        //two options with id 5 and 6
+        $options = $this->setupOptions([5, 6]);
+        //two existing options with id 4 and 5
+        $this->setupExistingOptions([4, 5]);
+
+        $this->productMock->expects($this->any())->method('getSku')
+            ->will($this->returnValue($productSku));
+
+        $this->productOptionRepositoryMock->expects($this->at(0))
+            ->method('save')
+            ->with($productSku, $options[0]);
+        $this->productOptionRepositoryMock->expects($this->at(1))
+            ->method('save')
+            ->with($productSku, $options[1]);
+        $this->productOptionRepositoryMock->expects($this->at(2))
+            ->method('deleteById')
+            ->with($productSku, 4);
+
+        $configurableProductTypeMock = $this->getMockBuilder(
+            '\Magento\ConfigurableProduct\Model\Product\Type\Configurable'
+        )->disableOriginalConstructor()->getMock();
+        $configurableProductTypeMock->expects($this->once())
+            ->method('resetConfigurableAttributes')
+            ->with($this->productMock)
+            ->willReturnSelf();
+        $this->productMock->expects($this->any())
+            ->method('getTypeInstance')
+            ->willReturn($configurableProductTypeMock);
+
+        $productId = 3;
+        $this->productMock->expects($this->once())
+            ->method('getId')
+            ->willReturn($productId);
+        $this->priceDataMock->expects($this->once())
+            ->method('setProductPrice')
+            ->with($productId, null);
+
+        $newProductMock = $this->setupReload($productSku);
+
+        $this->assertEquals(
+            $newProductMock,
+            $this->plugin->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productInterfaceMock)
+        );
+    }
+
+    protected function setupReload($productSku)
+    {
+        $newProductMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductInterface')
+            ->disableOriginalConstructor()->getMock();
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku, false, null, true)
+            ->willReturn($newProductMock);
+        return $newProductMock;
+    }
+
+    protected function setupExistingOptions(array $existingOptionIds)
+    {
+        $options = [];
+        foreach ($existingOptionIds as $existingOptionId) {
+            $optionMock = $this->getMock('\Magento\ConfigurableProduct\Api\Data\OptionInterface');
+            $optionMock->expects($this->any())
+                ->method('getId')
+                ->willReturn($existingOptionId);
+            $options[] = $optionMock;
+        }
+
+        $productExtensionMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductExtension')
+            ->disableOriginalConstructor()
+            ->setMethods(['getConfigurableProductOptions'])
+            ->getMock();
+        $productExtensionMock->expects($this->any())
+            ->method('getConfigurableProductOptions')
+            ->willReturn($options);
+
+        $this->productMock->expects($this->any())
+            ->method('getExtensionAttributes')
+            ->willReturn($productExtensionMock);
+    }
+
+    protected function setupOptions(array $optionIds)
+    {
+        $options = [];
+        foreach ($optionIds as $optionId) {
+            $optionMock = $this->getMock('\Magento\ConfigurableProduct\Api\Data\OptionInterface');
+            $optionMock->expects($this->any())
+                ->method('getId')
+                ->willReturn($optionId);
+            $options[] = $optionMock;
+        }
+
+        $productExtensionMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductExtension')
+            ->disableOriginalConstructor()
+            ->setMethods(['getConfigurableProductOptions', 'getConfigurableProductLinks'])
+            ->getMock();
+        $productExtensionMock->expects($this->any())
+            ->method('getConfigurableProductOptions')
+            ->willReturn($options);
+        $productExtensionMock->expects($this->any())
+            ->method('getConfigurableProductLinks')
+            ->willReturn(null);
+
+        $this->productInterfaceMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($productExtensionMock);
+        return $options;
+    }
+}
diff --git a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
index d0c5ae32ab1dc80a675f55233119de9eedcdc708..4ca090adef44b5e3786bd066067c7c6aaa03ac53 100644
--- a/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
+++ b/app/code/Magento/ConfigurableProduct/Test/Unit/Model/Product/Type/ConfigurableTest.php
@@ -408,6 +408,19 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
         ];
     }
 
+    public function testResetConfigurableAttributes()
+    {
+        $product = $this->getMockBuilder('\Magento\Catalog\Model\Product')
+            ->setMethods(['unsetData', '__wakeup', '__sleep'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $product->expects($this->any())->method('unsetData')
+            ->with('_cache_instance_configurable_attributes')
+            ->will($this->returnSelf());
+
+        $this->assertEquals($this->_model, $this->_model->resetConfigurableAttributes($product));
+    }
+
     public function testHasOptions()
     {
         $productMock = $this->getMockBuilder('\Magento\Catalog\Model\Product')
@@ -584,10 +597,6 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             ->setMethods(['getId', 'getAttributeCode'])
             ->disableOriginalConstructor()
             ->getMock();
-        $productResource = $this->getMockBuilder('\Magento\Catalog\Model\Resource\Product')
-            ->setMethods(['__wakeup', 'loadAllAttributes', 'getSortedAttributes'])
-            ->disableOriginalConstructor()
-            ->getMock();
         $productCollection = $this->getMockBuilder(
             'Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable\Product\Collection'
         )
@@ -616,14 +625,12 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
             ->method('getData')
             ->with('_cache_instance_store_filter')
             ->willReturn('some_filter');
-        $productMock->expects($this->once())->method('hasData')->willReturn(true);
-        $productMock->expects($this->at(3))->method('getData')->willReturn([$usedProductMock]);
-        $productMock->expects($this->once())->method('getResource')->willReturn($productResource);
-        $productMock->expects($this->once())->method('getAttributeSetId')->willReturn(5);
-        $productResource->expects($this->once())->method('loadAllAttributes')->with($productMock)->willReturnSelf();
-        $productResource->expects($this->once())
-            ->method('getSortedAttributes')
-            ->with(5)
+        $productMock->expects($this->any())->method('hasData')->willReturn(true);
+        $productMock->expects($this->at(3))->method('getData')
+            ->with('_cache_instance_products')
+            ->willReturn([$usedProductMock]);
+        $productMock->expects($this->at(5))->method('getData')
+            ->with('_cache_instance_product_set_attributes')
             ->willReturn([$eavAttributeMock]);
         $eavAttributeMock->expects($this->once())->method('getId')->willReturn(1);
         $eavAttributeMock->expects($this->once())->method('getAttributeCode')->willReturn('attr_code');
diff --git a/app/code/Magento/ConfigurableProduct/etc/di.xml b/app/code/Magento/ConfigurableProduct/etc/di.xml
index fcd5d77b81e4de8e9a5df180968909b02d290221..490c15a70a51fc150d80d3e8b42dd5c4ef8aa47e 100644
--- a/app/code/Magento/ConfigurableProduct/etc/di.xml
+++ b/app/code/Magento/ConfigurableProduct/etc/di.xml
@@ -6,7 +6,6 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
-    <preference for="Magento\ConfigurableProduct\Api\OptionTypesListInterface" type="Magento\ConfigurableProduct\Model\OptionTypesList" />
     <preference for="Magento\ConfigurableProduct\Api\ConfigurableProductManagementInterface" type="Magento\ConfigurableProduct\Model\ConfigurableProductManagement" />
     <preference for="Magento\ConfigurableProduct\Api\LinkManagementInterface" type="Magento\ConfigurableProduct\Model\LinkManagement" />
     <preference for="Magento\ConfigurableProduct\Api\OptionRepositoryInterface" type="Magento\ConfigurableProduct\Model\OptionRepository" />
@@ -59,6 +58,12 @@
     <type name="Magento\Catalog\Model\Product\Type">
         <plugin name="configurable_output" type="Magento\ConfigurableProduct\Model\Product\Type\Plugin" />
     </type>
+    <type name="Magento\Catalog\Api\ProductRepositoryInterface">
+        <plugin name="configurableProductSaveOptions" type="\Magento\ConfigurableProduct\Model\Plugin\AroundProductRepositorySave"/>
+    </type>
+    <type name="Magento\Catalog\Model\Product">
+        <plugin name="configurableProductLoadAfter" type="\Magento\ConfigurableProduct\Model\Plugin\AfterProductLoad"/>
+    </type>
     <virtualType name="Magento\ConfigurableProduct\Pricing\Price\Pool" type="Magento\Framework\Pricing\Price\Pool">
         <arguments>
             <argument name="prices" xsi:type="array">
diff --git a/app/code/Magento/ConfigurableProduct/etc/service_data_attributes.xml b/app/code/Magento/ConfigurableProduct/etc/service_data_attributes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..74edcdbf65a91e08cc384b50b416deff63e8780c
--- /dev/null
+++ b/app/code/Magento/ConfigurableProduct/etc/service_data_attributes.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
+        <attribute code="configurable_product_options" type="Magento\ConfigurableProduct\Api\Data\OptionInterface[]" />
+        <attribute code="configurable_product_links" type="int[]" />
+    </extension_attributes>
+</config>
diff --git a/app/code/Magento/ConfigurableProduct/etc/webapi.xml b/app/code/Magento/ConfigurableProduct/etc/webapi.xml
index 9c68aa71869f44782120dda382eb7de6c34e9f2d..158db3c3c5fa8313960e1735250f3f7cfb250388 100644
--- a/app/code/Magento/ConfigurableProduct/etc/webapi.xml
+++ b/app/code/Magento/ConfigurableProduct/etc/webapi.xml
@@ -43,12 +43,6 @@
             <resource ref="Magento_Catalog::products"/>
         </resources>
     </route>
-    <route url="/V1/configurable-products/options/types" method="GET">
-        <service class="Magento\ConfigurableProduct\Api\OptionTypesListInterface" method="getItems" />
-        <resources>
-            <resource ref="Magento_Catalog::products" />
-        </resources>
-    </route>
     <route url="/V1/configurable-products/:sku/options" method="POST">
         <service class="Magento\ConfigurableProduct\Api\OptionRepositoryInterface" method="save" />
         <resources>
diff --git a/app/code/Magento/Customer/Model/Config/Backend/Address/Street.php b/app/code/Magento/Customer/Model/Config/Backend/Address/Street.php
index 7e187a71e5c08bdad11cf84b9cfdc3c9ca85632c..b25f4c6d0b3a3cb83b3693f1d2d7c08fb4859247 100644
--- a/app/code/Magento/Customer/Model/Config/Backend/Address/Street.php
+++ b/app/code/Magento/Customer/Model/Config/Backend/Address/Street.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Customer\Model\Config\Backend\Address;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 /**
  * Line count config model for customer address street attribute
  *
@@ -64,7 +66,7 @@ class Street extends \Magento\Framework\App\Config\Value
                 }
                 break;
 
-            case \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT:
+            case ScopeConfigInterface::SCOPE_TYPE_DEFAULT:
                 $attribute->setData('multiline_count', $value);
                 break;
         }
diff --git a/app/code/Magento/Customer/Model/Customer.php b/app/code/Magento/Customer/Model/Customer.php
index c65cda9e51bbae8fa77d7f89b0bb440a7fb121f7..776c8e74e1ace9aa8cc4205174c6fb0977032368 100644
--- a/app/code/Magento/Customer/Model/Customer.php
+++ b/app/code/Magento/Customer/Model/Customer.php
@@ -12,6 +12,7 @@ use Magento\Customer\Model\Resource\Address\CollectionFactory;
 use Magento\Customer\Model\Resource\Customer as ResourceCustomer;
 use Magento\Customer\Api\Data\CustomerInterfaceFactory;
 use Magento\Customer\Model\Data\Customer as CustomerData;
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\Reflection\DataObjectProcessor;
 use Magento\Framework\Exception\EmailNotConfirmedException;
 use Magento\Framework\Exception\InvalidEmailOrPasswordException;
@@ -1310,7 +1311,7 @@ class Customer extends \Magento\Framework\Model\AbstractModel
     {
         return (int)$this->_scopeConfig->getValue(
             self::XML_PATH_CUSTOMER_RESET_PASSWORD_LINK_EXPIRATION_PERIOD,
-            \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+            ScopeConfigInterface::SCOPE_TYPE_DEFAULT
         );
     }
 
diff --git a/app/code/Magento/Customer/Model/Resource/Address.php b/app/code/Magento/Customer/Model/Resource/Address.php
index 57a5c1cbcf3d9c28e975a999395d5ffd18600696..3b6ae0a28c8f9e812e762b72dbfe45d35681ebe9 100644
--- a/app/code/Magento/Customer/Model/Resource/Address.php
+++ b/app/code/Magento/Customer/Model/Resource/Address.php
@@ -45,13 +45,22 @@ class Address extends \Magento\Eav\Model\Entity\AbstractEntity
      */
     protected function _construct()
     {
-        $resource = $this->_resource;
-        $this->setType(
-            'customer_address'
-        )->setConnection(
-            $resource->getConnection('customer_read'),
-            $resource->getConnection('customer_write')
-        );
+        $this->_read = 'customer_read';
+        $this->_write = 'customer_write';
+    }
+
+    /**
+     * Getter and lazy loader for _type
+     *
+     * @throws \Magento\Framework\Exception\LocalizedException
+     * @return \Magento\Eav\Model\Entity\Type
+     */
+    public function getEntityType()
+    {
+        if (empty($this->_type)) {
+            $this->setType('customer_address');
+        }
+        return parent::getEntityType();
     }
 
     /**
diff --git a/app/code/Magento/Customer/Model/Session.php b/app/code/Magento/Customer/Model/Session.php
index c01cd99d642cf7cb72c963fc20513f2e8e525235..4212be78b59114439b049203b03eca3a488991e4 100644
--- a/app/code/Magento/Customer/Model/Session.php
+++ b/app/code/Magento/Customer/Model/Session.php
@@ -102,6 +102,7 @@ class Session extends \Magento\Framework\Session\SessionManager
      * @param \Magento\Framework\Session\StorageInterface $storage
      * @param \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager
      * @param \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory
+     * @param \Magento\Framework\App\State $appState
      * @param Share $configShare
      * @param \Magento\Framework\Url\Helper\Data $coreUrl
      * @param \Magento\Customer\Model\Url $customerUrl
@@ -113,6 +114,7 @@ class Session extends \Magento\Framework\Session\SessionManager
      * @param \Magento\Framework\App\Http\Context $httpContext
      * @param CustomerRepositoryInterface $customerRepository
      * @param GroupManagementInterface $groupManagement
+     * @throws \Magento\Framework\Exception\SessionException
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
@@ -124,6 +126,7 @@ class Session extends \Magento\Framework\Session\SessionManager
         \Magento\Framework\Session\StorageInterface $storage,
         \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager,
         \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory,
+        \Magento\Framework\App\State $appState,
         Config\Share $configShare,
         \Magento\Framework\Url\Helper\Data $coreUrl,
         \Magento\Customer\Model\Url $customerUrl,
@@ -154,9 +157,9 @@ class Session extends \Magento\Framework\Session\SessionManager
             $validator,
             $storage,
             $cookieManager,
-            $cookieMetadataFactory
+            $cookieMetadataFactory,
+            $appState
         );
-        $this->start();
         $this->groupManagement = $groupManagement;
         $this->_eventManager->dispatch('customer_session_init', ['customer_session' => $this]);
     }
diff --git a/app/code/Magento/Customer/Test/Unit/Block/Widget/DobTest.php b/app/code/Magento/Customer/Test/Unit/Block/Widget/DobTest.php
index 5d1e91708b4fcd6da306011c551415bf3586d66a..834c64df6701f19605ccd05fb8298d1def87fa4a 100644
--- a/app/code/Magento/Customer/Test/Unit/Block/Widget/DobTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Block/Widget/DobTest.php
@@ -10,6 +10,7 @@ namespace Magento\Customer\Test\Unit\Block\Widget;
 
 use Magento\Framework\Exception\NoSuchEntityException;
 use Magento\Customer\Block\Widget\Dob;
+use Magento\Framework\Locale\Resolver;
 
 class DobTest extends \PHPUnit_Framework_TestCase
 {
@@ -69,7 +70,7 @@ class DobTest extends \PHPUnit_Framework_TestCase
         $localeResolver = $this->getMock('\Magento\Framework\Locale\ResolverInterface');
         $localeResolver->expects($this->any())
             ->method('getLocale')
-            ->willReturn(\Magento\Framework\Locale\ResolverInterface::DEFAULT_LOCALE);
+            ->willReturn(Resolver::DEFAULT_LOCALE);
         $timezone = $objectManager->getObject(
             'Magento\Framework\Stdlib\DateTime\Timezone',
             ['localeResolver' => $localeResolver]
diff --git a/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php b/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php
index fe17aa1aca70eb47723da99b6c9a8639944b76de..c15cf1596c8245fb30d8a79ba097923d545c26b0 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php
@@ -18,6 +18,9 @@ class AddressTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Customer\Model\CustomerFactory|\PHPUnit_Framework_MockObject_MockObject */
     protected $customerFactory;
 
+    /** @var \Magento\Eav\Model\Entity\Type */
+    protected $eavConfigType;
+
     protected function setUp()
     {
         $this->addressResource = (new ObjectManagerHelper($this))->getObject(
@@ -178,16 +181,16 @@ class AddressTest extends \PHPUnit_Framework_TestCase
                 )
             );
 
-        $eavConfigType = $this->getMock(
+        $this->eavConfigType = $this->getMock(
             'Magento\Eav\Model\Entity\Type',
             ['getEntityIdField', 'getId', 'getEntityTable', '__wakeup'],
             [],
             '',
             false
         );
-        $eavConfigType->expects($this->any())->method('getEntityIdField')->willReturn(false);
-        $eavConfigType->expects($this->any())->method('getId')->willReturn(false);
-        $eavConfigType->expects($this->any())->method('getEntityTable')->willReturn('customer_address_entity');
+        $this->eavConfigType->expects($this->any())->method('getEntityIdField')->willReturn(false);
+        $this->eavConfigType->expects($this->any())->method('getId')->willReturn(false);
+        $this->eavConfigType->expects($this->any())->method('getEntityTable')->willReturn('customer_address_entity');
 
         $eavConfig = $this->getMock(
             'Magento\Eav\Model\Config',
@@ -199,10 +202,10 @@ class AddressTest extends \PHPUnit_Framework_TestCase
         $eavConfig->expects($this->any())
             ->method('getEntityType')
             ->with('customer_address')
-            ->willReturn($eavConfigType);
+            ->willReturn($this->eavConfigType);
         $eavConfig->expects($this->any())
             ->method('getEntityAttributeCodes')
-            ->with($eavConfigType)
+            ->with($this->eavConfigType)
             ->willReturn(
                 [
                     'entity_type_id',
@@ -217,13 +220,13 @@ class AddressTest extends \PHPUnit_Framework_TestCase
         $eavConfig->expects($this->any())
             ->method('getAttribute')
             ->willReturnMap([
-                [$eavConfigType, 'entity_type_id', $attributeMock],
-                [$eavConfigType, 'attribute_set_id', $attributeMock],
-                [$eavConfigType, 'created_at', $attributeMock],
-                [$eavConfigType, 'updated_at', $attributeMock],
-                [$eavConfigType, 'parent_id', $attributeMock],
-                [$eavConfigType, 'increment_id', $attributeMock],
-                [$eavConfigType, 'entity_id', $attributeMock],
+                [$this->eavConfigType, 'entity_type_id', $attributeMock],
+                [$this->eavConfigType, 'attribute_set_id', $attributeMock],
+                [$this->eavConfigType, 'created_at', $attributeMock],
+                [$this->eavConfigType, 'updated_at', $attributeMock],
+                [$this->eavConfigType, 'parent_id', $attributeMock],
+                [$this->eavConfigType, 'increment_id', $attributeMock],
+                [$this->eavConfigType, 'entity_id', $attributeMock],
             ]);
 
         return $eavConfig;
@@ -261,4 +264,9 @@ class AddressTest extends \PHPUnit_Framework_TestCase
         $this->customerFactory = $this->getMock('Magento\Customer\Model\CustomerFactory', ['create'], [], '', false);
         return $this->customerFactory;
     }
+
+    public function testGetType()
+    {
+        $this->assertSame($this->eavConfigType, $this->addressResource->getEntityType());
+    }
 }
diff --git a/app/code/Magento/DesignEditor/Model/Url/NavigationMode.php b/app/code/Magento/DesignEditor/Model/Url/NavigationMode.php
index af413fcd477b0b044e36d1bc9ed4bfc3c6637eb5..cb54368e519392d63b842cd6227cce1644e51c7d 100644
--- a/app/code/Magento/DesignEditor/Model/Url/NavigationMode.php
+++ b/app/code/Magento/DesignEditor/Model/Url/NavigationMode.php
@@ -38,7 +38,7 @@ class NavigationMode extends \Magento\Framework\Url
      * @param \Magento\Framework\Url\ScopeResolverInterface $scopeResolver
      * @param \Magento\Framework\Session\Generic $session
      * @param \Magento\Framework\Session\SidResolverInterface $sidResolver
-     * @param \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolver
+     * @param \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory
      * @param \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param string $scopeType
@@ -53,7 +53,7 @@ class NavigationMode extends \Magento\Framework\Url
         \Magento\Framework\Url\ScopeResolverInterface $scopeResolver,
         \Magento\Framework\Session\Generic $session,
         \Magento\Framework\Session\SidResolverInterface $sidResolver,
-        \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolver,
+        \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory,
         \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         $scopeType,
@@ -75,7 +75,7 @@ class NavigationMode extends \Magento\Framework\Url
             $scopeResolver,
             $session,
             $sidResolver,
-            $routeParamsResolver,
+            $routeParamsResolverFactory,
             $queryParamsResolver,
             $scopeConfig,
             $scopeType,
diff --git a/app/code/Magento/DesignEditor/Test/Unit/Model/Url/NavigationModeTest.php b/app/code/Magento/DesignEditor/Test/Unit/Model/Url/NavigationModeTest.php
index e6de82bcf54ee3798e263bafb0d3a5f77c5e1435..e4ee8ff76365954f2ec2b404f72515d4c2cc3249 100644
--- a/app/code/Magento/DesignEditor/Test/Unit/Model/Url/NavigationModeTest.php
+++ b/app/code/Magento/DesignEditor/Test/Unit/Model/Url/NavigationModeTest.php
@@ -90,7 +90,7 @@ class NavigationModeTest extends \PHPUnit_Framework_TestCase
             [
                 'helper' => $this->_designHelperMock,
                 'data' => $this->_testData,
-                'routeParamsResolver' => $this->_routeParamsMock,
+                'routeParamsResolverFactory' => $this->_routeParamsMock,
                 'scopeResolver' => $this->_scopeResolverMock
             ]
         );
diff --git a/app/code/Magento/Developer/Console/Command/CssDeployCommand.php b/app/code/Magento/Developer/Console/Command/CssDeployCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..cb9a34ae543cab553d8ed8a992022df83f75e961
--- /dev/null
+++ b/app/code/Magento/Developer/Console/Command/CssDeployCommand.php
@@ -0,0 +1,235 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Developer\Console\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Magento\Framework\Filesystem;
+use Magento\Framework\View\Asset\Source;
+use Magento\Framework\App\State;
+use Magento\Framework\View\Asset\Repository;
+use Magento\Framework\ObjectManagerInterface;
+use Magento\Framework\App\ObjectManager\ConfigLoader;
+use Magento\Framework\View\Asset\SourceFileGeneratorPool;
+use Magento\Framework\View\Asset\PreProcessor\ChainFactoryInterface;
+use Magento\Framework\App\Filesystem\DirectoryList;
+
+/**
+ * Class CssDeployCommand - collects, processes and publishes source files like LESS or SASS
+ * @SuppressWarnings("PMD.CouplingBetweenObjects")
+ */
+class CssDeployCommand extends Command
+{
+    /**
+     * Locale option key
+     */
+    const LOCALE_OPTION = 'locale';
+
+    /**
+     * Area option key
+     */
+    const AREA_OPTION = 'area';
+
+    /**
+     * Theme option key
+     */
+    const THEME_OPTION = 'theme';
+
+    /**
+     * Type argument key
+     */
+    const TYPE_ARGUMENT = 'type';
+
+    /**
+     * Files argument key
+     */
+    const FILE_ARGUMENT = 'file';
+
+    /**
+     * @var ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * @var Repository
+     */
+    private $assetRepo;
+
+    /**
+     * @var ConfigLoader
+     */
+    private $configLoader;
+
+    /**
+     * @var State
+     */
+    private $state;
+
+    /**
+     * @var SourceFileGeneratorPool
+     */
+    private $sourceFileGeneratorPool;
+
+    /**
+     * @var Source
+     */
+    private $assetSource;
+
+    /**
+     * @var ChainFactoryInterface
+     */
+    private $chainFactory;
+
+    /**
+     * @var Filesystem
+     */
+    private $filesystem;
+
+    /**
+     * Inject dependencies
+     *
+     * @param ObjectManagerInterface $objectManager
+     * @param Repository $assetRepo
+     * @param ConfigLoader $configLoader
+     * @param State $state
+     * @param Source $assetSource
+     * @param SourceFileGeneratorPool $sourceFileGeneratorPoll
+     * @param ChainFactoryInterface $chainFactory
+     * @param Filesystem $filesystem
+     */
+    public function __construct(
+        ObjectManagerInterface $objectManager,
+        Repository $assetRepo,
+        ConfigLoader $configLoader,
+        State $state,
+        Source $assetSource,
+        SourceFileGeneratorPool $sourceFileGeneratorPoll,
+        ChainFactoryInterface $chainFactory,
+        Filesystem $filesystem
+    ) {
+        $this->state = $state;
+        $this->objectManager = $objectManager;
+        $this->configLoader = $configLoader;
+        $this->assetRepo = $assetRepo;
+        $this->sourceFileGeneratorPool = $sourceFileGeneratorPoll;
+        $this->assetSource = $assetSource;
+        $this->chainFactory = $chainFactory;
+        $this->filesystem = $filesystem;
+
+        parent::__construct();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('dev:css:deploy')
+            ->setDescription('Collects, processes and publishes source files like LESS or SASS')
+            ->setDefinition([
+                new InputArgument(
+                    self::TYPE_ARGUMENT,
+                    InputArgument::REQUIRED,
+                    'Type of dynamic stylesheet language: [less|sass]'
+                ),
+                new InputArgument(
+                    self::FILE_ARGUMENT,
+                    InputArgument::IS_ARRAY,
+                    'Files to pre-process (file should be specified without extension)',
+                    ['css/styles-m']
+                ),
+                new InputOption(
+                    self::LOCALE_OPTION,
+                    null,
+                    InputOption::VALUE_REQUIRED,
+                    'Locale',
+                    'en_US'
+                ),
+                new InputOption(
+                    self::AREA_OPTION,
+                    null,
+                    InputOption::VALUE_REQUIRED,
+                    'Area, one of [frontend|adminhtml|doc]',
+                    'frontend'
+                ),
+                new InputOption(
+                    self::THEME_OPTION,
+                    null,
+                    InputOption::VALUE_REQUIRED,
+                    'Theme in format Vendor/theme',
+                    'Magento/blank'
+                ),
+
+            ]);
+
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     * @throws \InvalidArgumentException
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $locale = $input->getOption(self::LOCALE_OPTION);
+
+        if (!preg_match('/^[a-z]{2}_[A-Z]{2}$/', $locale)) {
+            throw new \InvalidArgumentException(
+                $locale . ' argument has invalid value format'
+            );
+        }
+
+        $area = $input->getOption(self::AREA_OPTION);
+        $theme = $input->getOption(self::THEME_OPTION);
+
+        $type = $input->getArgument(self::TYPE_ARGUMENT);
+
+        $this->state->setAreaCode($area);
+        $this->objectManager->configure($this->configLoader->load($area));
+
+        $sourceFileGenerator = $this->sourceFileGeneratorPool->create($type);
+
+        foreach ($input->getArgument(self::FILE_ARGUMENT) as $file) {
+            $file .= '.' . $type;
+
+            $output->writeln("<info>Gathering {$file} sources.</info>");
+
+            $asset = $this->assetRepo->createAsset(
+                $file,
+                [
+                    'area' => $area,
+                    'theme' => $theme,
+                    'locale' => $locale,
+                ]
+            );
+
+            $sourceFile = $this->assetSource->findSource($asset);
+            $content = \file_get_contents($sourceFile);
+
+            $chain = $this->chainFactory->create(
+                [
+                    'asset'           => $asset,
+                    'origContent'     => $content,
+                    'origContentType' => $asset->getContentType()
+                ]
+            );
+
+            $processedCoreFile = $sourceFileGenerator->generateFileTree($chain);
+
+            $targetDir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW);
+            $rootDir = $this->filesystem->getDirectoryWrite(DirectoryList::ROOT);
+            $source = $rootDir->getRelativePath($processedCoreFile);
+            $destination = $asset->getPath();
+            $rootDir->copyFile($source, $destination, $targetDir);
+
+            $output->writeln("<info>Successfully processed LESS and/or SASS files</info>");
+        }
+    }
+}
diff --git a/app/code/Magento/Developer/Console/Command/DevTestsRunCommand.php b/app/code/Magento/Developer/Console/Command/DevTestsRunCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..a5f5ecf2b744fce4565f49368898371763ff090f
--- /dev/null
+++ b/app/code/Magento/Developer/Console/Command/DevTestsRunCommand.php
@@ -0,0 +1,148 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Developer\Console\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Class DevTestsRunCommand
+ *
+ * Runs tests (unit, static, integration, etc.)
+ */
+class DevTestsRunCommand extends Command
+{
+    /**
+     * input parameter parameter
+     */
+    const INPUT_ARG_TYPE = 'type';
+
+    /**
+     * command name
+     */
+    const COMMAND_NAME = 'dev:tests:run';
+
+    /**
+     * Maps types (from user input) to phpunit test names
+     *
+     * @var array
+     */
+    private $types;
+
+    /**
+     * Maps phpunit test names to directory and target name
+     *
+     * @var array
+     */
+    private $commands;
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setupTestInfo();
+        $this->setName(self::COMMAND_NAME)
+            ->setDescription('Runs tests');
+
+        $this->addArgument(
+            self::INPUT_ARG_TYPE,
+            InputArgument::OPTIONAL,
+            'Type of test to run. Available types: ' . implode(', ', array_keys($this->types)),
+            'default'
+        );
+
+        parent::configure();
+    }
+
+    /**
+     * Run the tests
+     *
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @return int Non zero if invalid type, 0 otherwise
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        /* Validate type argument is valid */
+        $type = $input->getArgument(self::INPUT_ARG_TYPE);
+        if (!isset($this->types[$type])) {
+            $output->writeln(
+                'Invalid type: "' . $type . '". Available types: ' . implode(', ', array_keys($this->types))
+            );
+            return 1;
+        }
+
+        $vendorDir = require BP . '/app/etc/vendor_path.php';
+
+        $failures = [];
+        $runCommands = $this->types[$type];
+        foreach ($runCommands as $key) {
+            list($dir, $options) = $this->commands[$key];
+            $dirName = realpath(BP . '/dev/tests/' . $dir);
+            chdir($dirName);
+            $command = 'php '. BP . '/' . $vendorDir . '/phpunit/phpunit/phpunit ' . $options;
+            $message = $dirName . '> ' . $command;
+            $output->writeln(['', str_pad("---- {$message} ", 70, '-'), '']);
+            passthru($command, $returnVal);
+            if ($returnVal) {
+                $failures[] = $message;
+            }
+        }
+
+        $output->writeln(str_repeat('-', 70));
+        if ($failures) {
+            $output->writeln("FAILED - " . count($failures) . ' of ' . count($runCommands) . ":");
+            foreach ($failures as $message) {
+                $output->writeln(' - ' . $message);
+            }
+        } else {
+            $output->writeln('PASSED (' . count($runCommands) . ')');
+        }
+        return 0;
+    }
+
+    /**
+     * Fills in arrays that link test types to php unit tests and directories.
+     *
+     * @return void
+     */
+    private function setupTestInfo()
+    {
+        $this->commands = [
+            'unit'                   => ['../tests/unit', ''],
+            'unit-performance'       => ['../tests/performance/framework/tests/unit', ''],
+            'unit-static'            => ['../tests/static/framework/tests/unit', ''],
+            'unit-integration'       => ['../tests/integration/framework/tests/unit', ''],
+            'integration'            => ['../tests/integration', ''],
+            'integration-integrity'  => ['../tests/integration', ' testsuite/Magento/Test/Integrity'],
+            'static-default'         => ['../tests/static', ''],
+            'static-legacy'          => ['../tests/static', ' testsuite/Magento/Test/Legacy'],
+            'static-integration-php' => ['../tests/static', ' testsuite/Magento/Test/Php/Exemplar'],
+            'static-integration-js'  => ['../tests/static', ' testsuite/Magento/Test/Js/Exemplar'],
+        ];
+        $this->types = [
+            'all'             => array_keys($this->commands),
+            'unit'            => ['unit', 'unit-performance', 'unit-static', 'unit-integration'],
+            'integration'     => ['integration'],
+            'integration-all' => ['integration', 'integration-integrity'],
+            'static'          => ['static-default'],
+            'static-all'      => ['static-default', 'static-legacy', 'static-integration-php', 'static-integration-js'],
+            'integrity'       => ['static-default', 'static-legacy', 'integration-integrity'],
+            'legacy'          => ['static-legacy'],
+            'default'         => [
+                'unit',
+                'unit-performance',
+                'unit-static',
+                'unit-integration',
+                'integration',
+                'static-default',
+            ],
+        ];
+    }
+}
diff --git a/app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php b/app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e740800579f632a6be6df09193a32dce67e62c82
--- /dev/null
+++ b/app/code/Magento/Developer/Test/Unit/Console/Command/CssDeployCommandTest.php
@@ -0,0 +1,164 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Developer\Test\Unit\Console\Command;
+
+use Magento\Framework\Filesystem;
+use Magento\Framework\View\Asset\Source;
+use Magento\Framework\App\State;
+use Magento\Framework\View\Asset\Repository;
+use Magento\Framework\ObjectManagerInterface;
+use Magento\Framework\App\ObjectManager\ConfigLoader;
+use Magento\Framework\View\Asset\SourceFileGeneratorPool;
+use Magento\Framework\View\Asset\PreProcessor\ChainFactoryInterface;
+use Magento\Developer\Console\Command\CssDeployCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class CssDeployCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var CssDeployCommand
+     */
+    private $command;
+
+    /**
+     * @var ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManager;
+
+    /**
+     * @var Repository|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $assetRepo;
+
+    /**
+     * @var ConfigLoader|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $configLoader;
+
+    /**
+     * @var State|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $state;
+
+    /**
+     * @var SourceFileGeneratorPool|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $sourceFileGeneratorPool;
+
+    /**
+     * @var Source|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $assetSource;
+
+    /**
+     * @var ChainFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $chainFactory;
+
+    /**
+     * @var Filesystem|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filesystem;
+
+    public function setUp()
+    {
+        $this->objectManager = $this->getMockForAbstractClass('Magento\Framework\ObjectManagerInterface');
+        $this->assetRepo = $this->getMock('Magento\Framework\View\Asset\Repository', [], [], '', false);
+        $this->configLoader = $this->getMock('Magento\Framework\App\ObjectManager\ConfigLoader', [], [], '', false);
+        $this->state = $this->getMock('Magento\Framework\App\State', [], [], '', false);
+        $this->assetSource = $this->getMock('Magento\Framework\View\Asset\Source', [], [], '', false);
+        $this->sourceFileGeneratorPool = $this->getMock(
+            'Magento\Framework\View\Asset\SourceFileGeneratorPool',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->chainFactory = $this->getMockForAbstractClass(
+            'Magento\Framework\View\Asset\PreProcessor\ChainFactoryInterface'
+        );
+        $this->filesystem = $this->getMock('Magento\Framework\Filesystem', [], [], '', false);
+
+        $this->command = new CssDeployCommand(
+            $this->objectManager,
+            $this->assetRepo,
+            $this->configLoader,
+            $this->state,
+            $this->assetSource,
+            $this->sourceFileGeneratorPool,
+            $this->chainFactory,
+            $this->filesystem
+        );
+    }
+
+    public function testExecute()
+    {
+        $file = 'css/styles-m' . '.less';
+
+        $this->configLoader->expects($this->once())->method('load')->with('frontend')->willReturn([]);
+        $this->objectManager->expects($this->once())->method('configure');
+        $this->sourceFileGeneratorPool->expects($this->once())
+            ->method('create')
+            ->with('less')
+            ->willReturn($this->getMock('Magento\Framework\Less\FileGenerator', [], [], '', false));
+        $this->assetRepo->expects($this->once())
+            ->method('createAsset')
+            ->with(
+                $file,
+                [
+                    'area' => 'frontend',
+                    'theme' => 'Magento/blank',
+                    'locale' => 'en_US'
+                ]
+            )
+            ->willReturn(
+                $this->getMockForAbstractClass('Magento\Framework\View\Asset\LocalInterface')
+            );
+        $this->assetSource->expects($this->once())->method('findSource')->willReturn('/dev/null');
+
+        $this->chainFactory->expects($this->once())->method('create')->willReturn(
+            $this->getMock('Magento\Framework\View\Asset\PreProcessor\Chain', [], [], '', false)
+        );
+
+        $this->filesystem->expects($this->atLeastOnce())->method('getDirectoryWrite')->willReturn(
+            $this->getMock('\Magento\Framework\Filesystem\Directory\WriteInterface', [], [], '', false)
+        );
+
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(
+            [
+                'type' => 'less'
+            ]
+        );
+        $this->assertContains('Successfully processed LESS and/or SASS files', $commandTester->getDisplay());
+    }
+
+    /**
+     * @expectedException \RuntimeException
+     * @expectedExceptionMessage Not enough arguments
+     */
+    public function testExecuteWithoutParameters()
+    {
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute([]);
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage WRONG_LOCALE argument has invalid value format
+     */
+    public function testExecuteWithWrongFormat()
+    {
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(
+            [
+                'type' => 'less',
+                '--locale' => 'WRONG_LOCALE'
+            ]
+        );
+    }
+}
diff --git a/app/code/Magento/Developer/Test/Unit/Console/Command/DevTestsRunCommandTest.php b/app/code/Magento/Developer/Test/Unit/Console/Command/DevTestsRunCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d5db9dc5a65fbeb5e2f3611832ec470c5874205f
--- /dev/null
+++ b/app/code/Magento/Developer/Test/Unit/Console/Command/DevTestsRunCommandTest.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Developer\Test\Unit\Console\Command;
+
+use Magento\Developer\Console\Command\DevTestsRunCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+/**
+ * Class DevTestsRunCommandTest
+ *
+ * Tests dev:tests:run command.  Only tests error case because DevTestsRunCommand calls phpunit with
+ * passthru, so there is no good way to mock out running the tests.
+ */
+class DevTestsRunCommandTest extends \PHPUnit_Framework_TestCase
+{
+
+    /**
+     * @var DevTestsRunCommand
+     */
+    private $command;
+
+    public function setUp()
+    {
+        $this->command = new DevTestsRunCommand();
+    }
+
+    public function testExecuteBadType()
+    {
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute([DevTestsRunCommand::INPUT_ARG_TYPE => 'bad']);
+        $this->assertContains('Invalid type: "bad"', $commandTester->getDisplay());
+    }
+}
diff --git a/app/code/Magento/Developer/etc/adminhtml/system.xml b/app/code/Magento/Developer/etc/adminhtml/system.xml
index f858f6b51bc275787d5b476b42a1a3f62277ec11..13ec5c3a13106fc5820440bb0b7754e6404a5074 100644
--- a/app/code/Magento/Developer/etc/adminhtml/system.xml
+++ b/app/code/Magento/Developer/etc/adminhtml/system.xml
@@ -9,7 +9,7 @@
         <section id="dev" translate="label">
             <group id="front_end_development_workflow" translate="label" type="text" sortOrder="8" showInDefault="1" showInWebsite="1" showInStore="1">
                 <label>Front-end development workflow</label>
-                <field id="type" translate="label comment" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="1">
+                <field id="type" translate="label comment" type="select" sortOrder="1" showInDefault="1" showInWebsite="0" showInStore="0">
                     <label>Workflow type</label>
                     <comment>Not available in production mode</comment>
                     <source_model>Magento\Developer\Model\Config\Source\WorkflowType</source_model>
diff --git a/app/code/Magento/Developer/etc/di.xml b/app/code/Magento/Developer/etc/di.xml
index 1a21f191e09094fc0f9275ddabd632807fbdc1ff..94be2446cc1404c4c37cc2c1a740773ba7ba84f1 100644
--- a/app/code/Magento/Developer/etc/di.xml
+++ b/app/code/Magento/Developer/etc/di.xml
@@ -26,4 +26,12 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\Console\CommandList">
+        <arguments>
+            <argument name="commands" xsi:type="array">
+                <item name="dev_tests_run" xsi:type="object">Magento\Developer\Console\Command\DevTestsRunCommand</item>
+                <item name="dev_css_deploy" xsi:type="object">Magento\Developer\Console\Command\CssDeployCommand</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Directory/Model/Currency.php b/app/code/Magento/Directory/Model/Currency.php
index 9e7d2b9abef186b2f221c94c7ef61007534c81eb..31ab3bf266dd24b8fb1b657731f5b8bcf2c1bda4 100644
--- a/app/code/Magento/Directory/Model/Currency.php
+++ b/app/code/Magento/Directory/Model/Currency.php
@@ -311,6 +311,16 @@ class Currency extends \Magento\Framework\Model\AbstractModel
         return $this->_localeCurrency->getCurrency($this->getCode())->toCurrency($price, $options);
     }
 
+    /**
+     * Return currency symbol for current locale and currency code
+     *
+     * @return string
+     */
+    public function getCurrencySymbol()
+    {
+        return $this->_localeCurrency->getCurrency($this->getCode())->getSymbol();
+    }
+
     /**
      * @return string
      */
diff --git a/app/code/Magento/Directory/Model/PriceCurrency.php b/app/code/Magento/Directory/Model/PriceCurrency.php
index 3aa697742a41687cf66d0e78517afd3549aaac1c..9cf7dabd2de746d5193abe8bbf7b1c1f5662e550 100644
--- a/app/code/Magento/Directory/Model/PriceCurrency.php
+++ b/app/code/Magento/Directory/Model/PriceCurrency.php
@@ -117,6 +117,16 @@ class PriceCurrency implements \Magento\Framework\Pricing\PriceCurrencyInterface
         return $currentCurrency;
     }
 
+    /**
+     * @param null|string|bool|int|\Magento\Framework\App\ScopeInterface $scope
+     * @param \Magento\Framework\Model\AbstractModel|string|null $currency
+     * @return string
+     */
+    public function getCurrencySymbol($scope = null, $currency = null)
+    {
+        return $this->getCurrency($scope, $currency)->getCurrencySymbol();
+    }
+
     /**
      * Get store model
      *
diff --git a/app/code/Magento/Directory/Test/Unit/Model/CurrencyTest.php b/app/code/Magento/Directory/Test/Unit/Model/CurrencyTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..33a312880adc33b16f3c0f2327573b2f08d1ae32
--- /dev/null
+++ b/app/code/Magento/Directory/Test/Unit/Model/CurrencyTest.php
@@ -0,0 +1,55 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Directory\Test\Unit\Model;
+
+use Magento\Directory\Model\Currency;
+
+class CurrencyTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Currency
+     */
+    protected $currency;
+
+    protected $currencyCode = 'USD';
+
+    /**
+     * @var \Magento\Framework\Locale\CurrencyInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $localeCurrencyMock;
+
+    public function setUp()
+    {
+        $this->localeCurrencyMock = $this->getMock('\Magento\Framework\Locale\CurrencyInterface');
+
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->currency = $objectManager->getObject('Magento\Directory\Model\Currency', [
+            'localeCurrency' => $this->localeCurrencyMock,
+            'data' => [
+                'currency_code' => $this->currencyCode,
+            ]
+        ]);
+    }
+
+    public function testGetCurrencySymbol()
+    {
+        $currencySymbol = '$';
+
+        $currencyMock = $this->getMockBuilder('\Magento\Framework\Currency')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $currencyMock->expects($this->once())
+            ->method('getSymbol')
+            ->willReturn($currencySymbol);
+
+        $this->localeCurrencyMock->expects($this->once())
+            ->method('getCurrency')
+            ->with($this->currencyCode)
+            ->willReturn($currencyMock);
+        $this->assertEquals($currencySymbol, $this->currency->getCurrencySymbol());
+    }
+}
diff --git a/app/code/Magento/Directory/Test/Unit/Model/PriceCurrencyTest.php b/app/code/Magento/Directory/Test/Unit/Model/PriceCurrencyTest.php
index 205a63e7b0c33f3ffaa312cf9256ee2607f4aab8..b934435151a040f0f7156c532aecdb85f313e6e8 100644
--- a/app/code/Magento/Directory/Test/Unit/Model/PriceCurrencyTest.php
+++ b/app/code/Magento/Directory/Test/Unit/Model/PriceCurrencyTest.php
@@ -168,6 +168,18 @@ class PriceCurrencyTest extends \PHPUnit_Framework_TestCase
         ));
     }
 
+    public function testGetCurrencySymbol()
+    {
+        $storeId = 2;
+        $currencySymbol = '$';
+
+        $currencyMock = $this->getCurrentCurrencyMock();
+        $currencyMock->expects($this->once())
+            ->method('getCurrencySymbol')
+            ->willReturn($currencySymbol);
+        $this->assertEquals($currencySymbol, $this->priceCurrency->getCurrencySymbol($storeId, $currencyMock));
+    }
+
     protected function getCurrentCurrencyMock()
     {
         $currency = $this->getMockBuilder('Magento\Directory\Model\Currency')
diff --git a/app/code/Magento/Downloadable/Api/Data/LinkContentInterface.php b/app/code/Magento/Downloadable/Api/Data/LinkContentInterface.php
deleted file mode 100644
index 1972068f435512611b3d564f875ec666f6d20b56..0000000000000000000000000000000000000000
--- a/app/code/Magento/Downloadable/Api/Data/LinkContentInterface.php
+++ /dev/null
@@ -1,194 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Downloadable\Api\Data;
-
-/**
- * @codeCoverageIgnore
- */
-interface LinkContentInterface extends \Magento\Framework\Api\ExtensibleDataInterface
-{
-    /**
-     * Retrieve sample title
-     *
-     * @return string
-     */
-    public function getTitle();
-
-    /**
-     * Set sample title
-     *
-     * @param string $title
-     * @return $this
-     */
-    public function setTitle($title);
-
-    /**
-     * Retrieve sample sort order
-     *
-     * @return int
-     */
-    public function getSortOrder();
-
-    /**
-     * Set sample sort order
-     *
-     * @param int $sortOrder
-     * @return $this
-     */
-    public function setSortOrder($sortOrder);
-
-    /**
-     * Retrieve link price
-     *
-     * @return string
-     */
-    public function getPrice();
-
-    /**
-     * Set link price
-     *
-     * @param string $price
-     * @return $this
-     */
-    public function setPrice($price);
-
-    /**
-     * Retrieve number of allowed downloads of the link
-     *
-     * @return int
-     */
-    public function getNumberOfDownloads();
-
-    /**
-     * Set number of allowed downloads of the link
-     *
-     * @param int $numberOfDownloads
-     * @return $this
-     */
-    public function setNumberOfDownloads($numberOfDownloads);
-
-    /**
-     * Check if link is shareable
-     *
-     * @return bool
-     */
-    public function isShareable();
-
-    /**
-     * Set whether link is shareable
-     *
-     * @param bool $shareable
-     * @return $this
-     */
-    public function setShareable($shareable);
-
-    /**
-     * Retrieve link file content
-     *
-     * @return \Magento\Downloadable\Api\Data\File\ContentInterface|null
-     */
-    public function getLinkFile();
-
-    /**
-     * Set link file content
-     *
-     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $linkFile
-     * @return $this
-     */
-    public function setLinkFile(\Magento\Downloadable\Api\Data\File\ContentInterface $linkFile = null);
-
-    /**
-     * Retrieve link URL
-     *
-     * @return string|null
-     */
-    public function getLinkUrl();
-
-    /**
-     * Set link URL
-     *
-     * @param string $linkUrl
-     * @return $this
-     */
-    public function setLinkUrl($linkUrl);
-
-    /**
-     * Retrieve link type ('url' or 'file')
-     *
-     * @return string|null
-     */
-    public function getLinkType();
-
-    /**
-     * Set link type ('url' or 'file')
-     *
-     * @param string $linkType
-     * @return $this
-     */
-    public function setLinkType($linkType);
-
-    /**
-     * Retrieve sample file content
-     *
-     * @return \Magento\Downloadable\Api\Data\File\ContentInterface|null
-     */
-    public function getSampleFile();
-
-    /**
-     * Retrieve sample file content
-     *
-     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $sampleFile
-     * @return $this
-     */
-    public function setSampleFile(\Magento\Downloadable\Api\Data\File\ContentInterface $sampleFile = null);
-
-    /**
-     * Retrieve sample URL
-     *
-     * @return string|null
-     */
-    public function getSampleUrl();
-
-    /**
-     * Set sample URL
-     *
-     * @param string $sampleUrl
-     * @return $this
-     */
-    public function setSampleUrl($sampleUrl);
-
-    /**
-     * Retrieve sample type ('url' or 'file')
-     *
-     * @return string|null
-     */
-    public function getSampleType();
-
-    /**
-     * Set sample type ('url' or 'file')
-     *
-     * @param string $sampleType
-     * @return $this
-     */
-    public function setSampleType($sampleType);
-
-    /**
-     * Retrieve existing extension attributes object or create a new one.
-     *
-     * @return \Magento\Downloadable\Api\Data\LinkContentExtensionInterface|null
-     */
-    public function getExtensionAttributes();
-
-    /**
-     * Set an extension attributes object.
-     *
-     * @param \Magento\Downloadable\Api\Data\LinkContentExtensionInterface $extensionAttributes
-     * @return $this
-     */
-    public function setExtensionAttributes(
-        \Magento\Downloadable\Api\Data\LinkContentExtensionInterface $extensionAttributes
-    );
-}
diff --git a/app/code/Magento/Downloadable/Api/Data/LinkInterface.php b/app/code/Magento/Downloadable/Api/Data/LinkInterface.php
index 0152a1a256540db9b0cab423e2804bd906475245..6fe62e070349e96c265a7d6d5e32da64de0eb976 100644
--- a/app/code/Magento/Downloadable/Api/Data/LinkInterface.php
+++ b/app/code/Magento/Downloadable/Api/Data/LinkInterface.php
@@ -119,9 +119,24 @@ interface LinkInterface extends \Magento\Framework\Api\ExtensibleDataInterface
     public function setLinkFile($linkFile);
 
     /**
-     * Return URL or NULL when type is 'file'
+     * Return file content
      *
-     * @return string|null file URL
+     * @return \Magento\Downloadable\Api\Data\File\ContentInterface|null
+     */
+    public function getLinkFileContent();
+
+    /**
+     * Set file content
+     *
+     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $linkFileContent
+     * @return $this
+     */
+    public function setLinkFileContent(\Magento\Downloadable\Api\Data\File\ContentInterface $linkFileContent = null);
+
+    /**
+     * Return link url or null when type is 'file'
+     *
+     * @return string|null
      */
     public function getLinkUrl();
 
@@ -159,6 +174,23 @@ interface LinkInterface extends \Magento\Framework\Api\ExtensibleDataInterface
      */
     public function setSampleFile($sampleFile);
 
+    /**
+     * Return sample file content when type is 'file'
+     *
+     * @return \Magento\Downloadable\Api\Data\File\ContentInterface|null relative file path
+     */
+    public function getSampleFileContent();
+
+    /**
+     * Set sample file content
+     *
+     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $sampleFileContent
+     * @return $this
+     */
+    public function setSampleFileContent(
+        \Magento\Downloadable\Api\Data\File\ContentInterface $sampleFileContent = null
+    );
+
     /**
      * Return URL or NULL when type is 'file'
      *
diff --git a/app/code/Magento/Downloadable/Api/Data/SampleContentInterface.php b/app/code/Magento/Downloadable/Api/Data/SampleContentInterface.php
deleted file mode 100644
index b4b0580bda1879b6aa75ab70371f6c522b7d1100..0000000000000000000000000000000000000000
--- a/app/code/Magento/Downloadable/Api/Data/SampleContentInterface.php
+++ /dev/null
@@ -1,104 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Downloadable\Api\Data;
-
-/**
- * @codeCoverageIgnore
- */
-interface SampleContentInterface extends \Magento\Framework\Api\ExtensibleDataInterface
-{
-    /**
-     * Retrieve sample title
-     *
-     * @return string
-     */
-    public function getTitle();
-
-    /**
-     * Set sample title
-     *
-     * @param string $title
-     * @return $this
-     */
-    public function setTitle($title);
-
-    /**
-     * Retrieve sample type ('url' or 'file')
-     *
-     * @return string|null
-     */
-    public function getSampleType();
-
-    /**
-     * Set sample type ('url' or 'file')
-     *
-     * @param string $sampleType
-     * @return $this
-     */
-    public function setSampleType($sampleType);
-
-    /**
-     * Retrieve sample file content
-     *
-     * @return \Magento\Downloadable\Api\Data\File\ContentInterface|null
-     */
-    public function getSampleFile();
-
-    /**
-     * Set sample file content
-     *
-     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $sampleFile
-     * @return $this
-     */
-    public function setSampleFile(\Magento\Downloadable\Api\Data\File\ContentInterface $sampleFile = null);
-
-    /**
-     * Retrieve sample sort order
-     *
-     * @return int
-     */
-    public function getSortOrder();
-
-    /**
-     * Set sample sort order
-     *
-     * @param int $sortOrder
-     * @return $this
-     */
-    public function setSortOrder($sortOrder);
-
-    /**
-     * Retrieve sample URL
-     *
-     * @return string|null
-     */
-    public function getSampleUrl();
-
-    /**
-     * Set sample URL
-     *
-     * @param string $sampleUrl
-     * @return $this
-     */
-    public function setSampleUrl($sampleUrl);
-
-    /**
-     * Retrieve existing extension attributes object or create a new one.
-     *
-     * @return \Magento\Downloadable\Api\Data\SampleContentExtensionInterface|null
-     */
-    public function getExtensionAttributes();
-
-    /**
-     * Set an extension attributes object.
-     *
-     * @param \Magento\Downloadable\Api\Data\SampleContentExtensionInterface $extensionAttributes
-     * @return $this
-     */
-    public function setExtensionAttributes(
-        \Magento\Downloadable\Api\Data\SampleContentExtensionInterface $extensionAttributes
-    );
-}
diff --git a/app/code/Magento/Downloadable/Api/Data/SampleInterface.php b/app/code/Magento/Downloadable/Api/Data/SampleInterface.php
index 3d6dfc937f3871a4a489e43c1f1912c5a7498082..8e30bf6f0e1ea0f3fc8bcf78b4261696e6119106 100644
--- a/app/code/Magento/Downloadable/Api/Data/SampleInterface.php
+++ b/app/code/Magento/Downloadable/Api/Data/SampleInterface.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Downloadable\Api\Data;
 
+use \Magento\Downloadable\Api\Data\File\ContentInterface;
+
 /**
  * @codeCoverageIgnore
  */
@@ -82,6 +84,21 @@ interface SampleInterface extends \Magento\Framework\Api\ExtensibleDataInterface
      */
     public function setSampleFile($sampleFile);
 
+    /**
+     * Retrieve sample file content
+     *
+     * @return \Magento\Downloadable\Api\Data\File\ContentInterface|null
+     */
+    public function getSampleFileContent();
+
+    /**
+     * Set sample file content
+     *
+     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $sampleFileContent
+     * @return $this
+     */
+    public function setSampleFileContent(ContentInterface $sampleFileContent = null);
+
     /**
      * Return URL or NULL when type is 'file'
      *
diff --git a/app/code/Magento/Downloadable/Api/LinkRepositoryInterface.php b/app/code/Magento/Downloadable/Api/LinkRepositoryInterface.php
index a8bd6f83d9be190834e0e92d34c039010a4d870c..3a0d8053e4f8d599af652e83d830ad6c7ead7b65 100644
--- a/app/code/Magento/Downloadable/Api/LinkRepositoryInterface.php
+++ b/app/code/Magento/Downloadable/Api/LinkRepositoryInterface.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Downloadable\Api;
 
-use Magento\Downloadable\Api\Data\LinkContentInterface;
+use Magento\Downloadable\Api\Data\LinkInterface;
 
 interface LinkRepositoryInterface
 {
@@ -17,6 +17,14 @@ interface LinkRepositoryInterface
      */
     public function getSamples($sku);
 
+    /**
+     * List of samples for downloadable product
+     *
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @return \Magento\Downloadable\Api\Data\SampleInterface[]
+     */
+    public function getSamplesByProduct(\Magento\Catalog\Api\Data\ProductInterface $product);
+
     /**
      * List of links with associated samples
      *
@@ -25,22 +33,29 @@ interface LinkRepositoryInterface
      */
     public function getLinks($sku);
 
+    /**
+     * List of links with associated samples
+     *
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @return \Magento\Downloadable\Api\Data\LinkInterface[]
+     */
+    public function getLinksByProduct(\Magento\Catalog\Api\Data\ProductInterface $product);
+
     /**
      * Update downloadable link of the given product (link type and its resources cannot be changed)
      *
      * @param string $sku
-     * @param \Magento\Downloadable\Api\Data\LinkContentInterface $linkContent
-     * @param int $linkId
+     * @param \Magento\Downloadable\Api\Data\LinkInterface $link
      * @param bool $isGlobalScopeContent
      * @return int
      */
-    public function save($sku, LinkContentInterface $linkContent, $linkId = null, $isGlobalScopeContent = false);
+    public function save($sku, LinkInterface $link, $isGlobalScopeContent = false);
 
     /**
      * Delete downloadable link
      *
-     * @param int $linkId
+     * @param int $id
      * @return bool
      */
-    public function delete($linkId);
+    public function delete($id);
 }
diff --git a/app/code/Magento/Downloadable/Api/SampleRepositoryInterface.php b/app/code/Magento/Downloadable/Api/SampleRepositoryInterface.php
index cd72680b21bae5b75bd3b245d5a867ebd8e7f168..9a52cea8819f4e413e8c5a1964e5732e5936ed6f 100644
--- a/app/code/Magento/Downloadable/Api/SampleRepositoryInterface.php
+++ b/app/code/Magento/Downloadable/Api/SampleRepositoryInterface.php
@@ -5,31 +5,29 @@
  */
 namespace Magento\Downloadable\Api;
 
-use Magento\Downloadable\Api\Data\SampleContentInterface;
+use Magento\Downloadable\Api\Data\SampleInterface;
 
 interface SampleRepositoryInterface
 {
     /**
-     * Update downloadable sample of the given product (sample type and its resource cannot be changed)
+     * Update downloadable sample of the given product
      *
-     * @param string $productSku
-     * @param \Magento\Downloadable\Api\Data\SampleContentInterface $sampleContent
-     * @param int $sampleId
+     * @param string $sku
+     * @param \Magento\Downloadable\Api\Data\SampleInterface $sample
      * @param bool $isGlobalScopeContent
      * @return int
      */
     public function save(
-        $productSku,
-        SampleContentInterface $sampleContent,
-        $sampleId = null,
+        $sku,
+        SampleInterface $sample,
         $isGlobalScopeContent = false
     );
 
     /**
      * Delete downloadable sample
      *
-     * @param int $sampleId
+     * @param int $id
      * @return bool
      */
-    public function delete($sampleId);
+    public function delete($id);
 }
diff --git a/app/code/Magento/Downloadable/Model/Link.php b/app/code/Magento/Downloadable/Model/Link.php
index 84de54915ab0edec47b492ac19a2fde4f5d131b4..66703a9dccb811ce294d5c4b39b053db7ec07cc2 100644
--- a/app/code/Magento/Downloadable/Model/Link.php
+++ b/app/code/Magento/Downloadable/Model/Link.php
@@ -43,9 +43,11 @@ class Link extends \Magento\Framework\Model\AbstractExtensibleModel implements C
     const KEY_NUMBER_OF_DOWNLOADS = 'number_of_downloads';
     const KEY_LINK_TYPE = 'link_type';
     const KEY_LINK_FILE = 'link_file';
+    const KEY_LINK_FILE_CONTENT = 'link_file_content';
     const KEY_LINK_URL = 'link_url';
     const KEY_SAMPLE_TYPE = 'sample_type';
     const KEY_SAMPLE_FILE = 'sample_file';
+    const KEY_SAMPLE_FILE_CONTENT = 'sample_file_content';
     const KEY_SAMPLE_URL = 'sample_url';
     /**#@-*/
 
@@ -213,6 +215,16 @@ class Link extends \Magento\Framework\Model\AbstractExtensibleModel implements C
         return $this->getData(self::KEY_LINK_FILE);
     }
 
+    /**
+     * Return file content
+     *
+     * @return \Magento\Downloadable\Api\Data\File\ContentInterface|null
+     */
+    public function getLinkFileContent()
+    {
+        return $this->getData(self::KEY_LINK_FILE_CONTENT);
+    }
+
     /**
      * {@inheritdoc}
      * @codeCoverageIgnore
@@ -240,6 +252,16 @@ class Link extends \Magento\Framework\Model\AbstractExtensibleModel implements C
         return $this->getData(self::KEY_SAMPLE_FILE);
     }
 
+    /**
+     * Return sample file content when type is 'file'
+     *
+     * @return \Magento\Downloadable\Api\Data\File\ContentInterface|null relative file path
+     */
+    public function getSampleFileContent()
+    {
+        return $this->getData(self::KEY_SAMPLE_FILE_CONTENT);
+    }
+
     /**
      * {@inheritdoc}
      * @codeCoverageIgnore
@@ -320,6 +342,17 @@ class Link extends \Magento\Framework\Model\AbstractExtensibleModel implements C
         return $this->setData(self::KEY_LINK_FILE, $linkFile);
     }
 
+    /**
+     * Set file content
+     *
+     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $linkFileContent
+     * @return $this
+     */
+    public function setLinkFileContent(\Magento\Downloadable\Api\Data\File\ContentInterface $linkFileContent = null)
+    {
+        return $this->setData(self::KEY_LINK_FILE_CONTENT, $linkFileContent);
+    }
+
     /**
      * Set URL
      *
@@ -351,6 +384,19 @@ class Link extends \Magento\Framework\Model\AbstractExtensibleModel implements C
         return $this->setData(self::KEY_SAMPLE_FILE, $sampleFile);
     }
 
+    /**
+     * Set sample file content
+     *
+     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $sampleFileContent
+     * @return $this
+     */
+    public function setSampleFileContent(
+        \Magento\Downloadable\Api\Data\File\ContentInterface $sampleFileContent = null
+    ) {
+        return $this->setData(self::KEY_SAMPLE_FILE_CONTENT, $sampleFileContent);
+    }
+
+
     /**
      * Set URL
      *
diff --git a/app/code/Magento/Downloadable/Model/Link/Content.php b/app/code/Magento/Downloadable/Model/Link/Content.php
deleted file mode 100644
index a40f76faf1cff5c353a8406943c9b51b4f95e428..0000000000000000000000000000000000000000
--- a/app/code/Magento/Downloadable/Model/Link/Content.php
+++ /dev/null
@@ -1,268 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Downloadable\Model\Link;
-
-use Magento\Downloadable\Api\Data\LinkContentInterface;
-
-/**
- * @codeCoverageIgnore
- */
-class Content extends \Magento\Framework\Model\AbstractExtensibleModel implements LinkContentInterface
-{
-    const TITLE = 'title';
-    const PRICE = 'price';
-    const NUMBER_OF_DOWNLOADS = 'number_of_downloads';
-    const SHAREABLE = 'shareable';
-    const SORT_ORDER = 'sort_order';
-    const LINK_FILE = 'link_file';
-    const LINK_URL = 'link_url';
-    const LINK_TYPE = 'link_type';
-    const SAMPLE_FILE = 'sample_file';
-    const SAMPLE_URL = 'sample_url';
-    const SAMPLE_TYPE = 'sample_type';
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getTitle()
-    {
-        return $this->getData(self::TITLE);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getSortOrder()
-    {
-        return $this->getData(self::SORT_ORDER);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getPrice()
-    {
-        return $this->getData(self::PRICE);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getNumberOfDownloads()
-    {
-        return $this->getData(self::NUMBER_OF_DOWNLOADS);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function isShareable()
-    {
-        return $this->getData(self::SHAREABLE);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getLinkFile()
-    {
-        return $this->getData(self::LINK_FILE);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getLinkUrl()
-    {
-        return $this->getData(self::LINK_URL);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getLinkType()
-    {
-        return $this->getData(self::LINK_TYPE);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getSampleFile()
-    {
-        return $this->getData(self::SAMPLE_FILE);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getSampleUrl()
-    {
-        return $this->getData(self::SAMPLE_URL);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getSampleType()
-    {
-        return $this->getData(self::SAMPLE_TYPE);
-    }
-
-    /**
-     * Set sample title
-     *
-     * @param string $title
-     * @return $this
-     */
-    public function setTitle($title)
-    {
-        return $this->setData(self::TITLE, $title);
-    }
-
-    /**
-     * Set sample sort order
-     *
-     * @param int $sortOrder
-     * @return $this
-     */
-    public function setSortOrder($sortOrder)
-    {
-        return $this->setData(self::SORT_ORDER, $sortOrder);
-    }
-
-    /**
-     * Set link price
-     *
-     * @param string $price
-     * @return $this
-     */
-    public function setPrice($price)
-    {
-        return $this->setData(self::PRICE, $price);
-    }
-
-    /**
-     * Set number of allowed downloads of the link
-     *
-     * @param int $numberOfDownloads
-     * @return $this
-     */
-    public function setNumberOfDownloads($numberOfDownloads)
-    {
-        return $this->setData(self::NUMBER_OF_DOWNLOADS, $numberOfDownloads);
-    }
-
-    /**
-     * Set whether link is shareable
-     *
-     * @param bool $shareable
-     * @return $this
-     */
-    public function setShareable($shareable)
-    {
-        return $this->setData(self::SHAREABLE, $shareable);
-    }
-
-    /**
-     * Set link file content
-     *
-     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $linkFile
-     * @return $this
-     */
-    public function setLinkFile(\Magento\Downloadable\Api\Data\File\ContentInterface $linkFile = null)
-    {
-        return $this->setData(self::LINK_FILE, $linkFile);
-    }
-
-    /**
-     * Set link URL
-     *
-     * @param string $linkUrl
-     * @return $this
-     */
-    public function setLinkUrl($linkUrl)
-    {
-        return $this->setData(self::LINK_URL, $linkUrl);
-    }
-
-    /**
-     * Set link type ('url' or 'file')
-     *
-     * @param string $linkType
-     * @return $this
-     */
-    public function setLinkType($linkType)
-    {
-        return $this->setData(self::LINK_TYPE, $linkType);
-    }
-
-    /**
-     * Retrieve sample file content
-     *
-     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $sampleFile
-     * @return $this
-     */
-    public function setSampleFile(\Magento\Downloadable\Api\Data\File\ContentInterface $sampleFile = null)
-    {
-        return $this->setData(self::SAMPLE_FILE, $sampleFile);
-    }
-
-    /**
-     * Set sample URL
-     *
-     * @param string $sampleUrl
-     * @return $this
-     */
-    public function setSampleUrl($sampleUrl)
-    {
-        return $this->setData(self::SAMPLE_URL, $sampleUrl);
-    }
-
-    /**
-     * Set sample type ('url' or 'file')
-     *
-     * @param string $sampleType
-     * @return $this
-     */
-    public function setSampleType($sampleType)
-    {
-        return $this->setData(self::SAMPLE_TYPE, $sampleType);
-    }
-
-    /**
-     * {@inheritdoc}
-     *
-     * @return \Magento\Downloadable\Api\Data\LinkContentExtensionInterface|null
-     */
-    public function getExtensionAttributes()
-    {
-        return $this->_getExtensionAttributes();
-    }
-
-    /**
-     * {@inheritdoc}
-     *
-     * @param \Magento\Downloadable\Api\Data\LinkContentExtensionInterface $extensionAttributes
-     * @return $this
-     */
-    public function setExtensionAttributes(
-        \Magento\Downloadable\Api\Data\LinkContentExtensionInterface $extensionAttributes
-    ) {
-        return $this->_setExtensionAttributes($extensionAttributes);
-    }
-}
diff --git a/app/code/Magento/Downloadable/Model/Link/ContentValidator.php b/app/code/Magento/Downloadable/Model/Link/ContentValidator.php
index 708302b7871c21c7bd1921b7a522019cbcd25aef..f1bf1d2dcbe85f819a0af7091d8806bee9cdcc12 100644
--- a/app/code/Magento/Downloadable/Model/Link/ContentValidator.php
+++ b/app/code/Magento/Downloadable/Model/Link/ContentValidator.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Downloadable\Model\Link;
 
-use Magento\Downloadable\Api\Data\LinkContentInterface;
+use Magento\Downloadable\Api\Data\LinkInterface;
 use Magento\Downloadable\Model\File\ContentValidator as FileContentValidator;
 use Magento\Framework\Exception\InputException;
 use Magento\Framework\Url\Validator as UrlValidator;
@@ -37,43 +37,50 @@ class ContentValidator
     /**
      * Check if link content is valid
      *
-     * @param LinkContentInterface $linkContent
+     * @param LinkInterface $link
+     * @param bool $validateLinkContent
+     * @param bool $validateSampleContent
      * @return bool
      * @throws InputException
      */
-    public function isValid(LinkContentInterface $linkContent)
+    public function isValid(LinkInterface $link, $validateLinkContent = true, $validateSampleContent = true)
     {
-        if (!is_numeric($linkContent->getPrice()) || $linkContent->getPrice() < 0) {
+        if (!is_numeric($link->getPrice()) || $link->getPrice() < 0) {
             throw new InputException(__('Link price must have numeric positive value.'));
         }
-        if (!is_int($linkContent->getNumberOfDownloads()) || $linkContent->getNumberOfDownloads() < 0) {
+        if (!is_int($link->getNumberOfDownloads()) || $link->getNumberOfDownloads() < 0) {
             throw new InputException(__('Number of downloads must be a positive integer.'));
         }
-        if (!is_int($linkContent->getSortOrder()) || $linkContent->getSortOrder() < 0) {
+        if (!is_int($link->getSortOrder()) || $link->getSortOrder() < 0) {
             throw new InputException(__('Sort order must be a positive integer.'));
         }
 
-        $this->validateLinkResource($linkContent);
-        $this->validateSampleResource($linkContent);
+        if ($validateLinkContent) {
+            $this->validateLinkResource($link);
+        }
+        if ($validateSampleContent) {
+            $this->validateSampleResource($link);
+        }
         return true;
     }
 
     /**
      * Validate link resource (file or URL)
      *
-     * @param LinkContentInterface $linkContent
+     * @param LinkInterface $link
      * @throws InputException
      * @return void
      */
-    protected function validateLinkResource(LinkContentInterface $linkContent)
+    protected function validateLinkResource(LinkInterface $link)
     {
-        if ($linkContent->getLinkType() == 'url'
-            && !$this->urlValidator->isValid($linkContent->getLinkUrl())
+        if ($link->getLinkType() == 'url'
+            && !$this->urlValidator->isValid($link->getLinkUrl())
         ) {
             throw new InputException(__('Link URL must have valid format.'));
         }
-        if ($linkContent->getLinkType() == 'file'
-            && (!$linkContent->getLinkFile() || !$this->fileContentValidator->isValid($linkContent->getLinkFile()))
+        if ($link->getLinkType() == 'file'
+            && (!$link->getLinkFileContent()
+                || !$this->fileContentValidator->isValid($link->getLinkFileContent()))
         ) {
             throw new InputException(__('Provided file content must be valid base64 encoded data.'));
         }
@@ -82,19 +89,20 @@ class ContentValidator
     /**
      * Validate sample resource (file or URL)
      *
-     * @param LinkContentInterface $linkContent
+     * @param LinkInterface $link
      * @throws InputException
      * @return void
      */
-    protected function validateSampleResource(LinkContentInterface $linkContent)
+    protected function validateSampleResource(LinkInterface $link)
     {
-        if ($linkContent->getSampleType() == 'url'
-            && !$this->urlValidator->isValid($linkContent->getSampleUrl())
+        if ($link->getSampleType() == 'url'
+            && !$this->urlValidator->isValid($link->getSampleUrl())
         ) {
             throw new InputException(__('Sample URL must have valid format.'));
         }
-        if ($linkContent->getSampleType() == 'file'
-            && (!$linkContent->getSampleFile() || !$this->fileContentValidator->isValid($linkContent->getSampleFile()))
+        if ($link->getSampleType() == 'file'
+            && (!$link->getSampleFileContent()
+                || !$this->fileContentValidator->isValid($link->getSampleFileContent()))
         ) {
             throw new InputException(__('Provided file content must be valid base64 encoded data.'));
         }
diff --git a/app/code/Magento/Downloadable/Model/LinkRepository.php b/app/code/Magento/Downloadable/Model/LinkRepository.php
index 426e8bf63f21ed644dae4394470c8bf71d6482b4..bca06682ba718dee04cdd59e0edbfc275cc18efb 100644
--- a/app/code/Magento/Downloadable/Model/LinkRepository.php
+++ b/app/code/Magento/Downloadable/Model/LinkRepository.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Downloadable\Model;
 
-use Magento\Downloadable\Api\Data\LinkContentInterface;
+use Magento\Downloadable\Api\Data\LinkInterface;
 use Magento\Downloadable\Api\Data\File\ContentUploaderInterface;
 use Magento\Framework\Exception\InputException;
 use Magento\Framework\Exception\NoSuchEntityException;
@@ -92,9 +92,18 @@ class LinkRepository implements \Magento\Downloadable\Api\LinkRepositoryInterfac
      */
     public function getLinks($sku)
     {
-        $linkList = [];
         /** @var \Magento\Catalog\Model\Product $product */
         $product = $this->productRepository->get($sku);
+        return $this->getLinksByProduct($product);
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @return array
+     */
+    public function getLinksByProduct(\Magento\Catalog\Api\Data\ProductInterface $product)
+    {
+        $linkList = [];
         $links = $this->downloadableType->getLinks($product);
         /** @var \Magento\Downloadable\Model\Link $link */
         foreach ($links as $link) {
@@ -152,9 +161,17 @@ class LinkRepository implements \Magento\Downloadable\Api\LinkRepositoryInterfac
      */
     public function getSamples($sku)
     {
-        $sampleList = [];
-        /** @var \Magento\Catalog\Model\Product $product */
         $product = $this->productRepository->get($sku);
+        return $this->getSamplesByProduct($product);
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @return array
+     */
+    public function getSamplesByProduct(\Magento\Catalog\Api\Data\ProductInterface $product)
+    {
+        $sampleList = [];
         $samples = $this->downloadableType->getSamples($product);
         /** @var \Magento\Downloadable\Model\Sample $sample */
         foreach ($samples as $sample) {
@@ -181,113 +198,149 @@ class LinkRepository implements \Magento\Downloadable\Api\LinkRepositoryInterfac
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      * @SuppressWarnings(PHPMD.NPathComplexity)
      */
-    public function save($sku, LinkContentInterface $linkContent, $linkId = null, $isGlobalScopeContent = false)
+    public function save($sku, LinkInterface $link, $isGlobalScopeContent = false)
     {
         $product = $this->productRepository->get($sku, true);
-        if ($linkId) {
-
-            /** @var $link \Magento\Downloadable\Model\Link */
-            $link = $this->linkFactory->create()->load($linkId);
-            if (!$link->getId()) {
-                throw new NoSuchEntityException(__('There is no downloadable link with provided ID.'));
-            }
-            if ($link->getProductId() != $product->getId()) {
-                throw new InputException(__('Provided downloadable link is not related to given product.'));
-            }
-            if (!$this->contentValidator->isValid($linkContent)) {
-                throw new InputException(__('Provided link information is invalid.'));
-            }
-            if ($isGlobalScopeContent) {
-                $product->setStoreId(0);
-            }
-            $title = $linkContent->getTitle();
-            if (empty($title)) {
-                if ($isGlobalScopeContent) {
-                    throw new InputException(__('Link title cannot be empty.'));
-                }
-                // use title from GLOBAL scope
-                $link->setTitle(null);
-            } else {
-                $link->setTitle($linkContent->getTitle());
-            }
-
-            $link->setProductId($product->getId())
-                ->setStoreId($product->getStoreId())
-                ->setWebsiteId($product->getStore()->getWebsiteId())
-                ->setProductWebsiteIds($product->getWebsiteIds())
-                ->setSortOrder($linkContent->getSortOrder())
-                ->setPrice($linkContent->getPrice())
-                ->setIsShareable($linkContent->isShareable())
-                ->setNumberOfDownloads($linkContent->getNumberOfDownloads())
-                ->save();
-            return $link->getId();
+        if ($link->getId() !== null) {
+            return $this->updateLink($product, $link, $isGlobalScopeContent);
         } else {
-            $product = $this->productRepository->get($sku, true);
             if ($product->getTypeId() !== \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE) {
                 throw new InputException(__('Product type of the product must be \'downloadable\'.'));
             }
-            if (!$this->contentValidator->isValid($linkContent)) {
+            if (!$this->contentValidator->isValid($link)) {
                 throw new InputException(__('Provided link information is invalid.'));
             }
 
-            if (!in_array($linkContent->getLinkType(), ['url', 'file'])) {
+            if (!in_array($link->getLinkType(), ['url', 'file'])) {
                 throw new InputException(__('Invalid link type.'));
             }
-            $title = $linkContent->getTitle();
+            $title = $link->getTitle();
             if (empty($title)) {
                 throw new InputException(__('Link title cannot be empty.'));
             }
+            return $this->saveLink($product, $link, $isGlobalScopeContent);
+        }
+    }
 
-            $linkData = [
-                'link_id' => 0,
-                'is_delete' => 0,
-                'type' => $linkContent->getLinkType(),
-                'sort_order' => $linkContent->getSortOrder(),
-                'title' => $linkContent->getTitle(),
-                'price' => $linkContent->getPrice(),
-                'number_of_downloads' => $linkContent->getNumberOfDownloads(),
-                'is_shareable' => $linkContent->isShareable(),
-            ];
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param LinkInterface $link
+     * @param bool $isGlobalScopeContent
+     * @return int
+     */
+    protected function saveLink(
+        \Magento\Catalog\Api\Data\ProductInterface $product,
+        LinkInterface $link,
+        $isGlobalScopeContent
+    ) {
+        $linkData = [
+            'link_id' => $link->getid() === null ? 0 : $link->getid(),
+            'is_delete' => 0,
+            'type' => $link->getLinkType(),
+            'sort_order' => $link->getSortOrder(),
+            'title' => $link->getTitle(),
+            'price' => $link->getPrice(),
+            'number_of_downloads' => $link->getNumberOfDownloads(),
+            'is_shareable' => $link->getIsShareable(),
+        ];
 
-            if ($linkContent->getLinkType() == 'file') {
-                $linkData['file'] = $this->jsonEncoder->encode(
+        if ($link->getLinkType() == 'file' && $link->getLinkFile() === null) {
+            $linkData['file'] = $this->jsonEncoder->encode(
+                [
+                    $this->fileContentUploader->upload($link->getLinkFileContent(), 'link_file'),
+                ]
+            );
+        } elseif ($link->getLinkType() === 'url') {
+            $linkData['link_url'] = $link->getLinkUrl();
+        } else {
+            //existing link file
+            $linkData['file'] = $this->jsonEncoder->encode(
+                [
                     [
-                        $this->fileContentUploader->upload($linkContent->getLinkFile(), 'link_file'),
+                        'file' => $link->getLinkFile(),
+                        'status' => 'old',
                     ]
-                );
-            } else {
-                $linkData['link_url'] = $linkContent->getLinkUrl();
-            }
+                ]
+            );
+        }
 
-            if ($linkContent->getSampleType() == 'file') {
-                $linkData['sample']['type'] = 'file';
-                $linkData['sample']['file'] = $this->jsonEncoder->encode(
-                    [
-                        $this->fileContentUploader->upload($linkContent->getSampleFile(), 'link_sample_file'),
-                    ]
-                );
-            } elseif ($linkContent->getSampleType() == 'url') {
-                $linkData['sample']['type'] = 'url';
-                $linkData['sample']['url'] = $linkContent->getSampleUrl();
-            }
+        if ($link->getSampleType() == 'file' && $link->getSampleFile() === null) {
+            $linkData['sample']['type'] = 'file';
+            $linkData['sample']['file'] = $this->jsonEncoder->encode(
+                [
+                    $this->fileContentUploader->upload($link->getSampleFileContent(), 'link_sample_file'),
+                ]
+            );
+        } elseif ($link->getSampleType() == 'url') {
+            $linkData['sample']['type'] = 'url';
+            $linkData['sample']['url'] = $link->getSampleUrl();
+        }
 
-            $downloadableData = ['link' => [$linkData]];
-            $product->setDownloadableData($downloadableData);
+        $downloadableData = ['link' => [$linkData]];
+        $product->setDownloadableData($downloadableData);
+        if ($isGlobalScopeContent) {
+            $product->setStoreId(0);
+        }
+        $this->downloadableType->save($product);
+        return $product->getLastAddedLinkId();
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param LinkInterface $link
+     * @param bool $isGlobalScopeContent
+     * @return mixed
+     * @throws InputException
+     * @throws NoSuchEntityException
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     */
+    protected function updateLink(
+        \Magento\Catalog\Api\Data\ProductInterface $product,
+        LinkInterface $link,
+        $isGlobalScopeContent
+    ) {
+        /** @var $existingLink \Magento\Downloadable\Model\Link */
+        $existingLink = $this->linkFactory->create()->load($link->getId());
+        if (!$existingLink->getId()) {
+            throw new NoSuchEntityException(__('There is no downloadable link with provided ID.'));
+        }
+        if ($existingLink->getProductId() != $product->getId()) {
+            throw new InputException(__('Provided downloadable link is not related to given product.'));
+        }
+        $validateLinkContent = $link->getLinkFileContent() === null ? false : true;
+        $validateSampleContent = $link->getSampleFileContent() === null ? false : true;
+        if (!$this->contentValidator->isValid($link, $validateLinkContent, $validateSampleContent)) {
+            throw new InputException(__('Provided link information is invalid.'));
+        }
+        if ($isGlobalScopeContent) {
+            $product->setStoreId(0);
+        }
+        $title = $link->getTitle();
+        if (empty($title)) {
             if ($isGlobalScopeContent) {
-                $product->setStoreId(0);
+                throw new InputException(__('Link title cannot be empty.'));
             }
-            $product->save();
-            return $product->getLastAddedLinkId();
         }
+
+        if ($link->getLinkType() == 'file' && $link->getLinkFileContent() === null) {
+            $link->setLinkFile($existingLink->getLinkFile());
+        }
+        if ($link->getSampleType() == 'file' && $link->getSampleFileContent() === null) {
+            $link->setSampleFile($existingLink->getSampleFile());
+        }
+
+        $this->saveLink($product, $link, $isGlobalScopeContent);
+        return $existingLink->getId();
     }
 
     /**
      * {@inheritdoc}
      */
-    public function delete($linkId)
+    public function delete($id)
     {
         /** @var $link \Magento\Downloadable\Model\Link */
-        $link = $this->linkFactory->create()->load($linkId);
+        $link = $this->linkFactory->create()->load($id);
         if (!$link->getId()) {
             throw new NoSuchEntityException(__('There is no downloadable link with provided ID.'));
         }
diff --git a/app/code/Magento/Downloadable/Model/Observer.php b/app/code/Magento/Downloadable/Model/Observer.php
index 0fd516bfa9fafc120ee467f52725eb0e974de334..68dc8f018d7f00aef5a9556f6622d518bb924142 100644
--- a/app/code/Magento/Downloadable/Model/Observer.php
+++ b/app/code/Magento/Downloadable/Model/Observer.php
@@ -114,10 +114,10 @@ class Observer
             //order not saved in the database
             return $this;
         }
-        $product = $orderItem->getProduct();
-        if ($product && $product->getTypeId() != \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE) {
+        if ($orderItem->getProductType() != \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE) {
             return $this;
         }
+        $product = $orderItem->getProduct();
         $purchasedLink = $this->_createPurchasedModel()->load($orderItem->getId(), 'order_item_id');
         if ($purchasedLink->getId()) {
             return $this;
diff --git a/app/code/Magento/Downloadable/Model/Plugin/AfterProductLoad.php b/app/code/Magento/Downloadable/Model/Plugin/AfterProductLoad.php
new file mode 100644
index 0000000000000000000000000000000000000000..83466a0fa080f34d7aa3d38fbcfd0fd8905d1101
--- /dev/null
+++ b/app/code/Magento/Downloadable/Model/Plugin/AfterProductLoad.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Downloadable\Model\Plugin;
+
+class AfterProductLoad
+{
+    /**
+     * @var \Magento\Downloadable\Api\LinkRepositoryInterface
+     */
+    protected $linkRepository;
+
+    /**
+     * @var \Magento\Catalog\Api\Data\ProductExtensionFactory
+     */
+    protected $productExtensionFactory;
+
+    /**
+     * @param \Magento\Downloadable\Api\LinkRepositoryInterface $linkRepository
+     * @param \Magento\Catalog\Api\Data\ProductExtensionFactory $productExtensionFactory
+     */
+    public function __construct(
+        \Magento\Downloadable\Api\LinkRepositoryInterface $linkRepository,
+        \Magento\Catalog\Api\Data\ProductExtensionFactory $productExtensionFactory
+    ) {
+        $this->linkRepository = $linkRepository;
+        $this->productExtensionFactory = $productExtensionFactory;
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $product
+     * @return \Magento\Catalog\Model\Product
+     */
+    public function afterLoad(
+        \Magento\Catalog\Model\Product $product
+    ) {
+        if ($product->getTypeId() != \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE) {
+            return $product;
+        }
+
+        $productExtension = $product->getExtensionAttributes();
+        if ($productExtension === null) {
+            $productExtension = $this->productExtensionFactory->create();
+        }
+        $links = $this->linkRepository->getLinksByProduct($product);
+        if ($links !== null) {
+            $productExtension->setDownloadableProductLinks($links);
+        }
+        $samples = $this->linkRepository->getSamplesByProduct($product);
+        if ($samples !== null) {
+            $productExtension->setDownloadableProductSamples($samples);
+        }
+
+        $product->setExtensionAttributes($productExtension);
+
+        return $product;
+    }
+}
diff --git a/app/code/Magento/Downloadable/Model/Plugin/AroundProductRepositorySave.php b/app/code/Magento/Downloadable/Model/Plugin/AroundProductRepositorySave.php
new file mode 100644
index 0000000000000000000000000000000000000000..13dd932c3a7683109c4fcef022556abb0dbfa519
--- /dev/null
+++ b/app/code/Magento/Downloadable/Model/Plugin/AroundProductRepositorySave.php
@@ -0,0 +1,145 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Downloadable\Model\Plugin;
+
+class AroundProductRepositorySave
+{
+    /**
+     * @var \Magento\Downloadable\Api\LinkRepositoryInterface
+     */
+    protected $linkRepository;
+
+    /**
+     * @var \Magento\Downloadable\Api\SampleRepositoryInterface
+     */
+    protected $sampleRepository;
+
+    /**
+     * @param \Magento\Downloadable\Api\LinkRepositoryInterface $linkRepository
+     * @param \Magento\Downloadable\Api\SampleRepositoryInterface $sampleRepository
+     */
+    public function __construct(
+        \Magento\Downloadable\Api\LinkRepositoryInterface $linkRepository,
+        \Magento\Downloadable\Api\SampleRepositoryInterface $sampleRepository
+    ) {
+        $this->linkRepository = $linkRepository;
+        $this->sampleRepository = $sampleRepository;
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\ProductRepositoryInterface $subject
+     * @param callable $proceed
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param bool $saveOptions
+     * @return \Magento\Catalog\Api\Data\ProductInterface
+     * @throws \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function aroundSave(
+        \Magento\Catalog\Api\ProductRepositoryInterface $subject,
+        \Closure $proceed,
+        \Magento\Catalog\Api\Data\ProductInterface $product,
+        $saveOptions = false
+    ) {
+        /** @var \Magento\Catalog\Api\Data\ProductInterface $result */
+        $result = $proceed($product, $saveOptions);
+
+        if ($product->getTypeId() != \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE) {
+            return $result;
+        }
+
+        /* @var \Magento\Catalog\Api\Data\ProductExtensionInterface $options */
+        $extendedAttributes = $product->getExtensionAttributes();
+        if ($extendedAttributes === null) {
+            return $result;
+        }
+        $links = $extendedAttributes->getDownloadableProductLinks();
+        $samples = $extendedAttributes->getDownloadableProductSamples();
+
+        if ($links === null && $samples === null) {
+            return $result;
+        }
+
+        if ($links !== null) {
+            $this->saveLinks($result, $links);
+        }
+        if ($samples !== null) {
+            $this->saveSamples($result, $samples);
+        }
+
+        return $subject->get($result->getSku(), false, $result->getStoreId(), true);
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param \Magento\Downloadable\Api\Data\LinkInterface[] $links
+     * @return $this
+     */
+    protected function saveLinks(\Magento\Catalog\Api\Data\ProductInterface $product, array $links)
+    {
+        $existingLinkIds = [];
+        //get existing links from extension attribute
+        $extensionAttributes = $product->getExtensionAttributes();
+        if ($extensionAttributes !== null) {
+            $existingLinks = $extensionAttributes->getDownloadableProductLinks();
+            if ($existingLinks !== null) {
+                foreach ($existingLinks as $existingLink) {
+                    $existingLinkIds[] = $existingLink->getId();
+                }
+            }
+        }
+
+        $updatedLinkIds = [];
+        foreach ($links as $link) {
+            $linkId = $link->getId();
+            if ($linkId) {
+                $updatedLinkIds[] = $linkId;
+            }
+            $this->linkRepository->save($product->getSku(), $link);
+        }
+        $linkIdsToDelete = array_diff($existingLinkIds, $updatedLinkIds);
+
+        foreach ($linkIdsToDelete as $linkId) {
+            $this->linkRepository->delete($linkId);
+        }
+        return $this;
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param \Magento\Downloadable\Api\Data\SampleInterface[] $samples
+     * @return $this
+     */
+    protected function saveSamples(\Magento\Catalog\Api\Data\ProductInterface $product, array $samples)
+    {
+        $existingSampleIds = [];
+        $extensionAttributes = $product->getExtensionAttributes();
+        if ($extensionAttributes !== null) {
+            $existingSamples = $extensionAttributes->getDownloadableProductSamples();
+            if ($existingSamples !== null) {
+                foreach ($existingSamples as $existingSample) {
+                    $existingSampleIds[] = $existingSample->getId();
+                }
+            }
+        }
+
+        $updatedSampleIds = [];
+        foreach ($samples as $sample) {
+            $sampleId = $sample->getId();
+            if ($sampleId) {
+                $updatedSampleIds[] = $sampleId;
+            }
+            $this->sampleRepository->save($product->getSku(), $sample);
+        }
+        $sampleIdsToDelete = array_diff($existingSampleIds, $updatedSampleIds);
+
+        foreach ($sampleIdsToDelete as $sampleId) {
+            $this->sampleRepository->delete($sampleId);
+        }
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Downloadable/Model/Sample.php b/app/code/Magento/Downloadable/Model/Sample.php
index 07dd821050aad1d60ae18abc38211afdd1fb4a55..4909fe6a39e649e071b47859b77a136eb31a1241 100644
--- a/app/code/Magento/Downloadable/Model/Sample.php
+++ b/app/code/Magento/Downloadable/Model/Sample.php
@@ -27,6 +27,7 @@ class Sample extends \Magento\Framework\Model\AbstractExtensibleModel implements
     const KEY_SORT_ORDER = 'sort_order';
     const KEY_SAMPLE_TYPE = 'sample_type';
     const KEY_SAMPLE_FILE = 'sample_file';
+    const KEY_SAMPLE_FILE_CONTENT = 'sample_file_content';
     const KEY_SAMPLE_URL = 'sample_url';
     /**#@-*/
 
@@ -163,6 +164,15 @@ class Sample extends \Magento\Framework\Model\AbstractExtensibleModel implements
         return $this->getData(self::KEY_SAMPLE_FILE);
     }
 
+    /**
+     * {@inheritdoc}
+     * @codeCoverageIgnore
+     */
+    public function getSampleFileContent()
+    {
+        return $this->getData(self::KEY_SAMPLE_FILE_CONTENT);
+    }
+
     /**
      * {@inheritdoc}
      * @codeCoverageIgnore
@@ -214,6 +224,17 @@ class Sample extends \Magento\Framework\Model\AbstractExtensibleModel implements
         return $this->setData(self::KEY_SAMPLE_FILE, $sampleFile);
     }
 
+    /**
+     * Set sample file content
+     *
+     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $sampleFileContent
+     * @return $this
+     */
+    public function setSampleFileContent(\Magento\Downloadable\Api\Data\File\ContentInterface $sampleFileContent = null)
+    {
+        return $this->setData(self::KEY_SAMPLE_FILE_CONTENT, $sampleFileContent);
+    }
+
     /**
      * Set sample URL
      *
diff --git a/app/code/Magento/Downloadable/Model/Sample/Content.php b/app/code/Magento/Downloadable/Model/Sample/Content.php
deleted file mode 100644
index 0fcf613353966548cfbf6ec83e2ca47837ff9f54..0000000000000000000000000000000000000000
--- a/app/code/Magento/Downloadable/Model/Sample/Content.php
+++ /dev/null
@@ -1,142 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Downloadable\Model\Sample;
-
-use Magento\Downloadable\Api\Data\SampleContentInterface;
-
-/**
- * @codeCoverageIgnore
- */
-class Content extends \Magento\Framework\Model\AbstractExtensibleModel implements SampleContentInterface
-{
-    const TITLE = 'title';
-    const SORT_ORDER = 'sort_order';
-    const SAMPLE_FILE = 'sample_file';
-    const SAMPLE_URL = 'sample_url';
-    const SAMPLE_TYPE = 'sample_type';
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getTitle()
-    {
-        return $this->getData(self::TITLE);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getSampleType()
-    {
-        return $this->getData(self::SAMPLE_TYPE);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getSampleFile()
-    {
-        return $this->getData(self::SAMPLE_FILE);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getSortOrder()
-    {
-        return $this->getData(self::SORT_ORDER);
-    }
-
-    /**
-     * {@inheritdoc}
-     * @codeCoverageIgnore
-     */
-    public function getSampleUrl()
-    {
-        return $this->getData(self::SAMPLE_URL);
-    }
-
-    /**
-     * Set sample title
-     *
-     * @param string $title
-     * @return $this
-     */
-    public function setTitle($title)
-    {
-        return $this->setData(self::TITLE, $title);
-    }
-
-    /**
-     * Set sample type ('url' or 'file')
-     *
-     * @param string $sampleType
-     * @return $this
-     */
-    public function setSampleType($sampleType)
-    {
-        return $this->setData(self::SAMPLE_TYPE, $sampleType);
-    }
-
-    /**
-     * Set sample file content
-     *
-     * @param \Magento\Downloadable\Api\Data\File\ContentInterface $sampleFile
-     * @return $this
-     */
-    public function setSampleFile(\Magento\Downloadable\Api\Data\File\ContentInterface $sampleFile = null)
-    {
-        return $this->setData(self::SAMPLE_FILE, $sampleFile);
-    }
-
-    /**
-     * Set sample sort order
-     *
-     * @param int $sortOrder
-     * @return $this
-     */
-    public function setSortOrder($sortOrder)
-    {
-        return $this->setData(self::SORT_ORDER, $sortOrder);
-    }
-
-    /**
-     * Set sample URL
-     *
-     * @param string $sampleUrl
-     * @return $this
-     */
-    public function setSampleUrl($sampleUrl)
-    {
-        return $this->setData(self::SAMPLE_URL, $sampleUrl);
-    }
-
-    /**
-     * {@inheritdoc}
-     *
-     * @return \Magento\Downloadable\Api\Data\SampleContentExtensionInterface|null
-     */
-    public function getExtensionAttributes()
-    {
-        return $this->_getExtensionAttributes();
-    }
-
-    /**
-     * {@inheritdoc}
-     *
-     * @param \Magento\Downloadable\Api\Data\SampleContentExtensionInterface $extensionAttributes
-     * @return $this
-     */
-    public function setExtensionAttributes(
-        \Magento\Downloadable\Api\Data\SampleContentExtensionInterface $extensionAttributes
-    ) {
-        return $this->_setExtensionAttributes($extensionAttributes);
-    }
-}
diff --git a/app/code/Magento/Downloadable/Model/Sample/ContentValidator.php b/app/code/Magento/Downloadable/Model/Sample/ContentValidator.php
index 294bd783d463560a5846eada1cc400f5e6a97ce7..83f44d1a5c1b07c20229193db238f53d93cfad6f 100644
--- a/app/code/Magento/Downloadable/Model/Sample/ContentValidator.php
+++ b/app/code/Magento/Downloadable/Model/Sample/ContentValidator.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Downloadable\Model\Sample;
 
-use Magento\Downloadable\Api\Data\SampleContentInterface;
+use Magento\Downloadable\Api\Data\SampleInterface;
 use Magento\Downloadable\Model\File\ContentValidator as FileContentValidator;
 use Magento\Framework\Exception\InputException;
 use Magento\Framework\Url\Validator as UrlValidator;
@@ -37,38 +37,41 @@ class ContentValidator
     /**
      * Check if sample content is valid
      *
-     * @param SampleContentInterface $sampleContent
+     * @param SampleInterface $sample
+     * @param bool $validateSampleContent
      * @return bool
      * @throws InputException
      */
-    public function isValid(SampleContentInterface $sampleContent)
+    public function isValid(SampleInterface $sample, $validateSampleContent = true)
     {
-        if (!is_int($sampleContent->getSortOrder()) || $sampleContent->getSortOrder() < 0) {
+        if (!is_int($sample->getSortOrder()) || $sample->getSortOrder() < 0) {
             throw new InputException(__('Sort order must be a positive integer.'));
         }
 
-        $this->validateSampleResource($sampleContent);
+        if ($validateSampleContent) {
+            $this->validateSampleResource($sample);
+        }
         return true;
     }
 
     /**
      * Validate sample resource (file or URL)
      *
-     * @param SampleContentInterface $sampleContent
+     * @param SampleInterface $sample
      * @throws InputException
      * @return void
      */
-    protected function validateSampleResource(SampleContentInterface $sampleContent)
+    protected function validateSampleResource(SampleInterface $sample)
     {
-        $sampleFile = $sampleContent->getSampleFile();
-        if ($sampleContent->getSampleType() == 'file'
+        $sampleFile = $sample->getSampleFileContent();
+        if ($sample->getSampleType() == 'file'
             && (!$sampleFile || !$this->fileContentValidator->isValid($sampleFile))
         ) {
             throw new InputException(__('Provided file content must be valid base64 encoded data.'));
         }
 
-        if ($sampleContent->getSampleType() == 'url'
-            && !$this->urlValidator->isValid($sampleContent->getSampleUrl())
+        if ($sample->getSampleType() == 'url'
+            && !$this->urlValidator->isValid($sample->getSampleUrl())
         ) {
             throw new InputException(__('Sample URL must have valid format.'));
         }
diff --git a/app/code/Magento/Downloadable/Model/SampleRepository.php b/app/code/Magento/Downloadable/Model/SampleRepository.php
index b97702bd9adaf8c143dbf0f62823c460121fe02c..f357e6a5d8541ce450fab6ee85cdb782dd8fcc4e 100644
--- a/app/code/Magento/Downloadable/Model/SampleRepository.php
+++ b/app/code/Magento/Downloadable/Model/SampleRepository.php
@@ -8,12 +8,17 @@ namespace Magento\Downloadable\Model;
 use Magento\Catalog\Api\ProductRepositoryInterface;
 use Magento\Downloadable\Model\SampleFactory;
 use Magento\Downloadable\Api\Data\File\ContentUploaderInterface;
-use Magento\Downloadable\Api\Data\SampleContentInterface;
+use Magento\Downloadable\Api\Data\SampleInterface;
 use Magento\Downloadable\Model\Sample\ContentValidator;
 use Magento\Framework\Exception\InputException;
 use Magento\Framework\Exception\NoSuchEntityException;
 use Magento\Framework\Json\EncoderInterface;
 
+/**
+ * Class SampleRepository
+ * @package Magento\Downloadable\Model
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class SampleRepository implements \Magento\Downloadable\Api\SampleRepositoryInterface
 {
     /**
@@ -21,6 +26,11 @@ class SampleRepository implements \Magento\Downloadable\Api\SampleRepositoryInte
      */
     protected $productRepository;
 
+    /**
+     * @var \Magento\Downloadable\Model\Product\Type
+     */
+    protected $downloadableType;
+
     /**
      * @var ContentValidator
      */
@@ -38,6 +48,7 @@ class SampleRepository implements \Magento\Downloadable\Api\SampleRepositoryInte
 
     /**
      * @param ProductRepositoryInterface $productRepository
+     * @param \Magento\Downloadable\Model\Product\Type $downloadableType
      * @param ContentValidator $contentValidator
      * @param ContentUploaderInterface $fileContentUploader
      * @param EncoderInterface $jsonEncoder
@@ -45,12 +56,14 @@ class SampleRepository implements \Magento\Downloadable\Api\SampleRepositoryInte
      */
     public function __construct(
         ProductRepositoryInterface $productRepository,
+        \Magento\Downloadable\Model\Product\Type $downloadableType,
         ContentValidator $contentValidator,
         ContentUploaderInterface $fileContentUploader,
         EncoderInterface $jsonEncoder,
         SampleFactory $sampleFactory
     ) {
         $this->productRepository = $productRepository;
+        $this->downloadableType = $downloadableType;
         $this->contentValidator = $contentValidator;
         $this->fileContentUploader = $fileContentUploader;
         $this->jsonEncoder = $jsonEncoder;
@@ -58,106 +71,153 @@ class SampleRepository implements \Magento\Downloadable\Api\SampleRepositoryInte
     }
 
     /**
-     * {@inheritdoc}
+     * Update downloadable sample of the given product
+     *
+     * @param string $sku
+     * @param \Magento\Downloadable\Api\Data\SampleInterface $sample
+     * @param bool $isGlobalScopeContent
+     * @return int
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
      */
     public function save(
-        $productSku,
-        SampleContentInterface $sampleContent,
-        $sampleId = null,
+        $sku,
+        SampleInterface $sample,
         $isGlobalScopeContent = false
     ) {
-        $product = $this->productRepository->get($productSku, true);
+        $product = $this->productRepository->get($sku, true);
 
+        $sampleId = $sample->getId();
         if ($sampleId) {
-
-            /** @var $sample \Magento\Downloadable\Model\Sample */
-            $sample = $this->sampleFactory->create()->load($sampleId);
-
-            if (!$sample->getId()) {
-                throw new NoSuchEntityException(__('There is no downloadable sample with provided ID.'));
-            }
-
-            if ($sample->getProductId() != $product->getId()) {
-                throw new InputException(__('Provided downloadable sample is not related to given product.'));
-            }
-            if (!$this->contentValidator->isValid($sampleContent)) {
-                throw new InputException(__('Provided sample information is invalid.'));
-            }
-            if ($isGlobalScopeContent) {
-                $product->setStoreId(0);
-            }
-
-            $title = $sampleContent->getTitle();
-            if (empty($title)) {
-                if ($isGlobalScopeContent) {
-                    throw new InputException(__('Sample title cannot be empty.'));
-                }
-                // use title from GLOBAL scope
-                $sample->setTitle(null);
-            } else {
-                $sample->setTitle($sampleContent->getTitle());
-            }
-
-            $sample->setProductId($product->getId())
-                ->setStoreId($product->getStoreId())
-                ->setSortOrder($sampleContent->getSortOrder())
-                ->save();
-
-            return $sample->getId();
+            return $this->updateSample($product, $sample, $isGlobalScopeContent);
         } else {
-
             if ($product->getTypeId() !== \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE) {
                 throw new InputException(__('Product type of the product must be \'downloadable\'.'));
             }
-            if (!$this->contentValidator->isValid($sampleContent)) {
+            if (!$this->contentValidator->isValid($sample)) {
                 throw new InputException(__('Provided sample information is invalid.'));
             }
 
-            if (!in_array($sampleContent->getSampleType(), ['url', 'file'])) {
+            if (!in_array($sample->getSampleType(), ['url', 'file'])) {
                 throw new InputException(__('Invalid sample type.'));
             }
 
-            $title = $sampleContent->getTitle();
+            $title = $sample->getTitle();
             if (empty($title)) {
                 throw new InputException(__('Sample title cannot be empty.'));
             }
 
-            $sampleData = [
-                'sample_id' => 0,
-                'is_delete' => 0,
-                'type' => $sampleContent->getSampleType(),
-                'sort_order' => $sampleContent->getSortOrder(),
-                'title' => $sampleContent->getTitle(),
-            ];
+            return $this->saveSample($product, $sample, $isGlobalScopeContent);
+        }
+    }
 
-            if ($sampleContent->getSampleType() == 'file') {
-                $sampleData['file'] = $this->jsonEncoder->encode(
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param SampleInterface $sample
+     * @param bool $isGlobalScopeContent
+     * @return int
+     */
+    protected function saveSample(
+        \Magento\Catalog\Api\Data\ProductInterface $product,
+        SampleInterface $sample,
+        $isGlobalScopeContent
+    ) {
+        $sampleData = [
+            'sample_id' => $sample->getid() === null ? 0 : $sample->getid(),
+            'is_delete' => 0,
+            'type' => $sample->getSampleType(),
+            'sort_order' => $sample->getSortOrder(),
+            'title' => $sample->getTitle(),
+        ];
+
+        if ($sample->getSampleType() == 'file' && $sample->getSampleFile() === null) {
+            $sampleData['file'] = $this->jsonEncoder->encode(
+                [
+                    $this->fileContentUploader->upload($sample->getSampleFileContent(), 'sample'),
+                ]
+            );
+        } elseif ($sample->getSampleType() === 'url') {
+            $sampleData['sample_url'] = $sample->getSampleUrl();
+        } else {
+            //existing file
+            $sampleData['file'] = $this->jsonEncoder->encode(
+                [
                     [
-                        $this->fileContentUploader->upload($sampleContent->getSampleFile(), 'sample'),
-                    ]
-                );
-            } else {
-                $sampleData['sample_url'] = $sampleContent->getSampleUrl();
-            }
+                        'file' => $sample->getSampleFile(),
+                        'status' => 'old',
+                    ],
+                ]
+            );
+        }
+
+        $downloadableData = ['sample' => [$sampleData]];
+        $product->setDownloadableData($downloadableData);
+        if ($isGlobalScopeContent) {
+            $product->setStoreId(0);
+        }
+        $this->downloadableType->save($product);
+        return $product->getLastAddedSampleId();
+    }
+
+    /**
+     * @param \Magento\Catalog\Api\Data\ProductInterface $product
+     * @param SampleInterface $sample
+     * @param bool $isGlobalScopeContent
+     * @return int
+     * @throws InputException
+     * @throws NoSuchEntityException
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     */
+    protected function updateSample(
+        \Magento\Catalog\Api\Data\ProductInterface $product,
+        SampleInterface $sample,
+        $isGlobalScopeContent
+    ) {
+        $sampleId = $sample->getId();
+        /** @var $existingSample \Magento\Downloadable\Model\Sample */
+        $existingSample = $this->sampleFactory->create()->load($sampleId);
 
-            $downloadableData = ['sample' => [$sampleData]];
-            $product->setDownloadableData($downloadableData);
+        if (!$existingSample->getId()) {
+            throw new NoSuchEntityException(__('There is no downloadable sample with provided ID.'));
+        }
+
+        if ($existingSample->getProductId() != $product->getId()) {
+            throw new InputException(__('Provided downloadable sample is not related to given product.'));
+        }
+
+        $validateFileContent = $sample->getSampleFileContent() === null ? false : true;
+        if (!$this->contentValidator->isValid($sample, $validateFileContent)) {
+            throw new InputException(__('Provided sample information is invalid.'));
+        }
+        if ($isGlobalScopeContent) {
+            $product->setStoreId(0);
+        }
+
+        $title = $sample->getTitle();
+        if (empty($title)) {
             if ($isGlobalScopeContent) {
-                $product->setStoreId(0);
+                throw new InputException(__('Sample title cannot be empty.'));
             }
-            $product->save();
-            return $product->getLastAddedSampleId();
+            // use title from GLOBAL scope
+            $existingSample->setTitle(null);
+        } else {
+            $existingSample->setTitle($sample->getTitle());
+        }
+
+        if ($sample->getSampleType() === 'file' && $sample->getSampleFileContent() === null) {
+            $sample->setSampleFile($existingSample->getSampleFile());
         }
+        $this->saveSample($product, $sample, $isGlobalScopeContent);
+        return $existingSample->getId();
     }
 
     /**
      * {@inheritdoc}
      */
-    public function delete($sampleId)
+    public function delete($id)
     {
         /** @var $sample \Magento\Downloadable\Model\Sample */
-        $sample = $this->sampleFactory->create()->load($sampleId);
+        $sample = $this->sampleFactory->create()->load($id);
         if (!$sample->getId()) {
             throw new NoSuchEntityException(__('There is no downloadable sample with provided ID.'));
         }
diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Link/ContentValidatorTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Link/ContentValidatorTest.php
index 6e7a6555514b345535e784fc4b2e3abf8839c195..685d116b2b700cd10a286a22b604b435597ad3bb 100644
--- a/app/code/Magento/Downloadable/Test/Unit/Model/Link/ContentValidatorTest.php
+++ b/app/code/Magento/Downloadable/Test/Unit/Model/Link/ContentValidatorTest.php
@@ -52,12 +52,14 @@ class ContentValidatorTest extends \PHPUnit_Framework_TestCase
         );
         $this->linkFileMock = $this->getMock('\Magento\Downloadable\Api\Data\File\ContentInterface');
         $this->sampleFileMock = $this->getMock('\Magento\Downloadable\Api\Data\File\ContentInterface');
-        $this->validator = new \Magento\Downloadable\Model\Link\ContentValidator($this->fileValidatorMock, $this->urlValidatorMock);
+        $this->validator = new ContentValidator($this->fileValidatorMock, $this->urlValidatorMock);
     }
 
     public function testIsValid()
     {
-        $linkContentData = [
+        $linkFileContentMock = $this->getMock('Magento\Downloadable\Api\Data\File\ContentInterface');
+        $sampleFileContentMock = $this->getMock('Magento\Downloadable\Api\Data\File\ContentInterface');
+        $linkData = [
             'title' => 'Title',
             'sort_order' => 1,
             'price' => 10.1,
@@ -65,11 +67,53 @@ class ContentValidatorTest extends \PHPUnit_Framework_TestCase
             'number_of_downloads' => 100,
             'link_type' => 'file',
             'sample_type' => 'file',
+            'link_file_content' => $linkFileContentMock,
+            'sample_file_content' => $sampleFileContentMock,
         ];
         $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
         $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
-        $contentMock = $this->getLinkContentMock($linkContentData);
-        $this->assertTrue($this->validator->isValid($contentMock));
+        $linkMock = $this->getLinkMock($linkData);
+        $this->assertTrue($this->validator->isValid($linkMock));
+    }
+
+    public function testIsValidSkipLinkContent()
+    {
+        $sampleFileContentMock = $this->getMock('Magento\Downloadable\Api\Data\File\ContentInterface');
+        $linkData = [
+            'title' => 'Title',
+            'sort_order' => 1,
+            'price' => 10.1,
+            'shareable' => true,
+            'number_of_downloads' => 100,
+            'link_type' => 'url',
+            'link_url' => 'http://example.com',
+            'sample_type' => 'file',
+            'sample_file_content' => $sampleFileContentMock,
+        ];
+        $this->fileValidatorMock->expects($this->once())->method('isValid')->will($this->returnValue(true));
+        $this->urlValidatorMock->expects($this->never())->method('isValid')->will($this->returnValue(true));
+        $linkMock = $this->getLinkMock($linkData);
+        $this->assertTrue($this->validator->isValid($linkMock, false));
+    }
+
+    public function testIsValidSkipSampleContent()
+    {
+        $sampleFileContentMock = $this->getMock('Magento\Downloadable\Api\Data\File\ContentInterface');
+        $linkData = [
+            'title' => 'Title',
+            'sort_order' => 1,
+            'price' => 10.1,
+            'shareable' => true,
+            'number_of_downloads' => 100,
+            'link_type' => 'url',
+            'link_url' => 'http://example.com',
+            'sample_type' => 'file',
+            'sample_file_content' => $sampleFileContentMock,
+        ];
+        $this->fileValidatorMock->expects($this->never())->method('isValid')->will($this->returnValue(true));
+        $this->urlValidatorMock->expects($this->once())->method('isValid')->will($this->returnValue(true));
+        $linkMock = $this->getLinkMock($linkData);
+        $this->assertTrue($this->validator->isValid($linkMock, true, false));
     }
 
     /**
@@ -91,7 +135,7 @@ class ContentValidatorTest extends \PHPUnit_Framework_TestCase
         ];
         $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
         $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
-        $contentMock = $this->getLinkContentMock($linkContentData);
+        $contentMock = $this->getLinkMock($linkContentData);
         $this->validator->isValid($contentMock);
     }
 
@@ -126,7 +170,7 @@ class ContentValidatorTest extends \PHPUnit_Framework_TestCase
         ];
         $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
         $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
-        $contentMock = $this->getLinkContentMock($linkContentData);
+        $contentMock = $this->getLinkMock($linkContentData);
         $this->validator->isValid($contentMock);
     }
 
@@ -160,7 +204,7 @@ class ContentValidatorTest extends \PHPUnit_Framework_TestCase
         ];
         $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
         $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
-        $contentMock = $this->getLinkContentMock($linkContentData);
+        $contentMock = $this->getLinkMock($linkContentData);
         $this->validator->isValid($contentMock);
     }
 
@@ -177,51 +221,58 @@ class ContentValidatorTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @param array $linkContentData
+     * @param array $linkData
      * @return \PHPUnit_Framework_MockObject_MockObject
      */
-    protected function getLinkContentMock(array $linkContentData)
+    protected function getLinkMock(array $linkData)
     {
-        $contentMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkContentInterface');
-        $contentMock->expects($this->any())->method('getTitle')->will($this->returnValue(
-            $linkContentData['title']
+        $linkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $linkMock->expects($this->any())->method('getTitle')->will($this->returnValue(
+            $linkData['title']
         ));
-        $contentMock->expects($this->any())->method('getPrice')->will($this->returnValue(
-            $linkContentData['price']
+        $linkMock->expects($this->any())->method('getPrice')->will($this->returnValue(
+            $linkData['price']
         ));
-        $contentMock->expects($this->any())->method('getSortOrder')->will($this->returnValue(
-            $linkContentData['sort_order']
+        $linkMock->expects($this->any())->method('getSortOrder')->will($this->returnValue(
+            $linkData['sort_order']
         ));
-        $contentMock->expects($this->any())->method('isShareable')->will($this->returnValue(
-            $linkContentData['shareable']
+        $linkMock->expects($this->any())->method('isShareable')->will($this->returnValue(
+            $linkData['shareable']
         ));
-        $contentMock->expects($this->any())->method('getNumberOfDownloads')->will($this->returnValue(
-            $linkContentData['number_of_downloads']
+        $linkMock->expects($this->any())->method('getNumberOfDownloads')->will($this->returnValue(
+            $linkData['number_of_downloads']
         ));
-        $contentMock->expects($this->any())->method('getLinkType')->will($this->returnValue(
-            $linkContentData['link_type']
+        $linkMock->expects($this->any())->method('getLinkType')->will($this->returnValue(
+            $linkData['link_type']
         ));
-        $contentMock->expects($this->any())->method('getLinkFile')->will($this->returnValue(
+        $linkMock->expects($this->any())->method('getLinkFile')->will($this->returnValue(
             $this->linkFileMock
         ));
-        if (isset($linkContentData['link_url'])) {
-            $contentMock->expects($this->any())->method('getLinkUrl')->will($this->returnValue(
-                $linkContentData['link_url']
+        if (isset($linkData['link_url'])) {
+            $linkMock->expects($this->any())->method('getLinkUrl')->will($this->returnValue(
+                $linkData['link_url']
             ));
         }
-        if (isset($linkContentData['sample_url'])) {
-            $contentMock->expects($this->any())->method('getSampleUrl')->will($this->returnValue(
-                $linkContentData['sample_url']
+        if (isset($linkData['sample_url'])) {
+            $linkMock->expects($this->any())->method('getSampleUrl')->will($this->returnValue(
+                $linkData['sample_url']
             ));
         }
-        if (isset($linkContentData['sample_type'])) {
-            $contentMock->expects($this->any())->method('getSampleType')->will($this->returnValue(
-                $linkContentData['sample_type']
+        if (isset($linkData['sample_type'])) {
+            $linkMock->expects($this->any())->method('getSampleType')->will($this->returnValue(
+                $linkData['sample_type']
             ));
         }
-        $contentMock->expects($this->any())->method('getSampleFile')->will($this->returnValue(
+        if (isset($linkData['link_file_content'])) {
+            $linkMock->expects($this->any())->method('getLinkFileContent')->willReturn($linkData['link_file_content']);
+        }
+        if (isset($linkData['sample_file_content'])) {
+            $linkMock->expects($this->any())->method('getSampleFileContent')
+                ->willReturn($linkData['sample_file_content']);
+        }
+        $linkMock->expects($this->any())->method('getSampleFile')->will($this->returnValue(
             $this->sampleFileMock
         ));
-        return $contentMock;
+        return $linkMock;
     }
 }
diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/LinkRepositoryTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/LinkRepositoryTest.php
index 06c849f969cd47da2759747c05254ef143d2b759..d4ec184847edcbdbca8feb4e8a08c04f1b664766 100644
--- a/app/code/Magento/Downloadable/Test/Unit/Model/LinkRepositoryTest.php
+++ b/app/code/Magento/Downloadable/Test/Unit/Model/LinkRepositoryTest.php
@@ -128,69 +128,80 @@ class LinkRepositoryTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @param array $linkContentData
+     * @param array $linkData
      * @return \PHPUnit_Framework_MockObject_MockObject
      */
-    protected function getLinkContentMock(array $linkContentData)
+    protected function getLinkMock(array $linkData)
     {
-        $contentMock = $this->getMock(
-            '\Magento\Downloadable\Api\Data\LinkContentInterface',
+        $linkMock = $this->getMock(
+            '\Magento\Downloadable\Api\Data\LinkInterface',
             [],
             [],
             '',
             false
         );
 
-        $contentMock->expects($this->any())->method('getPrice')->will(
+        if (isset($linkData['id'])) {
+            $linkMock->expects($this->any())->method('getId')->willReturn($linkData['id']);
+        }
+
+        $linkMock->expects($this->any())->method('getPrice')->will(
             $this->returnValue(
-                $linkContentData['price']
+                $linkData['price']
             )
         );
-        $contentMock->expects($this->any())->method('getTitle')->will(
+        $linkMock->expects($this->any())->method('getTitle')->will(
             $this->returnValue(
-                $linkContentData['title']
+                $linkData['title']
             )
         );
-        $contentMock->expects($this->any())->method('getSortOrder')->will(
+        $linkMock->expects($this->any())->method('getSortOrder')->will(
             $this->returnValue(
-                $linkContentData['sort_order']
+                $linkData['sort_order']
             )
         );
-        $contentMock->expects($this->any())->method('getNumberOfDownloads')->will(
+        $linkMock->expects($this->any())->method('getNumberOfDownloads')->will(
             $this->returnValue(
-                $linkContentData['number_of_downloads']
+                $linkData['number_of_downloads']
             )
         );
-        $contentMock->expects($this->any())->method('isShareable')->will(
+        $linkMock->expects($this->any())->method('getIsShareable')->will(
             $this->returnValue(
-                $linkContentData['shareable']
+                $linkData['is_shareable']
             )
         );
-        if (isset($linkContentData['link_type'])) {
-            $contentMock->expects($this->any())->method('getLinkType')->will(
+        if (isset($linkData['link_type'])) {
+            $linkMock->expects($this->any())->method('getLinkType')->will(
                 $this->returnValue(
-                    $linkContentData['link_type']
+                    $linkData['link_type']
                 )
             );
         }
-        if (isset($linkContentData['link_url'])) {
-            $contentMock->expects($this->any())->method('getLinkUrl')->will(
+        if (isset($linkData['link_url'])) {
+            $linkMock->expects($this->any())->method('getLinkUrl')->will(
                 $this->returnValue(
-                    $linkContentData['link_url']
+                    $linkData['link_url']
                 )
             );
         }
-        return $contentMock;
+        if (isset($linkData['link_file'])) {
+            $linkMock->expects($this->any())->method('getLinkFile')->will(
+                $this->returnValue(
+                    $linkData['link_file']
+                )
+            );
+        }
+        return $linkMock;
     }
 
     public function testCreate()
     {
         $productSku = 'simple';
-        $linkContentData = [
+        $linkData = [
             'title' => 'Title',
             'sort_order' => 1,
             'price' => 10.1,
-            'shareable' => true,
+            'is_shareable' => true,
             'number_of_downloads' => 100,
             'link_type' => 'url',
             'link_url' => 'http://example.com/',
@@ -198,8 +209,8 @@ class LinkRepositoryTest extends \PHPUnit_Framework_TestCase
         $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
             ->will($this->returnValue($this->productMock));
         $this->productMock->expects($this->any())->method('getTypeId')->will($this->returnValue('downloadable'));
-        $linkContentMock = $this->getLinkContentMock($linkContentData);
-        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkContentMock)
+        $linkMock = $this->getLinkMock($linkData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkMock)
             ->will($this->returnValue(true));
 
         $this->productMock->expects($this->once())->method('setDownloadableData')->with(
@@ -208,19 +219,20 @@ class LinkRepositoryTest extends \PHPUnit_Framework_TestCase
                     [
                         'link_id' => 0,
                         'is_delete' => 0,
-                        'type' => $linkContentData['link_type'],
-                        'sort_order' => $linkContentData['sort_order'],
-                        'title' => $linkContentData['title'],
-                        'price' => $linkContentData['price'],
-                        'number_of_downloads' => $linkContentData['number_of_downloads'],
-                        'is_shareable' => $linkContentData['shareable'],
-                        'link_url' => $linkContentData['link_url'],
+                        'type' => $linkData['link_type'],
+                        'sort_order' => $linkData['sort_order'],
+                        'title' => $linkData['title'],
+                        'price' => $linkData['price'],
+                        'number_of_downloads' => $linkData['number_of_downloads'],
+                        'is_shareable' => $linkData['is_shareable'],
+                        'link_url' => $linkData['link_url'],
                     ],
                 ],
             ]
         );
-        $this->productMock->expects($this->once())->method('save');
-        $this->service->save($productSku, $linkContentMock, null);
+        $this->productTypeMock->expects($this->once())->method('save')
+            ->with($this->productMock);
+        $this->service->save($productSku, $linkMock);
     }
 
     /**
@@ -230,12 +242,12 @@ class LinkRepositoryTest extends \PHPUnit_Framework_TestCase
     public function testCreateThrowsExceptionIfTitleIsEmpty()
     {
         $productSku = 'simple';
-        $linkContentData = [
+        $linkData = [
             'title' => '',
             'sort_order' => 1,
             'price' => 10.1,
             'number_of_downloads' => 100,
-            'shareable' => true,
+            'is_shareable' => true,
             'link_type' => 'url',
             'link_url' => 'http://example.com/',
         ];
@@ -243,13 +255,13 @@ class LinkRepositoryTest extends \PHPUnit_Framework_TestCase
         $this->productMock->expects($this->any())->method('getTypeId')->will($this->returnValue('downloadable'));
         $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
             ->will($this->returnValue($this->productMock));
-        $linkContentMock = $this->getLinkContentMock($linkContentData);
-        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkContentMock)
+        $linkMock = $this->getLinkMock($linkData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkMock)
             ->will($this->returnValue(true));
 
         $this->productMock->expects($this->never())->method('save');
 
-        $this->service->save($productSku, $linkContentMock, null);
+        $this->service->save($productSku, $linkMock);
     }
 
     public function testUpdate()
@@ -258,12 +270,15 @@ class LinkRepositoryTest extends \PHPUnit_Framework_TestCase
         $linkId = 1;
         $productSku = 'simple';
         $productId = 1;
-        $linkContentData = [
+        $linkData = [
+            'id' => $linkId,
             'title' => 'Updated Title',
             'sort_order' => 1,
             'price' => 10.1,
-            'shareable' => true,
+            'is_shareable' => true,
             'number_of_downloads' => 100,
+            'link_type' => 'url',
+            'link_url' => 'http://example.com/',
         ];
         $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
             ->will($this->returnValue($this->productMock));
@@ -271,54 +286,126 @@ class LinkRepositoryTest extends \PHPUnit_Framework_TestCase
         $storeMock = $this->getMock('\Magento\Store\Model\Store', [], [], '', false);
         $storeMock->expects($this->any())->method('getWebsiteId')->will($this->returnValue($websiteId));
         $this->productMock->expects($this->any())->method('getStore')->will($this->returnValue($storeMock));
-        $linkMock = $this->getMock(
+        $existingLinkMock = $this->getMock(
             '\Magento\Downloadable\Model\Link',
             [
                 '__wakeup',
-                'setTitle',
-                'setPrice',
-                'setSortOrder',
-                'setIsShareable',
-                'setNumberOfDownloads',
                 'getId',
-                'setProductId',
-                'setStoreId',
-                'setWebsiteId',
-                'setProductWebsiteIds',
                 'load',
-                'save',
                 'getProductId'
             ],
             [],
             '',
             false
         );
-        $this->linkFactoryMock->expects($this->once())->method('create')->will($this->returnValue($linkMock));
-        $linkContentMock = $this->getLinkContentMock($linkContentData);
-        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkContentMock)
+        $this->linkFactoryMock->expects($this->once())->method('create')->will($this->returnValue($existingLinkMock));
+        $linkMock = $this->getLinkMock($linkData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkMock)
             ->will($this->returnValue(true));
 
-        $linkMock->expects($this->any())->method('getId')->will($this->returnValue($linkId));
-        $linkMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
-        $linkMock->expects($this->once())->method('load')->with($linkId)->will($this->returnSelf());
-        $linkMock->expects($this->once())->method('setTitle')->with($linkContentData['title'])
-            ->will($this->returnSelf());
-        $linkMock->expects($this->once())->method('setSortOrder')->with($linkContentData['sort_order'])
-            ->will($this->returnSelf());
-        $linkMock->expects($this->once())->method('setPrice')->with($linkContentData['price'])
-            ->will($this->returnSelf());
-        $linkMock->expects($this->once())->method('setIsShareable')->with($linkContentData['shareable'])
-            ->will($this->returnSelf());
-        $linkMock->expects($this->once())->method('setNumberOfDownloads')->with($linkContentData['number_of_downloads'])
-            ->will($this->returnSelf());
-        $linkMock->expects($this->once())->method('setProductId')->with($productId)
-            ->will($this->returnSelf());
-        $linkMock->expects($this->once())->method('setStoreId')->will($this->returnSelf());
-        $linkMock->expects($this->once())->method('setWebsiteId')->with($websiteId)->will($this->returnSelf());
-        $linkMock->expects($this->once())->method('setProductWebsiteIds')->will($this->returnSelf());
-        $linkMock->expects($this->once())->method('save')->will($this->returnSelf());
-
-        $this->assertEquals($linkId, $this->service->save($productSku, $linkContentMock, $linkId));
+        $existingLinkMock->expects($this->any())->method('getId')->will($this->returnValue($linkId));
+        $existingLinkMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
+        $existingLinkMock->expects($this->once())->method('load')->with($linkId)->will($this->returnSelf());
+
+        $this->productMock->expects($this->once())->method('setDownloadableData')->with(
+            [
+                'link' => [
+                    [
+                        'link_id' => $linkId,
+                        'is_delete' => 0,
+                        'type' => $linkData['link_type'],
+                        'sort_order' => $linkData['sort_order'],
+                        'title' => $linkData['title'],
+                        'price' => $linkData['price'],
+                        'number_of_downloads' => $linkData['number_of_downloads'],
+                        'is_shareable' => $linkData['is_shareable'],
+                        'link_url' => $linkData['link_url'],
+                    ],
+                ],
+            ]
+        );
+        $this->productTypeMock->expects($this->once())->method('save')
+            ->with($this->productMock);
+
+        $this->assertEquals($linkId, $this->service->save($productSku, $linkMock));
+    }
+
+    public function testUpdateWithExistingFile()
+    {
+        $websiteId = 1;
+        $linkId = 1;
+        $productSku = 'simple';
+        $productId = 1;
+        $linkFile = '/l/i/link.jpg';
+        $encodedFiles = "something";
+        $linkData = [
+            'id' => $linkId,
+            'title' => 'Updated Title',
+            'sort_order' => 1,
+            'price' => 10.1,
+            'is_shareable' => true,
+            'number_of_downloads' => 100,
+            'link_type' => 'file',
+            'link_file' => $linkFile,
+        ];
+        $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
+            ->will($this->returnValue($this->productMock));
+        $this->productMock->expects($this->any())->method('getId')->will($this->returnValue($productId));
+        $storeMock = $this->getMock('\Magento\Store\Model\Store', [], [], '', false);
+        $storeMock->expects($this->any())->method('getWebsiteId')->will($this->returnValue($websiteId));
+        $this->productMock->expects($this->any())->method('getStore')->will($this->returnValue($storeMock));
+        $existingLinkMock = $this->getMock(
+            '\Magento\Downloadable\Model\Link',
+            [
+                '__wakeup',
+                'getId',
+                'load',
+                'getProductId'
+            ],
+            [],
+            '',
+            false
+        );
+        $this->linkFactoryMock->expects($this->once())->method('create')->will($this->returnValue($existingLinkMock));
+        $linkMock = $this->getLinkMock($linkData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkMock)
+            ->will($this->returnValue(true));
+
+        $existingLinkMock->expects($this->any())->method('getId')->will($this->returnValue($linkId));
+        $existingLinkMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
+        $existingLinkMock->expects($this->once())->method('load')->with($linkId)->will($this->returnSelf());
+
+        $this->jsonEncoderMock->expects($this->once())
+            ->method('encode')
+            ->with(
+                [
+                    [
+                        'file' => $linkFile,
+                        'status' => 'old'
+                    ]
+                ]
+            )->willReturn($encodedFiles);
+        $this->productMock->expects($this->once())->method('setDownloadableData')->with(
+            [
+                'link' => [
+                    [
+                        'link_id' => $linkId,
+                        'is_delete' => 0,
+                        'type' => $linkData['link_type'],
+                        'sort_order' => $linkData['sort_order'],
+                        'title' => $linkData['title'],
+                        'price' => $linkData['price'],
+                        'number_of_downloads' => $linkData['number_of_downloads'],
+                        'is_shareable' => $linkData['is_shareable'],
+                        'file' => $encodedFiles,
+                    ],
+                ],
+            ]
+        );
+        $this->productTypeMock->expects($this->once())->method('save')
+            ->with($this->productMock);
+
+        $this->assertEquals($linkId, $this->service->save($productSku, $linkMock));
     }
 
     /**
@@ -330,34 +417,34 @@ class LinkRepositoryTest extends \PHPUnit_Framework_TestCase
         $linkId = 1;
         $productSku = 'simple';
         $productId = 1;
-        $linkContentData = [
+        $linkData = [
+            'id' => $linkId,
             'title' => '',
             'sort_order' => 1,
             'price' => 10.1,
             'number_of_downloads' => 100,
-            'shareable' => true,
+            'is_shareable' => true,
         ];
         $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
             ->will($this->returnValue($this->productMock));
         $this->productMock->expects($this->any())->method('getId')->will($this->returnValue($productId));
-        $linkMock = $this->getMock(
+        $existingLinkMock = $this->getMock(
             '\Magento\Downloadable\Model\Link',
             ['__wakeup', 'getId', 'load', 'save', 'getProductId'],
             [],
             '',
             false
         );
-        $linkMock->expects($this->any())->method('getId')->will($this->returnValue($linkId));
-        $linkMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
-        $linkMock->expects($this->once())->method('load')->with($linkId)->will($this->returnSelf());
-        $this->linkFactoryMock->expects($this->once())->method('create')->will($this->returnValue($linkMock));
-        $linkContentMock = $this->getLinkContentMock($linkContentData);
+        $existingLinkMock->expects($this->any())->method('getId')->will($this->returnValue($linkId));
+        $existingLinkMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
+        $existingLinkMock->expects($this->once())->method('load')->with($linkId)->will($this->returnSelf());
+        $this->linkFactoryMock->expects($this->once())->method('create')->will($this->returnValue($existingLinkMock));
+        $linkContentMock = $this->getLinkMock($linkData);
         $this->contentValidatorMock->expects($this->any())->method('isValid')->with($linkContentMock)
             ->will($this->returnValue(true));
 
-        $linkMock->expects($this->never())->method('save');
-
-        $this->service->save($productSku, $linkContentMock, $linkId, true);
+        $this->productTypeMock->expects($this->never())->method('save');
+        $this->service->save($productSku, $linkContentMock, true);
     }
 
     public function testDelete()
diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/ObserverTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/ObserverTest.php
index 99fb7ed07618d23e136ce710af5ddb93010b97aa..f372aaa2451400888c72491ba1607e751d69dc0a 100644
--- a/app/code/Magento/Downloadable/Test/Unit/Model/ObserverTest.php
+++ b/app/code/Magento/Downloadable/Test/Unit/Model/ObserverTest.php
@@ -497,6 +497,33 @@ class ObserverTest extends \PHPUnit_Framework_TestCase
         $this->assertInstanceOf('\Magento\Downloadable\Model\Observer', $result);
     }
 
+    public function testSaveDownloadableOrderItemNotDownloadableItem()
+    {
+        $itemId = 100;
+        $itemMock = $this->getMockBuilder('\Magento\Sales\Model\Order\Item')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $itemMock->expects($this->any())
+            ->method('getId')
+            ->willReturn($itemId);
+        $itemMock->expects($this->any())
+            ->method('getProductType')
+            ->willReturn('simple');
+        $itemMock->expects($this->never())
+            ->method('getProduct');
+        $event = new \Magento\Framework\Object(
+            [
+                'item' => $itemMock,
+            ]
+        );
+        $observer = new \Magento\Framework\Object(
+            [
+                'event' => $event
+            ]
+        );
+        $this->observer->saveDownloadableOrderItem($observer);
+    }
+
     /**
      * @param $id
      * @param int $statusId
diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Plugin/AfterProductLoadTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Plugin/AfterProductLoadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..36f21e6fb5f28382cca4f4bec106d5772d125ec2
--- /dev/null
+++ b/app/code/Magento/Downloadable/Test/Unit/Model/Plugin/AfterProductLoadTest.php
@@ -0,0 +1,220 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+namespace Magento\Downloadable\Test\Unit\Model\Plugin;
+
+class AfterProductLoadTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Downloadable\Model\Plugin\AfterProductLoad
+     */
+    protected $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $linkRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productExtensionMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productExtensionFactory;
+
+    protected function setUp()
+    {
+        $this->linkRepositoryMock = $this->getMock('\Magento\Downloadable\Api\LinkRepositoryInterface');
+        $this->productExtensionFactory = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtensionFactory')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->model = new \Magento\Downloadable\Model\Plugin\AfterProductLoad(
+            $this->linkRepositoryMock,
+            $this->productExtensionFactory
+        );
+        $this->productMock = $this->getMockBuilder('\Magento\Catalog\Model\Product')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->productExtensionMock = $this->getMockBuilder('\Magento\Catalog\Api\Data\ProductExtension')
+            ->setMethods(['setDownloadableProductLinks', 'setDownloadableProductSamples'])->getMock();
+    }
+
+    public function testAfterLoad()
+    {
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE);
+
+        $this->productExtensionFactory->expects($this->once())
+            ->method('create')
+            ->willReturn($this->productExtensionMock);
+
+        $linkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $this->linkRepositoryMock->expects($this->once())
+            ->method('getLinksByProduct')
+            ->with($this->productMock)
+            ->willReturn([$linkMock]);
+        $sampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $this->linkRepositoryMock->expects($this->once())
+            ->method('getSamplesByProduct')
+            ->with($this->productMock)
+            ->willReturn([$sampleMock]);
+        $this->productExtensionMock->expects($this->once())
+            ->method('setDownloadableProductLinks')
+            ->with([$linkMock])
+            ->willReturnSelf();
+        $this->productExtensionMock->expects($this->once())
+            ->method('setDownloadableProductSamples')
+            ->with([$sampleMock])
+            ->willReturnSelf();
+        $this->productMock->expects($this->once())
+            ->method('setExtensionAttributes')
+            ->with($this->productExtensionMock)
+            ->willReturnSelf();
+
+        $this->assertEquals(
+            $this->productMock,
+            $this->model->afterLoad($this->productMock)
+        );
+    }
+
+    public function testAfterLoadWithExistingExtensionAttributes()
+    {
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+
+        $this->productExtensionFactory->expects($this->never())
+            ->method('create');
+
+        $linkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $this->linkRepositoryMock->expects($this->once())
+            ->method('getLinksByProduct')
+            ->with($this->productMock)
+            ->willReturn([$linkMock]);
+        $sampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $this->linkRepositoryMock->expects($this->once())
+            ->method('getSamplesByProduct')
+            ->with($this->productMock)
+            ->willReturn([$sampleMock]);
+        $this->productExtensionMock->expects($this->once())
+            ->method('setDownloadableProductLinks')
+            ->with([$linkMock])
+            ->willReturnSelf();
+        $this->productExtensionMock->expects($this->once())
+            ->method('setDownloadableProductSamples')
+            ->with([$sampleMock])
+            ->willReturnSelf();
+        $this->productMock->expects($this->once())
+            ->method('setExtensionAttributes')
+            ->with($this->productExtensionMock)
+            ->willReturnSelf();
+
+        $this->assertEquals(
+            $this->productMock,
+            $this->model->afterLoad($this->productMock)
+        );
+    }
+
+    public function testAfterLoadOnlyLinks()
+    {
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE);
+
+        $this->productExtensionFactory->expects($this->once())
+            ->method('create')
+            ->willReturn($this->productExtensionMock);
+
+        $linkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $this->linkRepositoryMock->expects($this->once())
+            ->method('getLinksByProduct')
+            ->with($this->productMock)
+            ->willReturn([$linkMock]);
+        $this->linkRepositoryMock->expects($this->once())
+            ->method('getSamplesByProduct')
+            ->with($this->productMock)
+            ->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('setDownloadableProductLinks')
+            ->with([$linkMock])
+            ->willReturnSelf();
+        $this->productExtensionMock->expects($this->never())
+            ->method('setDownloadableProductSamples');
+        $this->productMock->expects($this->once())
+            ->method('setExtensionAttributes')
+            ->with($this->productExtensionMock)
+            ->willReturnSelf();
+
+        $this->assertEquals(
+            $this->productMock,
+            $this->model->afterLoad($this->productMock)
+        );
+    }
+
+    public function testAfterLoadOnlySamples()
+    {
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE);
+
+        $this->productExtensionFactory->expects($this->once())
+            ->method('create')
+            ->willReturn($this->productExtensionMock);
+
+        $this->linkRepositoryMock->expects($this->once())
+            ->method('getLinksByProduct')
+            ->with($this->productMock)
+            ->willReturn(null);
+        $sampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $this->linkRepositoryMock->expects($this->once())
+            ->method('getSamplesByProduct')
+            ->with($this->productMock)
+            ->willReturn([$sampleMock]);
+        $this->productExtensionMock->expects($this->never())
+            ->method('setDownloadableProductLinks');
+        $this->productExtensionMock->expects($this->once())
+            ->method('setDownloadableProductSamples')
+            ->with([$sampleMock])
+            ->willReturnSelf();
+        $this->productMock->expects($this->once())
+            ->method('setExtensionAttributes')
+            ->with($this->productExtensionMock)
+            ->willReturnSelf();
+
+        $this->assertEquals(
+            $this->productMock,
+            $this->model->afterLoad($this->productMock)
+        );
+    }
+
+    public function testAfterLoadIfProductTypeNotDownloadable()
+    {
+        $this->productMock->expects($this->once())
+            ->method('getTypeId')
+            ->willReturn(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE);
+        $this->productMock->expects($this->never())->method('getExtensionAttributes');
+        $this->productMock->expects($this->never())->method('setExtensionAttributes');
+        $this->assertEquals(
+            $this->productMock,
+            $this->model->afterLoad($this->productMock)
+        );
+    }
+}
diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..e33241defa659ee03c309c4ca74fe85b237a9b07
--- /dev/null
+++ b/app/code/Magento/Downloadable/Test/Unit/Model/Plugin/AroundProductRepositorySaveTest.php
@@ -0,0 +1,328 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+namespace Magento\Downloadable\Test\Unit\Model\Plugin;
+
+use \Magento\Downloadable\Model\Plugin\AroundProductRepositorySave;
+
+class AroundProductRepositorySaveTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var AroundProductRepositorySave
+     */
+    protected $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $linkRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $sampleRepositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $savedProductMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productExtensionMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $existingProductExtensionMock;
+
+    /**
+     * @var \Closure
+     */
+    protected $closureMock;
+
+    protected function setUp()
+    {
+        $this->productRepositoryMock = $this->getMock('Magento\Catalog\Api\ProductRepositoryInterface');
+        $this->linkRepositoryMock = $this->getMock('Magento\Downloadable\Api\LinkRepositoryInterface');
+        $this->sampleRepositoryMock = $this->getMock('Magento\Downloadable\Api\SampleRepositoryInterface');
+        $this->productMock = $this->getMock('\Magento\Catalog\Api\Data\ProductInterface');
+        $this->savedProductMock = $this->getMock('\Magento\Catalog\Api\Data\ProductInterface');
+        $this->closureMock = function () {
+            return $this->savedProductMock;
+        };
+        $this->model = new AroundProductRepositorySave(
+            $this->linkRepositoryMock,
+            $this->sampleRepositoryMock        );
+        $this->productExtensionMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductExtension')
+            ->setMethods(['getDownloadableProductLinks', 'getDownloadableProductSamples'])->getMock();
+        $this->existingProductExtensionMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductExtension')
+            ->setMethods(['getDownloadableProductLinks', 'getDownloadableProductSamples'])
+            ->getMock();
+    }
+
+    public function testAroundSaveWhenProductIsSimple()
+    {
+        $this->productMock->expects($this->once())->method('getTypeId')->willReturn('simple');
+        $this->productMock->expects($this->never())->method('getExtensionAttributes');
+
+        $this->assertEquals(
+            $this->savedProductMock,
+            $this->model->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock)
+        );
+    }
+
+    public function testAroundSaveWhenProductHasNoExtensionAttributes()
+    {
+        $this->productMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn(null);
+
+        $this->savedProductMock->expects($this->never())->method('getExtensionAttributes');
+        $this->linkRepositoryMock->expects($this->never())->method('save');
+
+        $this->assertEquals(
+            $this->savedProductMock,
+            $this->model->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock)
+        );
+    }
+
+    /**
+     * Input has two links and two samples, one existing and one new
+     * Existing product has two links and two samples, one will be updated and one will be deleted
+     */
+    public function testAroundSave()
+    {
+        $productSku = "downloadable_product";
+        $existingLinkId = '2';
+        $existingSampleId = '5';
+        $toBeDeletedLinkId = '3';
+        $toBeDeletedSampleId = '4';
+
+        $this->productMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $updateLinkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $updateLinkMock->expects($this->once())->method('getId')->willReturn($existingLinkId);
+        $newLinkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $newLinkMock->expects($this->once())->method('getId')->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getDownloadableProductLinks')
+            ->willReturn([$newLinkMock, $updateLinkMock]);
+
+        $updateSampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $updateSampleMock->expects($this->once())->method('getId')->willReturn($existingSampleId);
+        $newSampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $newSampleMock->expects($this->once())->method('getId')->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getDownloadableProductSamples')
+            ->willReturn([$updateSampleMock, $newSampleMock]);
+
+        $existingLinkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $existingLinkMock->expects($this->once())->method('getId')->willReturn($existingLinkId);
+        $toBeDeletedLinkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $toBeDeletedLinkMock->expects($this->once())->method('getId')->willReturn($toBeDeletedLinkId);
+
+        $existingSampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $existingSampleMock->expects($this->once())->method('getId')->willReturn($existingSampleId);
+        $toBeDeletedSampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $toBeDeletedSampleMock->expects($this->once())->method('getId')->willReturn($toBeDeletedSampleId);
+
+        $this->savedProductMock->expects($this->any())->method('getSku')->willReturn($productSku);
+        $this->savedProductMock->expects($this->exactly(2))->method('getExtensionAttributes')
+            ->willReturn($this->existingProductExtensionMock);
+        $this->existingProductExtensionMock->expects($this->once())
+            ->method('getDownloadableProductLinks')
+            ->willReturn([$existingLinkMock, $toBeDeletedLinkMock]);
+        $this->existingProductExtensionMock->expects($this->once())
+            ->method('getDownloadableProductSamples')
+            ->willReturn([$existingSampleMock, $toBeDeletedSampleMock]);
+
+        $this->linkRepositoryMock->expects($this->at(0))
+            ->method('save')
+            ->with($productSku, $updateLinkMock);
+        $this->linkRepositoryMock->expects($this->at(1))
+            ->method('save')
+            ->with($productSku, $newLinkMock);
+        $this->linkRepositoryMock->expects($this->at(2))
+            ->method('delete')
+            ->with($toBeDeletedLinkId);
+
+        $this->sampleRepositoryMock->expects($this->at(0))
+            ->method('save')
+            ->with($productSku, $updateSampleMock);
+        $this->sampleRepositoryMock->expects($this->at(1))
+            ->method('save')
+            ->with($productSku, $newSampleMock);
+        $this->sampleRepositoryMock->expects($this->at(2))
+            ->method('delete')
+            ->with($toBeDeletedSampleId);
+
+        $newProductMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductInterface')
+            ->disableOriginalConstructor()->getMock();
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku, false, null, true)
+            ->willReturn($newProductMock);
+
+        $this->assertEquals(
+            $newProductMock,
+            $this->model->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock)
+        );
+    }
+
+    /**
+     * Input has two links and no samples, one existing and one new
+     * Existing product has two links, one will be updated and one will be deleted
+     */
+    public function testAroundSaveWithOnlyLinks()
+    {
+        $productSku = "downloadable_product";
+        $existingLinkId = '2';
+        $toBeDeletedLinkId = '3';
+
+        $this->productMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $updateLinkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $updateLinkMock->expects($this->once())->method('getId')->willReturn($existingLinkId);
+        $newLinkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $newLinkMock->expects($this->once())->method('getId')->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getDownloadableProductLinks')
+            ->willReturn([$newLinkMock, $updateLinkMock]);
+
+        $this->productExtensionMock->expects($this->once())
+            ->method('getDownloadableProductSamples')
+            ->willReturn(null);
+
+        $existingLinkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $existingLinkMock->expects($this->once())->method('getId')->willReturn($existingLinkId);
+        $toBeDeletedLinkMock = $this->getMock('\Magento\Downloadable\Api\Data\LinkInterface');
+        $toBeDeletedLinkMock->expects($this->once())->method('getId')->willReturn($toBeDeletedLinkId);
+
+        $this->savedProductMock->expects($this->any())->method('getSku')->willReturn($productSku);
+        $this->savedProductMock->expects($this->once())->method('getExtensionAttributes')
+            ->willReturn($this->existingProductExtensionMock);
+        $this->existingProductExtensionMock->expects($this->once())
+            ->method('getDownloadableProductLinks')
+            ->willReturn([$existingLinkMock, $toBeDeletedLinkMock]);
+        $this->existingProductExtensionMock->expects($this->never())
+            ->method('getDownloadableProductSamples');
+
+        $this->linkRepositoryMock->expects($this->at(0))
+            ->method('save')
+            ->with($productSku, $updateLinkMock);
+        $this->linkRepositoryMock->expects($this->at(1))
+            ->method('save')
+            ->with($productSku, $newLinkMock);
+        $this->linkRepositoryMock->expects($this->at(2))
+            ->method('delete')
+            ->with($toBeDeletedLinkId);
+
+        $this->sampleRepositoryMock->expects($this->never())
+            ->method('save');
+
+        $newProductMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductInterface')
+            ->disableOriginalConstructor()->getMock();
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku, false, null, true)
+            ->willReturn($newProductMock);
+
+        $this->assertEquals(
+            $newProductMock,
+            $this->model->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock)
+        );
+    }
+
+    /**
+     * Input has two samples, one existing and one new
+     * Existing product has two samples, one will be updated and one will be deleted
+     */
+    public function testAroundSaveWithOnlySamples()
+    {
+        $productSku = "downloadable_product";
+        $existingSampleId = '5';
+        $toBeDeletedSampleId = '4';
+
+        $this->productMock->expects($this->once())->method('getTypeId')
+            ->willReturn(\Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE);
+        $this->productMock->expects($this->once())
+            ->method('getExtensionAttributes')
+            ->willReturn($this->productExtensionMock);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getDownloadableProductLinks')
+            ->willReturn(null);
+
+        $updateSampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $updateSampleMock->expects($this->once())->method('getId')->willReturn($existingSampleId);
+        $newSampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $newSampleMock->expects($this->once())->method('getId')->willReturn(null);
+        $this->productExtensionMock->expects($this->once())
+            ->method('getDownloadableProductSamples')
+            ->willReturn([$updateSampleMock, $newSampleMock]);
+
+        $existingSampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $existingSampleMock->expects($this->once())->method('getId')->willReturn($existingSampleId);
+        $toBeDeletedSampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
+        $toBeDeletedSampleMock->expects($this->once())->method('getId')->willReturn($toBeDeletedSampleId);
+
+        $this->savedProductMock->expects($this->any())->method('getSku')->willReturn($productSku);
+        $this->savedProductMock->expects($this->once())->method('getExtensionAttributes')
+            ->willReturn($this->existingProductExtensionMock);
+        $this->existingProductExtensionMock->expects($this->never())
+            ->method('getDownloadableProductLinks');
+        $this->existingProductExtensionMock->expects($this->once())
+            ->method('getDownloadableProductSamples')
+            ->willReturn([$existingSampleMock, $toBeDeletedSampleMock]);
+
+        $this->linkRepositoryMock->expects($this->never())
+            ->method('save');
+
+        $this->sampleRepositoryMock->expects($this->at(0))
+            ->method('save')
+            ->with($productSku, $updateSampleMock);
+        $this->sampleRepositoryMock->expects($this->at(1))
+            ->method('save')
+            ->with($productSku, $newSampleMock);
+        $this->sampleRepositoryMock->expects($this->at(2))
+            ->method('delete')
+            ->with($toBeDeletedSampleId);
+
+        $newProductMock = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductInterface')
+            ->disableOriginalConstructor()->getMock();
+        $this->productRepositoryMock->expects($this->once())
+            ->method('get')
+            ->with($productSku, false, null, true)
+            ->willReturn($newProductMock);
+
+        $this->assertEquals(
+            $newProductMock,
+            $this->model->aroundSave($this->productRepositoryMock, $this->closureMock, $this->productMock)
+        );
+    }
+}
diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/Sample/ContentValidatorTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/Sample/ContentValidatorTest.php
index 8a94c4b8ba1279711a75d133a7697b5cf49738c5..517563a68cd8b58ee2baba39bf71ca479dd55005 100644
--- a/app/code/Magento/Downloadable/Test/Unit/Model/Sample/ContentValidatorTest.php
+++ b/app/code/Magento/Downloadable/Test/Unit/Model/Sample/ContentValidatorTest.php
@@ -51,15 +51,17 @@ class ContentValidatorTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->sampleFileMock = $this->getMock('\Magento\Downloadable\Api\Data\File\ContentInterface');
-        $this->validator = new \Magento\Downloadable\Model\Sample\ContentValidator($this->fileValidatorMock, $this->urlValidatorMock);
+        $this->validator = new ContentValidator($this->fileValidatorMock, $this->urlValidatorMock);
     }
 
     public function testIsValid()
     {
+        $sampleFileContentMock = $this->getMock('Magento\Downloadable\Api\Data\File\ContentInterface');
         $sampleContentData = [
             'title' => 'Title',
             'sort_order' => 1,
             'sample_type' => 'file',
+            'sample_file_content' => $sampleFileContentMock,
         ];
         $this->fileValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
         $this->urlValidatorMock->expects($this->any())->method('isValid')->will($this->returnValue(true));
@@ -103,7 +105,7 @@ class ContentValidatorTest extends \PHPUnit_Framework_TestCase
      */
     protected function getSampleContentMock(array $sampleContentData)
     {
-        $contentMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleContentInterface');
+        $contentMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
         $contentMock->expects($this->any())->method('getTitle')->will($this->returnValue(
             $sampleContentData['title']
         ));
@@ -119,6 +121,10 @@ class ContentValidatorTest extends \PHPUnit_Framework_TestCase
                 $sampleContentData['sample_url']
             ));
         }
+        if (isset($sampleContentData['sample_file_content'])) {
+            $contentMock->expects($this->any())->method('getSampleFileContent')
+                ->willReturn($sampleContentData['sample_file_content']);
+        }
         $contentMock->expects($this->any())->method('getSampleFile')->will($this->returnValue(
             $this->sampleFileMock
         ));
diff --git a/app/code/Magento/Downloadable/Test/Unit/Model/SampleRepositoryTest.php b/app/code/Magento/Downloadable/Test/Unit/Model/SampleRepositoryTest.php
index 4027405e14f5c27eaf84dc245574e21d4a8a156a..7e25af50c3f6b771308ffc0eed2f79b227bd35b6 100644
--- a/app/code/Magento/Downloadable/Test/Unit/Model/SampleRepositoryTest.php
+++ b/app/code/Magento/Downloadable/Test/Unit/Model/SampleRepositoryTest.php
@@ -15,6 +15,11 @@ class SampleRepositoryTest extends \PHPUnit_Framework_TestCase
      */
     protected $repositoryMock;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productTypeMock;
+
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject
      */
@@ -55,6 +60,7 @@ class SampleRepositoryTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->repositoryMock = $this->getMock('\Magento\Catalog\Model\ProductRepository', [], [], '', false);
+        $this->productTypeMock = $this->getMock('\Magento\Downloadable\Model\Product\Type', [], [], '', false);
         $this->contentValidatorMock = $this->getMock(
             'Magento\Downloadable\Model\Sample\ContentValidator',
             [],
@@ -78,6 +84,7 @@ class SampleRepositoryTest extends \PHPUnit_Framework_TestCase
 
         $this->service = new \Magento\Downloadable\Model\SampleRepository(
             $this->repositoryMock,
+            $this->productTypeMock,
             $this->contentValidatorMock,
             $this->contentUploaderMock,
             $this->jsonEncoderMock,
@@ -86,35 +93,43 @@ class SampleRepositoryTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @param array $sampleContentData
+     * @param array $sampleData
      * @return \PHPUnit_Framework_MockObject_MockObject
      */
-    protected function getSampleContentMock(array $sampleContentData)
+    protected function getSampleMock(array $sampleData)
     {
-        $contentMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleContentInterface');
+        $sampleMock = $this->getMock('\Magento\Downloadable\Api\Data\SampleInterface');
 
-        $contentMock->expects($this->any())->method('getTitle')->will($this->returnValue($sampleContentData['title']));
-        $contentMock->expects($this->any())->method('getSortOrder')->will($this->returnValue(
-            $sampleContentData['sort_order']
+        if (isset($sampleData['id'])) {
+            $sampleMock->expects($this->any())->method('getId')->willReturn($sampleData['id']);
+        }
+        $sampleMock->expects($this->any())->method('getTitle')->will($this->returnValue($sampleData['title']));
+        $sampleMock->expects($this->any())->method('getSortOrder')->will($this->returnValue(
+            $sampleData['sort_order']
         ));
 
-        if (isset($sampleContentData['sample_type'])) {
-            $contentMock->expects($this->any())->method('getSampleType')->will($this->returnValue(
-                $sampleContentData['sample_type']
+        if (isset($sampleData['sample_type'])) {
+            $sampleMock->expects($this->any())->method('getSampleType')->will($this->returnValue(
+                $sampleData['sample_type']
+            ));
+        }
+        if (isset($sampleData['sample_url'])) {
+            $sampleMock->expects($this->any())->method('getSampleUrl')->will($this->returnValue(
+                $sampleData['sample_url']
             ));
         }
-        if (isset($sampleContentData['sample_url'])) {
-            $contentMock->expects($this->any())->method('getSampleUrl')->will($this->returnValue(
-                $sampleContentData['sample_url']
+        if (isset($sampleData['sample_file'])) {
+            $sampleMock->expects($this->any())->method('getSampleFile')->will($this->returnValue(
+                $sampleData['sample_file']
             ));
         }
-        return $contentMock;
+        return $sampleMock;
     }
 
     public function testCreate()
     {
         $productSku = 'simple';
-        $sampleContentData = [
+        $sampleData = [
             'title' => 'Title',
             'sort_order' => 1,
             'sample_type' => 'url',
@@ -123,8 +138,8 @@ class SampleRepositoryTest extends \PHPUnit_Framework_TestCase
         $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
             ->will($this->returnValue($this->productMock));
         $this->productMock->expects($this->any())->method('getTypeId')->will($this->returnValue('downloadable'));
-        $sampleContentMock = $this->getSampleContentMock($sampleContentData);
-        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleContentMock)
+        $sampleMock = $this->getSampleMock($sampleData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleMock)
             ->will($this->returnValue(true));
 
         $this->productMock->expects($this->once())->method('setDownloadableData')->with([
@@ -132,15 +147,15 @@ class SampleRepositoryTest extends \PHPUnit_Framework_TestCase
                 [
                     'sample_id' => 0,
                     'is_delete' => 0,
-                    'type' => $sampleContentData['sample_type'],
-                    'sort_order' => $sampleContentData['sort_order'],
-                    'title' => $sampleContentData['title'],
-                    'sample_url' => $sampleContentData['sample_url'],
+                    'type' => $sampleData['sample_type'],
+                    'sort_order' => $sampleData['sort_order'],
+                    'title' => $sampleData['title'],
+                    'sample_url' => $sampleData['sample_url'],
                 ],
             ],
         ]);
-        $this->productMock->expects($this->once())->method('save');
-        $this->service->save($productSku, $sampleContentMock, null);
+        $this->productTypeMock->expects($this->once())->method('save')->with($this->productMock);
+        $this->service->save($productSku, $sampleMock);
     }
 
     /**
@@ -150,7 +165,7 @@ class SampleRepositoryTest extends \PHPUnit_Framework_TestCase
     public function testCreateThrowsExceptionIfTitleIsEmpty()
     {
         $productSku = 'simple';
-        $sampleContentData = [
+        $sampleData = [
             'title' => '',
             'sort_order' => 1,
             'sample_type' => 'url',
@@ -160,13 +175,13 @@ class SampleRepositoryTest extends \PHPUnit_Framework_TestCase
         $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
             ->will($this->returnValue($this->productMock));
         $this->productMock->expects($this->any())->method('getTypeId')->will($this->returnValue('downloadable'));
-        $sampleContentMock = $this->getSampleContentMock($sampleContentData);
-        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleContentMock)
+        $sampleMock = $this->getSampleMock($sampleData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleMock)
             ->will($this->returnValue(true));
 
-        $this->productMock->expects($this->never())->method('save');
+        $this->productTypeMock->expects($this->never())->method('save');
 
-        $this->service->save($productSku, $sampleContentMock, null);
+        $this->service->save($productSku, $sampleMock);
     }
 
     public function testUpdate()
@@ -174,39 +189,109 @@ class SampleRepositoryTest extends \PHPUnit_Framework_TestCase
         $sampleId = 1;
         $productId = 1;
         $productSku = 'simple';
-        $sampleContentData = [
+        $sampleData = [
+            'id' => $sampleId,
             'title' => 'Updated Title',
             'sort_order' => 1,
+            'sample_type' => 'url',
+            'sample_url' => 'http://example.com/',
         ];
         $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
             ->will($this->returnValue($this->productMock));
         $this->productMock->expects($this->any())->method('getId')->will($this->returnValue($productId));
-        $sampleMock = $this->getMock(
+        $existingSampleMock = $this->getMock(
             '\Magento\Downloadable\Model\Sample',
-            ['__wakeup', 'setTitle', 'setSortOrder', 'getId', 'setProductId', 'setStoreId',
-                'load', 'save', 'getProductId'],
+            ['__wakeup', 'getId', 'load', 'getProductId'],
             [],
             '',
             false
         );
-        $this->sampleFactoryMock->expects($this->once())->method('create')->will($this->returnValue($sampleMock));
-        $sampleContentMock = $this->getSampleContentMock($sampleContentData);
-        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleContentMock)
+        $this->sampleFactoryMock->expects($this->once())->method('create')
+            ->will($this->returnValue($existingSampleMock));
+        $sampleMock = $this->getSampleMock($sampleData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleMock)
             ->will($this->returnValue(true));
 
-        $sampleMock->expects($this->any())->method('getId')->will($this->returnValue($sampleId));
-        $sampleMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
-        $sampleMock->expects($this->once())->method('load')->with($sampleId)->will($this->returnSelf());
-        $sampleMock->expects($this->once())->method('setTitle')->with($sampleContentData['title'])
-            ->will($this->returnSelf());
-        $sampleMock->expects($this->once())->method('setSortOrder')->with($sampleContentData['sort_order'])
-            ->will($this->returnSelf());
-        $sampleMock->expects($this->once())->method('setProductId')->with($productId)
-            ->will($this->returnSelf());
-        $sampleMock->expects($this->once())->method('setStoreId')->will($this->returnSelf());
-        $sampleMock->expects($this->once())->method('save')->will($this->returnSelf());
-
-        $this->assertEquals($sampleId, $this->service->save($productSku, $sampleContentMock, $sampleId));
+        $existingSampleMock->expects($this->any())->method('getId')->will($this->returnValue($sampleId));
+        $existingSampleMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
+        $existingSampleMock->expects($this->once())->method('load')->with($sampleId)->will($this->returnSelf());
+
+        $this->productMock->expects($this->once())->method('setDownloadableData')->with([
+            'sample' => [
+                [
+                    'sample_id' => $sampleId,
+                    'is_delete' => 0,
+                    'type' => $sampleData['sample_type'],
+                    'sort_order' => $sampleData['sort_order'],
+                    'title' => $sampleData['title'],
+                    'sample_url' => $sampleData['sample_url'],
+                ],
+            ],
+        ]);
+        $this->productTypeMock->expects($this->once())->method('save')->with($this->productMock);
+
+        $this->assertEquals($sampleId, $this->service->save($productSku, $sampleMock));
+    }
+
+    public function testUpdateWithExistingFile()
+    {
+        $sampleId = 1;
+        $productId = 1;
+        $productSku = 'simple';
+        $sampleFile = '/s/a/sample.jpg';
+        $encodedFile = 'something';
+        $sampleData = [
+            'id' => $sampleId,
+            'title' => 'Updated Title',
+            'sort_order' => 1,
+            'sample_type' => 'file',
+            'sample_file' => $sampleFile,
+        ];
+        $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
+            ->will($this->returnValue($this->productMock));
+        $this->productMock->expects($this->any())->method('getId')->will($this->returnValue($productId));
+        $existingSampleMock = $this->getMock(
+            '\Magento\Downloadable\Model\Sample',
+            ['__wakeup', 'getId', 'load', 'getProductId'],
+            [],
+            '',
+            false
+        );
+        $this->sampleFactoryMock->expects($this->once())->method('create')
+            ->will($this->returnValue($existingSampleMock));
+        $sampleMock = $this->getSampleMock($sampleData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleMock)
+            ->will($this->returnValue(true));
+
+        $existingSampleMock->expects($this->any())->method('getId')->will($this->returnValue($sampleId));
+        $existingSampleMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
+        $existingSampleMock->expects($this->once())->method('load')->with($sampleId)->will($this->returnSelf());
+
+        $this->jsonEncoderMock->expects($this->once())
+            ->method('encode')
+            ->with(
+                [
+                    [
+                        'file' => $sampleFile,
+                        'status' => 'old',
+                    ]
+                ]
+            )->willReturn($encodedFile);
+        $this->productMock->expects($this->once())->method('setDownloadableData')->with([
+            'sample' => [
+                [
+                    'sample_id' => $sampleId,
+                    'is_delete' => 0,
+                    'type' => $sampleData['sample_type'],
+                    'sort_order' => $sampleData['sort_order'],
+                    'title' => $sampleData['title'],
+                    'file' => $encodedFile,
+                ],
+            ],
+        ]);
+        $this->productTypeMock->expects($this->once())->method('save')->with($this->productMock);
+
+        $this->assertEquals($sampleId, $this->service->save($productSku, $sampleMock));
     }
 
     /**
@@ -218,31 +303,33 @@ class SampleRepositoryTest extends \PHPUnit_Framework_TestCase
         $sampleId = 1;
         $productSku = 'simple';
         $productId = 1;
-        $sampleContentData = [
+        $sampleData = [
+            'id' => $sampleId,
             'title' => '',
             'sort_order' => 1,
         ];
         $this->repositoryMock->expects($this->any())->method('get')->with($productSku, true)
             ->will($this->returnValue($this->productMock));
         $this->productMock->expects($this->any())->method('getId')->will($this->returnValue($productId));
-        $sampleMock = $this->getMock(
+        $existingSampleMock = $this->getMock(
             '\Magento\Downloadable\Model\Sample',
             ['__wakeup', 'getId', 'load', 'save', 'getProductId'],
             [],
             '',
             false
         );
-        $sampleMock->expects($this->any())->method('getId')->will($this->returnValue($sampleId));
-        $sampleMock->expects($this->once())->method('load')->with($sampleId)->will($this->returnSelf());
-        $sampleMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
-        $this->sampleFactoryMock->expects($this->once())->method('create')->will($this->returnValue($sampleMock));
-        $sampleContentMock = $this->getSampleContentMock($sampleContentData);
-        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleContentMock)
+        $existingSampleMock->expects($this->any())->method('getId')->will($this->returnValue($sampleId));
+        $existingSampleMock->expects($this->once())->method('load')->with($sampleId)->will($this->returnSelf());
+        $existingSampleMock->expects($this->any())->method('getProductId')->will($this->returnValue($productId));
+        $this->sampleFactoryMock->expects($this->once())->method('create')
+            ->will($this->returnValue($existingSampleMock));
+        $sampleMock = $this->getSampleMock($sampleData);
+        $this->contentValidatorMock->expects($this->any())->method('isValid')->with($sampleMock)
             ->will($this->returnValue(true));
 
-        $sampleMock->expects($this->never())->method('save');
+        $this->productTypeMock->expects($this->never())->method('save');
 
-        $this->service->save($productSku, $sampleContentMock, $sampleId, true);
+        $this->service->save($productSku, $sampleMock, true);
     }
 
     public function testDelete()
diff --git a/app/code/Magento/Downloadable/etc/di.xml b/app/code/Magento/Downloadable/etc/di.xml
index 9b492b051acc779329be9e761c9ede86ce6752e7..acb63729a578108f11e7b5f9d59c60d3d1e00745 100644
--- a/app/code/Magento/Downloadable/etc/di.xml
+++ b/app/code/Magento/Downloadable/etc/di.xml
@@ -58,12 +58,16 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Catalog\Model\Product">
+        <plugin name="downloadableAfterLoad" type="\Magento\Downloadable\Model\Plugin\AfterProductLoad"/>
+    </type>
+    <type name="Magento\Catalog\Api\ProductRepositoryInterface">
+        <plugin name="downloadableAroundSave" type="\Magento\Downloadable\Model\Plugin\AroundProductRepositorySave"/>
+    </type>
     <preference for="\Magento\Downloadable\Api\LinkRepositoryInterface" type="\Magento\Downloadable\Model\LinkRepository" />
     <preference for="\Magento\Downloadable\Api\SampleRepositoryInterface" type="\Magento\Downloadable\Model\SampleRepository" />
     <preference for="\Magento\Downloadable\Api\Data\LinkInterface" type="\Magento\Downloadable\Model\Link" />
     <preference for="\Magento\Downloadable\Api\Data\SampleInterface" type="\Magento\Downloadable\Model\Sample" />
-    <preference for="\Magento\Downloadable\Api\Data\SampleContentInterface" type="\Magento\Downloadable\Model\Sample\Content" />
-    <preference for="\Magento\Downloadable\Api\Data\LinkContentInterface" type="\Magento\Downloadable\Model\Link\Content" />
     <preference for="\Magento\Downloadable\Api\Data\File\ContentInterface" type="\Magento\Downloadable\Model\File\Content" />
     <preference for="\Magento\Downloadable\Api\Data\File\ContentUploaderInterface" type="\Magento\Downloadable\Model\File\ContentUploader" />
     <preference for="\Magento\Downloadable\Model\Product\TypeHandler\TypeHandlerInterface" type="\Magento\Downloadable\Model\Product\TypeHandler\TypeHandler" />
diff --git a/app/code/Magento/Downloadable/etc/service_data_attributes.xml b/app/code/Magento/Downloadable/etc/service_data_attributes.xml
new file mode 100644
index 0000000000000000000000000000000000000000..80cc1cb0abf9ff457b97d12eddc9b3b6ee519784
--- /dev/null
+++ b/app/code/Magento/Downloadable/etc/service_data_attributes.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/Api/etc/service_data_attributes.xsd">
+    <extension_attributes for="Magento\Catalog\Api\Data\ProductInterface">
+        <attribute code="downloadable_product_links" type="Magento\Downloadable\Api\Data\LinkInterface[]" />
+        <attribute code="downloadable_product_samples" type="Magento\Downloadable\Api\Data\SampleInterface[]" />
+    </extension_attributes>
+</config>
diff --git a/app/code/Magento/Downloadable/etc/webapi.xml b/app/code/Magento/Downloadable/etc/webapi.xml
index 0291fe5322f8328380ab63b58dfd7b8b8322dbe2..7f597119f9e74db7142d3baa866ec3c697c67e45 100644
--- a/app/code/Magento/Downloadable/etc/webapi.xml
+++ b/app/code/Magento/Downloadable/etc/webapi.xml
@@ -25,13 +25,13 @@
             <resource ref="Magento_Downloadable::downloadable" />
         </resources>
     </route>
-    <route url="/V1/products/:sku/downloadable-links/:linkId" method="PUT">
+    <route url="/V1/products/:sku/downloadable-links/:id" method="PUT">
         <service class="Magento\Downloadable\Api\LinkRepositoryInterface" method="save"/>
         <resources>
             <resource ref="Magento_Downloadable::downloadable" />
         </resources>
     </route>
-    <route url="/V1/products/downloadable-links/:linkId" method="DELETE">
+    <route url="/V1/products/downloadable-links/:id" method="DELETE">
         <service class="Magento\Downloadable\Api\LinkRepositoryInterface" method="delete"/>
         <resources>
             <resource ref="Magento_Downloadable::downloadable" />
@@ -43,13 +43,13 @@
             <resource ref="Magento_Downloadable::downloadable" />
         </resources>
     </route>
-    <route url="/V1/products/:sku/downloadable-links/samples/:sampleId" method="PUT">
+    <route url="/V1/products/:sku/downloadable-links/samples/:id" method="PUT">
     <service class="Magento\Downloadable\Api\SampleRepositoryInterface" method="save"/>
     <resources>
         <resource ref="Magento_Downloadable::downloadable" />
     </resources>
 </route>
-    <route url="/V1/products/downloadable-links/samples/:sampleId" method="DELETE">
+    <route url="/V1/products/downloadable-links/samples/:id" method="DELETE">
         <service class="Magento\Downloadable\Api\SampleRepositoryInterface" method="delete"/>
         <resources>
             <resource ref="Magento_Downloadable::downloadable" />
diff --git a/app/code/Magento/Downloadable/view/frontend/templates/checkout/cart/item/default.phtml b/app/code/Magento/Downloadable/view/frontend/templates/checkout/cart/item/default.phtml
index 18fe84b7f729394938201bd5de4e8b39b4e2e7a7..b1b38150bd6acf8b53700272f443bc5c1516d608 100644
--- a/app/code/Magento/Downloadable/view/frontend/templates/checkout/cart/item/default.phtml
+++ b/app/code/Magento/Downloadable/view/frontend/templates/checkout/cart/item/default.phtml
@@ -87,7 +87,7 @@ $canApplyMsrp = $helper->isShowBeforeOrderConfirm($product) && $helper->isMinima
     <?php endif; ?>
         <td class="col qty" data-th="<?php echo $block->escapeHtml(__('Qty')); ?>">
             <div class="control qty">
-                <input name="cart[<?php echo $_item->getId() ?>][qty]" value="<?php echo $block->getQty() ?>" type="number" size="4" title="<?php echo __('Qty') ?>" class="input-text qty" maxlength="12" data-validate="{'required-number':true,'validate-greater-than-zero':true}"/>
+                <input name="cart[<?php echo $_item->getId() ?>][qty]" value="<?php echo $block->getQty() ?>" type="number" size="4" title="<?php echo __('Qty') ?>" class="input-text qty" maxlength="12" data-validate="{'required-number':true,'validate-greater-than-zero':true}" data-role="cart-item-qty"/>
             </div>
             <?php $cols++; ?>
         </td>
diff --git a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php
index ac8c5805f4b72f8727d09a4a4cbc71a0f05c2258..c8fa8214eab58921da003c19e9a5c55b4a3d66c1 100755
--- a/app/code/Magento/Eav/Model/Entity/AbstractEntity.php
+++ b/app/code/Magento/Eav/Model/Entity/AbstractEntity.php
@@ -31,14 +31,14 @@ abstract class AbstractEntity extends \Magento\Framework\Model\Resource\Abstract
     /**
      * Read connection
      *
-     * @var \Magento\Framework\DB\Adapter\Pdo\Mysql
+     * @var \Magento\Framework\DB\Adapter\Pdo\Mysql | string
      */
     protected $_read;
 
     /**
      * Write connection
      *
-     * @var \Magento\Framework\DB\Adapter\Pdo\Mysql
+     * @var \Magento\Framework\DB\Adapter\Pdo\Mysql | string
      */
     protected $_write;
 
diff --git a/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php b/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php
index e9d0fdc69cb0148ee5d5b412533564e40ad8fdc7..afb72584604e4dd4df86b693bacb6ac5d8aa9090 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/ConfigTest.php
@@ -77,12 +77,32 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
      * @param boolean $cacheEnabled
      * @param int $loadCalls
      * @param string $cachedValue
-     * @param array $factoryCalls
      * @dataProvider getAttributeCacheDataProvider
      * @return void
      */
-    public function testGetAttributeCache($cacheEnabled, $loadCalls, $cachedValue, $factoryCalls)
+    public function testGetAttributeCache($cacheEnabled, $loadCalls, $cachedValue)
     {
+        $attributeCollectionMock = $this->getMockBuilder('Magento\Eav\Model\Resource\Entity\Attribute\Collection')
+            ->disableOriginalConstructor()
+            ->setMethods(['getData', 'setEntityTypeFilter'])
+            ->getMock();
+        $attributeCollectionMock
+            ->expects($this->any())
+            ->method('setEntityTypeFilter')
+            ->will($this->returnSelf());
+        $attributeCollectionMock
+            ->expects($this->any())
+            ->method('getData')
+            ->willReturn([]);
+        $entityAttributeMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Attribute')
+            ->setMethods(['dummy'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $factoryCalls = [
+            ['Magento\Eav\Model\Resource\Entity\Attribute\Collection', [], $attributeCollectionMock],
+            ['Magento\Eav\Model\Entity\Attribute', [], $entityAttributeMock],
+        ];
+
         $this->stateMock
             ->expects($this->atLeastOnce())
             ->method('isEnabled')
@@ -95,7 +115,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             ->willReturn($cachedValue);
 
         $collectionStub = new Object([
-            ['entity_type_code' => 'type_code_1', 'entity_type_id' => 1]
+            ['entity_type_code' => 'type_code_1', 'entity_type_id' => 1],
         ]);
         $this->collectionFactoryMock
             ->expects($this->any())
@@ -108,7 +128,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
             ->willReturn(new Object(['id' => 101]));
 
         $this->universalFactoryMock
-            ->expects($this->exactly(count($factoryCalls)))
+            ->expects($this->atLeastOnce())
             ->method('create')
             ->will($this->returnValueMap($factoryCalls));
 
@@ -125,54 +145,26 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
      */
     public function getAttributeCacheDataProvider()
     {
-        $attributeCollectionMock = $this->getMockBuilder('Magento\Eav\Model\Resource\Entity\Attribute\Collection')
-            ->disableOriginalConstructor()
-            ->setMethods(['getData', 'setEntityTypeFilter'])
-            ->getMock();
-        $attributeCollectionMock
-            ->expects($this->any())
-            ->method('setEntityTypeFilter')
-            ->will($this->returnSelf());
-        $attributeCollectionMock
-            ->expects($this->any())
-            ->method('getData')
-            ->willReturn([]);
-        $entityAttributeMock = $this->getMockBuilder('Magento\Eav\Model\Entity\Attribute')
-            ->setMethods(['dummy'])
-            ->disableOriginalConstructor()
-            ->getMock();
-
         return [
             'cache-disabled' => [
                 false,
                 0,
                 false,
-                [
-                    ['Magento\Eav\Model\Resource\Entity\Attribute\Collection', [], $attributeCollectionMock],
-                    ['Magento\Eav\Model\Entity\Attribute', [], $entityAttributeMock]
-                ]
             ],
             'cache-miss' => [
                 true,
                 1,
                 false,
-                [
-                    ['Magento\Eav\Model\Resource\Entity\Attribute\Collection', [], $attributeCollectionMock],
-                    ['Magento\Eav\Model\Entity\Attribute', [], $entityAttributeMock]
-                ]
             ],
             'cached' => [
                 true,
                 1,
                 serialize(
                     [
-                        ['attribute_code' => 'attribute_code_1', 'attribute_id' => 1]
+                        ['attribute_code' => 'attribute_code_1', 'attribute_id' => 1],
                     ]
                 ),
-                [
-                    ['Magento\Eav\Model\Entity\Attribute', [], $entityAttributeMock]
-                ]
-            ]
+            ],
         ];
     }
 
@@ -185,7 +177,7 @@ class ConfigTest extends \PHPUnit_Framework_TestCase
                 $this->equalTo(
                     [
                         \Magento\Eav\Model\Cache\Type::CACHE_TAG,
-                        \Magento\Eav\Model\Entity\Attribute::CACHE_TAG
+                        \Magento\Eav\Model\Entity\Attribute::CACHE_TAG,
                     ]
                 )
             );
diff --git a/app/code/Magento/Eav/etc/di.xml b/app/code/Magento/Eav/etc/di.xml
index 3dfebf456c7ff4ae26f6f8a118431872c7c2f67e..00524114f784dd3bc859a8395a9c1d23012433cc 100644
--- a/app/code/Magento/Eav/etc/di.xml
+++ b/app/code/Magento/Eav/etc/di.xml
@@ -57,4 +57,9 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Eav\Model\Entity\Attribute">
+        <arguments>
+            <argument name="reservedAttributeList" xsi:type="object">Magento\Catalog\Model\Product\ReservedAttributeList\Proxy</argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Email/Model/BackendTemplate.php b/app/code/Magento/Email/Model/BackendTemplate.php
index be5b232564a67e139724e96f6d7a51a89702ed9c..c8bc6b34398e0c492f9123cfaeedc8182da23299 100644
--- a/app/code/Magento/Email/Model/BackendTemplate.php
+++ b/app/code/Magento/Email/Model/BackendTemplate.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Email\Model;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 /**
  * Adminhtml email template model
  *
@@ -78,7 +80,7 @@ class BackendTemplate extends Template
             return [];
         }
 
-        $configData = $this->_scopeConfig->getValue(null, \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT);
+        $configData = $this->_scopeConfig->getValue(null, ScopeConfigInterface::SCOPE_TYPE_DEFAULT);
         $paths = $this->_findEmailTemplateUsages($templateCode, $configData, '');
         return $paths;
     }
diff --git a/app/code/Magento/GoogleAdwords/etc/di.xml b/app/code/Magento/GoogleAdwords/etc/di.xml
new file mode 100644
index 0000000000000000000000000000000000000000..293db157d7c38cca198df46a541016f71c97dd54
--- /dev/null
+++ b/app/code/Magento/GoogleAdwords/etc/di.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
+    <type name="Magento\GoogleAdwords\Model\Observer">
+        <arguments>
+            <argument name="collection" xsi:type="object">Magento\Sales\Model\Resource\Order\Collection\Proxy</argument>
+        </arguments>
+    </type>
+</config>
diff --git a/app/code/Magento/GoogleShopping/Model/Attribute/Tax.php b/app/code/Magento/GoogleShopping/Model/Attribute/Tax.php
index 089f14216bdadb05a1ee8c4b4530526b46ad892a..d20e9cc0cc88c9215df5aa15b0b69cd32ccb5061 100644
--- a/app/code/Magento/GoogleShopping/Model/Attribute/Tax.php
+++ b/app/code/Magento/GoogleShopping/Model/Attribute/Tax.php
@@ -8,6 +8,7 @@ namespace Magento\GoogleShopping\Model\Attribute;
 use Magento\Framework\Parse\Zip;
 use Magento\Store\Model\Store;
 use Magento\Tax\Api\Data\TaxClassKeyInterface;
+use Magento\Tax\Model\TaxClass\Key;
 
 /**
  * Tax attribute model
@@ -179,8 +180,8 @@ class Tax extends \Magento\GoogleShopping\Model\Attribute\DefaultAttribute
                         'code' => $product->getSku(),
                         'type' => 'product',
                         'tax_class_key' => [
-                            TaxClassKeyInterface::KEY_TYPE => TaxClassKeyInterface::TYPE_ID,
-                            TaxClassKeyInterface::KEY_VALUE => $product->getTaxClassId(),
+                            Key::KEY_TYPE => TaxClassKeyInterface::TYPE_ID,
+                            Key::KEY_VALUE => $product->getTaxClassId(),
                         ],
                         'unit_price' => $product->getPrice(),
                         'quantity' => 1,
@@ -204,8 +205,8 @@ class Tax extends \Magento\GoogleShopping\Model\Attribute\DefaultAttribute
                         'billing_address' => $billingAddressDataArray,
                         'shipping_address' => $shippingAddressDataArray,
                         'customer_tax_class_key' => [
-                            TaxClassKeyInterface::KEY_TYPE => TaxClassKeyInterface::TYPE_ID,
-                            TaxClassKeyInterface::KEY_VALUE => $defaultCustomerTaxClassId,
+                            Key::KEY_TYPE => TaxClassKeyInterface::TYPE_ID,
+                            Key::KEY_VALUE => $defaultCustomerTaxClassId,
                         ],
                         'items' => [
                             $quoteDetailsItemDataArray,
diff --git a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php
index d856527779116c8c6795c79d704fc90a892bfcd2..5ee51f1ecbfb45622fd6f8c28955de99da4c2874 100644
--- a/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php
+++ b/app/code/Magento/GroupedProduct/Model/Product/Type/Grouped.php
@@ -480,7 +480,7 @@ class Grouped extends \Magento\Catalog\Model\Product\Type\AbstractType
      */
     public function beforeSave($product)
     {
-        if ($product->hasData('product_options')) {
+        if ($product->hasData('product_options') && !empty($product->getData('product_options'))) {
             throw new \Exception('Custom options for grouped product type are not supported');
         }
         return parent::beforeSave($product);
diff --git a/app/code/Magento/GroupedProduct/Test/Unit/Model/ProductTest.php b/app/code/Magento/GroupedProduct/Test/Unit/Model/ProductTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..04d7f729f8c86ad5a0c85435bfa266584cf3fbb1
--- /dev/null
+++ b/app/code/Magento/GroupedProduct/Test/Unit/Model/ProductTest.php
@@ -0,0 +1,430 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+namespace Magento\GroupedProduct\Test\Unit\Model;
+
+use \Magento\Catalog\Model\Product;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+
+/**
+ * Product Test
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.TooManyFields)
+ *
+ */
+class ProductTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManagerHelper
+     */
+    protected $objectManagerHelper;
+
+    /**
+     * @var \Magento\Catalog\Model\Product
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\Module\Manager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $moduleManager;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $stockItemFactoryMock;
+
+    /**
+     * @var \Magento\Indexer\Model\IndexerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $categoryIndexerMock;
+
+    /**
+     * @var \Magento\Catalog\Model\Indexer\Product\Flat\Processor|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productFlatProcessor;
+
+    /**
+     * @var \Magento\Catalog\Model\Indexer\Product\Price\Processor|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productPriceProcessor;
+
+    /**
+     * @var Product\Type|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productTypeInstanceMock;
+
+    /**
+     * @var Product\Option|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $optionInstanceMock;
+
+    /**
+     * @var \Magento\Framework\Pricing\PriceInfo\Base|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $_priceInfoMock;
+
+    /**
+     * @var \Magento\Store\Model\Store|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $store;
+
+    /**
+     * @var \Magento\Catalog\Model\Resource\Product|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resource;
+
+    /**
+     * @var \Magento\Framework\Registry|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $registry;
+
+    /**
+     * @var \Magento\Catalog\Model\Category|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $category;
+
+    /**
+     * @var \Magento\Store\Model\Website|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $website;
+
+    /**
+     * @var \Magento\Indexer\Model\IndexerRegistry|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $indexerRegistryMock;
+
+    /**
+     * @var \Magento\Catalog\Api\CategoryRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $categoryRepository;
+
+    /**
+     * @var \Magento\Catalog\Helper\Product|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $_catalogProduct;
+
+    /**
+     * @var \Magento\Catalog\Model\Product\Image\Cache|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $imageCache;
+
+    /**
+     * @var \Magento\Catalog\Model\Product\Image\CacheFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $imageCacheFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $mediaGalleryEntryFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productLinkFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $dataObjectHelperMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $metadataServiceMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $attributeValueFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $linkTypeProviderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $entityCollectionProviderMock;
+
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function setUp()
+    {
+        $this->categoryIndexerMock = $this->getMockForAbstractClass('\Magento\Indexer\Model\IndexerInterface');
+
+        $this->moduleManager = $this->getMock(
+            'Magento\Framework\Module\Manager',
+            ['isEnabled'],
+            [],
+            '',
+            false
+        );
+        $this->stockItemFactoryMock = $this->getMock(
+            'Magento\CatalogInventory\Api\Data\StockItemInterfaceFactory',
+            ['create'],
+            [],
+            '',
+            false
+        );
+        $this->dataObjectHelperMock = $this->getMockBuilder('\Magento\Framework\Api\DataObjectHelper')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->productFlatProcessor = $this->getMock(
+            'Magento\Catalog\Model\Indexer\Product\Flat\Processor',
+            [],
+            [],
+            '',
+            false
+        );
+
+        $this->_priceInfoMock = $this->getMock('Magento\Framework\Pricing\PriceInfo\Base', [], [], '', false);
+        $this->productTypeInstanceMock = $this->getMock('Magento\Catalog\Model\Product\Type', [], [], '', false);
+        $this->productPriceProcessor = $this->getMock(
+            'Magento\Catalog\Model\Indexer\Product\Price\Processor',
+            [],
+            [],
+            '',
+            false
+        );
+
+        $stateMock = $this->getMock('Magento\FrameworkApp\State', ['getAreaCode'], [], '', false);
+        $stateMock->expects($this->any())
+            ->method('getAreaCode')
+            ->will($this->returnValue(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE));
+
+        $eventManagerMock = $this->getMock('Magento\Framework\Event\ManagerInterface');
+        $actionValidatorMock = $this->getMock(
+            '\Magento\Framework\Model\ActionValidator\RemoveAction',
+            [],
+            [],
+            '',
+            false
+        );
+        $actionValidatorMock->expects($this->any())->method('isAllowed')->will($this->returnValue(true));
+        $cacheInterfaceMock = $this->getMock('Magento\Framework\App\CacheInterface');
+
+        $contextMock = $this->getMock(
+            '\Magento\Framework\Model\Context',
+            ['getEventDispatcher', 'getCacheManager', 'getAppState', 'getActionValidator'], [], '', false
+        );
+        $contextMock->expects($this->any())->method('getAppState')->will($this->returnValue($stateMock));
+        $contextMock->expects($this->any())->method('getEventDispatcher')->will($this->returnValue($eventManagerMock));
+        $contextMock->expects($this->any())
+            ->method('getCacheManager')
+            ->will($this->returnValue($cacheInterfaceMock));
+        $contextMock->expects($this->any())
+            ->method('getActionValidator')
+            ->will($this->returnValue($actionValidatorMock));
+
+        $this->optionInstanceMock = $this->getMockBuilder('Magento\Catalog\Model\Product\Option')
+            ->setMethods(['setProduct', 'saveOptions', '__wakeup', '__sleep'])
+            ->disableOriginalConstructor()->getMock();
+
+        $this->resource = $this->getMockBuilder('Magento\Catalog\Model\Resource\Product')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->registry = $this->getMockBuilder('Magento\Framework\Registry')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->category = $this->getMockBuilder('Magento\Catalog\Model\Category')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->store = $this->getMockBuilder('Magento\Store\Model\Store')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->website = $this->getMockBuilder('\Magento\Store\Model\Website')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $storeManager = $this->getMockBuilder('Magento\Store\Model\StoreManagerInterface')
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $storeManager->expects($this->any())
+            ->method('getStore')
+            ->will($this->returnValue($this->store));
+        $storeManager->expects($this->any())
+            ->method('getWebsite')
+            ->will($this->returnValue($this->website));
+        $this->indexerRegistryMock = $this->getMock('Magento\Indexer\Model\IndexerRegistry', ['get'], [], '', false);
+        $this->categoryRepository = $this->getMock('Magento\Catalog\Api\CategoryRepositoryInterface');
+
+        $this->_catalogProduct = $this->getMock(
+            'Magento\Catalog\Helper\Product',
+            ['isDataForProductCategoryIndexerWasChanged'],
+            [],
+            '',
+            false
+        );
+
+        $this->imageCache = $this->getMockBuilder('Magento\Catalog\Model\Product\Image\Cache')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->imageCacheFactory = $this->getMockBuilder('Magento\Catalog\Model\Product\Image\CacheFactory')
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->productLinkFactory = $this->getMockBuilder('Magento\Catalog\Api\Data\ProductLinkInterfaceFactory')
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->mediaGalleryEntryFactoryMock =
+            $this->getMockBuilder('Magento\Catalog\Api\Data\ProductAttributeMediaGalleryEntryInterfaceFactory')
+                ->setMethods(['create'])
+                ->disableOriginalConstructor()
+                ->getMock();
+
+        $this->metadataServiceMock = $this->getMock('\Magento\Catalog\Api\ProductAttributeRepositoryInterface');
+        $this->attributeValueFactory = $this->getMockBuilder('Magento\Framework\Api\AttributeValueFactory')
+            ->disableOriginalConstructor()->getMock();
+        $this->linkTypeProviderMock = $this->getMock('Magento\Catalog\Model\Product\LinkTypeProvider',
+            ['getLinkTypes'], [], '', false);
+        $this->entityCollectionProviderMock = $this->getMock('Magento\Catalog\Model\ProductLink\CollectionProvider',
+            ['getCollection'], [], '', false);
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->model = $this->objectManagerHelper->getObject(
+            'Magento\Catalog\Model\Product',
+            [
+                'context' => $contextMock,
+                'catalogProductType' => $this->productTypeInstanceMock,
+                'productFlatIndexerProcessor' => $this->productFlatProcessor,
+                'productPriceIndexerProcessor' => $this->productPriceProcessor,
+                'catalogProductOption' => $this->optionInstanceMock,
+                'storeManager' => $storeManager,
+                'resource' => $this->resource,
+                'registry' => $this->registry,
+                'moduleManager' => $this->moduleManager,
+                'stockItemFactory' => $this->stockItemFactoryMock,
+                'dataObjectHelper' => $this->dataObjectHelperMock,
+                'indexerRegistry' => $this->indexerRegistryMock,
+                'categoryRepository' => $this->categoryRepository,
+                'catalogProduct' => $this->_catalogProduct,
+                'imageCacheFactory' => $this->imageCacheFactory,
+                'productLinkFactory' => $this->productLinkFactory,
+                'mediaGalleryEntryFactory' => $this->mediaGalleryEntryFactoryMock,
+                'metadataService' => $this->metadataServiceMock,
+                'customAttributeFactory' => $this->attributeValueFactory,
+                'entityCollectionProvider' => $this->entityCollectionProviderMock,
+                'linkTypeProvider' => $this->linkTypeProviderMock,
+                'data' => ['id' => 1]
+            ]
+        );
+
+    }
+
+    /**
+     *  Test for getProductLinks() with associated product links
+     */
+    public function testGetProductLinks()
+    {
+        $this->markTestIncomplete('Skipped due to https://jira.corp.x.com/browse/MAGETWO-36926');
+        $linkTypes = ['related' => 1, 'upsell' => 4, 'crosssell' => 5, 'associated' => 3];
+        $this->linkTypeProviderMock->expects($this->once())
+            ->method('getLinkTypes')
+            ->willReturn($linkTypes);
+
+        $inputRelatedLink = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $inputRelatedLink->setProductSku("Simple Product 1");
+        $inputRelatedLink->setLinkType("related");
+        $inputRelatedLink->setData("sku", "Simple Product 2");
+        $inputRelatedLink->setData("type", "simple");
+        $inputRelatedLink->setPosition(0);
+
+        $customData = ["attribute_code" => "qty", "value" => 1];
+        $inputGroupLink = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $inputGroupLink->setProductSku("Simple Product 1");
+        $inputGroupLink->setLinkType("associated");
+        $inputGroupLink->setData("sku", "Simple Product 2");
+        $inputGroupLink->setData("type", "simple");
+        $inputGroupLink->setPosition(0);
+        $inputGroupLink["custom_attributes"] = [$customData];
+
+        $outputRelatedLink = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $outputRelatedLink->setProductSku("Simple Product 1");
+        $outputRelatedLink->setLinkType("related");
+        $outputRelatedLink->setLinkedProductSku("Simple Product 2");
+        $outputRelatedLink->setLinkedProductType("simple");
+        $outputRelatedLink->setPosition(0);
+
+        $groupExtension = $this->objectManagerHelper->getObject('Magento\Catalog\Api\Data\ProductLinkExtension');
+        $reflectionOfExtension = new \ReflectionClass('Magento\Catalog\Api\Data\ProductLinkExtension');
+        $method = $reflectionOfExtension->getMethod('setData');
+        $method->setAccessible(true);
+        $method->invokeArgs($groupExtension, array('qty', 1));
+
+        $outputGroupLink = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $outputGroupLink->setProductSku("Simple Product 1");
+        $outputGroupLink->setLinkType("associated");
+        $outputGroupLink->setLinkedProductSku("Simple Product 2");
+        $outputGroupLink->setLinkedProductType("simple");
+        $outputGroupLink->setPosition(0);
+        $outputGroupLink->setExtensionAttributes($groupExtension);
+
+        $this->entityCollectionProviderMock->expects($this->at(0))
+            ->method('getCollection')
+            ->with($this->model, 'related')
+            ->willReturn([$inputRelatedLink]);
+        $this->entityCollectionProviderMock->expects($this->at(1))
+            ->method('getCollection')
+            ->with($this->model, 'upsell')
+            ->willReturn([]);
+        $this->entityCollectionProviderMock->expects($this->at(2))
+            ->method('getCollection')
+            ->with($this->model, 'crosssell')
+            ->willReturn([]);
+        $this->entityCollectionProviderMock->expects($this->at(3))
+            ->method('getCollection')
+            ->with($this->model, 'associated')
+            ->willReturn([$inputGroupLink]);
+
+        $expectedOutput = [$outputRelatedLink, $outputGroupLink];
+        $typeInstanceMock = $this->getMock(
+            'Magento\ConfigurableProduct\Model\Product\Type\Simple', ["getSku"], [], '', false);
+        $typeInstanceMock
+            ->expects($this->atLeastOnce())
+            ->method('getSku')
+            ->willReturn("Simple Product 1");
+        $this->model->setTypeInstance($typeInstanceMock);
+
+        $productLink1 = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $productLink2 = $this->objectManagerHelper->getObject('Magento\Catalog\Model\ProductLink\Link');
+        $this->productLinkFactory->expects($this->at(0))
+            ->method('create')
+            ->willReturn($productLink1);
+        $this->productLinkFactory->expects($this->at(1))
+            ->method('create')
+            ->willReturn($productLink2);
+
+        $extension = $this->objectManagerHelper->getObject('Magento\Catalog\Api\Data\ProductLinkExtension');
+        $productLink2->setExtensionAttributes($extension);
+
+        $links = $this->model->getProductLinks();
+        // Match the links
+        $matches = 0;
+        foreach ($links as $link) {
+            foreach ($expectedOutput as $expected) {
+                if ($expected->getData() == $link->getData()) {
+                    $matches++;
+                }
+            }
+        }
+        $this->assertEquals($matches, 2);
+    }
+}
diff --git a/app/code/Magento/Indexer/App/Shell.php b/app/code/Magento/Indexer/App/Shell.php
deleted file mode 100644
index 4fc81d4145176d652472e2f08fc49c4d809620c5..0000000000000000000000000000000000000000
--- a/app/code/Magento/Indexer/App/Shell.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Indexer\App;
-
-use Magento\Framework\App\Bootstrap;
-
-class Shell implements \Magento\Framework\AppInterface
-{
-    /**
-     * Filename of the entry point script
-     *
-     * @var string
-     */
-    protected $entryFileName;
-
-    /**
-     * @var \Magento\Framework\App\Console\Response
-     */
-    protected $response;
-
-    /**
-     * @var \Magento\Indexer\Model\ShellFactory
-     */
-    protected $shellFactory;
-
-    /**
-     * @param string $entryFileName
-     * @param \Magento\Indexer\Model\ShellFactory $shellFactory
-     * @param \Magento\Framework\App\Console\Response $response
-     */
-    public function __construct(
-        $entryFileName,
-        \Magento\Indexer\Model\ShellFactory $shellFactory,
-        \Magento\Framework\App\Console\Response $response
-    ) {
-        $this->entryFileName = $entryFileName;
-        $this->shellFactory = $shellFactory;
-        $this->response = $response;
-    }
-
-    /**
-     * Run application
-     *
-     * @return \Magento\Framework\App\ResponseInterface
-     */
-    public function launch()
-    {
-        /** @var $shell \Magento\Indexer\Model\Shell */
-        $shell = $this->shellFactory->create(['entryPoint' => $this->entryFileName]);
-        $shell->run();
-        if ($shell->hasErrors()) {
-            $this->response->setCode(-1);
-        } else {
-            $this->response->setCode(0);
-        }
-        return $this->response;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function catchException(Bootstrap $bootstrap, \Exception $exception)
-    {
-        return false;
-    }
-}
diff --git a/app/code/Magento/Indexer/Console/Command/AbstractIndexerCommand.php b/app/code/Magento/Indexer/Console/Command/AbstractIndexerCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..36f9ec1dd5b273cb2b94efaa0266afb2495e09e8
--- /dev/null
+++ b/app/code/Magento/Indexer/Console/Command/AbstractIndexerCommand.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Console\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Magento\Indexer\Model\IndexerFactory;
+use Magento\Indexer\Model\Indexer\CollectionFactory;
+use Magento\Indexer\Model\IndexerInterface;
+use Magento\Indexer\Model\Indexer;
+use Magento\Store\Model\StoreManager;
+use Magento\Framework\App\ObjectManagerFactory;
+
+/**
+ * An Abstract class for Indexer related commands.
+ */
+abstract class AbstractIndexerCommand extends Command
+{
+    /**#@+
+     * Names of input arguments or options
+     */
+    const INPUT_KEY_ALL = 'all';
+    const INPUT_KEY_INDEXERS = 'index';
+    /**#@- */
+
+    /**
+     * Collection of Indexers factory
+     *
+     * @var CollectionFactory
+     */
+    protected $collectionFactory;
+
+    /**
+     * Indexer factory
+     *
+     * @var IndexerFactory
+     */
+    protected $indexerFactory;
+
+    /**
+     * Constructor
+     * @param ObjectManagerFactory $objectManagerFactory
+     */
+    public function __construct(ObjectManagerFactory $objectManagerFactory)
+    {
+        $params = $_SERVER;
+        $params[StoreManager::PARAM_RUN_CODE] = 'admin';
+        $params[StoreManager::PARAM_RUN_TYPE] = 'store';
+        $objectManager = $objectManagerFactory->create($params);
+        $this->collectionFactory = $objectManager->create('Magento\Indexer\Model\Indexer\CollectionFactory');
+        $this->indexerFactory = $objectManager->create('Magento\Indexer\Model\IndexerFactory');
+        parent::__construct();
+    }
+
+    /**
+     * Returns all indexers
+     *
+     * @return IndexerInterface[]
+     */
+    protected function getAllIndexers()
+    {
+        /** @var Indexer[] $indexers */
+        return $this->collectionFactory->create()->getItems();
+    }
+}
diff --git a/app/code/Magento/Indexer/Console/Command/AbstractIndexerManageCommand.php b/app/code/Magento/Indexer/Console/Command/AbstractIndexerManageCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..0105728d25404c8673aa2221f7f0e6cf6cc38753
--- /dev/null
+++ b/app/code/Magento/Indexer/Console/Command/AbstractIndexerManageCommand.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputArgument;
+use Magento\Indexer\Model\IndexerInterface;
+
+/**
+ * An Abstract class for all Indexer related commands.
+ */
+abstract class AbstractIndexerManageCommand extends AbstractIndexerCommand
+{
+    /**
+     * Gets list of indexers
+     *
+     * @param InputInterface $input
+     * @param OutputInterface $output
+     * @return IndexerInterface[]
+     */
+    protected function getIndexers(InputInterface $input, OutputInterface $output)
+    {
+        $inputArguments = $input->getArgument(self::INPUT_KEY_INDEXERS);
+        if (isset($inputArguments) && sizeof($inputArguments)>0) {
+            $indexers = [];
+            foreach ($inputArguments as $code) {
+                $indexer = $this->indexerFactory->create();
+                try {
+                    $indexer->load($code);
+                    $indexers[] = $indexer;
+                } catch (\Exception $e) {
+                    $output->writeln('Warning: Unknown indexer with code ' . trim($code));
+                }
+            }
+        } else {
+            $indexers = $this->getAllIndexers();
+        }
+        return $indexers;
+    }
+
+    /**
+     * Get list of options and arguments for the command
+     *
+     * @return mixed
+     */
+    public function getInputList()
+    {
+        return [
+            new InputOption(self::INPUT_KEY_ALL, 'a', InputOption::VALUE_NONE, 'All Indexes'),
+            new InputArgument(
+                self::INPUT_KEY_INDEXERS,
+                InputArgument::OPTIONAL | InputArgument::IS_ARRAY,
+                'List of Indexes'
+            ),
+        ];
+    }
+}
diff --git a/app/code/Magento/Indexer/Console/Command/IndexerInfoCommand.php b/app/code/Magento/Indexer/Console/Command/IndexerInfoCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..e0b724a2b1e82e098d15e6ad19ea8a45ca1a3421
--- /dev/null
+++ b/app/code/Magento/Indexer/Console/Command/IndexerInfoCommand.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Command for displaying information related to indexers.
+ */
+class IndexerInfoCommand extends AbstractIndexerCommand
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('indexer:info')->setDescription('Shows allowed Indexers');
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $indexers = $this->getAllIndexers();
+        foreach ($indexers as $indexer) {
+            $output->writeln(sprintf('%-40s %s', $indexer->getId(), $indexer->getTitle()));
+        }
+    }
+}
diff --git a/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php b/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..b52d1da6154e1288a14c414d8b2765a2afcb653d
--- /dev/null
+++ b/app/code/Magento/Indexer/Console/Command/IndexerReindexCommand.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Command for reindexing indexers.
+ */
+class IndexerReindexCommand extends AbstractIndexerManageCommand
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('indexer:reindex')
+            ->setDescription(
+                'Reindexes Data'
+            )->setDefinition($this->getInputList());
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $indexers = $this->getIndexers($input, $output);
+        foreach ($indexers as $indexer) {
+            try {
+                $startTime = microtime(true);
+                $indexer->reindexAll();
+                $resultTime = microtime(true) - $startTime;
+                $output->writeln(
+                    $indexer->getTitle() . ' index has been rebuilt successfully in ' . gmdate('H:i:s', $resultTime)
+                );
+            } catch (\Magento\Framework\Exception\LocalizedException $e) {
+                $output->writeln($e->getMessage());
+            } catch (\Exception $e) {
+                $output->writeln($indexer->getTitle() . ' indexer process unknown error:');
+                $output->writeln($e->getMessage());
+            }
+        }
+    }
+}
diff --git a/app/code/Magento/Indexer/Console/Command/IndexerSetModeCommand.php b/app/code/Magento/Indexer/Console/Command/IndexerSetModeCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..e5901edc53d588da92892863b25d821298df3064
--- /dev/null
+++ b/app/code/Magento/Indexer/Console/Command/IndexerSetModeCommand.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputArgument;
+
+/**
+ * Command for setting index mode for indexers.
+ */
+class IndexerSetModeCommand extends AbstractIndexerManageCommand
+{
+    /**#@+
+     * Names of input arguments or options
+     */
+    const INPUT_KEY_MODE = 'mode';
+    const INPUT_KEY_REALTIME = 'realtime';
+    const INPUT_KEY_SCHEDULE = 'schedule';
+    /**#@- */
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('indexer:set-mode')
+            ->setDescription(
+                'Sets index mode type'
+            )->setDefinition($this->getInputList());
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $errors = $this->validate($input);
+        if ($errors) {
+            throw new \InvalidArgumentException(implode("\n", $errors));
+        }
+
+        $indexers = $this->getIndexers($input, $output);
+
+        foreach ($indexers as $indexer) {
+            try {
+                $previousStatus = $indexer->isScheduled() ? 'Update by Schedule' : 'Update on Save';
+                $indexer->setScheduled($input->getArgument(self::INPUT_KEY_MODE) === self::INPUT_KEY_SCHEDULE);
+                $currentStatus = $indexer->isScheduled() ? 'Update by Schedule' : 'Update on Save';
+                if ($previousStatus !== $currentStatus) {
+                    $output->writeln(
+                        'Index mode for Indexer ' . $indexer->getTitle() . ' was changed from \''
+                        . $previousStatus . '\' to \'' . $currentStatus . '\''
+                    );
+                } else {
+                    $output->writeln('Index mode for Indexer ' . $indexer->getTitle() . ' has not been changed');
+                }
+            } catch (\Magento\Framework\Exception\LocalizedException $e) {
+                $output->writeln($e->getMessage() . PHP_EOL);
+            } catch (\Exception $e) {
+                $output->writeln($indexer->getTitle() . " indexer process unknown error:" . PHP_EOL);
+                $output->writeln($e->getMessage() . PHP_EOL);
+            }
+        }
+
+        return $this;
+    }
+
+    /**
+     * Get list of arguments for the command
+     *
+     * @return InputOption[]
+     */
+    public function getInputList()
+    {
+        $modeOptions[] = new InputArgument(
+            self::INPUT_KEY_MODE,
+            InputArgument::OPTIONAL,
+            'Indexer mode type ['. self::INPUT_KEY_REALTIME . '|' . self::INPUT_KEY_SCHEDULE .']'
+        );
+        $optionsList = array_merge($modeOptions, parent::getInputList());
+        return $optionsList;
+    }
+
+    /**
+     * Check if all admin options are provided
+     *
+     * @param InputInterface $input
+     * @return string[]
+     */
+    public function validate(InputInterface $input)
+    {
+        $errors = [];
+        $acceptedValues = ' Accepted values for ' . self::INPUT_KEY_MODE . ' are \''
+            . self::INPUT_KEY_REALTIME . '\' or \'' . self::INPUT_KEY_SCHEDULE . '\'';
+
+        $inputMode = $input->getArgument(self::INPUT_KEY_MODE);
+        if (!$inputMode) {
+            $errors[] = 'Missing argument \'' . self::INPUT_KEY_MODE .'\'.' . $acceptedValues;
+        } elseif (!in_array($inputMode, [self::INPUT_KEY_REALTIME, self::INPUT_KEY_SCHEDULE])) {
+            $errors[] = $acceptedValues;
+        }
+        return $errors;
+    }
+}
diff --git a/app/code/Magento/Indexer/Console/Command/IndexerShowModeCommand.php b/app/code/Magento/Indexer/Console/Command/IndexerShowModeCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..35c3886de1e72fff56b3ec7013a599cab4956282
--- /dev/null
+++ b/app/code/Magento/Indexer/Console/Command/IndexerShowModeCommand.php
@@ -0,0 +1,38 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Command for displaying current index mode for indexers.
+ */
+class IndexerShowModeCommand extends AbstractIndexerManageCommand
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('indexer:show-mode')
+            ->setDescription('Shows Index Mode')
+            ->setDefinition($this->getInputList());
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $indexers = $this->getIndexers($input, $output);
+        foreach ($indexers as $indexer) {
+            $status = $indexer->isScheduled() ? 'Update by Schedule' : 'Update on Save';
+            $output->writeln(sprintf('%-50s ', $indexer->getTitle() . ':') . $status);
+        }
+    }
+}
diff --git a/app/code/Magento/Indexer/Console/Command/IndexerStatusCommand.php b/app/code/Magento/Indexer/Console/Command/IndexerStatusCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..6eda0f852453d7278c818c85f23628b817c31143
--- /dev/null
+++ b/app/code/Magento/Indexer/Console/Command/IndexerStatusCommand.php
@@ -0,0 +1,49 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Command for displaying status of indexers.
+ */
+class IndexerStatusCommand extends AbstractIndexerManageCommand
+{
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('indexer:status')
+            ->setDescription('Shows status of Indexer')
+            ->setDefinition($this->getInputList());
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $indexers = $this->getIndexers($input, $output);
+        foreach ($indexers as $indexer) {
+            $status = 'unknown';
+            switch ($indexer->getStatus()) {
+                case \Magento\Indexer\Model\Indexer\State::STATUS_VALID:
+                    $status = 'Ready';
+                    break;
+                case \Magento\Indexer\Model\Indexer\State::STATUS_INVALID:
+                    $status = 'Reindex required';
+                    break;
+                case \Magento\Indexer\Model\Indexer\State::STATUS_WORKING:
+                    $status = 'Processing';
+                    break;
+            }
+            $output->writeln(sprintf('%-50s ', $indexer->getTitle() . ':') . $status);
+        }
+    }
+}
diff --git a/app/code/Magento/Indexer/Model/Shell.php b/app/code/Magento/Indexer/Model/Shell.php
deleted file mode 100644
index 37509102c38f05e49c954d9465b455b62cbf9f69..0000000000000000000000000000000000000000
--- a/app/code/Magento/Indexer/Model/Shell.php
+++ /dev/null
@@ -1,248 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Indexer\Model;
-
-class Shell extends \Magento\Framework\App\AbstractShell
-{
-    /**
-     * Error status - whether errors have happened
-     *
-     * @var bool
-     */
-    protected $hasErrors = false;
-
-    /**
-     * @var Indexer\CollectionFactory
-     */
-    protected $indexersFactory;
-
-    /**
-     * @var IndexerFactory
-     */
-    protected $indexerFactory;
-
-    /**
-     * @param \Magento\Framework\Filesystem $filesystem
-     * @param string $entryPoint
-     * @param Indexer\CollectionFactory $indexersFactory
-     * @param IndexerFactory $indexerFactory
-     */
-    public function __construct(
-        \Magento\Framework\Filesystem $filesystem,
-        $entryPoint,
-        Indexer\CollectionFactory $indexersFactory,
-        IndexerFactory $indexerFactory
-    ) {
-        $this->indexersFactory = $indexersFactory;
-        $this->indexerFactory = $indexerFactory;
-        parent::__construct($filesystem, $entryPoint);
-    }
-
-    /**
-     * Run this model, assumed to be run by command-line
-     *
-     * @return \Magento\Indexer\Model\Shell
-     */
-    public function run()
-    {
-        if ($this->_showHelp()) {
-            return $this;
-        }
-
-        if ($this->getArg('info')) {
-            $this->runShowInfo();
-        } elseif ($this->getArg('status') || $this->getArg('mode')) {
-            $this->runShowStatusOrMode();
-        } elseif ($this->getArg('mode-realtime') || $this->getArg('mode-schedule')) {
-            $this->runSetMode();
-        } elseif ($this->getArg('reindex') || $this->getArg('reindexall')) {
-            $this->runReindex();
-        } else {
-            echo $this->getUsageHelp();
-        }
-
-        return $this;
-    }
-
-    /**
-     * Show information about indexes
-     *
-     * @return \Magento\Indexer\Model\Shell
-     */
-    protected function runShowInfo()
-    {
-        $indexers = $this->parseIndexerString('all');
-        foreach ($indexers as $indexer) {
-            echo sprintf('%-40s', $indexer->getId());
-            echo $indexer->getTitle() . PHP_EOL;
-        }
-
-        return $this;
-    }
-
-    /**
-     * Show information about statuses or modes
-     *
-     * @return \Magento\Indexer\Model\Shell
-     */
-    protected function runShowStatusOrMode()
-    {
-        if ($this->getArg('status')) {
-            $indexers = $this->parseIndexerString($this->getArg('status'));
-        } else {
-            $indexers = $this->parseIndexerString($this->getArg('mode'));
-        }
-
-        foreach ($indexers as $indexer) {
-            $status = 'unknown';
-            if ($this->getArg('status')) {
-                switch ($indexer->getStatus()) {
-                    case \Magento\Indexer\Model\Indexer\State::STATUS_VALID:
-                        $status = 'Ready';
-                        break;
-                    case \Magento\Indexer\Model\Indexer\State::STATUS_INVALID:
-                        $status = 'Reindex required';
-                        break;
-                    case \Magento\Indexer\Model\Indexer\State::STATUS_WORKING:
-                        $status = 'Processing';
-                        break;
-                }
-            } else {
-                $status = $indexer->isScheduled() ? 'Update by Schedule' : 'Update on Save';
-            }
-            echo sprintf('%-50s ', $indexer->getTitle() . ':') . $status . PHP_EOL;
-        }
-
-        return $this;
-    }
-
-    /**
-     * Set new mode for indexers
-     *
-     * @return \Magento\Indexer\Model\Shell
-     */
-    protected function runSetMode()
-    {
-        if ($this->getArg('mode-realtime')) {
-            $method = 'turnViewOff';
-            $indexers = $this->parseIndexerString($this->getArg('mode-realtime'));
-        } else {
-            $method = 'turnViewOn';
-            $indexers = $this->parseIndexerString($this->getArg('mode-schedule'));
-        }
-
-        foreach ($indexers as $indexer) {
-            try {
-                $indexer->{$method}();
-                echo $indexer->getTitle() . " indexer was successfully changed index mode" . PHP_EOL;
-            } catch (\Magento\Framework\Exception\LocalizedException $e) {
-                echo $e->getMessage() . PHP_EOL;
-                $this->hasErrors = true;
-            } catch (\Exception $e) {
-                echo $indexer->getTitle() . " indexer process unknown error:" . PHP_EOL;
-                echo $e . PHP_EOL;
-                $this->hasErrors = true;
-            }
-        }
-
-        return $this;
-    }
-
-    /**
-     * Reindex indexer(s)
-     *
-     * @return \Magento\Indexer\Model\Shell
-     */
-    protected function runReindex()
-    {
-        if ($this->getArg('reindex')) {
-            $indexers = $this->parseIndexerString($this->getArg('reindex'));
-        } else {
-            $indexers = $this->parseIndexerString('all');
-        }
-
-        foreach ($indexers as $indexer) {
-            try {
-                $startTime = microtime(true);
-                $indexer->reindexAll();
-                $resultTime = microtime(true) - $startTime;
-                echo $indexer->getTitle() . ' index has been rebuilt successfully in '
-                    . gmdate('H:i:s', $resultTime) . PHP_EOL;
-            } catch (\Magento\Framework\Exception\LocalizedException $e) {
-                echo $e->getMessage() . PHP_EOL;
-                $this->hasErrors = true;
-            } catch (\Exception $e) {
-                echo $indexer->getTitle() . ' indexer process unknown error:' . PHP_EOL;
-                echo $e . PHP_EOL;
-                $this->hasErrors = true;
-            }
-        }
-
-        return $this;
-    }
-
-    /**
-     * Parses string with indexers and return array of indexer instances
-     *
-     * @param string $string
-     * @return IndexerInterface[]
-     */
-    protected function parseIndexerString($string)
-    {
-        $indexers = [];
-        if ($string == 'all') {
-            /** @var Indexer[] $indexers */
-            $indexers = $this->indexersFactory->create()->getItems();
-        } elseif (!empty($string)) {
-            $codes = explode(',', $string);
-            foreach ($codes as $code) {
-                $indexer = $this->indexerFactory->create();
-                try {
-                    $indexer->load($code);
-                    $indexers[] = $indexer;
-                } catch (\Exception $e) {
-                    echo 'Warning: Unknown indexer with code ' . trim($code) . PHP_EOL;
-                    $this->hasErrors = true;
-                }
-            }
-        }
-        return $indexers;
-    }
-
-    /**
-     * Return whether there errors have happened
-     *
-     * @return bool
-     */
-    public function hasErrors()
-    {
-        return $this->hasErrors;
-    }
-
-    /**
-     * Retrieves usage help message
-     *
-     * @return string
-     */
-    public function getUsageHelp()
-    {
-        return <<<USAGE
-Usage:  php -f {$this->_entryPoint} -- [options]
-
-  --status <indexer>            Show Indexer(s) Status
-  --mode <indexer>              Show Indexer(s) Index Mode
-  --mode-realtime <indexer>     Set index mode type "Update on Save"
-  --mode-schedule <indexer>     Set index mode type "Update by Schedule"
-  --reindex <indexer>           Reindex Data
-  info                          Show allowed indexers
-  reindexall                    Reindex Data by all indexers
-  help                          This help
-
-  <indexer>     Comma separated indexer codes or value "all" for all indexers
-
-USAGE;
-    }
-}
diff --git a/app/code/Magento/Indexer/Test/Unit/App/ShellTest.php b/app/code/Magento/Indexer/Test/Unit/App/ShellTest.php
deleted file mode 100644
index d86b89477a9e78a8da96bc3f70d6c469fc39d099..0000000000000000000000000000000000000000
--- a/app/code/Magento/Indexer/Test/Unit/App/ShellTest.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Indexer\Test\Unit\App;
-
-class ShellTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \Magento\Indexer\App\Shell
-     */
-    protected $entryPoint;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $shellFactoryMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $responseMock;
-
-    protected function setUp()
-    {
-        $this->shellFactoryMock = $this->getMock(
-            'Magento\Indexer\Model\ShellFactory',
-            ['create'],
-            [],
-            '',
-            false
-        );
-        $this->responseMock = $this->getMock('Magento\Framework\App\Console\Response', [], [], '', false);
-        $this->entryPoint = new \Magento\Indexer\App\Shell(
-            'indexer.php',
-            $this->shellFactoryMock,
-            $this->responseMock
-        );
-    }
-
-    /**
-     * @param boolean $shellHasErrors
-     * @dataProvider processRequestDataProvider
-     */
-    public function testProcessRequest($shellHasErrors)
-    {
-        $shell = $this->getMock('Magento\Indexer\Model\Shell', [], [], '', false);
-        $shell->expects($this->once())->method('hasErrors')->will($this->returnValue($shellHasErrors));
-        $shell->expects($this->once())->method('run');
-        $this->shellFactoryMock->expects($this->any())->method('create')->will($this->returnValue($shell));
-
-        $this->entryPoint->launch();
-    }
-
-    /**
-     * @return array
-     */
-    public function processRequestDataProvider()
-    {
-        return [[true], [false]];
-    }
-
-    public function testCatchException()
-    {
-        $bootstrap = $this->getMock('Magento\Framework\App\Bootstrap', [], [], '', false);
-        $this->assertFalse($this->entryPoint->catchException($bootstrap, new \Exception()));
-    }
-}
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerCommandCommonTestSetup.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerCommandCommonTestSetup.php
new file mode 100644
index 0000000000000000000000000000000000000000..323e8c9be7a45d5520311a6fc00e13d07073ef56
--- /dev/null
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerCommandCommonTestSetup.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Test\Unit\Console\Command;
+
+use Magento\Framework\App\ObjectManagerFactory;
+
+class IndexerCommandCommonTestSetup extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|IndexerFactory
+     */
+    protected $indexerFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|CollectionFactory
+     */
+    protected $collectionFactory;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject|ObjectManagerFactory
+     */
+    protected $objectManagerFactory;
+
+    protected function setUp()
+    {
+        $this->objectManagerFactory = $this->getMock('Magento\Framework\App\ObjectManagerFactory', [], [], '', false);
+        $objectManager = $this->getMockForAbstractClass('Magento\Framework\ObjectManagerInterface');
+
+        $this->collectionFactory = $this->getMock(
+            'Magento\Indexer\Model\Indexer\CollectionFactory',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->indexerFactory = $this->getMock('Magento\Indexer\Model\IndexerFactory', [], [], '', false);
+
+        $objectManager
+            ->expects($this->exactly(2))
+            ->method('create')
+            ->will($this->returnValueMap([
+                ['Magento\Indexer\Model\Indexer\CollectionFactory', [], $this->collectionFactory],
+                ['Magento\Indexer\Model\IndexerFactory', [], $this->indexerFactory],
+            ]));
+
+        $this->objectManagerFactory->expects($this->once())->method('create')->willReturn($objectManager);
+    }
+}
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerInfoCommandTest.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerInfoCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..2f6da06042dd634065895283c8250a8234684180
--- /dev/null
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerInfoCommandTest.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Test\Unit\Console\Command;
+
+use Magento\Indexer\Console\Command\IndexerInfoCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class IndexerInfoCommandTest extends IndexerCommandCommonTestSetup
+{
+    /**
+     * Command being tested
+     *
+     * @var IndexerInfoCommand
+     */
+    private $command;
+
+    public function testExecute()
+    {
+        $collection = $this->getMock('Magento\Indexer\Model\Indexer\Collection', [], [], '', false);
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerOne->expects($this->once())->method('getId')->willReturn('id_indexerOne');
+        $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $collection->expects($this->once())->method('getItems')->willReturn([$indexerOne]);
+
+        $this->collectionFactory->expects($this->once())->method('create')->will($this->returnValue($collection));
+        $this->indexerFactory->expects($this->never())->method('create');
+        $this->command = new IndexerInfoCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute([]);
+        $actualValue = $commandTester->getDisplay();
+        $this->assertSame(sprintf('%-40s %s', 'id_indexerOne', 'Title_indexerOne') . PHP_EOL, $actualValue);
+    }
+}
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..80eb1d9c2f84fc87da14881672f91c48be33e90e
--- /dev/null
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerReindexCommandTest.php
@@ -0,0 +1,110 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Test\Unit\Console\Command;
+
+use Magento\Indexer\Console\Command\IndexerReindexCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class IndexerReindexCommandTest extends IndexerCommandCommonTestSetup
+{
+    /**
+     * Command being tested
+     *
+     * @var IndexerReindexCommand
+     */
+    private $command;
+
+    public function testGetOptions()
+    {
+        $this->command = new IndexerReindexCommand($this->objectManagerFactory);
+        $optionsList = $this->command->getInputList();
+        $this->assertSame(2, sizeof($optionsList));
+        $this->assertSame('all', $optionsList[0]->getName());
+        $this->assertSame('index', $optionsList[1]->getName());
+    }
+
+    public function testExecuteAll()
+    {
+        $collection = $this->getMock('Magento\Indexer\Model\Indexer\Collection', [], [], '', false);
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $collection->expects($this->once())->method('getItems')->willReturn([$indexerOne]);
+
+        $this->collectionFactory->expects($this->once())->method('create')->will($this->returnValue($collection));
+        $this->indexerFactory->expects($this->never())->method('create');
+        $this->command = new IndexerReindexCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute([]);
+        $actualValue = $commandTester->getDisplay();
+        $this->assertStringStartsWith('Title_indexerOne index has been rebuilt successfully in', $actualValue);
+    }
+
+    public function testExecuteWithIndex()
+    {
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerOne->expects($this->once())->method('reindexAll');
+        $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $indexerOne->expects($this->once())->method('load')->with('id_indexerOne')->willReturn($indexerOne);
+
+        $indexerTwo = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerTwo->expects($this->once())->method('reindexAll');
+        $indexerTwo->expects($this->once())->method('getTitle')->willReturn('Title_indexerTwo');
+        $indexerTwo->expects($this->once())->method('load')->with('id_indexerTwo')->willReturn($indexerTwo);
+
+        $this->collectionFactory->expects($this->never())->method('create');
+        $this->indexerFactory->expects($this->at(0))->method('create')->willReturn($indexerOne);
+        $this->indexerFactory->expects($this->at(1))->method('create')->willReturn($indexerTwo);
+        $this->command = new IndexerReindexCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(['index' => ['id_indexerOne', 'id_indexerTwo']]);
+        $actualValue = $commandTester->getDisplay();
+        $this->assertStringStartsWith('Title_indexerOne index has been rebuilt successfully in', $actualValue);
+    }
+
+    public function testExecuteWithLocalizedException()
+    {
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $localizedException = new \Magento\Framework\Exception\LocalizedException(__('Some Exception Message'));
+        $indexerOne->expects($this->once())->method('reindexAll')->will($this->throwException($localizedException));
+        $this->collectionFactory->expects($this->never())->method('create');
+        $this->indexerFactory->expects($this->once())->method('create')->willReturn($indexerOne);
+        $this->command = new IndexerReindexCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(['index' => ['id_indexerOne']]);
+        $actualValue = $commandTester->getDisplay();
+        $this->assertStringStartsWith('Some Exception Message', $actualValue);
+    }
+
+    public function testExecuteWithException()
+    {
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $exception = new \Exception();
+        $indexerOne->expects($this->once())->method('reindexAll')->will($this->throwException($exception));
+        $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $this->collectionFactory->expects($this->never())->method('create');
+        $this->indexerFactory->expects($this->once())->method('create')->willReturn($indexerOne);
+        $this->command = new IndexerReindexCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(['index' => ['id_indexerOne']]);
+        $actualValue = $commandTester->getDisplay();
+        $this->assertStringStartsWith('Title_indexerOne indexer process unknown error:', $actualValue);
+    }
+
+    public function testExecuteWithExceptionInLoad()
+    {
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $exception = new \Exception();
+        $indexerOne->expects($this->once())->method('load')->will($this->throwException($exception));
+        $indexerOne->expects($this->never())->method('getTitle');
+        $this->collectionFactory->expects($this->never())->method('create');
+        $this->indexerFactory->expects($this->once())->method('create')->willReturn($indexerOne);
+        $this->command = new IndexerReindexCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(['index' => ['id_indexerOne']]);
+        $actualValue = $commandTester->getDisplay();
+        $this->assertStringStartsWith('Warning: Unknown indexer with code', $actualValue);
+    }
+}
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerSetModeCommandTest.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerSetModeCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..dcd345dc6ffe505a1f3049c48faff5f784d39fcb
--- /dev/null
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerSetModeCommandTest.php
@@ -0,0 +1,176 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Test\Unit\Console\Command;
+
+use Magento\Indexer\Console\Command\IndexerSetModeCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+/**
+ * Command for updating installed application after the code base has changed
+ */
+class IndexerSetModeCommandTest extends IndexerCommandCommonTestSetup
+{
+    /**
+     * Command being tested
+     *
+     * @var IndexerSetModeCommand
+     */
+    private $command;
+
+    public function testGetOptions()
+    {
+        $this->command = new IndexerSetModeCommand($this->objectManagerFactory);
+        $optionsList = $this->command->getInputList();
+        $this->assertSame(3, sizeof($optionsList));
+        $this->assertSame('mode', $optionsList[0]->getName());
+        $this->assertSame('all', $optionsList[1]->getName());
+        $this->assertSame('index', $optionsList[2]->getName());
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     * @expectedExceptionMessage Missing argument 'mode'. Accepted values for mode are 'realtime' or 'schedule'
+     */
+    public function testExecuteInvalidArgument()
+    {
+        $this->command = new IndexerSetModeCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute([]);
+    }
+
+    /**
+     * @expectedException InvalidArgumentException
+     * @expectedExceptionMessage Accepted values for mode are 'realtime' or 'schedule'
+     */
+    public function testExecuteInvalidMode()
+    {
+        $this->command = new IndexerSetModeCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(['mode' => 'wrong_mode']);
+    }
+
+    public function testExecuteAll()
+    {
+        $collection = $this->getMock('Magento\Indexer\Model\Indexer\Collection', [], [], '', false);
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+
+        $indexerOne->expects($this->at(0))->method('isScheduled')->willReturn(true);
+        $indexerOne->expects($this->at(2))->method('isScheduled')->willReturn(false);
+
+        $indexerOne->expects($this->once())->method('setScheduled')->with(false);
+        $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $collection->expects($this->once())->method('getItems')->willReturn([$indexerOne]);
+
+        $this->collectionFactory->expects($this->once())->method('create')->will($this->returnValue($collection));
+        $this->indexerFactory->expects($this->never())->method('create');
+        $this->command = new IndexerSetModeCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(['mode' => 'realtime']);
+        $actualValue = $commandTester->getDisplay();
+        $this->assertSame(
+            'Index mode for Indexer Title_indexerOne was changed from '. '\'Update by Schedule\' to \'Update on Save\''
+            . PHP_EOL,
+            $actualValue
+        );
+    }
+
+    /**
+     * @param bool $isScheduled
+     * @param bool $previous
+     * @param bool $current
+     * @param string $mode
+     * @param $expectedValue
+     * @dataProvider executeWithIndexDataProvider
+     */
+    public function testExecuteWithIndex($isScheduled, $previous, $current, $mode, $expectedValue)
+    {
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $indexerOne->expects($this->once())->method('load')->with('id_indexerOne')->willReturn($indexerOne);
+        $indexerOne->expects($this->once())->method('setScheduled')->with($isScheduled);
+        $indexerOne->expects($this->at(1))->method('isScheduled')->willReturn($previous);
+        $indexerOne->expects($this->at(3))->method('isScheduled')->willReturn($current);
+
+        $this->collectionFactory->expects($this->never())->method('create');
+        $this->indexerFactory->expects($this->once())->method('create')->willReturn($indexerOne);
+
+        $this->command = new IndexerSetModeCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(['mode' => $mode, 'index' => ['id_indexerOne']]);
+        $actualValue = $commandTester->getDisplay();
+        $this->assertSame($expectedValue, $actualValue);
+    }
+
+    /**
+     * @return array
+     */
+    public function executeWithIndexDataProvider()
+    {
+        return [
+            [
+                false,
+                true,
+                false,
+                'realtime',
+                'Index mode for Indexer Title_indexerOne was changed from \'Update by Schedule\' to \'Update on Save\''
+                . PHP_EOL
+            ],
+            [
+                false,
+                false,
+                false,
+                'realtime',
+                'Index mode for Indexer Title_indexerOne has not been changed'
+                . PHP_EOL
+            ],
+            [
+                true,
+                true,
+                true,
+                'schedule',
+                'Index mode for Indexer Title_indexerOne has not been changed'
+                . PHP_EOL
+            ],
+            [
+                true,
+                false,
+                true,
+                'schedule',
+                'Index mode for Indexer Title_indexerOne was changed from \'Update on Save\' to \'Update by Schedule\''
+                . PHP_EOL
+            ],
+        ];
+    }
+
+    public function testExecuteWithLocalizedException()
+    {
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $localizedException = new \Magento\Framework\Exception\LocalizedException(__('Some Exception Message'));
+        $indexerOne->expects($this->once())->method('setScheduled')->will($this->throwException($localizedException));
+        $this->collectionFactory->expects($this->never())->method('create');
+        $this->indexerFactory->expects($this->once())->method('create')->willReturn($indexerOne);
+        $this->command = new IndexerSetModeCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(['mode' => 'schedule', 'index' => ['id_indexerOne']]);
+        $actualValue = $commandTester->getDisplay();
+        $this->assertStringStartsWith('Some Exception Message', $actualValue);
+    }
+
+    public function testExecuteWithException()
+    {
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $exception = new \Exception();
+        $indexerOne->expects($this->once())->method('setScheduled')->will($this->throwException($exception));
+        $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $this->collectionFactory->expects($this->never())->method('create');
+        $this->indexerFactory->expects($this->once())->method('create')->willReturn($indexerOne);
+        $this->command = new IndexerSetModeCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(['mode' => 'schedule', 'index' => ['id_indexerOne']]);
+        $actualValue = $commandTester->getDisplay();
+        $this->assertStringStartsWith('Title_indexerOne indexer process unknown error:', $actualValue);
+    }
+}
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerShowModeCommandTest.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerShowModeCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..8c7a527ae4392a66f3e0b350099e2e73a5e472ef
--- /dev/null
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerShowModeCommandTest.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Test\Unit\Console\Command;
+
+use Magento\Indexer\Console\Command\IndexerShowModeCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class IndexerShowModeCommandTest extends IndexerCommandCommonTestSetup
+{
+    /**
+     * Command being tested
+     *
+     * @var IndexerShowModeCommand
+     */
+    private $command;
+
+    public function testGetOptions()
+    {
+        $this->command = new IndexerShowModeCommand($this->objectManagerFactory);
+        $optionsList = $this->command->getInputList();
+        $this->assertSame(2, sizeof($optionsList));
+        $this->assertSame('all', $optionsList[0]->getName());
+        $this->assertSame('index', $optionsList[1]->getName());
+    }
+
+    public function testExecuteAll()
+    {
+
+        $collection = $this->getMock('Magento\Indexer\Model\Indexer\Collection', [], [], '', false);
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $indexerOne->expects($this->once())->method('isScheduled')->willReturn(true);
+        $indexerTwo = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerTwo->expects($this->once())->method('getTitle')->willReturn('Title_indexerTwo');
+        $indexerTwo->expects($this->once())->method('isScheduled')->willReturn(false);
+        $collection->expects($this->once())->method('getItems')->willReturn([$indexerOne, $indexerTwo]);
+
+        $this->collectionFactory->expects($this->once())->method('create')->will($this->returnValue($collection));
+        $this->indexerFactory->expects($this->never())->method('create');
+
+        $this->command = new IndexerShowModeCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute([]);
+        $actualValue = $commandTester->getDisplay();
+        $expectedValue = sprintf('%-50s ', 'Title_indexerOne' . ':') . 'Update by Schedule' . PHP_EOL
+            . sprintf('%-50s ', 'Title_indexerTwo' . ':') . 'Update on Save';
+        $this->assertStringStartsWith($expectedValue, $actualValue);
+    }
+
+    public function testExecuteWithIndex()
+    {
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $indexerOne->expects($this->once())->method('isScheduled')->willReturn(true);
+        $indexerTwo = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerTwo->expects($this->once())->method('getTitle')->willReturn('Title_indexerTwo');
+        $indexerTwo->expects($this->once())->method('isScheduled')->willReturn(false);
+        $indexerThree = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerThree->expects($this->never())->method('getTitle')->willReturn('Title_indexer3');
+        $indexerThree->expects($this->never())->method('isScheduled')->willReturn(false);
+
+        $this->collectionFactory->expects($this->never())->method('create');
+        $this->indexerFactory->expects($this->at(0))->method('create')->willReturn($indexerOne);
+        $this->indexerFactory->expects($this->at(1))->method('create')->willReturn($indexerTwo);
+
+        $this->command = new IndexerShowModeCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute(['index' => ['id_indexerOne', 'id_indexerTwo']]);
+        $actualValue = $commandTester->getDisplay();
+        $expectedValue = sprintf('%-50s ', 'Title_indexerOne' . ':') . 'Update by Schedule' . PHP_EOL
+            . sprintf('%-50s ', 'Title_indexerTwo' . ':') . 'Update on Save';
+        $this->assertStringStartsWith($expectedValue, $actualValue);
+    }
+}
diff --git a/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerStatusCommandTest.php b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerStatusCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b5fd291e330c07b5080b74e3764927d739d03bd3
--- /dev/null
+++ b/app/code/Magento/Indexer/Test/Unit/Console/Command/IndexerStatusCommandTest.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Indexer\Test\Unit\Console\Command;
+
+use Magento\Indexer\Console\Command\IndexerStatusCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class IndexerStatusCommandTest extends IndexerCommandCommonTestSetup
+{
+    /**
+     * Command being tested
+     *
+     * @var IndexerStatusCommand
+     */
+    private $command;
+
+    public function testExecuteAll()
+    {
+        $collection = $this->getMock('Magento\Indexer\Model\Indexer\Collection', [], [], '', false);
+        $indexerOne = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerOne->expects($this->once())->method('getTitle')->willReturn('Title_indexerOne');
+        $indexerOne
+            ->expects($this->once())
+            ->method('getStatus')
+            ->willReturn(\Magento\Indexer\Model\Indexer\State::STATUS_VALID);
+        $indexerTwo = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerTwo->expects($this->once())->method('getTitle')->willReturn('Title_indexerTwo');
+        $indexerTwo
+            ->expects($this->once())
+            ->method('getStatus')
+            ->willReturn(\Magento\Indexer\Model\Indexer\State::STATUS_INVALID);
+        $indexerThree = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerThree->expects($this->once())->method('getTitle')->willReturn('Title_indexerThree');
+        $indexerThree
+            ->expects($this->once())
+            ->method('getStatus')
+            ->willReturn(\Magento\Indexer\Model\Indexer\State::STATUS_WORKING);
+        $indexerFour = $this->getMock('Magento\Indexer\Model\Indexer', [], [], '', false);
+        $indexerFour->expects($this->once())->method('getTitle')->willReturn('Title_indexerFour');
+        $collection
+            ->expects($this->once())
+            ->method('getItems')
+            ->willReturn([$indexerOne, $indexerTwo, $indexerThree, $indexerFour]);
+
+        $this->collectionFactory->expects($this->once())->method('create')->will($this->returnValue($collection));
+        $this->indexerFactory->expects($this->never())->method('create');
+        $this->command = new IndexerStatusCommand($this->objectManagerFactory);
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute([]);
+        $actualValue = $commandTester->getDisplay();
+        $expectedValue = sprintf('%-50s ', 'Title_indexerOne' . ':') . 'Ready' . PHP_EOL
+            . sprintf('%-50s ', 'Title_indexerTwo' . ':') . 'Reindex required' . PHP_EOL
+            . sprintf('%-50s ', 'Title_indexerThree' . ':') . 'Processing' . PHP_EOL
+            . sprintf('%-50s ', 'Title_indexerFour' . ':') . 'unknown' . PHP_EOL;
+
+        $this->assertStringStartsWith($expectedValue, $actualValue);
+    }
+}
diff --git a/app/code/Magento/Indexer/Test/Unit/Model/ShellTest.php b/app/code/Magento/Indexer/Test/Unit/Model/ShellTest.php
deleted file mode 100644
index 1a73b3de682eda8c3c754a201db7e1aee38b473e..0000000000000000000000000000000000000000
--- a/app/code/Magento/Indexer/Test/Unit/Model/ShellTest.php
+++ /dev/null
@@ -1,226 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Indexer\Test\Unit\Model;
-
-class ShellTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \Magento\Indexer\Model\Shell
-     */
-    protected $model;
-
-    /**
-     * @var \Magento\Framework\Filesystem|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $filesystemMock;
-
-    /**
-     * @var \Magento\Indexer\Model\Indexer\CollectionFactory|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $indexersFactoryMock;
-
-    /**
-     * @var \Magento\Indexer\Model\IndexerFactory|\PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $indexerFactoryMock;
-
-    /**
-     * Set up test
-     */
-    protected function setUp()
-    {
-        $entryPoint = '';
-
-        $this->filesystemMock = $this->getMock(
-            '\Magento\Framework\Filesystem',
-            ['getDirectoryRead'],
-            [],
-            '',
-            false
-        );
-        $this->indexerFactoryMock = $this->getMock(
-            'Magento\Indexer\Model\IndexerFactory',
-            ['create', 'load', 'reindexAll', 'getTitle'],
-            [],
-            '',
-            false
-        );
-        $this->indexersFactoryMock = $this->getMock(
-            'Magento\Indexer\Model\Indexer\CollectionFactory',
-            ['create', 'getItems'],
-            [],
-            '',
-            false
-        );
-        $readInterfaceMock = $this->getMockForAbstractClass(
-            '\Magento\Framework\Filesystem\Directory\ReadInterface',
-            [],
-            '',
-            false,
-            false,
-            true,
-            []
-        );
-
-        $this->filesystemMock->expects($this->once())->method('getDirectoryRead')->will(
-            $this->returnValue($readInterfaceMock)
-        );
-
-        $this->model = new \Magento\Indexer\Model\Shell(
-            $this->filesystemMock,
-            $entryPoint,
-            $this->indexersFactoryMock,
-            $this->indexerFactoryMock
-        );
-    }
-
-    /**
-     * @param string $args
-     * @param string $status
-     * @dataProvider runDataProvider
-     */
-    public function testRun($args, $status = null)
-    {
-        $withItems = [
-            'info',
-            'status',
-            'mode',
-            '--mode-realtime',
-            '--mode-schedule',
-            'reindex',
-            'reindexall'
-        ];
-        $this->model->setRawArgs(['testme.php', '--', $args]);
-        
-        $indexerMock = $this->getMock(
-            '\Magento\Indexer\Model\Indexer',
-            ['getStatus', 'isScheduled', 'reindexAll', 'turnViewOff', 'turnViewOn'],
-            [],
-            '',
-            false
-        );
-
-        if (in_array($args, $withItems)) {
-            if ($args == 'status') {
-                $indexerMock->expects($this->any())->method('getStatus')->will(
-                    $this->returnValue($status)
-                );
-            }
-            $this->indexersFactoryMock->expects($this->once())->method('create')->will($this->returnSelf());
-            $this->indexersFactoryMock->expects($this->once())->method('getItems')->will(
-                $this->returnValue([$indexerMock])
-            );
-        }
-        if ($args == '--reindex=price') {
-            $this->indexerFactoryMock->expects($this->once())->method('create')->will($this->returnSelf());
-            $this->indexerFactoryMock->expects($this->any())->method('load')->will(
-                $this->returnValue($indexerMock)
-            );
-        }
-
-        ob_start();
-        $this->assertInstanceOf('\Magento\Indexer\Model\Shell', $this->model->run());
-        ob_end_clean();
-    }
-
-    /**
-     * @return array
-     */
-    public function runDataProvider()
-    {
-        return [
-            ['h'],
-            ['info'],
-            ['mode'],
-            ['status', \Magento\Indexer\Model\Indexer\State::STATUS_VALID],
-            ['status', \Magento\Indexer\Model\Indexer\State::STATUS_INVALID],
-            ['status', \Magento\Indexer\Model\Indexer\State::STATUS_WORKING],
-            ['--mode-realtime'],
-            ['--mode-schedule'],
-            ['reindex'],
-            ['reindexall'],
-            ['--reindex=price'],
-            ['other']
-        ];
-    }
-
-    /**
-     * @param string $args
-     * @dataProvider runExceptionDataProvider
-     */
-    public function testRunException($args)
-    {
-        $indexerMock = $this->getMock(
-            '\Magento\Indexer\Model\Indexer',
-            ['reindexAll', 'turnViewOff', 'turnViewOn'],
-            [],
-            '',
-            false
-        );
-
-        $this->model->setRawArgs(['testme.php', '--', $args]);
-
-        if ($args == 'reindex') {
-            $indexerMock->expects($this->any())->method('reindexAll')->will(
-                $this->throwException(new \Exception())
-            );
-        }
-        if ($args == '--mode-realtime') {
-            $indexerMock->expects($this->any())->method('turnViewOff')->will(
-                $this->throwException(new \Exception())
-            );
-        }
-        if ($args == 'reindexall') {
-            $indexerMock->expects($this->any())->method('reindexAll')->will(
-                $this->throwException(
-                    new \Magento\Framework\Exception\LocalizedException(
-                        __('Something went wrong during reindexing all.')
-                    )
-                )
-            );
-        }
-        if ($args == '--mode-schedule') {
-            $indexerMock->expects($this->any())->method('turnViewOn')->will(
-                $this->throwException(
-                    new \Magento\Framework\Exception\LocalizedException(
-                        __('Something went wrong during turning view on.')
-                    )
-                )
-            );
-        }
-        if ($args == '--reindex=price') {
-            $this->indexerFactoryMock->expects($this->once())->method('create')->will($this->returnSelf());
-            $this->indexerFactoryMock->expects($this->any())->method('load')->will(
-                $this->throwException(new \Exception())
-            );
-        } else {
-            $this->indexersFactoryMock->expects($this->once())->method('create')->will($this->returnSelf());
-            $this->indexersFactoryMock->expects($this->once())->method('getItems')->will(
-                $this->returnValue([$indexerMock])
-            );
-        }
-
-        ob_start();
-        $this->assertInstanceOf('\Magento\Indexer\Model\Shell', $this->model->run());
-        ob_end_clean();
-
-        $this->assertEquals(true, $this->model->hasErrors());
-    }
-
-    /**
-     * @return array
-     */
-    public function runExceptionDataProvider()
-    {
-        return [
-            ['reindex'],
-            ['reindexall'],
-            ['--mode-realtime'],
-            ['--mode-schedule'],
-            ['--reindex=price']
-        ];
-    }
-}
diff --git a/app/code/Magento/Indexer/composer.json b/app/code/Magento/Indexer/composer.json
index dc50f4ea54aa7305e118a771a6a57ce857a7d7ee..b346637038367b28a5ad2c08d5d57e1bed717eaa 100644
--- a/app/code/Magento/Indexer/composer.json
+++ b/app/code/Magento/Indexer/composer.json
@@ -3,6 +3,7 @@
     "description": "N/A",
     "require": {
         "php": "~5.5.0|~5.6.0",
+        "magento/module-store": "0.74.0-beta7",
         "magento/module-backend": "0.74.0-beta7",
         "magento/module-page-cache": "0.74.0-beta7",
         "magento/framework": "0.74.0-beta7",
diff --git a/app/code/Magento/Indexer/etc/di.xml b/app/code/Magento/Indexer/etc/di.xml
index 496e19449aecfc297fd63babe067af151dc7a9aa..8c6730dffb5c959d732d78f590c366eae74ef1bb 100644
--- a/app/code/Magento/Indexer/etc/di.xml
+++ b/app/code/Magento/Indexer/etc/di.xml
@@ -34,4 +34,16 @@
         <plugin name="page-cache-indexer-reindex-invalidate"
                 type="Magento\Indexer\Model\Processor\InvalidateCache" sortOrder="10"/>
     </type>
+
+    <type name="Magento\Framework\Console\CommandList">
+        <arguments>
+            <argument name="commands" xsi:type="array">
+                <item name="info" xsi:type="object">Magento\Indexer\Console\Command\IndexerInfoCommand</item>
+                <item name="reindex" xsi:type="object">Magento\Indexer\Console\Command\IndexerReindexCommand</item>
+                <item name="set-mode" xsi:type="object">Magento\Indexer\Console\Command\IndexerSetModeCommand</item>
+                <item name="show-mode" xsi:type="object">Magento\Indexer\Console\Command\IndexerShowModeCommand</item>
+                <item name="status" xsi:type="object">Magento\Indexer\Console\Command\IndexerStatusCommand</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Log/App/Shell.php b/app/code/Magento/Log/App/Shell.php
deleted file mode 100644
index 1941350d0a182ef6099ba8f43480e5c6e89cb0d9..0000000000000000000000000000000000000000
--- a/app/code/Magento/Log/App/Shell.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-/**
- * Log shell application
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\App;
-
-use Magento\Framework\App\Bootstrap;
-use Magento\Framework\App\Console\Response;
-use Magento\Framework\AppInterface;
-
-class Shell implements AppInterface
-{
-    /**
-     * Filename of the entry point script
-     *
-     * @var string
-     */
-    protected $_entryFileName;
-
-    /**
-     * @var \Magento\Log\Model\ShellFactory
-     */
-    protected $_shellFactory;
-
-    /**
-     * @var \Magento\Framework\App\Console\Response
-     */
-    protected $_response;
-
-    /**
-     * @param string $entryFileName
-     * @param \Magento\Log\Model\ShellFactory $shellFactory
-     * @param Response $response
-     */
-    public function __construct($entryFileName, \Magento\Log\Model\ShellFactory $shellFactory, Response $response)
-    {
-        $this->_entryFileName = $entryFileName;
-        $this->_shellFactory = $shellFactory;
-        $this->_response = $response;
-    }
-
-    /**
-     * Run application
-     *
-     * @return \Magento\Framework\App\ResponseInterface
-     */
-    public function launch()
-    {
-        /** @var $shell \Magento\Log\Model\Shell */
-        $shell = $this->_shellFactory->create(['entryPoint' => $this->_entryFileName]);
-        $shell->run();
-        $this->_response->setCode(0);
-        return $this->_response;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function catchException(Bootstrap $bootstrap, \Exception $exception)
-    {
-        return false;
-    }
-}
diff --git a/app/code/Magento/Log/Console/Command/AbstractLogCommand.php b/app/code/Magento/Log/Console/Command/AbstractLogCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..d158c1538cd638ea1a85f7e7915963f45ec89d8c
--- /dev/null
+++ b/app/code/Magento/Log/Console/Command/AbstractLogCommand.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Log\Console\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Magento\Store\Model\StoreManager;
+use Magento\Framework\App\DeploymentConfig;
+use Magento\Framework\App\ObjectManagerFactory;
+use Magento\Framework\App\ObjectManager;
+
+/**
+ * Abstract class for commands related to manage Magento logs
+ */
+abstract class AbstractLogCommand extends Command
+{
+    /**
+     * Object Manager
+     *
+     * @var ObjectManager
+     */
+    protected $objectManager;
+
+    /**
+     * Constructor
+     *
+     * @param ObjectManagerFactory $objectManagerFactory
+     */
+    public function __construct(ObjectManagerFactory $objectManagerFactory)
+    {
+        $params = $_SERVER;
+        $params[StoreManager::PARAM_RUN_CODE] = 'admin';
+        $params[StoreManager::PARAM_RUN_TYPE] = 'store';
+        $this->objectManager = $objectManagerFactory->create($params);
+        parent::__construct();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        parent::configure();
+    }
+}
diff --git a/app/code/Magento/Log/Console/Command/LogCleanCommand.php b/app/code/Magento/Log/Console/Command/LogCleanCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..00827c20b96c856520aa5b859e32dc73317058c5
--- /dev/null
+++ b/app/code/Magento/Log/Console/Command/LogCleanCommand.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Log\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Input\InputOption;
+
+/**
+ * Command for displaying status of Magento logs
+ */
+class LogCleanCommand extends AbstractLogCommand
+{
+    /**
+     * Name of input option
+     */
+    const INPUT_KEY_DAYS = 'days';
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $options = [
+            new InputOption(
+                self::INPUT_KEY_DAYS,
+                null,
+                InputOption::VALUE_REQUIRED,
+                'Save log for specified number of days',
+                '1'
+            ),
+        ];
+        $this->setName('log:clean')
+            ->setDescription('Cleans Logs')
+            ->setDefinition($options);
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     * @throws \InvalidArgumentException
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $errorMsg = 'Invalid value for option "' . self::INPUT_KEY_DAYS
+            . '". It should be a whole number greater than 0.';
+        $days = $input->getOption(self::INPUT_KEY_DAYS);
+        if (!is_numeric($days) || (strpos($days, '.') !== false)) {
+            $output->writeln('<error>' . $errorMsg . '</error>');
+            return;
+        }
+        $days = (int) $days;
+        if ($days <= 0) {
+            $output->writeln('<error>' . $errorMsg . '</error>');
+            return;
+        }
+        /** @var \Magento\Framework\App\Config\MutableScopeConfigInterface $mutableConfig */
+        $mutableConfig = $this->objectManager->create('Magento\Framework\App\Config\MutableScopeConfigInterface');
+        $mutableConfig->setValue(
+            \Magento\Log\Model\Log::XML_LOG_CLEAN_DAYS,
+            $days,
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE
+        );
+        /** @var \Magento\Log\Model\LogFactory $logFactory */
+        $logFactory = $this->objectManager->create('Magento\Log\Model\LogFactory');
+        /** @var \Magento\Log\Model\Log $model */
+        $model = $logFactory->create();
+        $model->clean();
+        $output->writeln('<info>' . 'Log cleaned.' . '</info>');
+    }
+}
diff --git a/app/code/Magento/Log/Model/Shell/Command/Status.php b/app/code/Magento/Log/Console/Command/LogStatusCommand.php
similarity index 52%
rename from app/code/Magento/Log/Model/Shell/Command/Status.php
rename to app/code/Magento/Log/Console/Command/LogStatusCommand.php
index 8ac5c4817bf6b13b69e28bee9218a3591f1e5dd8..8ae090f76f9a67ac942db7735b13d0c4bb8f0d30 100644
--- a/app/code/Magento/Log/Model/Shell/Command/Status.php
+++ b/app/code/Magento/Log/Console/Command/LogStatusCommand.php
@@ -3,28 +3,76 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Log\Model\Shell\Command;
 
-class Status implements \Magento\Log\Model\Shell\CommandInterface
-{
-    /**
-     * @var \Magento\Log\Model\Resource\ShellFactory
-     */
-    protected $_resourceFactory;
+namespace Magento\Log\Console\Command;
+
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
 
+/**
+ * Command for displaying status of Magento logs
+ */
+class LogStatusCommand extends AbstractLogCommand
+{
     /**
      * Output data
      *
      * @var array
      */
-    protected $_output = [];
+    private $output = [];
 
     /**
-     * @param \Magento\Log\Model\Resource\ShellFactory $resourceFactory
+     * {@inheritdoc}
      */
-    public function __construct(\Magento\Log\Model\Resource\ShellFactory $resourceFactory)
+    protected function configure()
     {
-        $this->_resourceFactory = $resourceFactory;
+        $this->setName('log:status')->setDescription('Displays statistics per log tables');
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        /** @var \Magento\Log\Model\Resource\ShellFactory $resourceFactory */
+        $resourceFactory = $this->objectManager->create('Magento\Log\Model\Resource\ShellFactory');
+        /** @var \Magento\Log\Model\Resource\Shell $resource */
+        $resource = $resourceFactory->create();
+        $tables = $resource->getTablesInfo();
+
+        $this->addRowDelimiter();
+        $line = sprintf('%-35s|', 'Table Name');
+        $line .= sprintf(' %-11s|', 'Rows');
+        $line .= sprintf(' %-11s|', 'Data Size');
+        $line .= sprintf(' %-11s|', 'Index Size');
+        $this->addOutput($line);
+        $this->addRowDelimiter();
+
+        $rows = 0;
+        $dataLength = 0;
+        $indexLength = 0;
+        foreach ($tables as $table) {
+            $rows += $table['rows'];
+            $dataLength += $table['data_length'];
+            $indexLength += $table['index_length'];
+
+            $line = sprintf('%-35s|', $table['name']);
+            $line .= sprintf(' %-11s|', $this->humanCount($table['rows']));
+            $line .= sprintf(' %-11s|', $this->humanSize($table['data_length']));
+            $line .= sprintf(' %-11s|', $this->humanSize($table['index_length']));
+            $this->addOutput($line);
+        }
+
+        $this->addRowDelimiter();
+        $line = sprintf('%-35s|', 'Total');
+        $line .= sprintf(' %-11s|', $this->humanCount($rows));
+        $line .= sprintf(' %-11s|', $this->humanSize($dataLength));
+        $line .= sprintf(' %-11s|', $this->humanSize($indexLength));
+        $this->addOutput($line);
+        $this->addRowDelimiter();
+
+        $output->writeln('<info>' . $this->getOutput() . '</info>');
     }
 
     /**
@@ -33,9 +81,9 @@ class Status implements \Magento\Log\Model\Shell\CommandInterface
      * @param string $output
      * @return void
      */
-    protected function _addOutput($output)
+    private function addOutput($output)
     {
-        $this->_output[] = $output;
+        $this->output[] = $output;
     }
 
     /**
@@ -43,9 +91,9 @@ class Status implements \Magento\Log\Model\Shell\CommandInterface
      *
      * @return string
      */
-    protected function _getOutput()
+    private function getOutput()
     {
-        return implode("\n", $this->_output);
+        return implode("\n", $this->output);
     }
 
     /**
@@ -54,7 +102,7 @@ class Status implements \Magento\Log\Model\Shell\CommandInterface
      * @param int $number
      * @return string
      */
-    protected function _humanCount($number)
+    private function humanCount($number)
     {
         if ($number < 1000) {
             return $number;
@@ -73,7 +121,7 @@ class Status implements \Magento\Log\Model\Shell\CommandInterface
      * @param int $number
      * @return string
      */
-    protected function _humanSize($number)
+    private function humanSize($number)
     {
         if ($number < 1024) {
             return sprintf('%d b', $number);
@@ -91,53 +139,8 @@ class Status implements \Magento\Log\Model\Shell\CommandInterface
      *
      * @return void
      */
-    protected function _addRowDelimiter()
+    private function addRowDelimiter()
     {
-        $this->_addOutput('-----------------------------------+------------+------------+------------+');
-    }
-
-    /**
-     * Execute command
-     *
-     * @return string
-     */
-    public function execute()
-    {
-        /** @var $resource \Magento\Log\Model\Resource\Shell */
-        $resource = $this->_resourceFactory->create();
-        $tables = $resource->getTablesInfo();
-
-        $this->_addRowDelimiter();
-        $line = sprintf('%-35s|', 'Table Name');
-        $line .= sprintf(' %-11s|', 'Rows');
-        $line .= sprintf(' %-11s|', 'Data Size');
-        $line .= sprintf(' %-11s|', 'Index Size');
-        $this->_addOutput($line);
-        $this->_addRowDelimiter();
-
-        $rows = 0;
-        $dataLength = 0;
-        $indexLength = 0;
-        foreach ($tables as $table) {
-            $rows += $table['rows'];
-            $dataLength += $table['data_length'];
-            $indexLength += $table['index_length'];
-
-            $line = sprintf('%-35s|', $table['name']);
-            $line .= sprintf(' %-11s|', $this->_humanCount($table['rows']));
-            $line .= sprintf(' %-11s|', $this->_humanSize($table['data_length']));
-            $line .= sprintf(' %-11s|', $this->_humanSize($table['index_length']));
-            $this->_addOutput($line);
-        }
-
-        $this->_addRowDelimiter();
-        $line = sprintf('%-35s|', 'Total');
-        $line .= sprintf(' %-11s|', $this->_humanCount($rows));
-        $line .= sprintf(' %-11s|', $this->_humanSize($dataLength));
-        $line .= sprintf(' %-11s|', $this->_humanSize($indexLength));
-        $this->_addOutput($line);
-        $this->_addRowDelimiter();
-
-        return $this->_getOutput();
+        $this->addOutput('-----------------------------------+------------+------------+------------+');
     }
 }
diff --git a/app/code/Magento/Log/Model/Shell.php b/app/code/Magento/Log/Model/Shell.php
deleted file mode 100644
index 30a1cf875d740cf651103974f86ab21fe717121b..0000000000000000000000000000000000000000
--- a/app/code/Magento/Log/Model/Shell.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\Model;
-
-/**
- * Shell model, used to work with logs via command line
- *
- * @author      Magento Core Team <core@magentocommerce.com>
- */
-class Shell extends \Magento\Framework\App\AbstractShell
-{
-    /**
-     * @var \Magento\Log\Model\Shell\Command\Factory
-     */
-    protected $_commandFactory;
-
-    /**
-     * @param \Magento\Framework\Filesystem $filesystem
-     * @param string $entryPoint
-     * @param \Magento\Log\Model\Shell\Command\Factory $commandFactory
-     */
-    public function __construct(
-        \Magento\Framework\Filesystem $filesystem,
-        $entryPoint,
-        \Magento\Log\Model\Shell\Command\Factory $commandFactory
-    ) {
-        parent::__construct($filesystem, $entryPoint);
-        $this->_commandFactory = $commandFactory;
-    }
-
-    /**
-     * Runs script
-     *
-     * @return $this
-     */
-    public function run()
-    {
-        if ($this->_showHelp()) {
-            return $this;
-        }
-
-        if ($this->getArg('clean')) {
-            $output = $this->_commandFactory->createCleanCommand($this->getArg('days'))->execute();
-        } elseif ($this->getArg('status')) {
-            $output = $this->_commandFactory->createStatusCommand()->execute();
-        } else {
-            $output = $this->getUsageHelp();
-        }
-
-        echo $output;
-
-        return $this;
-    }
-
-    /**
-     * Retrieves usage help message
-     *
-     * @return string
-     */
-    public function getUsageHelp()
-    {
-        return <<<USAGE
-Usage:  php -f {$this->_entryPoint} -- [options]
-        php -f {$this->_entryPoint} -- clean --days 1
-
-  clean             Clean Logs
-  --days <days>     Save log, days. (Minimum 1 day, if defined - ignoring system value)
-  status            Display statistics per log tables
-  help              This help
-
-USAGE;
-    }
-}
diff --git a/app/code/Magento/Log/Model/Shell/Command/Clean.php b/app/code/Magento/Log/Model/Shell/Command/Clean.php
deleted file mode 100644
index 65415c82f489bacadaf34c2dd2fae709f859d77a..0000000000000000000000000000000000000000
--- a/app/code/Magento/Log/Model/Shell/Command/Clean.php
+++ /dev/null
@@ -1,65 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\Model\Shell\Command;
-
-use Magento\Log\Model\LogFactory;
-
-class Clean implements \Magento\Log\Model\Shell\CommandInterface
-{
-    /**
-     * Mutable Config
-     *
-     * @var \Magento\Framework\App\Config\MutableScopeConfigInterface
-     */
-    protected $_mutableConfig;
-
-    /**
-     * @var LogFactory
-     */
-    protected $_logFactory;
-
-    /**
-     * Clean after days count
-     *
-     * @var int
-     */
-    protected $_days;
-
-    /**
-     * @param \Magento\Framework\App\Config\MutableScopeConfigInterface $mutableConfig
-     * @param LogFactory $logFactory
-     * @param int $days
-     */
-    public function __construct(
-        \Magento\Framework\App\Config\MutableScopeConfigInterface $mutableConfig,
-        LogFactory $logFactory,
-        $days
-    ) {
-        $this->_mutableConfig = $mutableConfig;
-        $this->_logFactory = $logFactory;
-        $this->_days = $days;
-    }
-
-    /**
-     * Execute command
-     *
-     * @return string
-     */
-    public function execute()
-    {
-        if ($this->_days > 0) {
-            $this->_mutableConfig->setValue(
-                \Magento\Log\Model\Log::XML_LOG_CLEAN_DAYS,
-                $this->_days,
-                \Magento\Store\Model\ScopeInterface::SCOPE_STORE
-            );
-        }
-        /** @var $model \Magento\Log\Model\Log */
-        $model = $this->_logFactory->create();
-        $model->clean();
-        return "Log cleaned\n";
-    }
-}
diff --git a/app/code/Magento/Log/Model/Shell/Command/Factory.php b/app/code/Magento/Log/Model/Shell/Command/Factory.php
deleted file mode 100644
index 96363024cd1023374efb9c38f6a599d94126c586..0000000000000000000000000000000000000000
--- a/app/code/Magento/Log/Model/Shell/Command/Factory.php
+++ /dev/null
@@ -1,43 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\Model\Shell\Command;
-
-class Factory
-{
-    /**
-     * @var \Magento\Framework\ObjectManagerInterface
-     */
-    protected $_objectManager;
-
-    /**
-     * @param \Magento\Framework\ObjectManagerInterface $objectManager
-     */
-    public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager)
-    {
-        $this->_objectManager = $objectManager;
-    }
-
-    /**
-     * Create clean command
-     *
-     * @param int $days
-     * @return \Magento\Log\Model\Shell\CommandInterface
-     */
-    public function createCleanCommand($days)
-    {
-        return $this->_objectManager->create('Magento\Log\Model\Shell\Command\Clean', ['days' => $days]);
-    }
-
-    /**
-     * Create status command
-     *
-     * @return \Magento\Log\Model\Shell\CommandInterface
-     */
-    public function createStatusCommand()
-    {
-        return $this->_objectManager->create('Magento\Log\Model\Shell\Command\Status');
-    }
-}
diff --git a/app/code/Magento/Log/Model/Shell/CommandInterface.php b/app/code/Magento/Log/Model/Shell/CommandInterface.php
deleted file mode 100644
index 84ccdf5dde23cd0df1f9135a7f3c6af66f7aa18d..0000000000000000000000000000000000000000
--- a/app/code/Magento/Log/Model/Shell/CommandInterface.php
+++ /dev/null
@@ -1,16 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\Model\Shell;
-
-interface CommandInterface
-{
-    /**
-     * Execute command
-     *
-     * @return string
-     */
-    public function execute();
-}
diff --git a/app/code/Magento/Log/Test/Unit/App/ShellTest.php b/app/code/Magento/Log/Test/Unit/App/ShellTest.php
deleted file mode 100644
index b9f28ad53b12bf80297bbee56601e975ff3a93cd..0000000000000000000000000000000000000000
--- a/app/code/Magento/Log/Test/Unit/App/ShellTest.php
+++ /dev/null
@@ -1,59 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\Test\Unit\App;
-
-class ShellTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \Magento\Log\App\Shell
-     */
-    protected $_model;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_shellFactoryMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_responseMock;
-
-    protected function setUp()
-    {
-        $this->_shellFactoryMock = $this->getMock(
-            'Magento\Log\Model\ShellFactory',
-            ['create'],
-            [],
-            '',
-            false
-        );
-        $this->_responseMock = $this->getMock('Magento\Framework\App\Console\Response', [], [], '', false);
-        $this->_model = new \Magento\Log\App\Shell('shell.php', $this->_shellFactoryMock, $this->_responseMock);
-    }
-
-    public function testProcessRequest()
-    {
-        $shellMock = $this->getMock('Magento\Log\App\Shell', ['run'], [], '', false);
-        $this->_shellFactoryMock->expects(
-            $this->once()
-        )->method(
-            'create'
-        )->with(
-            ['entryPoint' => 'shell.php']
-        )->will(
-            $this->returnValue($shellMock)
-        );
-        $shellMock->expects($this->once())->method('run');
-        $this->assertEquals($this->_responseMock, $this->_model->launch());
-    }
-
-    public function testCatchException()
-    {
-        $bootstrap = $this->getMock('Magento\Framework\App\Bootstrap', [], [], '', false);
-        $this->assertFalse($this->_model->catchException($bootstrap, new \Exception()));
-    }
-}
diff --git a/app/code/Magento/Log/Test/Unit/Console/Command/LogCleanCommandTest.php b/app/code/Magento/Log/Test/Unit/Console/Command/LogCleanCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0db32a17c32950dec9a9ea4ab20f6ed4827c31cd
--- /dev/null
+++ b/app/code/Magento/Log/Test/Unit/Console/Command/LogCleanCommandTest.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Log\Test\Unit\Console\Command;
+
+use Magento\Log\Console\Command\LogCleanCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+use Magento\Framework\App\ObjectManager;
+
+class LogCleanCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var ObjectManager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManager;
+
+    /**
+     * @var CommandTester
+     */
+    private $commandTester;
+
+    public function setUp()
+    {
+        $this->objectManager = $this->getMock('Magento\Framework\App\ObjectManager', [], [], '', false);
+        $objectManagerFactory = $this->getMock('Magento\Framework\App\ObjectManagerFactory', [], [], '', false);
+        $objectManagerFactory->expects($this->once())->method('create')->willReturn($this->objectManager);
+        $this->commandTester = new CommandTester(new LogCleanCommand($objectManagerFactory));
+    }
+
+    public function testExecute()
+    {
+        $mutableConfig = $this->getMock('Magento\Framework\App\Config\MutableScopeConfigInterface', [], [], '', false);
+        $logFactory = $this->getMock('Magento\Log\Model\LogFactory', [], [], '', false);
+        $returnValueMap = [
+            [
+                'Magento\Framework\App\Config\MutableScopeConfigInterface',
+                [],
+                $mutableConfig,
+            ],
+            [
+                'Magento\Log\Model\LogFactory',
+                [],
+                $logFactory,
+            ],
+        ];
+        $this->objectManager
+            ->expects($this->exactly(2))->method('create')
+            ->will($this->returnValueMap($returnValueMap));
+        $mutableConfig->expects($this->once())->method('setValue');
+        $log = $this->getMock('Magento\Log\Model\Log', [], [], '', false);
+        $logFactory->expects($this->once())->method('create')->willReturn($log);
+        $log->expects($this->once())->method('clean');
+        $this->commandTester->execute(['--days' => '1']);
+        $this->assertEquals('Log cleaned.' . PHP_EOL, $this->commandTester->getDisplay());
+    }
+
+    /**
+     *
+     * @param string $days
+     * @dataProvider daysDataProvider
+     */
+    public function testExecuteInvalidNegativeDays($days)
+    {
+        $this->commandTester->execute(['--days' => $days]);
+        //Invalid value for option "days". It should be a whole number greater than 0.
+        $this->assertEquals(
+            'Invalid value for option "days". It should be a whole number greater than 0.' . PHP_EOL,
+            $this->commandTester->getDisplay()
+        );
+    }
+
+    /**
+     * @return array
+     */
+    public function daysDataProvider()
+    {
+        return [['-1'], ['5.5'], ['test']];
+    }
+}
diff --git a/app/code/Magento/Log/Test/Unit/Console/Command/LogStatusCommandTest.php b/app/code/Magento/Log/Test/Unit/Console/Command/LogStatusCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7a7df444bb6a1f88ec83718be29276d2e73872b5
--- /dev/null
+++ b/app/code/Magento/Log/Test/Unit/Console/Command/LogStatusCommandTest.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Log\Test\Unit\Console\Command;
+
+use Magento\Log\Console\Command\LogStatusCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class LogStatusCommandTest extends \PHPUnit_Framework_TestCase
+{
+    public function testExecute()
+    {
+        $objectManagerFactory = $this->getMock('Magento\Framework\App\ObjectManagerFactory', [], [], '', false);
+        $objectManager = $this->getMock('Magento\Framework\App\ObjectManager', [], [], '', false);
+        $resourceFactory = $this->getMock('Magento\Log\Model\Resource\ShellFactory', [], [], '', false);
+        $objectManager->expects($this->once())->method('create')->willReturn($resourceFactory);
+        $resource = $this->getMock('Magento\Log\Model\Resource\Shell', [], [], '', false);
+        $resourceFactory->expects($this->once())->method('create')->willReturn($resource);
+        $resource->expects($this->once())->method('getTablesInfo')->willReturn(
+            [['name' => 'log_customer', 'rows' => '1', 'data_length' => '16384', 'index_length' => '1024']]
+        );
+        $objectManagerFactory->expects($this->once())->method('create')->willReturn($objectManager);
+        $commandTester = new CommandTester(new LogStatusCommand($objectManagerFactory));
+        $commandTester->execute([]);
+        $expectedMsg = '-----------------------------------+------------+------------+------------+' . PHP_EOL
+            . 'Table Name                         | Rows       | Data Size  | Index Size |' . PHP_EOL
+            . '-----------------------------------+------------+------------+------------+' . PHP_EOL
+            . 'log_customer                       | 1          | 16.00Kb    | 1.00Kb     |' . PHP_EOL
+            . '-----------------------------------+------------+------------+------------+' . PHP_EOL
+            . 'Total                              | 1          | 16.00Kb    | 1.00Kb     |' . PHP_EOL
+            . '-----------------------------------+------------+------------+------------+%w';
+        $this->assertStringMatchesFormat($expectedMsg, $commandTester->getDisplay());
+    }
+}
diff --git a/app/code/Magento/Log/Test/Unit/Model/Shell/Command/CleanTest.php b/app/code/Magento/Log/Test/Unit/Model/Shell/Command/CleanTest.php
deleted file mode 100644
index 1438ec7b080e134a810a1914e73c1dfb3866cc60..0000000000000000000000000000000000000000
--- a/app/code/Magento/Log/Test/Unit/Model/Shell/Command/CleanTest.php
+++ /dev/null
@@ -1,55 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\Test\Unit\Model\Shell\Command;
-
-class CleanTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_mutableConfigMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_logFactoryMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_logMock;
-
-    protected function setUp()
-    {
-        $this->_mutableConfigMock = $this->getMock('Magento\Framework\App\Config\MutableScopeConfigInterface');
-        $this->_logFactoryMock = $this->getMock('Magento\Log\Model\LogFactory', ['create'], [], '', false);
-        $this->_logMock = $this->getMock('Magento\Log\Model\Log', [], [], '', false);
-        $this->_logFactoryMock->expects($this->once())->method('create')->will($this->returnValue($this->_logMock));
-    }
-
-    public function testExecuteWithoutDaysOffset()
-    {
-        $model = new \Magento\Log\Model\Shell\Command\Clean($this->_mutableConfigMock, $this->_logFactoryMock, 0);
-        $this->_mutableConfigMock->expects($this->never())->method('setValue');
-        $this->_logMock->expects($this->once())->method('clean');
-        $this->assertStringStartsWith('Log cleaned', $model->execute());
-    }
-
-    public function testExecuteWithDaysOffset()
-    {
-        $model = new \Magento\Log\Model\Shell\Command\Clean($this->_mutableConfigMock, $this->_logFactoryMock, 10);
-        $this->_mutableConfigMock->expects($this->once())
-            ->method('setValue')
-            ->with(
-                \Magento\Log\Model\Log::XML_LOG_CLEAN_DAYS,
-                10,
-                \Magento\Store\Model\ScopeInterface::SCOPE_STORE
-            );
-
-        $this->_logMock->expects($this->once())->method('clean');
-        $this->assertStringStartsWith('Log cleaned', $model->execute());
-    }
-}
diff --git a/app/code/Magento/Log/Test/Unit/Model/Shell/Command/FactoryTest.php b/app/code/Magento/Log/Test/Unit/Model/Shell/Command/FactoryTest.php
deleted file mode 100644
index 0f4435fbc907dd1b6b1bda248afeb942e9c26d10..0000000000000000000000000000000000000000
--- a/app/code/Magento/Log/Test/Unit/Model/Shell/Command/FactoryTest.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\Test\Unit\Model\Shell\Command;
-
-class FactoryTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_objectManagerMock;
-
-    /**
-     * @var \Magento\Log\Model\Shell\Command\Factory
-     */
-    protected $_model;
-
-    protected function setUp()
-    {
-        $this->_objectManagerMock = $this->getMock('Magento\Framework\ObjectManagerInterface');
-        $this->_model = new \Magento\Log\Model\Shell\Command\Factory($this->_objectManagerMock);
-    }
-
-    public function testCreateCleanCommand()
-    {
-        $this->_objectManagerMock->expects(
-            $this->once()
-        )->method(
-            'create'
-        )->with(
-            'Magento\Log\Model\Shell\Command\Clean',
-            ['days' => 1]
-        )->will(
-            $this->returnValue($this->getMock('Magento\Log\Model\Shell\Command\Clean', [], [], '', false))
-        );
-        $this->isInstanceOf('Magento\Log\Model\Shell\CommandInterface', $this->_model->createCleanCommand(1));
-    }
-
-    public function testCreateStatusCommand()
-    {
-        $this->_objectManagerMock->expects(
-            $this->once()
-        )->method(
-            'create'
-        )->with(
-            'Magento\Log\Model\Shell\Command\Status'
-        )->will(
-            $this->returnValue($this->getMock('Magento\Log\Model\Shell\Command\Status', [], [], '', false))
-        );
-        $this->isInstanceOf('Magento\Log\Model\Shell\CommandInterface', $this->_model->createStatusCommand());
-    }
-}
diff --git a/app/code/Magento/Log/Test/Unit/Model/Shell/Command/StatusTest.php b/app/code/Magento/Log/Test/Unit/Model/Shell/Command/StatusTest.php
deleted file mode 100644
index 0482cd7faecb5aa68f8ade580b6a1e383ca92135..0000000000000000000000000000000000000000
--- a/app/code/Magento/Log/Test/Unit/Model/Shell/Command/StatusTest.php
+++ /dev/null
@@ -1,81 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\Test\Unit\Model\Shell\Command;
-
-class StatusTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_factoryMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_shellMock;
-
-    /**
-     * @var \Magento\Log\Model\Shell\Command\Status
-     */
-    protected $_model;
-
-    protected function setUp()
-    {
-        $this->_factoryMock = $this->getMock(
-            'Magento\Log\Model\Resource\ShellFactory',
-            ['create'],
-            [],
-            '',
-            false
-        );
-        $this->_shellMock = $this->getMock('Magento\Log\Model\Resource\Shell', [], [], '', false);
-        $this->_factoryMock->expects($this->once())->method('create')->will($this->returnValue($this->_shellMock));
-        $this->_model = new \Magento\Log\Model\Shell\Command\Status($this->_factoryMock);
-    }
-
-    public function testExecuteWithoutDataTotalAndHeadLinesFormatting()
-    {
-        $data = [];
-        $this->_shellMock->expects($this->once())->method('getTablesInfo')->will($this->returnValue($data));
-        $output = $this->_model->execute();
-        $total = '/Total( )+\|( )+0( )+\|( )+0 b( )+\|( )+0 b( )+\|/';
-        $this->assertRegExp($total, $output, 'Incorrect Total Line');
-
-        $head = '/Table Name( )+\|( )+Rows( )+\|( )+Data Size( )+\|( )+Index Size( )+\|/';
-        $this->assertRegExp($head, $output, 'Incorrect Head Line');
-    }
-
-    /**
-     * @param array $tableData
-     * @param string $expected
-     * @dataProvider executeDataFormatDataProvider
-     */
-    public function testExecuteWithData($tableData, $expected)
-    {
-        $data = [$tableData];
-        $this->_shellMock->expects($this->once())->method('getTablesInfo')->will($this->returnValue($data));
-        $this->assertRegExp($expected, $this->_model->execute());
-    }
-
-    public function executeDataFormatDataProvider()
-    {
-        return [
-            [
-                ['name' => 'table_1', 'rows' => 1500, 'data_length' => 1000, 'index_length' => 1024 * 1024],
-                '/table_1( )+\|( )+1\.50K( )+\|( )+1000 b( )+\|( )+1\.00Mb( )+\|/',
-            ],
-            [
-                [
-                    'name' => 'table_2',
-                    'rows' => 1500000,
-                    'data_length' => 1024 * 1024 * 1024,
-                    'index_length' => 1024 * 1024 * 1024 * 500,
-                ],
-                '/table_2( )+\|( )+1\.50M( )+\|( )+1\.00Gb( )+\|( )+500\.00Gb( )+\|/'
-            ]
-        ];
-    }
-}
diff --git a/app/code/Magento/Log/Test/Unit/Model/ShellTest.php b/app/code/Magento/Log/Test/Unit/Model/ShellTest.php
deleted file mode 100644
index 2b7071cd7a061b8ceb6a23c655c20e93f5087c19..0000000000000000000000000000000000000000
--- a/app/code/Magento/Log/Test/Unit/Model/ShellTest.php
+++ /dev/null
@@ -1,88 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\Test\Unit\Model;
-
-class ShellTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_factoryMock;
-
-    /**
-     * @var \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_shellMock;
-
-    /**
-     * @var \Magento\Log\Model\Shell
-     */
-    protected $_model;
-
-    protected function setUp()
-    {
-        $this->_factoryMock = $this->getMock('Magento\Log\Model\Shell\Command\Factory', [], [], '', false);
-        $filesystemMock = $this->getMock('Magento\Framework\Filesystem', [], [], '', false);
-        $this->_model = $this->getMock(
-            'Magento\Log\Model\Shell',
-            ['_applyPhpVariables'],
-            [$filesystemMock, 'entryPoint.php', $this->_factoryMock]
-        );
-    }
-
-    public function testRunWithShowHelp()
-    {
-        $this->expectOutputRegex('/Usage\:  php -f entryPoint\.php/');
-        $this->_model->setRawArgs(['h']);
-        $this->_factoryMock->expects($this->never())->method('createCleanCommand');
-        $this->_factoryMock->expects($this->never())->method('createStatusCommand');
-        $this->_model->run();
-    }
-
-    public function testRunWithCleanCommand()
-    {
-        $this->expectOutputRegex('/clean command message/');
-        $this->_model->setRawArgs(['clean', '--days', 10]);
-        $commandMock = $this->getMock('Magento\Log\Model\Shell\CommandInterface');
-        $this->_factoryMock->expects(
-            $this->once()
-        )->method(
-            'createCleanCommand'
-        )->with(
-            10
-        )->will(
-            $this->returnValue($commandMock)
-        );
-        $commandMock->expects($this->once())->method('execute')->will($this->returnValue('clean command message'));
-        $this->_factoryMock->expects($this->never())->method('createStatusCommand');
-        $this->_model->run();
-    }
-
-    public function testRunWithStatusCommand()
-    {
-        $this->expectOutputRegex('/status command message/');
-        $this->_model->setRawArgs(['status']);
-        $commandMock = $this->getMock('Magento\Log\Model\Shell\CommandInterface');
-        $this->_factoryMock->expects(
-            $this->once()
-        )->method(
-            'createStatusCommand'
-        )->will(
-            $this->returnValue($commandMock)
-        );
-        $commandMock->expects($this->once())->method('execute')->will($this->returnValue('status command message'));
-        $this->_factoryMock->expects($this->never())->method('createCleanCommand');
-        $this->_model->run();
-    }
-
-    public function testRunWithoutCommand()
-    {
-        $this->expectOutputRegex('/Usage\:  php -f entryPoint\.php/');
-        $this->_factoryMock->expects($this->never())->method('createStatusCommand');
-        $this->_factoryMock->expects($this->never())->method('createCleanCommand');
-        $this->_model->run();
-    }
-}
diff --git a/app/code/Magento/Log/etc/di.xml b/app/code/Magento/Log/etc/di.xml
index 078c0d6e4a283a5d92161651e52e0fd1c405d885..ff051483d833a93d6cd55b226558fedba642815f 100644
--- a/app/code/Magento/Log/etc/di.xml
+++ b/app/code/Magento/Log/etc/di.xml
@@ -11,4 +11,12 @@
             <argument name="storeManager" xsi:type="object">Magento\Store\Model\StoreManager\Proxy</argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\Console\CommandList">
+        <arguments>
+            <argument name="commands" xsi:type="array">
+                <item name="logStatusCommand" xsi:type="object">Magento\Log\Console\Command\LogStatusCommand</item>
+                <item name="logCleanCommand" xsi:type="object">Magento\Log\Console\Command\LogCleanCommand</item>
+            </argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Newsletter/Model/Session.php b/app/code/Magento/Newsletter/Model/Session.php
index 18d680df142601fb39eab95181cee59a79cca4cb..2ffb0b2f25236066922a7510267f10135c1a518f 100644
--- a/app/code/Magento/Newsletter/Model/Session.php
+++ b/app/code/Magento/Newsletter/Model/Session.php
@@ -8,7 +8,7 @@ namespace Magento\Newsletter\Model;
 /**
  * Newsletter session model
  */
-class Session extends \Magento\Framework\Session\Generic
+class Session extends \Magento\Framework\Session\SessionManager
 {
     /**
      * Set error message
diff --git a/app/code/Magento/Payment/Block/Adminhtml/Transparent/Form.php b/app/code/Magento/Payment/Block/Adminhtml/Transparent/Form.php
new file mode 100644
index 0000000000000000000000000000000000000000..60717bda74798f92b9f1318da44139a16df86039
--- /dev/null
+++ b/app/code/Magento/Payment/Block/Adminhtml/Transparent/Form.php
@@ -0,0 +1,27 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Block\Adminhtml\Transparent;
+
+class Form extends \Magento\Payment\Block\Transparent\Form
+{
+    /**
+     * On backend this block does not have any conditional checks
+     *
+     * @return bool
+     */
+    protected function shouldRender()
+    {
+        return true;
+    }
+
+    /**
+     * {inheritdoc}
+     */
+    protected function initializeMethod()
+    {
+        return;
+    }
+}
diff --git a/app/code/Magento/Payment/Block/Form.php b/app/code/Magento/Payment/Block/Form.php
index 762baad7f3741b485b73ac458eeed8a66434770d..f56d9ac3df0474b2d1f28bbbb16c35ea45510bc3 100644
--- a/app/code/Magento/Payment/Block/Form.php
+++ b/app/code/Magento/Payment/Block/Form.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Payment\Block;
 
+use Magento\Payment\Model\MethodInterface;
+
 /**
  * Payment method form base block
  */
@@ -13,14 +15,14 @@ class Form extends \Magento\Framework\View\Element\Template
     /**
      * Retrieve payment method model
      *
-     * @return \Magento\Payment\Model\MethodInterface
+     * @return MethodInterface
      * @throws \Magento\Framework\Exception\LocalizedException
      */
     public function getMethod()
     {
         $method = $this->getData('method');
 
-        if (!$method instanceof \Magento\Payment\Model\MethodInterface) {
+        if (!$method instanceof MethodInterface) {
             throw new \Magento\Framework\Exception\LocalizedException(
                 __('We cannot retrieve the payment method model object.')
             );
@@ -28,6 +30,18 @@ class Form extends \Magento\Framework\View\Element\Template
         return $method;
     }
 
+    /**
+     * Sets payment method instance to form
+     *
+     * @param MethodInterface $method
+     * @return $this
+     */
+    public function setMethod(MethodInterface $method)
+    {
+        $this->setData('method', $method);
+        return $this;
+    }
+
     /**
      * Retrieve payment method code
      *
diff --git a/app/code/Magento/Payment/Block/Transparent/Form.php b/app/code/Magento/Payment/Block/Transparent/Form.php
new file mode 100644
index 0000000000000000000000000000000000000000..3237e6e21191af8c37ce16ff0085007d5b8d190a
--- /dev/null
+++ b/app/code/Magento/Payment/Block/Transparent/Form.php
@@ -0,0 +1,191 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Block\Transparent;
+
+use Magento\Framework\Exception\LocalizedException;
+use Magento\Payment\Model\Method\TransparentInterface;
+use Magento\Checkout\Model\Session;
+use Magento\Payment\Model\Config;
+use Magento\Framework\View\Element\Template\Context;
+
+/**
+ * Transparent form block
+ *
+ * @author     Magento Core Team <core@magentocommerce.com>
+ */
+class Form extends \Magento\Payment\Block\Form\Cc
+{
+    /**
+     * @var Session
+     */
+    private $checkoutSession;
+
+    /**
+     * @var string
+     */
+    protected $_template = 'Magento_Payment::transparent/form.phtml';
+
+    /**
+     * @param Context $context
+     * @param Config $paymentConfig
+     * @param Session $checkoutSession
+     * @param array $data
+     */
+    public function __construct(
+        Context $context,
+        Config $paymentConfig,
+        Session $checkoutSession,
+        array $data = []
+    ) {
+        parent::__construct($context, $paymentConfig, $data);
+        $this->checkoutSession = $checkoutSession;
+    }
+
+    /**
+     * {inheritdoc}
+     */
+    protected function _toHtml()
+    {
+        if ($this->shouldRender()) {
+            return $this->processHtml();
+        }
+
+        return '';
+    }
+
+    /**
+     * Checks whether block should be rendered
+     * basing on TransparentInterface presence in checkout session
+     *
+     * @return bool
+     */
+    protected function shouldRender()
+    {
+        $quote = $this->checkoutSession->getQuote();
+        if ($quote) {
+            $payment = $quote->getPayment();
+            return $payment && $payment->getMethodInstance() instanceof TransparentInterface;
+        }
+
+        return false;
+    }
+
+    /**
+     * Initializes method
+     *
+     * @return void
+     */
+    protected function initializeMethod()
+    {
+        $this->setData(
+            'method',
+            $this->checkoutSession
+                ->getQuote()
+                ->getPayment()
+                ->getMethodInstance()
+        );
+    }
+
+    /**
+     * Parent rendering wrapper
+     *
+     * @return string
+     */
+    protected function processHtml()
+    {
+        $this->initializeMethod();
+        return parent::_toHtml();
+    }
+
+    /**
+     * Get type of request
+     *
+     * @return bool
+     */
+    public function isAjaxRequest()
+    {
+        return $this->getRequest()->getParam('isAjax');
+    }
+
+    /**
+     * Get delimiter for date
+     *
+     * @return string
+     */
+    public function getDateDelim()
+    {
+        return $this->getMethodConfigData('date_delim');
+    }
+
+    /**
+     * Get map of cc_code, cc_num, cc_expdate for gateway
+     * Returns json formatted string
+     *
+     * @return string
+     */
+    public function getCardFieldsMap()
+    {
+        $keys = ['cccvv', 'ccexpdate', 'ccnum'];
+        $ccfields = array_combine($keys, explode(',', $this->getMethodConfigData('ccfields')));
+        return json_encode($ccfields);
+    }
+
+    /**
+     * Retrieve place order url on front
+     *
+     * @return string
+     */
+    public function getOrderUrl()
+    {
+        return $this->_urlBuilder->getUrl(
+            $this->getMethodConfigData('place_order_url'),
+            [
+                '_secure' => $this->getRequest()->isSecure()
+            ]
+        );
+    }
+
+    /**
+     * Retrieve gateway url
+     *
+     * @return string
+     */
+    public function getCgiUrl()
+    {
+        return (bool)$this->getMethodConfigData('sandbox_flag')
+            ? $this->getMethodConfigData('cgi_url_test_mode')
+            : $this->getMethodConfigData('cgi_url');
+    }
+
+    /**
+     * Retrieve config data value by field name
+     *
+     * @param string $fieldName
+     * @return mixed
+     */
+    public function getMethodConfigData($fieldName)
+    {
+        return $this->getMethod()->getConfigInterface()->getConfigValue($fieldName);
+    }
+
+    /**
+     * Returns transparent method service
+     *
+     * @return TransparentInterface
+     * @throws LocalizedException
+     */
+    public function getMethod()
+    {
+        $method = parent::getMethod();
+
+        if (!$method instanceof TransparentInterface) {
+            throw new LocalizedException(
+                __('We cannot retrieve the transparent payment method model object.')
+            );
+        }
+        return $method;
+    }
+}
diff --git a/app/code/Magento/Payment/Block/Transparent/Iframe.php b/app/code/Magento/Payment/Block/Transparent/Iframe.php
new file mode 100644
index 0000000000000000000000000000000000000000..3070173f92b36c0bae20d66aadce8981b7c322af
--- /dev/null
+++ b/app/code/Magento/Payment/Block/Transparent/Iframe.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Block\Transparent;
+
+/**
+ * Iframe block for register specific params in layout
+ *
+ * @author     Magento Core Team <core@magentocommerce.com>
+ */
+class Iframe extends \Magento\Framework\View\Element\Template
+{
+    /**
+     * Core registry
+     *
+     * @var \Magento\Framework\Registry
+     */
+    protected $coreRegistry;
+
+    /**
+     * Constructor
+     *
+     * @param \Magento\Framework\View\Element\Template\Context $context
+     * @param \Magento\Framework\Registry $registry
+     * @param array $data
+     */
+    public function __construct(
+        \Magento\Framework\View\Element\Template\Context $context,
+        \Magento\Framework\Registry $registry,
+        array $data = []
+    ) {
+        $this->coreRegistry = $registry;
+        parent::__construct($context, $data);
+    }
+
+    /**
+     * Preparing layout
+     *
+     * @return $this
+     */
+    protected function _prepareLayout()
+    {
+        if ($this->hasRegistryKey()) {
+            $params = $this->coreRegistry->registry($this->getRegistryKey());
+            $this->setParams($params);
+        }
+        return parent::_prepareLayout();
+    }
+}
diff --git a/app/code/Magento/Payment/Block/Transparent/Info.php b/app/code/Magento/Payment/Block/Transparent/Info.php
new file mode 100644
index 0000000000000000000000000000000000000000..af21b0e1758a59f2a7c3e9adb1b5905de346cd89
--- /dev/null
+++ b/app/code/Magento/Payment/Block/Transparent/Info.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Block\Transparent;
+
+/**
+ * Class Info. Payment Information block used for transparent redirect feature
+ * @package Magento\Payment\Block\Transparent
+ */
+class Info extends \Magento\Framework\View\Element\Template
+{
+    /**
+     * @var string
+     */
+    protected $_template = 'Magento_Payment::transparent/info.phtml';
+}
diff --git a/app/code/Magento/Payment/Model/Method/AbstractMethod.php b/app/code/Magento/Payment/Model/Method/AbstractMethod.php
index e316982a1be7081f470bc8cb2493d19ea0debfea..5a3a5a8b46262889fcd8a574a8b2fffb2a26f61c 100644
--- a/app/code/Magento/Payment/Model/Method/AbstractMethod.php
+++ b/app/code/Magento/Payment/Model/Method/AbstractMethod.php
@@ -254,6 +254,20 @@ abstract class AbstractMethod extends \Magento\Framework\Model\AbstractExtensibl
         $this->_scopeConfig = $scopeConfig;
         $this->_eventManager = $context->getEventDispatcher();
         $this->logger = $context->getLogger();
+        $this->initializeData($data);
+    }
+
+    /**
+     * Initializes injected data
+     *
+     * @param array $data
+     * @return void
+     */
+    protected function initializeData($data = [])
+    {
+        if (!empty($data['formBlockType'])) {
+            $this->_formBlockType = $data['formBlockType'];
+        }
     }
 
     /**
diff --git a/app/code/Magento/Payment/Model/Method/ConfigInterface.php b/app/code/Magento/Payment/Model/Method/ConfigInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..600f4fdb53a8c0eada317308eeda14a9a26907ee
--- /dev/null
+++ b/app/code/Magento/Payment/Model/Method/ConfigInterface.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Model\Method;
+
+/**
+ * Interface for payment methods config
+ *
+ * @author     Magento Core Team <core@magentocommerce.com>
+ */
+interface ConfigInterface
+{
+    /**
+     * Config field getter
+     * The specified key can be either in camelCase or under_score format
+     *
+     * @param string $key
+     * @return mixed
+     */
+    public function getConfigValue($key);
+}
diff --git a/app/code/Magento/Payment/Model/Method/Logger.php b/app/code/Magento/Payment/Model/Method/Logger.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c9e54e5e23636527f64eaff58997e6bb0de70c7
--- /dev/null
+++ b/app/code/Magento/Payment/Model/Method/Logger.php
@@ -0,0 +1,44 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Model\Method;
+
+use Psr\Log\LoggerInterface;
+
+/**
+ * Class Logger for payment related information (request, response, etc.) which is used for debug
+ *
+ * @author     Magento Core Team <core@magentocommerce.com>
+ */
+class Logger
+{
+    /**
+     * @var LoggerInterface
+     */
+    protected $logger;
+
+    /**
+     * @param LoggerInterface $logger
+     */
+    public function __construct(LoggerInterface $logger)
+    {
+        $this->logger = $logger;
+    }
+
+    /**
+     * Logs payment related information used for debug
+     *
+     * @param mixed $logData
+     * @param ConfigInterface $config
+     *
+     * @return void
+     */
+    public function debug($logData, ConfigInterface $config)
+    {
+        if ($config->getConfigValue('debug')) {
+            $this->logger->debug(var_export($logData, true));
+        }
+    }
+}
diff --git a/app/code/Magento/Payment/Model/Method/Online/GatewayInterface.php b/app/code/Magento/Payment/Model/Method/Online/GatewayInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..4a99a7e8308758e368ad364463673f4828e2ca0e
--- /dev/null
+++ b/app/code/Magento/Payment/Model/Method/Online/GatewayInterface.php
@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Model\Method\Online;
+
+use Magento\Framework\Object;
+use Magento\Payment\Model\Method\ConfigInterface;
+
+/**
+ * Gateway interface for online payment methods
+ *
+ * @author     Magento Core Team <core@magentocommerce.com>
+ */
+interface GatewayInterface
+{
+    /**
+     * Post request to gateway and return response
+     *
+     * @param Object $request
+     * @param ConfigInterface $config
+     *
+     * @return Object
+     *
+     * @throws \Exception
+     */
+    public function postRequest(Object $request, ConfigInterface $config);
+}
diff --git a/app/code/Magento/Payment/Model/Method/TransparentInterface.php b/app/code/Magento/Payment/Model/Method/TransparentInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..eebb8594cc2ea9a0259edd508aef77bd6fa1c9b2
--- /dev/null
+++ b/app/code/Magento/Payment/Model/Method/TransparentInterface.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Model\Method;
+
+use Magento\Payment\Model\MethodInterface;
+
+/**
+ * Interface TransparentInterface need to be implemented by Payment Method service
+ * which supports transparent redirect feature
+ * @package Magento\Payment\Model\Method
+ */
+interface TransparentInterface extends MethodInterface
+{
+    /**
+     * Returns payment method configured config
+     *
+     * @return ConfigInterface
+     */
+    public function getConfigInterface();
+}
diff --git a/app/code/Magento/Payment/Test/Unit/Block/Adminhtml/Transparent/FormTest.php b/app/code/Magento/Payment/Test/Unit/Block/Adminhtml/Transparent/FormTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3281e616a649bd16ce9293069d052a965e380c5d
--- /dev/null
+++ b/app/code/Magento/Payment/Test/Unit/Block/Adminhtml/Transparent/FormTest.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Test\Unit\Block\Adminhtml\Transparent;
+
+use Magento\Framework\App\RequestInterface;
+use Magento\Framework\Object;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Framework\UrlInterface;
+use Magento\Payment\Model\Method\TransparentInterface;
+
+class FormTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var FormTesting | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $form;
+
+    /**
+     * @var TransparentInterface | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $methodMock;
+
+    /**
+     * @var \Magento\Checkout\Model\Session | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $checkoutSessionMock;
+
+    protected function setUp()
+    {
+        $objectManagerHelper = new ObjectManager($this);
+
+        $this->requestMock = $this->getMockBuilder('\Magento\Framework\App\RequestInterface')
+            ->setMethods(['getParam'])
+            ->getMockForAbstractClass();
+
+        $this->urlBuilderMock = $this->getMockBuilder('\Magento\Framework\UrlInterface')
+            ->setMethods(['getUrl'])
+            ->getMockForAbstractClass();
+
+        $context = $objectManagerHelper->getObject('Magento\Framework\View\Element\Template\Context');
+
+        $this->methodMock = $this->getMockBuilder('Magento\Payment\Model\Method\TransparentInterface')
+            ->getMock();
+
+        $this->checkoutSessionMock = $this->getMockBuilder('Magento\Checkout\Model\Session')
+            ->setMethods([])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $paymentConfigMock = $this->getMockBuilder('Magento\Payment\Model\Config')
+            ->setMethods([])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->form = new FormTesting(
+            $context,
+            $paymentConfigMock,
+            $this->checkoutSessionMock
+        );
+    }
+
+    public function testToHtmlShouldRender()
+    {
+        $quoteMock = $this->getMockBuilder('Magento\Quote\Model\Quote')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $paymentMock = $this->getMockBuilder('Magento\Quote\Model\Quote\Payment')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->checkoutSessionMock->expects($this->never())
+            ->method('getQuote')
+            ->willReturn($quoteMock);
+        $quoteMock->expects($this->never())
+            ->method('getPayment')
+            ->willReturn($paymentMock);
+        $paymentMock->expects($this->never())
+            ->method('getMethodInstance')
+            ->willReturn($this->methodMock);
+
+        $this->form->toHtml();
+    }
+}
diff --git a/app/code/Magento/Payment/Test/Unit/Block/Adminhtml/Transparent/FormTesting.php b/app/code/Magento/Payment/Test/Unit/Block/Adminhtml/Transparent/FormTesting.php
new file mode 100644
index 0000000000000000000000000000000000000000..e48bf8f6a57e7cea7576db24e565c4b1e2a2b0bf
--- /dev/null
+++ b/app/code/Magento/Payment/Test/Unit/Block/Adminhtml/Transparent/FormTesting.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Test\Unit\Block\Adminhtml\Transparent;
+
+use Magento\Payment\Block\Adminhtml\Transparent\Form;
+
+/**
+ * Class FormTesting extended test class, used to substitute calls to parent methods
+ * @package Magento\Payment\Test\Unit\Block\Adminhtml\Transparent
+ */
+class FormTesting extends Form
+{
+    /**
+     * Return values for processHtml() method
+     */
+    const PROCESS_HTML_RESULT = 'parent_result';
+
+    /**
+     * {inheritdoc}
+     */
+    protected function processHtml()
+    {
+        return self::PROCESS_HTML_RESULT;
+    }
+}
diff --git a/app/code/Magento/Payment/Test/Unit/Block/FormTest.php b/app/code/Magento/Payment/Test/Unit/Block/FormTest.php
index 2db84edbdfd599c017242715d510240ce944a5f7..9f01df530fa1520c38e79312f2f309de3b4df336 100644
--- a/app/code/Magento/Payment/Test/Unit/Block/FormTest.php
+++ b/app/code/Magento/Payment/Test/Unit/Block/FormTest.php
@@ -119,4 +119,12 @@ class FormTest extends \PHPUnit_Framework_TestCase
             ]
         ];
     }
+
+    public function testSetMethod()
+    {
+        $methodInterfaceMock = $this->getMockBuilder('\Magento\Payment\Model\MethodInterface')
+            ->getMockForAbstractClass();
+
+        $this->assertSame($this->_object, $this->_object->setMethod($methodInterfaceMock));
+    }
 }
diff --git a/app/code/Magento/Payment/Test/Unit/Block/Transparent/FormTest.php b/app/code/Magento/Payment/Test/Unit/Block/Transparent/FormTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b361cc1881eec8ae1c463dbf7b2ead8d1ce39a19
--- /dev/null
+++ b/app/code/Magento/Payment/Test/Unit/Block/Transparent/FormTest.php
@@ -0,0 +1,301 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Test\Unit\Block\Transparent;
+
+use Magento\Checkout\Model\Session;
+use Magento\Framework\App\RequestInterface;
+use Magento\Framework\Object;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Framework\UrlInterface;
+use Magento\Payment\Model\Method\TransparentInterface;
+
+class FormTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var FormTesting | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $form;
+
+    /**
+     * @var RequestInterface | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $requestMock;
+
+    /**
+     * @var UrlInterface | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $urlBuilderMock;
+
+    /**
+     * @var TransparentInterface | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $methodMock;
+
+    /**
+     * @var Session | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $checkoutSessionMock;
+
+    protected function setUp()
+    {
+        $objectManagerHelper = new ObjectManager($this);
+
+        $this->requestMock = $this->getMockBuilder('\Magento\Framework\App\RequestInterface')
+            ->setMethods(['getParam'])
+            ->getMockForAbstractClass();
+
+        $this->urlBuilderMock = $this->getMockBuilder('\Magento\Framework\UrlInterface')
+            ->setMethods(['getUrl'])
+            ->getMockForAbstractClass();
+
+        $context = $objectManagerHelper->getObject(
+            'Magento\Framework\View\Element\Template\Context',
+            [
+                'request' => $this->requestMock,
+                'urlBuilder' => $this->urlBuilderMock
+            ]
+        );
+
+        $this->methodMock = $this->getMockBuilder('Magento\Payment\Model\Method\TransparentInterface')
+            ->getMock();
+
+        $this->checkoutSessionMock = $this->getMockBuilder('Magento\Checkout\Model\Session')
+            ->setMethods([])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $paymentConfigMock = $this->getMockBuilder('Magento\Payment\Model\Config')
+            ->setMethods([])
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->form = new FormTesting(
+            $context,
+            $paymentConfigMock,
+            $this->checkoutSessionMock
+        );
+    }
+
+    public function testIsAjaxRequest()
+    {
+        $this->requestMock->expects($this->exactly(2))
+            ->method('getParam')
+            ->with('isAjax')
+            ->willReturnOnConsecutiveCalls(true, false);
+
+        $this->assertTrue($this->form->isAjaxRequest());
+        $this->assertFalse($this->form->isAjaxRequest());
+    }
+
+    /**
+     * @param string $fieldName
+     * @param mixed $fieldValue
+     * @param mixed $expected
+     *
+     * @dataProvider getMethodConfigDataDataProvider
+     */
+    public function testGetMethodConfigData($fieldName, $fieldValue, $expected)
+    {
+        $this->initializeMethodWithConfigMock([[$fieldName, $fieldValue]]);
+
+        $this->form->setMethod($this->methodMock);
+
+        $this->assertEquals($expected, $this->form->getMethodConfigData($fieldName));
+    }
+
+    /**
+     * Initializes method mock with config mock
+     *
+     * @param array $configMap
+     */
+    private function initializeMethodWithConfigMock(array $configMap = [])
+    {
+        $configInterface = $this->getMockBuilder('Magento\Payment\Model\Method\ConfigInterface')
+            ->getMock();
+
+        $configInterface->expects($this->any())
+            ->method('getConfigValue')
+            ->willReturnMap($configMap);
+
+        $this->methodMock->expects($this->any())
+            ->method('getConfigInterface')
+            ->willReturn($configInterface);
+    }
+
+    /**
+     * Data provider for testGetMethodConfigData
+     *
+     * @see testGetMethodConfigData
+     *
+     * @case #1 Set string value
+     * @case #2 Set boolean value
+     *
+     * @return array
+     */
+    public function getMethodConfigDataDataProvider()
+    {
+        return [
+            ['gateway_name', 'payment_gateway', 'payment_gateway'],
+            ['sandbox_flag', true, true],
+        ];
+    }
+
+    /**
+     * @dataProvider getCgiUrlDataProvider
+     *
+     * @param $sandboxFlag
+     * @param $cgiUrlTestMode
+     * @param $cgiUrl
+     * @param $expectedUrl
+     */
+    public function testGetCgiUrl($sandboxFlag, $cgiUrlTestMode, $cgiUrl, $expectedUrl)
+    {
+        $this->initializeMethodWithConfigMock(
+            [
+                ['sandbox_flag', $sandboxFlag],
+                ['cgi_url_test_mode', $cgiUrlTestMode],
+                ['cgi_url', $cgiUrl]
+            ]
+        );
+
+        $this->form->setMethod($this->methodMock);
+
+        $this->assertEquals($expectedUrl, $this->form->getCgiUrl());
+    }
+
+    /**
+     * Data provider for testGetCgiUrl
+     *
+     * @see testGetCgiUrl
+     *
+     * @case #1 The sandboxFlag is 1 we expected cgi_url_test_mode_value
+     * @case #2 The sandboxFlag is 0 we expected cgi_url_value
+     *
+     * @return array
+     */
+    public function getCgiUrlDataProvider()
+    {
+        return [
+            [
+                1,
+                'cgi_url_test_mode_value',
+                'cgi_url_value',
+                'cgi_url_test_mode_value'
+            ],
+            [
+                0,
+                'cgi_url_test_mode_value',
+                'cgi_url_value',
+                'cgi_url_value'
+            ],
+        ];
+    }
+
+    public function testGetOrderUrl()
+    {
+        $orderUrlPattern = 'order_url';
+        $builtOrderUrl = 'built_url';
+        $this->initializeMethodWithConfigMock([['place_order_url', $orderUrlPattern]]);
+
+        $this->urlBuilderMock->expects($this->once())
+            ->method('getUrl')
+            ->with($orderUrlPattern)
+            ->willReturn($builtOrderUrl);
+
+        $this->form->setMethod($this->methodMock);
+
+        $this->assertEquals($builtOrderUrl, $this->form->getOrderUrl());
+    }
+
+    public function testGetDateDelim()
+    {
+        $dateDelimiter = '/';
+        $this->initializeMethodWithConfigMock([['date_delim', $dateDelimiter]]);
+
+        $this->form->setMethod($this->methodMock);
+
+        $this->assertEquals($dateDelimiter, $this->form->getDateDelim());
+    }
+
+    public function testGetCardFieldsMap()
+    {
+        $ccfields = 'x_card_code,x_exp_date,x_card_num';
+        $this->initializeMethodWithConfigMock([['ccfields', $ccfields]]);
+
+        $this->form->setMethod($this->methodMock);
+
+        $expected = json_encode(['cccvv' => 'x_card_code', 'ccexpdate' => 'x_exp_date', 'ccnum' => 'x_card_num']);
+
+        $this->assertEquals($expected, $this->form->getCardFieldsMap());
+    }
+
+    public function testToHtmlShouldRender()
+    {
+        $quoteMock = $this->getMockBuilder('Magento\Quote\Model\Quote')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $paymentMock = $this->getMockBuilder('Magento\Quote\Model\Quote\Payment')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->checkoutSessionMock->expects($this->once())
+            ->method('getQuote')
+            ->willReturn($quoteMock);
+        $quoteMock->expects($this->once())
+            ->method('getPayment')
+            ->willReturn($paymentMock);
+        $paymentMock->expects($this->once())
+            ->method('getMethodInstance')
+            ->willReturn($this->methodMock);
+
+        $this->form->toHtml();
+    }
+
+    public function testToHtmlShouldNotRenderEmptyQuote()
+    {
+        $this->checkoutSessionMock->expects($this->once())
+            ->method('getQuote')
+            ->willReturn(null);
+
+        $this->assertEmpty($this->form->toHtml());
+    }
+
+    public function testToHtmlShouldNotRenderEmptyPayment()
+    {
+        $quoteMock = $this->getMockBuilder('Magento\Quote\Model\Quote')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->checkoutSessionMock->expects($this->once())
+            ->method('getQuote')
+            ->willReturn($quoteMock);
+        $quoteMock->expects($this->once())
+            ->method('getPayment')
+            ->willReturn(null);
+
+        $this->assertEmpty($this->form->toHtml());
+    }
+
+    public function testGetMethodSuccess()
+    {
+        $this->form->setMethod($this->methodMock);
+        $this->assertSame($this->methodMock, $this->form->getMethod());
+    }
+
+    public function testGetMethodNotTransparentInterface()
+    {
+        $this->setExpectedException(
+            'Magento\Framework\Exception\LocalizedException',
+            __('We cannot retrieve the transparent payment method model object.')
+        );
+
+        $methodMock = $this->getMockBuilder('Magento\Payment\Model\MethodInterface')
+            ->getMockForAbstractClass();
+
+        $this->form->setMethod($methodMock);
+        $this->form->getMethod();
+    }
+}
diff --git a/app/code/Magento/Payment/Test/Unit/Block/Transparent/FormTesting.php b/app/code/Magento/Payment/Test/Unit/Block/Transparent/FormTesting.php
new file mode 100644
index 0000000000000000000000000000000000000000..cdeb6a8b5fc76d2fe77e824c3b1b9b56f6582274
--- /dev/null
+++ b/app/code/Magento/Payment/Test/Unit/Block/Transparent/FormTesting.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Test\Unit\Block\Transparent;
+
+use Magento\Payment\Block\Transparent\Form;
+
+/**
+ * Class FormTesting extended test class, used to substitute calls to parent methods
+ * @package Magento\Payment\Test\Unit\Block\Transparent
+ */
+class FormTesting extends Form
+{
+    /**
+     * Return values for processHtml() method
+     */
+    const PROCESS_HTML_RESULT = 'parent_result';
+
+    /**
+     * {inheritdoc}
+     */
+    protected function processHtml()
+    {
+        return self::PROCESS_HTML_RESULT;
+    }
+}
diff --git a/app/code/Magento/Payment/Test/Unit/Model/Method/LoggerTest.php b/app/code/Magento/Payment/Test/Unit/Model/Method/LoggerTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..75efef237b33a53a318e56ca50920d21f644418f
--- /dev/null
+++ b/app/code/Magento/Payment/Test/Unit/Model/Method/LoggerTest.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Payment\Test\Unit\Model\Method;
+
+use Magento\Payment\Model\Method\ConfigInterface;
+use Magento\Payment\Model\Method\Logger;
+use Psr\Log\LoggerInterface;
+
+class LoggerTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var Logger | \PHPUnit_Framework_MockObject_MockObject */
+    private $logger;
+
+    /** @var LoggerInterface | \PHPUnit_Framework_MockObject_MockObject */
+    private $loggerMock;
+
+    /** @var ConfigInterface | \PHPUnit_Framework_MockObject_MockObject */
+    private $configMock;
+
+    protected function setUp()
+    {
+        $this->loggerMock = $this->getMockForAbstractClass('Psr\Log\LoggerInterface');
+        $this->configMock = $this->getMockForAbstractClass('Magento\Payment\Model\Method\ConfigInterface');
+
+        $this->logger = new Logger($this->loggerMock);
+    }
+
+    public function testDebugOn()
+    {
+        $this->configMock->expects($this->once())
+            ->method('getConfigValue')
+            ->with('debug')
+            ->willReturn(true);
+        $this->loggerMock->expects($this->once())
+            ->method('debug')
+            ->with("'test_value'");
+
+        $this->logger->debug('test_value', $this->configMock);
+    }
+
+    public function testDebugOff()
+    {
+        $this->configMock->expects($this->once())
+            ->method('getConfigValue')
+            ->with('debug')
+            ->willReturn(false);
+        $this->loggerMock->expects($this->never())
+            ->method('debug');
+
+        $this->logger->debug('', $this->configMock);
+    }
+}
diff --git a/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml b/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..e9632aa0f89155238a8a659b660687a2bc4ce743
--- /dev/null
+++ b/app/code/Magento/Payment/view/adminhtml/templates/transparent/form.phtml
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+?>
+<?php
+// @codingStandardsIgnoreFile
+
+/** @var \Magento\Payment\Block\Transparent\Form $block*/
+$code = $block->getMethodCode();
+?>
+
+<!-- IFRAME for request to Payment Gateway -->
+<iframe id="<?php echo $code ?>-transparent-iframe" data-container="<?php echo $code ?>-transparent-iframe" allowtransparency="true" frameborder="0"  name="iframeTransparent" style="display:none;width:100%;background-color:transparent" src="<?php echo $block->getViewFileUrl('blank.html') ?>"></iframe>
+<div id="payment_form_<?php echo $code ?>"
+     data-mage-init='{
+     "transparent":{
+        "controller":"<?php echo $block->getRequest()->getControllerName() ?>",
+        "gateway":"<?php echo $block->getMethodCode() ?>",
+        "dateDelim":"<?php echo $block->getDateDelim() ?>",
+        "cardFieldsMap":<?php echo $block->getCardFieldsMap() ?>,
+        "orderSaveUrl":"<?php echo $block->getOrderUrl() ?>",
+        "cgiUrl":"<?php echo $block->getCgiUrl() ?>",
+        "nativeAction":"<?php echo $block->getUrl('*/*/save', ['_secure' => $block->getRequest()->isSecure()]) ?>"
+      }, "validation":[]}'
+     style="display:none;">
+
+        <div class="field required type">
+            <label for="<?php echo $code ?>_cc_type" class="label"><span><?php echo __('Credit Card Type') ?></span></label>
+            <div class="control">
+                <select id="<?php echo $code ?>_cc_type" data-container="<?php echo $code ?>-cc-type" name="payment[cc_type]" data-validate='{required:true, "validate-cc-type-select":"#<?php echo $code ?>_cc_number"}'>
+                    <option value=""><?php echo __('--Please Select--')?></option>
+                    <?php $_ccType = $block->getInfoData('cc_type') ?>
+                    <?php foreach ($block->getCcAvailableTypes() as $_typeCode => $_typeName): ?>
+                        <option value="<?php echo $_typeCode ?>"<?php if ($_typeCode == $_ccType): ?> selected="selected"<?php endif ?>><?php echo $_typeName ?></option>
+                    <?php endforeach ?>
+                </select>
+            </div>
+        </div>
+
+        <div class="field required number">
+            <label for="<?php echo $code ?>_cc_number" class="label"><span><?php echo __('Credit Card Number') ?></span></label>
+            <div class="control">
+                <input type="number" id="<?php echo $code ?>_cc_number" data-container="<?php echo $code ?>-cc-number" name="payment[cc_number]" title="<?php echo __('Credit Card Number') ?>" class="input-text" value="" data-validate='{"required-number":true, "validate-cc-number":"#<?php echo $code ?>_cc_type", "validate-cc-type":"#<?php echo $code ?>_cc_type"}' autocomplete="off"/>
+            </div>
+        </div>
+
+        <div class="field required date" id="<?php echo $code ?>_cc_type_exp_div">
+            <label for="<?php echo $code ?>_expiration" class="label"><span><?php echo __('Expiration Date') ?></span></label>
+            <div class="control">
+                <div class="fields group group-2">
+                    <div class="field no-label month">
+                        <div class="control">
+                            <select id="<?php echo $code ?>_expiration" name="payment[cc_exp_month]" data-container="<?php echo $code ?>-cc-month" class="month" data-validate='{required:true, "validate-cc-exp":"#<?php echo $code ?>_expiration_yr"}'>
+                                <?php $_ccExpMonth = $block->getInfoData('cc_exp_month') ?>
+                                <?php foreach ($block->getCcMonths() as $k => $v): ?>
+                                    <option value="<?php echo $k ? $k : '' ?>"<?php if ($k == $_ccExpMonth): ?> selected="selected"<?php endif ?>><?php echo $v ?></option>
+                                <?php endforeach ?>
+                            </select>
+                        </div>
+                    </div>
+                    <div class="field no-label year">
+                        <div class="control">
+                            <?php $_ccExpYear = $block->getInfoData('cc_exp_year') ?>
+                            <select id="<?php echo $code ?>_expiration_yr" name="payment[cc_exp_year]" class="year" data-container="<?php echo $code ?>-cc-year" data-validate='{required:true}'>
+                                <?php foreach ($block->getCcYears() as $k => $v): ?>
+                                    <option value="<?php echo $k ? $k : '' ?>"<?php if ($k == $_ccExpYear): ?> selected="selected"<?php endif ?>><?php echo $v ?></option>
+                                <?php endforeach ?>
+                            </select>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <?php if ($block->hasVerification()): ?>
+            <div class="field required cvv" id="<?php echo $code ?>_cc_type_cvv_div">
+                <label for="<?php echo $code ?>_cc_cid" class="label"><span><?php echo __('Card Verification Number') ?></span></label>
+                <div class="control">
+                    <input type="number" title="<?php echo __('Card Verification Number') ?>" data-container="<?php echo $code ?>-cc-cvv" class="input-text cvv" id="<?php echo $code ?>_cc_cid" name="payment[cc_cid]" value="" data-validate='{"required-number":true, "validate-cc-cvn":"#<?php echo $code ?>_cc_type"}' autocomplete="off"/>
+                </div>
+            </div>
+        <?php endif; ?>
+        <?php echo $block->getChildHtml() ?>
+</div>
+
+<script>
+    /**
+     * Disable card server validation in admin
+     */
+    require(["Magento_Sales/order/create/form"], function(){
+        order.addExcludedPaymentMethod('<?php echo $code ?>');
+    });
+</script>
diff --git a/app/code/Magento/Payment/view/adminhtml/templates/transparent/iframe.phtml b/app/code/Magento/Payment/view/adminhtml/templates/transparent/iframe.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..943767e9b80556510bc3d2aa637da38fa9a5ea44
--- /dev/null
+++ b/app/code/Magento/Payment/view/adminhtml/templates/transparent/iframe.phtml
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+$params = $block->getParams();
+
+?>
+<html>
+<head>
+<script>
+<?php if (isset($params['redirect'])): ?>
+    window.location="<?php echo $block->escapeUrl($params['redirect']) ?>";
+<?php elseif (isset($params['redirect_parent'])): ?>
+    window.top.location="<?php echo $block->escapeUrl($params['redirect_parent']) ?>";
+<?php elseif (isset($params['error_msg'])): ?>
+    window.top.alert(<?php echo $block->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($params['error_msg']) ?>);
+<?php elseif (isset($params['order_success'])): ?>
+    window.top.location = "<?php echo $params['order_success'] ?>";
+<?php else: ?>
+    var require = window.top.require;
+    require(['jquery'], function($) {
+        $('#edit_form').trigger('processStop');
+
+        $("input[name='payment[cc_number]']").prop('disabled', true);
+        $("select[name='payment[cc_type]']").prop('disabled', true);
+        $("select[name='payment[cc_exp_month]']").prop('disabled', true);
+        $("select[name='payment[cc_exp_year]']").prop('disabled', true);
+        $("input[name='payment[cc_cid]']").prop('disabled', true);
+
+        $('#edit_form').trigger('realOrder');
+    });
+<?php endif; ?>
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/app/code/Magento/Payment/view/adminhtml/templates/transparent/info.phtml b/app/code/Magento/Payment/view/adminhtml/templates/transparent/info.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..badfd92d13a478cb0c409eccb4f9f3af9210e150
--- /dev/null
+++ b/app/code/Magento/Payment/view/adminhtml/templates/transparent/info.phtml
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/**
+ * @see \Magento\Payment\Block\Transparent\Info
+ */
+?>
+<fieldset id="payment_form_<?php echo $block->getMethodCode() ?>" style="display:none" class="fieldset items redirect">
+    <div><?php echo __('You\'ll be asked for your payment details before placing an order.') ?></div>
+</fieldset>
diff --git a/app/code/Magento/Payment/view/adminhtml/web/transparent.js b/app/code/Magento/Payment/view/adminhtml/web/transparent.js
new file mode 100644
index 0000000000000000000000000000000000000000..1317880d7f062c08ebe1c1fee96be951796b1a53
--- /dev/null
+++ b/app/code/Magento/Payment/view/adminhtml/web/transparent.js
@@ -0,0 +1,165 @@
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    "jquery",
+    "mage/template",
+    "jquery/ui"
+], function($, mageTemplate){
+    "use strict";
+
+    $.widget('mage.transparent', {
+        options: {
+            hiddenFormTmpl:
+                '<form target="<%= data.target %>" action="<%= data.action %>" method="POST" hidden enctype="application/x-www-form-urlencoded" class="no-display">' +
+                    '<% _.each(data.inputs, function(val, key){ %>' +
+                    '<input value="<%= val %>" name="<%= key %>" type="hidden">' +
+                    '<% }); %>' +
+                '</form>',
+            cgiUrl: null,
+            orderSaveUrl: null,
+            controller: null,
+            gateway: null,
+            dateDelim: null,
+            cardFieldsMap: null
+        },
+
+        _create: function() {
+            var prepare = function (event, method) {
+                if (method === this.options.gateway) {
+                    $('#edit_form')
+                        .off('submitOrder')
+                        .on('submitOrder', this._orderSave.bind(this))
+                }
+            };
+            this.hiddenFormTmpl = mageTemplate(this.options.hiddenFormTmpl);
+            jQuery('#edit_form').on('changePaymentMethod', prepare.bind(this));
+
+            jQuery('#edit_form').trigger(
+                'changePaymentMethod',
+                [
+                    jQuery('#edit_form').find(':radio[name="payment[method]"]:checked').val()
+                ]
+            );
+        },
+
+        /**
+         * handler for Place Order button to call gateway for credit card validation
+         * Save order and generate post data for gateway call
+         * @private
+         */
+        _orderSave: function() {
+            var postData = "form_key="+FORM_KEY;
+            $.ajax({
+                url: this.options.orderSaveUrl,
+                type: 'post',
+                context: this,
+                data: postData,
+                dataType: 'json',
+                success: function(response) {
+                    if (response.success && response[this.options.gateway]) {
+                        this._postPaymentToGateway(response);
+                    } else {
+                        this._processErrors(response);
+                    }
+                }
+            });
+        },
+
+        /**
+         * Post data to gateway for credit card validation
+         * @param response
+         * @private
+         */
+        _postPaymentToGateway: function(response) {
+            var data,
+                tmpl,
+                iframe;
+
+            data = this._preparePaymentData(response);
+            var iframeSelector = '[data-container="' + this.options.gateway + '-transparent-iframe"]';
+
+            tmpl = this.hiddenFormTmpl({
+                data: {
+                    target: $(iframeSelector).attr('name'),
+                    action: this.options.cgiUrl,
+                    inputs: data
+                }
+            });
+
+            iframe = $(iframeSelector)
+                .on('submit', function(event){
+                    event.stopPropagation();
+                });
+            $(tmpl).appendTo(iframe).submit();
+            iframe.html('');
+        },
+
+        /**
+         * Add credit card fields to post data for gateway
+         *
+         * @param response
+         * @private
+         */
+        _preparePaymentData: function(response) {
+            var ccfields,
+                data,
+                preparedata;
+
+            data = response[this.options.gateway].fields;
+            ccfields = this.options.cardFieldsMap;
+
+            if (this.element.find('[data-container="' + this.options.gateway + '-cc-cvv"]').length) {
+                data[ccfields.cccvv] = this.element.find(
+                    '[data-container="' + this.options.gateway + '-cc-cvv"]'
+                ).val();
+            }
+            preparedata = this._prepareExpDate();
+            data[ccfields.ccexpdate] = preparedata.month + this.options.dateDelim + preparedata.year;
+            data[ccfields.ccnum] = this.element.find(
+                '[data-container="' + this.options.gateway + '-cc-number"]'
+            ).val();
+            return data;
+        },
+
+        /**
+         * Grab Month and Year into one
+         * @returns {object}
+         * @private
+         */
+        _prepareExpDate: function() {
+            var year = this.element.find('[data-container="' + this.options.gateway + '-cc-year"]').val(),
+                month = parseInt(
+                    this.element.find('[data-container="' + this.options.gateway + '-cc-month"]').val()
+                    , 10
+                );
+            if (year.length > 2) {
+                year = year.substring(2);
+            }
+            if (month < 10) {
+                month = '0' + month;
+            }
+            return {month: month, year: year};
+        },
+
+        /**
+         * Processing errors
+         *
+         * @param response
+         * @private
+         */
+        _processErrors: function (response) {
+            var msg = response.error_messages;
+            if (typeof (msg) === 'object') {
+                alert(msg.join("\n"));
+            }
+            if (msg) {
+                alert(msg);
+            }
+        }
+    });
+
+    return $.mage.transparent;
+});
diff --git a/app/code/Magento/Payment/view/frontend/layout/checkout_onepage_review.xml b/app/code/Magento/Payment/view/frontend/layout/checkout_onepage_review.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8bdab785e571d24a7092c52b5ac420fe697dc1d5
--- /dev/null
+++ b/app/code/Magento/Payment/view/frontend/layout/checkout_onepage_review.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+-->
+<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_configuration.xsd">
+    <body>
+        <referenceContainer name="checkout.onepage.review.info.items.after">
+            <block class="Magento\Payment\Block\Transparent\Form" name="payment.form.transparent">
+                <action method="setTemplate">
+                    <argument name="template" xsi:type="string">Magento_Payment::transparent/form.phtml</argument>
+                </action>
+            </block>
+        </referenceContainer>
+    </body>
+</page>
diff --git a/app/code/Magento/Payment/view/frontend/templates/transparent/form.phtml b/app/code/Magento/Payment/view/frontend/templates/transparent/form.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..5a4e8c63822a4ba2097d266cfd99232c67378ba6
--- /dev/null
+++ b/app/code/Magento/Payment/view/frontend/templates/transparent/form.phtml
@@ -0,0 +1,86 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+/** @var \Magento\Payment\Block\Transparent\Form $block */
+$code = $block->getMethodCode();
+?>
+
+<!-- IFRAME for request to Payment Gateway -->
+<iframe width="0" height="0" id="<?php echo $code ?>-transparent-iframe" data-container="<?php echo $code ?>-transparent-iframe" allowtransparency="true" frameborder="0"  name="iframeTransparent" style="display:none;width:100%;background-color:transparent" src="<?php echo $block->getViewFileUrl('blank.html') ?>"></iframe>
+<form class="form" id="co-transparent-form" action="#" method="post" data-mage-init='{
+    "transparent":{
+        "controller":"<?php echo $block->getRequest()->getControllerName() ?>",
+        "gateway":"<?php echo $code ?>",
+        "orderSaveUrl":"<?php echo $block->getOrderUrl() ?>",
+        "cgiUrl":"<?php echo $block->getCgiUrl() ?>",
+        "dateDelim":"<?php echo $block->getDateDelim() ?>",
+        "cardFieldsMap":<?php echo $block->getCardFieldsMap() ?>,
+        "nativeAction":"<?php echo $block->getUrl('checkout/onepage/saveOrder', ['_secure' => $block->getRequest()->isSecure()]) ?>"
+    }, "validation":[]}'>
+    <fieldset class="fieldset ccard <?php echo $code ?>" id="payment_form_<?php echo $code ?>">
+        <legend class="legend"><span><?php echo __('Credit Card Information') ?></span></legend><br />
+        <div class="field required type">
+            <label for="<?php echo $code ?>_cc_type" class="label"><span><?php echo __('Credit Card Type') ?></span></label>
+            <div class="control">
+                <select id="<?php echo $code ?>_cc_type" data-container="<?php echo $code ?>-cc-type" name="payment[cc_type]" data-validate='{required:true, "validate-cc-type-select":"#<?php echo $code ?>_cc_number"}'>
+                    <option value=""><?php echo __('--Please Select--')?></option>
+                <?php $_ccType = $block->getInfoData('cc_type') ?>
+                <?php foreach ($block->getCcAvailableTypes() as $_typeCode => $_typeName): ?>
+                    <option value="<?php echo $_typeCode ?>"<?php if ($_typeCode == $_ccType): ?> selected="selected"<?php endif ?>><?php echo $_typeName ?></option>
+                <?php endforeach ?>
+                </select>
+            </div>
+        </div>
+        <div class="field required number">
+            <label for="<?php echo $code ?>_cc_number" class="label"><span><?php echo __('Credit Card Number') ?></span></label>
+            <div class="control">
+                <input type="number" id="<?php echo $code ?>_cc_number" data-container="<?php echo $code ?>-cc-number" name="payment[cc_number]" title="<?php echo __('Credit Card Number') ?>" class="input-text" value="" data-validate='{"required-number":true, "validate-cc-number":"#<?php echo $code ?>_cc_type", "validate-cc-type":"#<?php echo $code ?>_cc_type"}' autocomplete="off"/>
+            </div>
+        </div>
+        <div class="field required date" id="<?php echo $code ?>_cc_type_exp_div">
+            <label for="<?php echo $code ?>_expiration" class="label"><span><?php echo __('Expiration Date') ?></span></label>
+            <div class="control">
+                <div class="fields group group-2">
+                    <div class="field no-label month">
+                        <div class="control">
+                            <select id="<?php echo $code ?>_expiration" name="payment[cc_exp_month]" data-container="<?php echo $code ?>-cc-month" class="month" data-validate='{required:true, "validate-cc-exp":"#<?php echo $code ?>_expiration_yr"}'>
+                            <?php $ccExpMonth = $block->getInfoData('cc_exp_month') ?>
+                            <?php foreach ($block->getCcMonths() as $k => $v): ?>
+                                <option value="<?php echo $k ? $k : '' ?>"<?php if ($k == $ccExpMonth): ?> selected="selected"<?php endif ?>><?php echo $v ?></option>
+                            <?php endforeach ?>
+                            </select>
+                        </div>
+                    </div>
+                    <div class="field no-label year">
+                        <div class="control">
+                            <select id="<?php echo $code ?>_expiration_yr" name="payment[cc_exp_year]" class="year" data-container="<?php echo $code ?>-cc-year" data-validate='{required:true}'>
+                            <?php $ccExpYear = $block->getInfoData('cc_exp_year') ?>
+                            <?php foreach ($block->getCcYears() as $k => $v): ?>
+                                <option value="<?php echo $k ? $k : '' ?>"<?php if ($k == $ccExpYear): ?> selected="selected"<?php endif ?>><?php echo $v ?></option>
+                            <?php endforeach ?>
+                            </select>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+        <?php if ($block->hasVerification()): ?>
+        <div class="field required cvv" id="<?php echo $code ?>_cc_type_cvv_div">
+            <label for="<?php echo $code ?>_cc_cid" class="label"><span><?php echo __('Card Verification Number') ?></span></label>
+            <div class="control">
+                <input type="number" title="<?php echo __('Card Verification Number') ?>" data-container="<?php echo $code ?>-cc-cvv" class="input-text cvv" id="<?php echo $code ?>_cc_cid" name="payment[cc_cid]" value="" data-validate='{"required-number":true, "validate-cc-cvn":"#<?php echo $code ?>_cc_type"}' autocomplete="off"/>
+                <?php $_content = '<img src=\"' . $block->getViewFileUrl('Magento_Checkout::cvv.png') . '\" alt=\"' . __('Card Verification Number Visual Reference') . '\" title=\"' . __('Card Verification Number Visual Reference') . '\" />'; ?>
+                <div class="note">
+                    <a href="#" id="<?php echo $code ?>-cvv-what-is-this" class="action cvv" title="<?php echo $block->escapeHtml(__('What is this?'));?>" data-mage-init='{"tooltip": {"content": "<?php echo $_content ?>"}}'><span><?php echo __('What is this?') ?></span></a>
+                </div>
+            </div>
+        </div>
+        <?php endif; ?>
+    <?php echo $block->getChildHtml() ?>
+</fieldset>
+</form>
diff --git a/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..d090920cb02945f4d00f34b66d6c65355e084007
--- /dev/null
+++ b/app/code/Magento/Payment/view/frontend/templates/transparent/iframe.phtml
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+// @codingStandardsIgnoreFile
+
+/** @var \Magento\Payment\Block\Transparent\Iframe $block */
+$params = $block->getParams();
+?>
+<html>
+    <head>
+        <script>
+        <?php if (isset($params['redirect'])): ?>
+            window.location="<?php echo $block->escapeUrl($params['redirect']) ?>";
+        <?php elseif (isset($params['redirect_parent'])): ?>
+            window.top.location="<?php echo $block->escapeUrl($params['redirect_parent']) ?>";
+        <?php elseif (isset($params['error_msg'])): ?>
+            window.top.alert(<?php echo $this->helper('Magento\Framework\Json\Helper\Data')->jsonEncode($params['error_msg']) ?>);
+        <?php elseif (isset($params['order_success'])): ?>
+            window.top.location = "<?php echo $params['order_success'] ?>";
+        <?php else: ?>
+            var require = window.top.require;
+            require(['jquery'], function($) {
+                $('#opc-review').trigger('hideAjaxLoader');
+                $('#opc-review').trigger('saveOrder');
+            });
+        <?php endif; ?>
+        </script>
+    </head>
+    <body></body>
+</html>
diff --git a/app/code/Magento/Payment/view/frontend/templates/transparent/info.phtml b/app/code/Magento/Payment/view/frontend/templates/transparent/info.phtml
new file mode 100644
index 0000000000000000000000000000000000000000..badfd92d13a478cb0c409eccb4f9f3af9210e150
--- /dev/null
+++ b/app/code/Magento/Payment/view/frontend/templates/transparent/info.phtml
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/**
+ * @see \Magento\Payment\Block\Transparent\Info
+ */
+?>
+<fieldset id="payment_form_<?php echo $block->getMethodCode() ?>" style="display:none" class="fieldset items redirect">
+    <div><?php echo __('You\'ll be asked for your payment details before placing an order.') ?></div>
+</fieldset>
diff --git a/app/code/Magento/Payment/view/frontend/web/transparent.js b/app/code/Magento/Payment/view/frontend/web/transparent.js
new file mode 100644
index 0000000000000000000000000000000000000000..570772d6d430c67d6dcd4ea10325fade6d3407b0
--- /dev/null
+++ b/app/code/Magento/Payment/view/frontend/web/transparent.js
@@ -0,0 +1,154 @@
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+define([
+    "jquery",
+    "mage/template",
+    "jquery/ui"
+], function($, mageTemplate){
+    "use strict";
+
+    $.widget('mage.transparent', {
+        options: {
+            placeOrderSelector: '[data-role="review-save"]',
+            paymentFormSelector: '#co-payment-form',
+            updateSelectorPrefix: '#checkout-',
+            updateSelectorSuffix: '-load',
+            hiddenFormTmpl:
+                '<form target="<%= data.target %>" action="<%= data.action %>" method="POST" hidden enctype="application/x-www-form-urlencoded" class="no-display">' +
+                    '<% _.each(data.inputs, function(val, key){ %>' +
+                    '<input value="<%= val %>" name="<%= key %>" type="hidden">' +
+                    '<% }); %>' +
+                '</form>',
+            reviewAgreementForm: '#checkout-agreements',
+            cgiUrl: null,
+            orderSaveUrl: null,
+            controller: null,
+            gateway: null,
+            dateDelim: null,
+            cardFieldsMap: null
+        },
+
+        _create: function() {
+            this.hiddenFormTmpl = mageTemplate(this.options.hiddenFormTmpl);
+            $(this.options.placeOrderSelector)
+                .off('click')
+                .on('click', $.proxy(this._placeOrderHandler, this));
+        },
+
+        /**
+         * handler for Place Order button to call gateway for credit card validation
+         * @return {Boolean}
+         * @private
+         */
+        _placeOrderHandler: function() {
+            if (this.element.validation && this.element.validation('isValid')) {
+                this._orderSave();
+            }
+            return false;
+        },
+
+        /**
+         * Save order and generate post data for gateway call
+         * @private
+         */
+        _orderSave: function() {
+            var postData = $(this.options.paymentFormSelector).serialize();
+            if ($(this.options.reviewAgreementForm).length) {
+                postData += '&' + $(this.options.reviewAgreementForm).serialize();
+            }
+            postData += '&controller=' + this.options.controller;
+            $.ajax({
+                url: this.options.orderSaveUrl,
+                type: 'post',
+                context: this,
+                data: postData,
+                dataType: 'json',
+                beforeSend: function() {this.element.trigger('showAjaxLoader');},
+                success: function(response) {
+                    var preparedData,
+                        msg;
+                    if (response.success && response[this.options.gateway]) {
+                        preparedData = this._preparePaymentData(
+                            response[this.options.gateway].fields,
+                            this.options.cardFieldsMap
+                        );
+                        this._postPaymentToGateway(preparedData);
+                    } else {
+                        msg = response.error_messages;
+                        if (typeof (msg) === 'object') {
+                            alert(msg.join("\n"));
+                        }
+                        if (msg) {
+                            alert(msg);
+                        }
+                    }
+                }
+            });
+        },
+
+        /**
+         * Post data to gateway for credit card validation
+         * @param data
+         * @private
+         */
+        _postPaymentToGateway: function(data) {
+            var tmpl;
+            var iframeSelector = '[data-container="' + this.options.gateway + '-transparent-iframe"]';
+
+            tmpl = this.hiddenFormTmpl({
+                data: {
+                    target: $(iframeSelector).attr('name'),
+                    action: this.options.cgiUrl,
+                    inputs: data
+                }
+            });
+
+            $(tmpl).appendTo($(iframeSelector)).submit();
+        },
+
+        /**
+         * Add credit card fields to post data for gateway
+         * @param data
+         * @param ccfields
+         * @private
+         */
+        _preparePaymentData: function(data, ccfields) {
+            if (this.element.find('[data-container="' + this.options.gateway + '-cc-cvv"]').length) {
+                data[ccfields.cccvv] = this.element.find(
+                    '[data-container="' + this.options.gateway + '-cc-cvv"]'
+                ).val();
+            }
+            var preparedata = this._prepareExpDate();
+            data[ccfields.ccexpdate] = preparedata.month + this.options.dateDelim + preparedata.year;
+            data[ccfields.ccnum] = this.element.find(
+                '[data-container="' + this.options.gateway + '-cc-number"]'
+            ).val();
+            return data;
+        },
+
+        /**
+         * Grab Month and Year into one
+         * @returns {object}
+         * @private
+         */
+        _prepareExpDate: function() {
+            var year = this.element.find('[data-container="' + this.options.gateway + '-cc-year"]').val(),
+                month = parseInt(
+                    this.element.find('[data-container="' + this.options.gateway + '-cc-month"]').val(),
+                    10
+                );
+            if (year.length > 2) {
+                year = year.substring(2);
+            }
+            if (month < 10) {
+                month = '0' + month;
+            }
+            return {month: month, year: year};
+        }
+    });
+
+    return $.mage.transparent;
+});
diff --git a/app/code/Magento/Quote/Model/PaymentMethodManagement.php b/app/code/Magento/Quote/Model/PaymentMethodManagement.php
index fa4add6be7b7ec66b9872c55d1f1f1983ea1c475..b3a512ae1b9330585b778670e4bd647a556e4210 100644
--- a/app/code/Magento/Quote/Model/PaymentMethodManagement.php
+++ b/app/code/Magento/Quote/Model/PaymentMethodManagement.php
@@ -7,10 +7,13 @@ namespace Magento\Quote\Model;
 
 use Magento\Framework\Exception\State\InvalidTransitionException;
 
+/**
+ * Class PaymentMethodManagement
+ */
 class PaymentMethodManagement implements \Magento\Quote\Api\PaymentMethodManagementInterface
 {
     /**
-     * @var \Magento\Quote\Model\QuoteRepository
+     * @var \Magento\Quote\Api\CartRepositoryInterface
      */
     protected $quoteRepository;
 
@@ -25,12 +28,14 @@ class PaymentMethodManagement implements \Magento\Quote\Api\PaymentMethodManagem
     protected $methodList;
 
     /**
-     * @param QuoteRepository $quoteRepository
+     * Constructor
+     *
+     * @param \Magento\Quote\Api\CartRepositoryInterface $quoteRepository
      * @param \Magento\Payment\Model\Checks\ZeroTotal $zeroTotalValidator
      * @param \Magento\Payment\Model\MethodList $methodList
      */
     public function __construct(
-        \Magento\Quote\Model\QuoteRepository $quoteRepository,
+        \Magento\Quote\Api\CartRepositoryInterface $quoteRepository,
         \Magento\Payment\Model\Checks\ZeroTotal $zeroTotalValidator,
         \Magento\Payment\Model\MethodList $methodList
     ) {
@@ -45,7 +50,7 @@ class PaymentMethodManagement implements \Magento\Quote\Api\PaymentMethodManagem
     public function set($cartId, \Magento\Quote\Api\Data\PaymentInterface $method)
     {
         /** @var \Magento\Quote\Model\Quote $quote */
-        $quote = $this->quoteRepository->getActive($cartId);
+        $quote = $this->quoteRepository->get($cartId);
 
         $method->setChecks([
             \Magento\Payment\Model\Method\AbstractMethod::CHECK_USE_CHECKOUT,
@@ -87,7 +92,7 @@ class PaymentMethodManagement implements \Magento\Quote\Api\PaymentMethodManagem
     public function get($cartId)
     {
         /** @var \Magento\Quote\Model\Quote $quote */
-        $quote = $this->quoteRepository->getActive($cartId);
+        $quote = $this->quoteRepository->get($cartId);
         $payment = $quote->getPayment();
         if (!$payment->getId()) {
             return null;
@@ -101,7 +106,7 @@ class PaymentMethodManagement implements \Magento\Quote\Api\PaymentMethodManagem
     public function getList($cartId)
     {
         /** @var \Magento\Quote\Model\Quote $quote */
-        $quote = $this->quoteRepository->getActive($cartId);
+        $quote = $this->quoteRepository->get($cartId);
         return $this->methodList->getAvailableMethods($quote);
     }
 }
diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php
index 88010642002f69ba6d36ff56c882fd2f96076ccd..377ba1d34f937857dc446288129b6cb389284e1d 100644
--- a/app/code/Magento/Quote/Model/Quote.php
+++ b/app/code/Magento/Quote/Model/Quote.php
@@ -11,6 +11,7 @@ namespace Magento\Quote\Model;
 use Magento\Customer\Api\Data\CustomerInterface;
 use Magento\Customer\Api\Data\GroupInterface;
 use Magento\Framework\Model\AbstractExtensibleModel;
+use Magento\Quote\Api\Data\PaymentInterface;
 use Magento\Quote\Model\Quote\Address;
 use Magento\Sales\Model\Resource;
 use Magento\Sales\Model\Status;
@@ -1857,10 +1858,12 @@ class Quote extends AbstractExtensibleModel implements \Magento\Quote\Api\Data\C
     }
 
     /**
-     * @param \Magento\Quote\Model\Quote\Payment $payment
+     * Adds a payment to quote
+     *
+     * @param PaymentInterface $payment
      * @return $this
      */
-    public function addPayment(\Magento\Quote\Model\Quote\Payment $payment)
+    public function addPayment(PaymentInterface $payment)
     {
         $payment->setQuote($this);
         if (!$payment->getId()) {
@@ -1870,10 +1873,12 @@ class Quote extends AbstractExtensibleModel implements \Magento\Quote\Api\Data\C
     }
 
     /**
-     * @param \Magento\Quote\Model\Quote\Payment $payment
-     * @return \Magento\Quote\Model\Quote\Payment
+     * Sets payment to current quote
+     *
+     * @param PaymentInterface $payment
+     * @return PaymentInterface
      */
-    public function setPayment(\Magento\Quote\Model\Quote\Payment $payment)
+    public function setPayment(PaymentInterface $payment)
     {
         if (!$this->getIsMultiPayment() && ($old = $this->getPayment())) {
             $payment->setId($old->getId());
diff --git a/app/code/Magento/Quote/Model/Quote/Payment/ToOrderPayment.php b/app/code/Magento/Quote/Model/Quote/Payment/ToOrderPayment.php
index 9e34d40fdb342ab5ede3cd784d687250c89c41fe..a65e71d224697d8d38abad335a3ba3354482a6c4 100644
--- a/app/code/Magento/Quote/Model/Quote/Payment/ToOrderPayment.php
+++ b/app/code/Magento/Quote/Model/Quote/Payment/ToOrderPayment.php
@@ -67,11 +67,9 @@ class ToOrderPayment
             '\Magento\Sales\Api\Data\OrderPaymentInterface'
         );
         $orderPayment->setAdditionalInformation(
-            serialize(
-                array_merge(
-                    $object->getAdditionalInformation(),
-                    [Substitution::INFO_KEY_TITLE => $object->getMethodInstance()->getTitle()]
-                )
+            array_merge(
+                $object->getAdditionalInformation(),
+                [Substitution::INFO_KEY_TITLE => $object->getMethodInstance()->getTitle()]
             )
         );
         // set directly on the model
diff --git a/app/code/Magento/Quote/Test/Unit/Model/PaymentMethodManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/PaymentMethodManagementTest.php
index 70dd9e5238ad2e7427574c95c5f39ed533dea5a4..78751a96441cc1cf17f18f01eb3d41fe2fc2f252 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/PaymentMethodManagementTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/PaymentMethodManagementTest.php
@@ -34,12 +34,20 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
     protected function setUp()
     {
         $this->objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->quoteRepositoryMock = $this->getMock('\Magento\Quote\Model\QuoteRepository', [], [], '', false);
-        $this->methodListMock = $this->getMock('\Magento\Payment\Model\MethodList', [], [], '', false);
-        $this->zeroTotalMock = $this->getMock('\Magento\Payment\Model\Checks\ZeroTotal', [], [], '', false);
+        $this->quoteRepositoryMock = $this->getMockForAbstractClass(
+            'Magento\Quote\Api\CartRepositoryInterface',
+            [],
+            '',
+            false,
+            true,
+            true,
+            []
+        );
+        $this->methodListMock = $this->getMock('Magento\Payment\Model\MethodList', [], [], '', false);
+        $this->zeroTotalMock = $this->getMock('Magento\Payment\Model\Checks\ZeroTotal', [], [], '', false);
 
         $this->model = $this->objectManager->getObject(
-            '\Magento\Quote\Model\PaymentMethodManagement',
+            'Magento\Quote\Model\PaymentMethodManagement',
             [
                 'quoteRepository' => $this->quoteRepositoryMock,
                 'methodList' => $this->methodListMock,
@@ -51,13 +59,13 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
     public function testGetPaymentIfPaymentMethodNotSet()
     {
         $cartId = 11;
-        $quoteMock = $this->getMock('\Magento\Quote\Model\Quote', [], [], '', false);
-        $paymentMock = $this->getMock('\Magento\Quote\Model\Quote\Payment', [], [], '', false);
+        $quoteMock = $this->getMock('Magento\Quote\Model\Quote', [], [], '', false);
+        $paymentMock = $this->getMock('Magento\Quote\Model\Quote\Payment', [], [], '', false);
         $quoteMock->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock));
         $paymentMock->expects($this->once())->method('getId')->will($this->returnValue(null));
 
         $this->quoteRepositoryMock->expects($this->once())
-            ->method('getActive')
+            ->method('get')
             ->with($cartId)
             ->will($this->returnValue($quoteMock));
 
@@ -68,14 +76,14 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
     {
         $cartId = 11;
 
-        $paymentMock = $this->getMock('\Magento\Quote\Model\Quote\Payment', [], [], '', false);
+        $paymentMock = $this->getMock('Magento\Quote\Model\Quote\Payment', [], [], '', false);
         $paymentMock->expects($this->once())->method('getId')->will($this->returnValue(1));
 
-        $quoteMock = $this->getMock('\Magento\Quote\Model\Quote', [], [], '', false);
+        $quoteMock = $this->getMock('Magento\Quote\Model\Quote', [], [], '', false);
         $quoteMock->expects($this->once())->method('getPayment')->will($this->returnValue($paymentMock));
 
         $this->quoteRepositoryMock->expects($this->once())
-            ->method('getActive')
+            ->method('get')
             ->with($cartId)
             ->will($this->returnValue($quoteMock));
         $this->assertEquals($paymentMock, $this->model->get($cartId));
@@ -84,13 +92,13 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
     public function testGetList()
     {
         $cartId = 10;
-        $quoteMock = $this->getMock('\Magento\Quote\Model\Quote', [], [], '', false);
+        $quoteMock = $this->getMock('Magento\Quote\Model\Quote', [], [], '', false);
         $this->quoteRepositoryMock->expects($this->once())
-            ->method('getActive')
+            ->method('get')
             ->with($cartId)
             ->will($this->returnValue($quoteMock));
 
-        $paymentMethod = $this->getMock('\Magento\Quote\Api\Data\PaymentMethodInterface');
+        $paymentMethod = $this->getMock('Magento\Quote\Api\Data\PaymentMethodInterface');
         $this->methodListMock->expects($this->once())
             ->method('getAvailableMethods')
             ->with($quoteMock)
@@ -106,15 +114,15 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $paymentMethod = 'checkmo';
 
         $quoteMock = $this->getMock(
-            '\Magento\Quote\Model\Quote',
+            'Magento\Quote\Model\Quote',
             ['setTotalsCollectedFlag', 'getPayment', 'isVirtual', 'getBillingAddress', 'collectTotals', 'save'],
             [],
             '',
             false
         );
-        $this->quoteRepositoryMock->expects($this->once())->method('getActive')->with($cartId)->willReturn($quoteMock);
+        $this->quoteRepositoryMock->expects($this->once())->method('get')->with($cartId)->willReturn($quoteMock);
 
-        $methodMock = $this->getMock('\Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
+        $methodMock = $this->getMock('Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
         $methodMock->expects($this->once())
             ->method('setChecks')
             ->with([
@@ -127,7 +135,7 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $methodMock->expects($this->once())->method('getData')->willReturn($methodData);
 
         $paymentMock = $this->getMock(
-            '\Magento\Quote\Model\Quote\Payment',
+            'Magento\Quote\Model\Quote\Payment',
             ['importData', 'getMethod', 'getMethodInstance', 'getId'],
             [],
             '',
@@ -137,7 +145,7 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $paymentMock->expects($this->once())->method('getMethod')->willReturn($paymentMethod);
 
         $billingAddressMock = $this->getMock(
-            '\Magento\Quote\Model\Quote\Address',
+            'Magento\Quote\Model\Quote\Address',
             ['getCountryId', 'setPaymentMethod'],
             [],
             '',
@@ -153,7 +161,7 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $quoteMock->expects($this->exactly(2))->method('isVirtual')->willReturn(true);
         $quoteMock->expects($this->exactly(2))->method('getBillingAddress')->willReturn($billingAddressMock);
 
-        $methodInstance = $this->getMock('\Magento\Payment\Model\Checks\PaymentMethodChecksInterface');
+        $methodInstance = $this->getMock('Magento\Payment\Model\Checks\PaymentMethodChecksInterface');
         $paymentMock->expects($this->once())->method('getMethodInstance')->willReturn($methodInstance);
 
         $this->zeroTotalMock->expects($this->once())
@@ -179,15 +187,15 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $methodData = ['method' => 'data'];
 
         $quoteMock = $this->getMock(
-            '\Magento\Quote\Model\Quote',
+            'Magento\Quote\Model\Quote',
             ['getPayment', 'isVirtual', 'getBillingAddress'],
             [],
             '',
             false
         );
-        $this->quoteRepositoryMock->expects($this->once())->method('getActive')->with($cartId)->willReturn($quoteMock);
+        $this->quoteRepositoryMock->expects($this->once())->method('get')->with($cartId)->willReturn($quoteMock);
 
-        $methodMock = $this->getMock('\Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
+        $methodMock = $this->getMock('Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
         $methodMock->expects($this->once())
             ->method('setChecks')
             ->with([
@@ -199,10 +207,10 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
             ->willReturnSelf();
         $methodMock->expects($this->once())->method('getData')->willReturn($methodData);
 
-        $paymentMock = $this->getMock('\Magento\Quote\Model\Quote\Payment', ['importData', 'getMethod'], [], '', false);
+        $paymentMock = $this->getMock('Magento\Quote\Model\Quote\Payment', ['importData', 'getMethod'], [], '', false);
         $paymentMock->expects($this->once())->method('importData')->with($methodData)->willReturnSelf();
 
-        $billingAddressMock = $this->getMock('\Magento\Quote\Model\Quote\Address', ['getCountryId'], [], '', false);
+        $billingAddressMock = $this->getMock('Magento\Quote\Model\Quote\Address', ['getCountryId'], [], '', false);
         $billingAddressMock->expects($this->once())->method('getCountryId')->willReturn(null);
 
         $quoteMock->expects($this->once())->method('getPayment')->willReturn($paymentMock);
@@ -223,15 +231,15 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $paymentMethod = 'checkmo';
 
         $quoteMock = $this->getMock(
-            '\Magento\Quote\Model\Quote',
+            'Magento\Quote\Model\Quote',
             ['getPayment', 'isVirtual', 'getBillingAddress'],
             [],
             '',
             false
         );
-        $this->quoteRepositoryMock->expects($this->once())->method('getActive')->with($cartId)->willReturn($quoteMock);
+        $this->quoteRepositoryMock->expects($this->once())->method('get')->with($cartId)->willReturn($quoteMock);
 
-        $methodMock = $this->getMock('\Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
+        $methodMock = $this->getMock('Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
         $methodMock->expects($this->once())
             ->method('setChecks')
             ->with([
@@ -244,7 +252,7 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $methodMock->expects($this->once())->method('getData')->willReturn($methodData);
 
         $paymentMock = $this->getMock(
-            '\Magento\Quote\Model\Quote\Payment',
+            'Magento\Quote\Model\Quote\Payment',
             ['importData', 'getMethod', 'getMethodInstance'],
             [],
             '',
@@ -254,7 +262,7 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $paymentMock->expects($this->once())->method('getMethod')->willReturn($paymentMethod);
 
         $billingAddressMock = $this->getMock(
-            '\Magento\Quote\Model\Quote\Address',
+            'Magento\Quote\Model\Quote\Address',
             ['getCountryId', 'setPaymentMethod'],
             [],
             '',
@@ -270,7 +278,7 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $quoteMock->expects($this->exactly(2))->method('isVirtual')->willReturn(true);
         $quoteMock->expects($this->exactly(2))->method('getBillingAddress')->willReturn($billingAddressMock);
 
-        $methodInstance = $this->getMock('\Magento\Payment\Model\Checks\PaymentMethodChecksInterface');
+        $methodInstance = $this->getMock('Magento\Payment\Model\Checks\PaymentMethodChecksInterface');
         $paymentMock->expects($this->once())->method('getMethodInstance')->willReturn($methodInstance);
 
         $this->zeroTotalMock->expects($this->once())
@@ -288,15 +296,15 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $paymentMethod = 'checkmo';
 
         $quoteMock = $this->getMock(
-            '\Magento\Quote\Model\Quote',
+            'Magento\Quote\Model\Quote',
             ['getPayment', 'isVirtual', 'getShippingAddress', 'setTotalsCollectedFlag', 'collectTotals', 'save'],
             [],
             '',
             false
         );
-        $this->quoteRepositoryMock->expects($this->once())->method('getActive')->with($cartId)->willReturn($quoteMock);
+        $this->quoteRepositoryMock->expects($this->once())->method('get')->with($cartId)->willReturn($quoteMock);
 
-        $methodMock = $this->getMock('\Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
+        $methodMock = $this->getMock('Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
         $methodMock->expects($this->once())
             ->method('setChecks')
             ->with([
@@ -309,7 +317,7 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $methodMock->expects($this->once())->method('getData')->willReturn($methodData);
 
         $paymentMock = $this->getMock(
-            '\Magento\Quote\Model\Quote\Payment',
+            'Magento\Quote\Model\Quote\Payment',
             ['importData', 'getMethod', 'getMethodInstance', 'getId'],
             [],
             '',
@@ -319,7 +327,7 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $paymentMock->expects($this->once())->method('getMethod')->willReturn($paymentMethod);
 
         $shippingAddressMock = $this->getMock(
-            '\Magento\Quote\Model\Quote\Address',
+            'Magento\Quote\Model\Quote\Address',
             ['getCountryId', 'setPaymentMethod'],
             [],
             '',
@@ -335,7 +343,7 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $quoteMock->expects($this->exactly(2))->method('isVirtual')->willReturn(false);
         $quoteMock->expects($this->exactly(4))->method('getShippingAddress')->willReturn($shippingAddressMock);
 
-        $methodInstance = $this->getMock('\Magento\Payment\Model\Checks\PaymentMethodChecksInterface');
+        $methodInstance = $this->getMock('Magento\Payment\Model\Checks\PaymentMethodChecksInterface');
         $paymentMock->expects($this->once())->method('getMethodInstance')->willReturn($methodInstance);
 
         $this->zeroTotalMock->expects($this->once())
@@ -361,15 +369,15 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
         $methodData = ['method' => 'data'];
 
         $quoteMock = $this->getMock(
-            '\Magento\Quote\Model\Quote',
+            'Magento\Quote\Model\Quote',
             ['getPayment', 'isVirtual', 'getShippingAddress'],
             [],
             '',
             false
         );
-        $this->quoteRepositoryMock->expects($this->once())->method('getActive')->with($cartId)->willReturn($quoteMock);
+        $this->quoteRepositoryMock->expects($this->once())->method('get')->with($cartId)->willReturn($quoteMock);
 
-        $methodMock = $this->getMock('\Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
+        $methodMock = $this->getMock('Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
         $methodMock->expects($this->once())
             ->method('setChecks')
             ->with([
@@ -381,10 +389,10 @@ class PaymentMethodManagementTest extends \PHPUnit_Framework_TestCase
             ->willReturnSelf();
         $methodMock->expects($this->once())->method('getData')->willReturn($methodData);
 
-        $paymentMock = $this->getMock('\Magento\Quote\Model\Quote\Payment', ['importData'], [], '', false);
+        $paymentMock = $this->getMock('Magento\Quote\Model\Quote\Payment', ['importData'], [], '', false);
         $paymentMock->expects($this->once())->method('importData')->with($methodData)->willReturnSelf();
 
-        $shippingAddressMock = $this->getMock('\Magento\Quote\Model\Quote\Address', ['getCountryId'], [], '', false);
+        $shippingAddressMock = $this->getMock('Magento\Quote\Model\Quote\Address', ['getCountryId'], [], '', false);
         $shippingAddressMock->expects($this->once())->method('getCountryId')->willReturn(null);
 
         $quoteMock->expects($this->once())->method('getPayment')->willReturn($paymentMock);
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Payment/ToOrderPaymentTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Payment/ToOrderPaymentTest.php
index b68aeb602acb6cfd7d7d8af9cf45b60595dcd6c6..aa6099192147fe2557b93e465f822f1b30753d57 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Payment/ToOrderPaymentTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Payment/ToOrderPaymentTest.php
@@ -113,7 +113,7 @@ class ToOrderPaymentTest extends \PHPUnit_Framework_TestCase
         );
         $orderPayment->expects($this->once())
             ->method('setAdditionalInformation')
-            ->with(serialize(array_merge($additionalInfo, [Substitution::INFO_KEY_TITLE => $paymentMethodTitle])))
+            ->with(array_merge($additionalInfo, [Substitution::INFO_KEY_TITLE => $paymentMethodTitle]))
             ->willReturnSelf();
         $orderPayment->expects($this->once())
             ->method('setCcNumber')
diff --git a/app/code/Magento/Quote/etc/di.xml b/app/code/Magento/Quote/etc/di.xml
index 4eeb1ff2b61a7e865d24c28af7411c599b7c3f05..0b46fc59fb7dcbead0e93d40563787ce7f6af5b7 100644
--- a/app/code/Magento/Quote/etc/di.xml
+++ b/app/code/Magento/Quote/etc/di.xml
@@ -25,7 +25,6 @@
     <preference for="Magento\Quote\Api\Data\TotalsInterface" type="\Magento\Quote\Model\Cart\Totals" />
     <preference for="Magento\Quote\Api\Data\TotalsItemInterface" type="\Magento\Quote\Model\Quote\Cart\Totals\Item" />
     <preference for="Magento\Quote\Api\Data\CurrencyInterface" type="\Magento\Quote\Model\Cart\Currency" />
-
     <preference for="Magento\Quote\Api\GuestCartManagementInterface" type="Magento\Quote\Model\GuestCart\GuestCartManagement" />
     <preference for="Magento\Quote\Api\GuestCartRepositoryInterface" type="Magento\Quote\Model\GuestCart\GuestCartRepository" />
     <preference for="Magento\Quote\Api\GuestCartItemRepositoryInterface" type="Magento\Quote\Model\GuestCart\GuestCartItemRepository" />
@@ -35,7 +34,6 @@
     <preference for="Magento\Quote\Api\GuestShippingAddressManagementInterface" type="Magento\Quote\Model\GuestCart\GuestShippingAddressManagement" />
     <preference for="Magento\Quote\Api\GuestShippingMethodManagementInterface" type="Magento\Quote\Model\GuestCart\GuestShippingMethodManagement" />
     <preference for="Magento\Quote\Api\GuestBillingAddressManagementInterface" type="Magento\Quote\Model\GuestCart\GuestBillingAddressManagement" />
-
     <type name="Magento\Webapi\Controller\Rest\ParamsOverrider">
         <arguments>
             <argument name="paramOverriders" xsi:type="array">
@@ -43,4 +41,14 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Quote\Model\QuoteRepository">
+        <arguments>
+            <argument name="quoteCollection" xsi:type="object">Magento\Quote\Model\Resource\Quote\Collection\Proxy</argument>
+        </arguments>
+    </type>
+    <type name="Magento\Quote\Model\Quote\Address">
+        <arguments>
+            <argument name="addressConfig" xsi:type="object">Magento\Customer\Model\Address\Config\Proxy</argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Review/Block/Form.php b/app/code/Magento/Review/Block/Form.php
index 9682f444c4100126155f6daa0ecde88b656ce156..cf506a09857d50ca75e60af14307933802b9678b 100644
--- a/app/code/Magento/Review/Block/Form.php
+++ b/app/code/Magento/Review/Block/Form.php
@@ -163,7 +163,11 @@ class Form extends \Magento\Framework\View\Element\Template
      */
     public function getProductInfo()
     {
-        return $this->productRepository->getById($this->getProductId());
+        return $this->productRepository->getById(
+            $this->getProductId(),
+            false,
+            $this->_storeManager->getStore()->getId()
+        );
     }
 
     /**
diff --git a/app/code/Magento/Review/Model/Resource/Review/Collection.php b/app/code/Magento/Review/Model/Resource/Review/Collection.php
index 7bd2de244b7adb3bdff739d5782cb681e832c41b..d32a6b04ac03043b9fc8a2c596ece7d84af58eaf 100644
--- a/app/code/Magento/Review/Model/Resource/Review/Collection.php
+++ b/app/code/Magento/Review/Model/Resource/Review/Collection.php
@@ -17,35 +17,35 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
      *
      * @var string
      */
-    protected $_reviewTable;
+    protected $_reviewTable = null;
 
     /**
      * Review detail table
      *
      * @var string
      */
-    protected $_reviewDetailTable;
+    protected $_reviewDetailTable = null;
 
     /**
      * Review status table
      *
      * @var string
      */
-    protected $_reviewStatusTable;
+    protected $_reviewStatusTable = null;
 
     /**
      * Review entity table
      *
      * @var string
      */
-    protected $_reviewEntityTable;
+    protected $_reviewEntityTable = null;
 
     /**
      * Review store table
      *
      * @var string
      */
-    protected $_reviewStoreTable;
+    protected $_reviewStoreTable = null;
 
     /**
      * Add store data flag
@@ -111,11 +111,6 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
     protected function _construct()
     {
         $this->_init('Magento\Review\Model\Review', 'Magento\Review\Model\Resource\Review');
-        $this->_reviewTable = $this->getTable('review');
-        $this->_reviewDetailTable = $this->getTable('review_detail');
-        $this->_reviewStatusTable = $this->getTable('review_status');
-        $this->_reviewEntityTable = $this->getTable('review_entity');
-        $this->_reviewStoreTable = $this->getTable('review_store');
     }
 
     /**
@@ -127,7 +122,7 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
     {
         parent::_initSelect();
         $this->getSelect()->join(
-            ['detail' => $this->_reviewDetailTable],
+            ['detail' => $this->getReviewDetailTable()],
             'main_table.review_id = detail.review_id',
             ['detail_id', 'title', 'detail', 'nickname', 'customer_id']
         );
@@ -156,7 +151,7 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
     {
         $inCond = $this->getConnection()->prepareSqlCondition('store.store_id', ['in' => $storeId]);
         $this->getSelect()->join(
-            ['store' => $this->_reviewStoreTable],
+            ['store' => $this->getReviewStoreTable()],
             'main_table.review_id=store.review_id',
             []
         );
@@ -184,18 +179,19 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
      */
     public function addEntityFilter($entity, $pkValue)
     {
+        $reviewEntityTable = $this->getReviewEntityTable();
         if (is_numeric($entity)) {
             $this->addFilter('entity', $this->getConnection()->quoteInto('main_table.entity_id=?', $entity), 'string');
         } elseif (is_string($entity)) {
             $this->_select->join(
-                $this->_reviewEntityTable,
-                'main_table.entity_id=' . $this->_reviewEntityTable . '.entity_id',
+                $reviewEntityTable,
+                'main_table.entity_id=' . $reviewEntityTable . '.entity_id',
                 ['entity_code']
             );
 
             $this->addFilter(
                 'entity',
-                $this->getConnection()->quoteInto($this->_reviewEntityTable . '.entity_code=?', $entity),
+                $this->getConnection()->quoteInto($reviewEntityTable . '.entity_code=?', $entity),
                 'string'
             );
         }
@@ -268,7 +264,7 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
     public function addReviewsTotalCount()
     {
         $this->_select->joinLeft(
-            ['r' => $this->_reviewTable],
+            ['r' => $this->getReviewTable()],
             'main_table.entity_pk_value = r.entity_pk_value',
             ['total_reviews' => new \Zend_Db_Expr('COUNT(r.review_id)')]
         )->group(
@@ -311,7 +307,7 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
         $storesToReviews = [];
         if (count($reviewsIds) > 0) {
             $inCond = $adapter->prepareSqlCondition('review_id', ['in' => $reviewsIds]);
-            $select = $adapter->select()->from($this->_reviewStoreTable)->where($inCond);
+            $select = $adapter->select()->from($this->getReviewStoreTable())->where($inCond);
             $result = $adapter->fetchAll($select);
             foreach ($result as $row) {
                 if (!isset($storesToReviews[$row['review_id']])) {
@@ -329,4 +325,69 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
             }
         }
     }
+
+    /**
+     * Get review table
+     *
+     * @return string
+     */
+    protected function getReviewTable()
+    {
+        if ($this->_reviewTable === null) {
+            $this->_reviewTable = $this->getTable('review');
+        }
+        return $this->_reviewTable;
+    }
+
+    /**
+     * Get review detail table
+     *
+     * @return string
+     */
+    protected function getReviewDetailTable()
+    {
+        if ($this->_reviewDetailTable === null) {
+            $this->_reviewDetailTable = $this->getTable('review_detail');
+        }
+        return $this->_reviewDetailTable;
+    }
+
+    /**
+     * Get review status table
+     *
+     * @return string
+     */
+    protected function getReviewStatusTable()
+    {
+        if ($this->_reviewStatusTable === null) {
+            $this->_reviewStatusTable = $this->getTable('review_status');
+        }
+        return $this->_reviewStatusTable;
+    }
+
+    /**
+     * Get review entity table
+     *
+     * @return string
+     */
+    protected function getReviewEntityTable()
+    {
+        if ($this->_reviewEntityTable === null) {
+            $this->_reviewEntityTable = $this->getTable('review_entity');
+        }
+        return $this->_reviewEntityTable;
+    }
+
+    /**
+     * Get review store table
+     *
+     * @return string
+     */
+    protected function getReviewStoreTable()
+    {
+        if ($this->_reviewStoreTable === null) {
+            $this->_reviewStoreTable = $this->getTable('review_store');
+        }
+        return $this->_reviewStoreTable;
+    }
 }
diff --git a/app/code/Magento/Review/Test/Unit/Block/FormTest.php b/app/code/Magento/Review/Test/Unit/Block/FormTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..32a59cf8334c59766d49955916821c587a1bb32f
--- /dev/null
+++ b/app/code/Magento/Review/Test/Unit/Block/FormTest.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Review\Test\Unit\Block;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+
+class FormTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var \Magento\Review\Block\Form */
+    protected $object;
+
+    /** @var ObjectManagerHelper */
+    protected $objectManagerHelper;
+
+    /**
+     * @var \Magento\Framework\App\RequestInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $requestMock;
+
+    /** @var \Magento\Framework\View\Element\Template\Context|\PHPUnit_Framework_MockObject_MockObject */
+    protected $context;
+
+    /**
+     * @var \Magento\Review\Helper\Data|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $reviewDataMock;
+
+    /** @var \Magento\Catalog\Api\ProductRepositoryInterface|\PHPUnit_Framework_MockObject_MockObject */
+    protected $productRepository;
+
+    /** @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject */
+    protected $storeManager;
+
+    protected function setUp()
+    {
+        $this->storeManager = $this->getMock('\Magento\Store\Model\StoreManagerInterface');
+        $this->requestMock = $this->getMock('\Magento\Framework\App\RequestInterface');
+        $this->reviewDataMock = $this->getMockBuilder('\Magento\Review\Helper\Data')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->reviewDataMock->expects($this->once())
+            ->method('getIsGuestAllowToWrite')
+            ->willReturn(true);
+
+        $this->context = $this->getMock('Magento\Framework\View\Element\Template\Context', [], [], '', false);
+        $this->context->expects(
+            $this->any()
+        )->method(
+            'getStoreManager'
+        )->will(
+            $this->returnValue($this->storeManager)
+        );
+        $this->context->expects($this->any())
+            ->method('getRequest')
+            ->willReturn($this->requestMock);
+        $this->productRepository = $this->getMock('\Magento\Catalog\Api\ProductRepositoryInterface');
+
+        $this->objectManagerHelper = new ObjectManagerHelper($this);
+        $this->object = $this->objectManagerHelper->getObject(
+            'Magento\Review\Block\Form',
+            [
+                'context' => $this->context,
+                'reviewData' => $this->reviewDataMock,
+                'productRepository' => $this->productRepository,
+            ]
+        );
+    }
+
+    public function testGetProductInfo()
+    {
+        $productId = 3;
+        $storeId = 1;
+
+        $this->storeManager->expects(
+            $this->any()
+        )->method(
+            'getStore'
+        )->will(
+            $this->returnValue(new \Magento\Framework\Object(['id' => $storeId]))
+        );
+
+        $this->requestMock->expects($this->once())
+            ->method('getParam')
+            ->with('id', false)
+            ->willReturn($productId);
+
+        $productMock = $this->getMock('Magento\Catalog\Api\Data\ProductInterface');
+        $this->productRepository->expects($this->once())
+            ->method('getById')
+            ->with($productId, false, $storeId)
+            ->willReturn($productMock);
+
+        $this->assertSame($productMock, $this->object->getProductInfo());
+    }
+}
diff --git a/app/code/Magento/Review/Test/Unit/Model/Resource/Review/CollectionTest.php b/app/code/Magento/Review/Test/Unit/Model/Resource/Review/CollectionTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..67e67cdf8381745aa356f7b85129945f2d563d33
--- /dev/null
+++ b/app/code/Magento/Review/Test/Unit/Model/Resource/Review/CollectionTest.php
@@ -0,0 +1,188 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Review\Test\Unit\Model\Resource\Review;
+
+class CollectionTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Review\Model\Resource\Review\Collection
+     */
+    protected $model;
+
+    /**
+     * @var \Zend_Db_Select | \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $selectMock;
+
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface | \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $storeManagerMock;
+
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\AbstractDb | \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $resourceMock;
+
+    /**
+     * @var \Zend_Db_Adapter_Abstract | \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $readerAdapterMock;
+
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper\ObjectManager
+     */
+    protected $objectManager;
+
+    public function setUp()
+    {
+        $store = $this->getMock('\Magento\Store\Model\Store', ['getId'], [], '', false);
+        $store->expects($this->any())->method('getId')->will($this->returnValue(1));
+        $this->storeManagerMock = $this->getMock('Magento\Store\Model\StoreManagerInterface');
+        $this->storeManagerMock->expects($this->any())->method('getStore')->will($this->returnValue($store));
+        $this->objectManager = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this));
+        $this->resourceMock = $this->getMockBuilder('Magento\Framework\Model\Resource\Db\AbstractDb')
+            ->disableOriginalConstructor()
+            ->setMethods(['getReadConnection', 'getMainTable', 'getTable'])
+            ->getMockForAbstractClass();
+        $this->readerAdapterMock = $this->getMockBuilder('\Zend_Db_Adapter_Abstract')
+            ->disableOriginalConstructor()
+            ->setMethods(['select', 'prepareSqlCondition', 'quoteInto'])
+            ->getMockForAbstractClass();
+        $this->selectMock = $this->getMockBuilder('\Zend_Db_Select')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->readerAdapterMock->expects($this->any())
+            ->method('select')
+            ->willReturn($this->selectMock);
+        $this->resourceMock->expects($this->any())
+            ->method('getReadConnection')
+            ->willReturn($this->readerAdapterMock);
+        $this->resourceMock->expects($this->any())
+            ->method('getMainTable')
+            ->willReturn('maintable');
+        $this->resourceMock->expects($this->any())
+            ->method('getTable')
+            ->willReturnCallback(function ($table) {
+                return $table;
+            });
+        $this->model = $this->objectManager->getObject(
+            '\Magento\Review\Model\Resource\Review\Collection',
+            [
+                'storeManager' => $this->storeManagerMock,
+                'resource' => $this->resourceMock,
+            ]
+        );
+
+    }
+
+    public function testInitSelect()
+    {
+        $this->selectMock->expects($this->once())
+            ->method('join')
+            ->with(
+                ['detail' => 'review_detail'],
+                'main_table.review_id = detail.review_id',
+                ['detail_id', 'title', 'detail', 'nickname', 'customer_id']
+            );
+        $this->objectManager->getObject(
+            '\Magento\Review\Model\Resource\Review\Collection',
+            [
+                'storeManager' => $this->storeManagerMock,
+                'resource' => $this->resourceMock,
+            ]
+        );
+    }
+
+    public function testAddStoreFilter()
+    {
+        $this->readerAdapterMock->expects($this->once())
+            ->method('prepareSqlCondition');
+        $this->selectMock->expects($this->once())
+            ->method('join')
+            ->with(
+                ['store' => 'review_store'],
+                'main_table.review_id=store.review_id',
+                []
+            );
+        $this->model->addStoreFilter(1);
+    }
+
+    /**
+     * @param int|string $entity
+     * @param int $pkValue
+     * @param string $quoteIntoArguments1
+     * @param string $quoteIntoArguments2
+     * @param string $quoteIntoReturn1
+     * @param string $quoteIntoReturn2
+     * @param int $callNum
+     * @dataProvider addEntityFilterDataProvider
+     */
+    public function testAddEntityFilter(
+        $entity,
+        $pkValue,
+        $quoteIntoArguments1,
+        $quoteIntoArguments2,
+        $quoteIntoReturn1,
+        $quoteIntoReturn2,
+        $callNum
+    ) {
+        $this->readerAdapterMock->expects($this->at(0))
+            ->method('quoteInto')
+            ->with($quoteIntoArguments1[0], $quoteIntoArguments1[1])
+            ->willReturn($quoteIntoReturn1);
+        $this->readerAdapterMock->expects($this->at(1))
+            ->method('quoteInto')
+            ->with($quoteIntoArguments2[0], $quoteIntoArguments2[1])
+            ->willReturn($quoteIntoReturn2);
+        $this->selectMock->expects($this->exactly($callNum))
+            ->method('join')
+            ->with(
+                'review_entity',
+                'main_table.entity_id=' . 'review_entity' . '.entity_id',
+                ['entity_code']
+            );
+        $this->model->addEntityFilter($entity, $pkValue);
+    }
+
+    public function addEntityFilterDataProvider()
+    {
+        return [
+            [
+                1,
+                2,
+                ['main_table.entity_id=?', 1],
+                ['main_table.entity_pk_value=?', 2],
+                'quoteIntoReturn1',
+                'quoteIntoReturn2',
+                0
+            ],
+            [
+                'entity',
+                2,
+                ['review_entity.entity_code=?', 'entity'],
+                ['main_table.entity_pk_value=?', 2],
+                'quoteIntoReturn1',
+                'quoteIntoReturn2',
+                1
+            ]
+        ];
+    }
+
+    public function testAddReviewsTotalCount()
+    {
+        $this->selectMock->expects($this->once())
+            ->method('joinLeft')
+            ->with(
+                ['r' => 'review'],
+                'main_table.entity_pk_value = r.entity_pk_value',
+                ['total_reviews' => new \Zend_Db_Expr('COUNT(r.review_id)')]
+            )->willReturnSelf();
+        $this->selectMock->expects($this->once())
+            ->method('group');
+        $this->model->addReviewsTotalCount();
+    }
+}
diff --git a/app/code/Magento/Sales/Api/Data/CreditmemoCommentInterface.php b/app/code/Magento/Sales/Api/Data/CreditmemoCommentInterface.php
index 28afae3c0f9528343770c22dfe283b82324a7c5a..3a4a5c23033f48a2b2fcc41eb519330cb3e955fd 100644
--- a/app/code/Magento/Sales/Api/Data/CreditmemoCommentInterface.php
+++ b/app/code/Magento/Sales/Api/Data/CreditmemoCommentInterface.php
@@ -57,6 +57,14 @@ interface CreditmemoCommentInterface extends \Magento\Framework\Api\ExtensibleDa
      */
     public function getCreatedAt();
 
+    /**
+     * Sets the credit memo created-at timestamp.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets the credit memo ID.
      *
diff --git a/app/code/Magento/Sales/Api/Data/CreditmemoInterface.php b/app/code/Magento/Sales/Api/Data/CreditmemoInterface.php
index 205d5c37b3f1033132c9679a240e036223a2e5e8..ce5a46b9838b447159bcf96b87bbd8753e46ed5e 100644
--- a/app/code/Magento/Sales/Api/Data/CreditmemoInterface.php
+++ b/app/code/Magento/Sales/Api/Data/CreditmemoInterface.php
@@ -383,6 +383,15 @@ interface CreditmemoInterface extends \Magento\Framework\Api\ExtensibleDataInter
      * @return string Credit memo created-at timestamp.
      */
     public function getCreatedAt();
+
+    /**
+     * Sets the credit memo created-at timestamp.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets the credit memo status.
      *
diff --git a/app/code/Magento/Sales/Api/Data/InvoiceCommentInterface.php b/app/code/Magento/Sales/Api/Data/InvoiceCommentInterface.php
index 10c86a870231cd4cd0c24a165c1cc5cf022bcdaf..ec6fce4016f6a0d397858b3ebf5848cacdc3e047 100644
--- a/app/code/Magento/Sales/Api/Data/InvoiceCommentInterface.php
+++ b/app/code/Magento/Sales/Api/Data/InvoiceCommentInterface.php
@@ -55,6 +55,14 @@ interface InvoiceCommentInterface extends \Magento\Framework\Api\ExtensibleDataI
      */
     public function getCreatedAt();
 
+    /**
+     * Sets the created-at timestamp for the invoice.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets the ID for the invoice.
      *
diff --git a/app/code/Magento/Sales/Api/Data/InvoiceInterface.php b/app/code/Magento/Sales/Api/Data/InvoiceInterface.php
index e17decc98e0bbd364313f43a2d7373cbfd7990cc..fcbe20b83f28c96b939277d524a04dec9f923b7d 100644
--- a/app/code/Magento/Sales/Api/Data/InvoiceInterface.php
+++ b/app/code/Magento/Sales/Api/Data/InvoiceInterface.php
@@ -319,6 +319,14 @@ interface InvoiceInterface extends \Magento\Framework\Api\ExtensibleDataInterfac
      */
     public function getCreatedAt();
 
+    /**
+     * Sets the created-at timestamp for the invoice.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets the discount amount for the invoice.
      *
diff --git a/app/code/Magento/Sales/Api/Data/OrderInterface.php b/app/code/Magento/Sales/Api/Data/OrderInterface.php
index 7bd62fbe1c3228b2241690b981a7f0ab8c2f84eb..42ccf6aee23c151088f27b7d6e714237a75ce845 100644
--- a/app/code/Magento/Sales/Api/Data/OrderInterface.php
+++ b/app/code/Magento/Sales/Api/Data/OrderInterface.php
@@ -914,6 +914,14 @@ interface OrderInterface extends \Magento\Framework\Api\ExtensibleDataInterface
      */
     public function getCreatedAt();
 
+    /**
+     * Sets the created-at timestamp for the order.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets the customer date-of-birth (DOB) for the order.
      *
diff --git a/app/code/Magento/Sales/Api/Data/OrderItemInterface.php b/app/code/Magento/Sales/Api/Data/OrderItemInterface.php
index 6e59b03a98370feb88a6d6522c9fb84560e12bf3..e10e196380670f54fd11963a281738c50226d20c 100644
--- a/app/code/Magento/Sales/Api/Data/OrderItemInterface.php
+++ b/app/code/Magento/Sales/Api/Data/OrderItemInterface.php
@@ -578,6 +578,14 @@ interface OrderItemInterface extends \Magento\Framework\Api\ExtensibleDataInterf
      */
     public function getCreatedAt();
 
+    /**
+     * Sets the created-at timestamp for the order item.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets the description for the order item.
      *
diff --git a/app/code/Magento/Sales/Api/Data/OrderStatusHistoryInterface.php b/app/code/Magento/Sales/Api/Data/OrderStatusHistoryInterface.php
index 4ef7daf322d37f0ca1b26f0ab7501e7ad5a79fcf..3a27e326c3b88866c1cb03ec4c84227391e46416 100644
--- a/app/code/Magento/Sales/Api/Data/OrderStatusHistoryInterface.php
+++ b/app/code/Magento/Sales/Api/Data/OrderStatusHistoryInterface.php
@@ -64,6 +64,14 @@ interface OrderStatusHistoryInterface extends \Magento\Framework\Api\ExtensibleD
      */
     public function getCreatedAt();
 
+    /**
+     * Sets the created-at timestamp for the order status history.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets the ID for the order status history.
      *
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentCommentInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentCommentInterface.php
index 213b7c2e5e4931bd9f9295aee3b537f817891a68..e6bcd71928463f0bd09446f60bc303a1a31f4864 100644
--- a/app/code/Magento/Sales/Api/Data/ShipmentCommentInterface.php
+++ b/app/code/Magento/Sales/Api/Data/ShipmentCommentInterface.php
@@ -55,6 +55,14 @@ interface ShipmentCommentInterface extends \Magento\Framework\Api\ExtensibleData
      */
     public function getCreatedAt();
 
+    /**
+     * Sets the created-at timestamp for the shipment comment.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets the ID for the shipment comment.
      *
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentInterface.php
index 41c676ea2081219e35d7e7d6561206f4f5bf5c24..67b3b60b05266ef8febff35e6df0952414ebdea1 100644
--- a/app/code/Magento/Sales/Api/Data/ShipmentInterface.php
+++ b/app/code/Magento/Sales/Api/Data/ShipmentInterface.php
@@ -103,6 +103,14 @@ interface ShipmentInterface extends \Magento\Framework\Api\ExtensibleDataInterfa
      */
     public function getCreatedAt();
 
+    /**
+     * Sets the created-at timestamp for the shipment.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets the customer ID for the shipment.
      *
diff --git a/app/code/Magento/Sales/Api/Data/ShipmentTrackInterface.php b/app/code/Magento/Sales/Api/Data/ShipmentTrackInterface.php
index 7ace1ead4114db6c8c81c9a3921d56f1e9195727..e9bfa3915c4074096f9d5023e5a5c13514a92267 100644
--- a/app/code/Magento/Sales/Api/Data/ShipmentTrackInterface.php
+++ b/app/code/Magento/Sales/Api/Data/ShipmentTrackInterface.php
@@ -76,6 +76,14 @@ interface ShipmentTrackInterface extends \Magento\Framework\Api\ExtensibleDataIn
      */
     public function getCreatedAt();
 
+    /**
+     * Sets the created-at timestamp for the shipment package.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets the description for the shipment package.
      *
diff --git a/app/code/Magento/Sales/Api/Data/TransactionInterface.php b/app/code/Magento/Sales/Api/Data/TransactionInterface.php
index 224d9765582f0e3381846f159814103e72111351..92d431c6e0b5754ed8222c5deb9f8fb02f28ce05 100644
--- a/app/code/Magento/Sales/Api/Data/TransactionInterface.php
+++ b/app/code/Magento/Sales/Api/Data/TransactionInterface.php
@@ -75,6 +75,14 @@ interface TransactionInterface extends \Magento\Framework\Api\ExtensibleDataInte
      */
     public function getTransactionId();
 
+    /**
+     * Sets the transaction ID for the transaction.
+     *
+     * @param int $id
+     * @return $this
+     */
+    public function setTransactionId($id);
+
     /**
      * Gets the parent ID for the transaction.
      *
@@ -138,6 +146,14 @@ interface TransactionInterface extends \Magento\Framework\Api\ExtensibleDataInte
      */
     public function getCreatedAt();
 
+    /**
+     * Sets the created-at timestamp for the transaction.
+     *
+     * @param string $createdAt timestamp
+     * @return $this
+     */
+    public function setCreatedAt($createdAt);
+
     /**
      * Gets an array of child transactions for the transaction.
      *
diff --git a/app/code/Magento/Sales/Controller/Adminhtml/Order/EditInterface.php b/app/code/Magento/Sales/Controller/Adminhtml/Order/EditInterface.php
deleted file mode 100644
index 79fefe2a18515d4f143f561aba1c9a2f9e3f4cde..0000000000000000000000000000000000000000
--- a/app/code/Magento/Sales/Controller/Adminhtml/Order/EditInterface.php
+++ /dev/null
@@ -1,11 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Sales\Controller\Adminhtml\Order;
-
-interface EditInterface extends \Magento\Framework\App\ActionInterface
-{
-}
diff --git a/app/code/Magento/Sales/Model/Order.php b/app/code/Magento/Sales/Model/Order.php
index 02077b3e30163a4794f260175e74ec667ed17592..43f4b95497720ed8df3e7f74a4cc03e31255b980 100644
--- a/app/code/Magento/Sales/Model/Order.php
+++ b/app/code/Magento/Sales/Model/Order.php
@@ -35,7 +35,6 @@ use Magento\Sales\Model\Resource\Order\Status\History\Collection as HistoryColle
  * @method \Magento\Sales\Model\Resource\Order getResource()
  * @method int getGiftMessageId()
  * @method \Magento\Sales\Model\Order setGiftMessageId(int $value)
- * @method \Magento\Sales\Model\Order setCreatedAt(string $value)
  * @method bool hasBillingAddressId()
  * @method \Magento\Sales\Model\Order unsBillingAddressId()
  * @method bool hasShippingAddressId()
@@ -2481,6 +2480,14 @@ class Order extends AbstractModel implements EntityInterface, OrderInterface
         return $this->getData(OrderInterface::CREATED_AT);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(OrderInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * Returns customer_dob
      *
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Order/Creditmemo.php
index 9e77f5afd8635e1b6421a1915684a4c0a858cbd0..7fbc58d77171b57ccf708e81a9a4ad77a827293b 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo.php
@@ -20,7 +20,6 @@ use Magento\Sales\Model\EntityInterface;
  *
  * @method \Magento\Sales\Model\Resource\Order\Creditmemo _getResource()
  * @method \Magento\Sales\Model\Resource\Order\Creditmemo getResource()
- * @method \Magento\Sales\Model\Order\Creditmemo setCreatedAt(string $value)
  * @method \Magento\Sales\Model\Order\Invoice setSendEmail(bool $value)
  * @method \Magento\Sales\Model\Order\Invoice setCustomerNote(string $value)
  * @method string getCustomerNote()
@@ -1034,6 +1033,14 @@ class Creditmemo extends AbstractModel implements EntityInterface, CreditmemoInt
         return $this->getData(CreditmemoInterface::CREATED_AT);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(CreditmemoInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * Returns creditmemo_status
      *
diff --git a/app/code/Magento/Sales/Model/Order/Creditmemo/Comment.php b/app/code/Magento/Sales/Model/Order/Creditmemo/Comment.php
index a488162c322611e892d33bc90cd60be5dac7cc6f..2dac94c26b818bc2eab23acc83aea3079166a9d5 100644
--- a/app/code/Magento/Sales/Model/Order/Creditmemo/Comment.php
+++ b/app/code/Magento/Sales/Model/Order/Creditmemo/Comment.php
@@ -12,7 +12,6 @@ use Magento\Sales\Model\AbstractModel;
 /**
  * @method \Magento\Sales\Model\Resource\Order\Creditmemo\Comment _getResource()
  * @method \Magento\Sales\Model\Resource\Order\Creditmemo\Comment getResource()
- * @method \Magento\Sales\Model\Order\Creditmemo\Comment setCreatedAt(string $value)
  */
 class Comment extends AbstractModel implements CreditmemoCommentInterface
 {
@@ -126,6 +125,14 @@ class Comment extends AbstractModel implements CreditmemoCommentInterface
         return $this->getData(CreditmemoCommentInterface::CREATED_AT);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(CreditmemoCommentInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * Returns is_customer_notified
      *
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender.php b/app/code/Magento/Sales/Model/Order/Email/Sender.php
index 4ead2bc500e1ae7df9522528637795fe0bc99669..a1686c30614f4da30a30a1734aa798bf41126b07 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender.php
@@ -8,6 +8,7 @@ namespace Magento\Sales\Model\Order\Email;
 use Magento\Sales\Model\Order;
 use Magento\Sales\Model\Order\Email\Container\IdentityInterface;
 use Magento\Sales\Model\Order\Email\Container\Template;
+use Magento\Sales\Model\Order\Address\Renderer;
 
 abstract class Sender
 {
@@ -31,22 +32,30 @@ abstract class Sender
      */
     protected $logger;
 
+    /**
+     * @var Renderer
+     */
+    protected $addressRenderer;
+
     /**
      * @param Template $templateContainer
      * @param IdentityInterface $identityContainer
      * @param SenderBuilderFactory $senderBuilderFactory
      * @param \Psr\Log\LoggerInterface $logger
+     * @param Renderer $addressRenderer
      */
     public function __construct(
         Template $templateContainer,
         IdentityInterface $identityContainer,
         \Magento\Sales\Model\Order\Email\SenderBuilderFactory $senderBuilderFactory,
-        \Psr\Log\LoggerInterface $logger
+        \Psr\Log\LoggerInterface $logger,
+        Renderer $addressRenderer
     ) {
         $this->templateContainer = $templateContainer;
         $this->identityContainer = $identityContainer;
         $this->senderBuilderFactory = $senderBuilderFactory;
         $this->logger = $logger;
+        $this->addressRenderer = $addressRenderer;
     }
 
     /**
@@ -118,4 +127,24 @@ abstract class Sender
             'store' => $this->identityContainer->getStore()->getStoreId()
         ];
     }
+
+    /**
+     * @param Order $order
+     * @return string|null
+     */
+    protected function getFormattedShippingAddress($order)
+    {
+        return $order->getIsVirtual()
+            ? null
+            : $this->addressRenderer->format($order->getShippingAddress(), 'html');
+    }
+
+    /**
+     * @param Order $order
+     * @return string|null
+     */
+    protected function getFormattedBillingAddress($order)
+    {
+        return $this->addressRenderer->format($order->getBillingAddress(), 'html');
+    }
 }
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoCommentSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoCommentSender.php
index 09d01d2e0a55cdf874ba8cbe9add9567998a5c5c..5c8eae7d309499f413e3084245788b79a1738e22 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoCommentSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoCommentSender.php
@@ -46,7 +46,7 @@ class CreditmemoCommentSender extends NotifySender
         Renderer $addressRenderer,
         ManagerInterface $eventManager
     ) {
-        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger);
+        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger, $addressRenderer);
         $this->addressRenderer = $addressRenderer;
         $this->eventManager = $eventManager;
     }
@@ -62,33 +62,22 @@ class CreditmemoCommentSender extends NotifySender
     public function send(Creditmemo $creditmemo, $notify = true, $comment = '')
     {
         $order = $creditmemo->getOrder();
-        if ($order->getShippingAddress()) {
-            $formattedShippingAddress = $this->addressRenderer->format($order->getShippingAddress(), 'html');
-        } else {
-            $formattedShippingAddress = '';
-        }
-        $formattedBillingAddress = $this->addressRenderer->format($order->getBillingAddress(), 'html');
-
-        $transport = new \Magento\Framework\Object(
-            ['template_vars' =>
-                 [
-                     'order'                    => $order,
-                     'creditmemo'               => $creditmemo,
-                     'comment'                  => $comment,
-                     'billing'                  => $order->getBillingAddress(),
-                     'store'                    => $order->getStore(),
-                     'formattedShippingAddress' => $formattedShippingAddress,
-                     'formattedBillingAddress'  => $formattedBillingAddress,
-                 ]
-            ]
-        );
+        $transport = [
+            'order' => $order,
+            'creditmemo' => $creditmemo,
+            'comment' => $comment,
+            'billing' => $order->getBillingAddress(),
+            'store' => $order->getStore(),
+            'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
+            'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
+        ];
 
         $this->eventManager->dispatch(
             'email_creditmemo_comment_set_template_vars_before',
             ['sender' => $this, 'transport' => $transport]
         );
 
-        $this->templateContainer->setTemplateVars($transport->getTemplateVars());
+        $this->templateContainer->setTemplateVars($transport);
 
         return $this->checkAndSend($order, $notify);
     }
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoSender.php
index 8bcd58fafd941a3dc185de14ac7f33b932ed2d7b..b3061c2000cea4d0df0c057eac60d451819e2c40 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/CreditmemoSender.php
@@ -67,13 +67,13 @@ class CreditmemoSender extends Sender
         CreditmemoIdentity $identityContainer,
         \Magento\Sales\Model\Order\Email\SenderBuilderFactory $senderBuilderFactory,
         \Psr\Log\LoggerInterface $logger,
+        Renderer $addressRenderer,
         PaymentHelper $paymentHelper,
         CreditmemoResource $creditmemoResource,
         \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig,
-        Renderer $addressRenderer,
         ManagerInterface $eventManager
     ) {
-        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger);
+        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger, $addressRenderer);
         $this->paymentHelper = $paymentHelper;
         $this->creditmemoResource = $creditmemoResource;
         $this->globalConfig = $globalConfig;
@@ -102,37 +102,24 @@ class CreditmemoSender extends Sender
 
         if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
             $order = $creditmemo->getOrder();
-
-            if ($order->getShippingAddress()) {
-                $formattedShippingAddress = $this->addressRenderer->format($order->getShippingAddress(), 'html');
-            } else {
-                $formattedShippingAddress = '';
-            }
-
-            $formattedBillingAddress = $this->addressRenderer->format($order->getBillingAddress(), 'html');
-
-            $transport = new \Magento\Framework\Object(
-                ['template_vars' =>
-                     [
-                         'order'                    => $order,
-                         'creditmemo'               => $creditmemo,
-                         'comment'                  => $creditmemo->getCustomerNoteNotify()
-                             ? $creditmemo->getCustomerNote() : '',
-                         'billing'                  => $order->getBillingAddress(),
-                         'payment_html'             => $this->getPaymentHtml($order),
-                         'store'                    => $order->getStore(),
-                         'formattedShippingAddress' => $formattedShippingAddress,
-                         'formattedBillingAddress'  => $formattedBillingAddress
-                     ]
-                ]
-            );
+            
+            $transport = [
+                'order' => $order,
+                'creditmemo' => $creditmemo,
+                'comment' => $creditmemo->getCustomerNoteNotify() ? $creditmemo->getCustomerNote() : '',
+                'billing' => $order->getBillingAddress(),
+                'payment_html' => $this->getPaymentHtml($order),
+                'store' => $order->getStore(),
+                'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
+                'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
+            ];
 
             $this->eventManager->dispatch(
                 'email_creditmemo_set_template_vars_before',
                 ['sender' => $this, 'transport' => $transport]
             );
 
-            $this->templateContainer->setTemplateVars($transport->getTemplateVars());
+            $this->templateContainer->setTemplateVars($transport);
 
             if ($this->checkAndSend($order)) {
                 $creditmemo->setEmailSent(true);
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceCommentSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceCommentSender.php
index b994034cf480a12c17738832e1bb44e9920be569..249d3321fc80c583d0a2c89f71ece66c850dd49f 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceCommentSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceCommentSender.php
@@ -46,7 +46,7 @@ class InvoiceCommentSender extends NotifySender
         Renderer $addressRenderer,
         ManagerInterface $eventManager
     ) {
-        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger);
+        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger, $addressRenderer);
         $this->addressRenderer = $addressRenderer;
         $this->eventManager = $eventManager;
     }
@@ -62,33 +62,22 @@ class InvoiceCommentSender extends NotifySender
     public function send(Invoice $invoice, $notify = true, $comment = '')
     {
         $order = $invoice->getOrder();
-        if ($order->getShippingAddress()) {
-            $formattedShippingAddress = $this->addressRenderer->format($order->getShippingAddress(), 'html');
-        } else {
-            $formattedShippingAddress = '';
-        }
-        $formattedBillingAddress = $this->addressRenderer->format($order->getBillingAddress(), 'html');
-
-        $transport = new \Magento\Framework\Object(
-            ['template_vars' =>
-                 [
-                     'order'                    => $order,
-                     'invoice'                  => $invoice,
-                     'comment'                  => $comment,
-                     'billing'                  => $order->getBillingAddress(),
-                     'store'                    => $order->getStore(),
-                     'formattedShippingAddress' => $formattedShippingAddress,
-                     'formattedBillingAddress'  => $formattedBillingAddress,
-                 ]
-            ]
-        );
+        $transport = [
+            'order' => $order,
+            'invoice' => $invoice,
+            'comment' => $comment,
+            'billing' => $order->getBillingAddress(),
+            'store' => $order->getStore(),
+            'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
+            'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
+        ];
 
         $this->eventManager->dispatch(
             'email_invoice_comment_set_template_vars_before',
             ['sender' => $this, 'transport' => $transport]
         );
 
-        $this->templateContainer->setTemplateVars($transport->getTemplateVars());
+        $this->templateContainer->setTemplateVars($transport);
 
         return $this->checkAndSend($order, $notify);
     }
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceSender.php
index d879b0f529aab42479a89acc597f14867f4268a4..30fc4ae612bae3b0b1d2d4fbfa9d70b24dfd099b 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/InvoiceSender.php
@@ -67,13 +67,13 @@ class InvoiceSender extends Sender
         InvoiceIdentity $identityContainer,
         \Magento\Sales\Model\Order\Email\SenderBuilderFactory $senderBuilderFactory,
         \Psr\Log\LoggerInterface $logger,
+        Renderer $addressRenderer,
         PaymentHelper $paymentHelper,
         InvoiceResource $invoiceResource,
         \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig,
-        Renderer $addressRenderer,
         ManagerInterface $eventManager
     ) {
-        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger);
+        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger, $addressRenderer);
         $this->paymentHelper = $paymentHelper;
         $this->invoiceResource = $invoiceResource;
         $this->globalConfig = $globalConfig;
@@ -103,35 +103,23 @@ class InvoiceSender extends Sender
         if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
             $order = $invoice->getOrder();
 
-            if ($order->getShippingAddress()) {
-                $formattedShippingAddress = $this->addressRenderer->format($order->getShippingAddress(), 'html');
-            } else {
-                $formattedShippingAddress = '';
-            }
-            $formattedBillingAddress = $this->addressRenderer->format($order->getBillingAddress(), 'html');
-
-            $transport = new \Magento\Framework\Object(
-                ['template_vars' =>
-                     [
-                         'order'                    => $order,
-                         'invoice'                  => $invoice,
-                         'comment'                  => $invoice->getCustomerNoteNotify() ? $invoice->getCustomerNote()
-                             : '',
-                         'billing'                  => $order->getBillingAddress(),
-                         'payment_html'             => $this->getPaymentHtml($order),
-                         'store'                    => $order->getStore(),
-                         'formattedShippingAddress' => $formattedShippingAddress,
-                         'formattedBillingAddress'  => $formattedBillingAddress
-                     ]
-                ]
-            );
+            $transport = [
+                'order' => $order,
+                'invoice' => $invoice,
+                'comment' => $invoice->getCustomerNoteNotify() ? $invoice->getCustomerNote() : '',
+                'billing' => $order->getBillingAddress(),
+                'payment_html' => $this->getPaymentHtml($order),
+                'store' => $order->getStore(),
+                'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
+                'formattedBillingAddress' => $this->getFormattedBillingAddress($order)
+            ];
 
             $this->eventManager->dispatch(
                 'email_invoice_set_template_vars_before',
                 ['sender' => $this, 'transport' => $transport]
             );
 
-            $this->templateContainer->setTemplateVars($transport->getTemplateVars());
+            $this->templateContainer->setTemplateVars($transport);
 
             if ($this->checkAndSend($order)) {
                 $invoice->setEmailSent(true);
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/OrderCommentSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/OrderCommentSender.php
index 64f67cb80ce8f98b8fc07de60fc5a48efeae534e..35d45ece6480fcbcc37c99bb8f55b805264350a5 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/OrderCommentSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/OrderCommentSender.php
@@ -45,7 +45,7 @@ class OrderCommentSender extends NotifySender
         Renderer $addressRenderer,
         ManagerInterface $eventManager
     ) {
-        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger);
+        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger, $addressRenderer);
         $this->addressRenderer = $addressRenderer;
         $this->eventManager = $eventManager;
     }
@@ -60,32 +60,21 @@ class OrderCommentSender extends NotifySender
      */
     public function send(Order $order, $notify = true, $comment = '')
     {
-        if ($order->getShippingAddress()) {
-            $formattedShippingAddress = $this->addressRenderer->format($order->getShippingAddress(), 'html');
-        } else {
-            $formattedShippingAddress = '';
-        }
-        $formattedBillingAddress = $this->addressRenderer->format($order->getBillingAddress(), 'html');
-
-        $transport = new \Magento\Framework\Object(
-            ['template_vars' =>
-                 [
-                     'order'                    => $order,
-                     'comment'                  => $comment,
-                     'billing'                  => $order->getBillingAddress(),
-                     'store'                    => $order->getStore(),
-                     'formattedShippingAddress' => $formattedShippingAddress,
-                     'formattedBillingAddress'  => $formattedBillingAddress,
-                 ]
-            ]
-        );
+        $transport = [
+            'order' => $order,
+            'comment' => $comment,
+            'billing' => $order->getBillingAddress(),
+            'store' => $order->getStore(),
+            'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
+            'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
+        ];
 
         $this->eventManager->dispatch(
             'email_order_comment_set_template_vars_before',
             ['sender' => $this, 'transport' => $transport]
         );
 
-        $this->templateContainer->setTemplateVars($transport->getTemplateVars());
+        $this->templateContainer->setTemplateVars($transport);
 
         return $this->checkAndSend($order, $notify);
     }
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php
index 59c7e404c940a55abd252ae429a572e0d8b45c66..32628844736dfece992d984ba9b6be5debcb3bf9 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/OrderSender.php
@@ -65,13 +65,13 @@ class OrderSender extends Sender
         OrderIdentity $identityContainer,
         \Magento\Sales\Model\Order\Email\SenderBuilderFactory $senderBuilderFactory,
         \Psr\Log\LoggerInterface $logger,
+        Renderer $addressRenderer,
         PaymentHelper $paymentHelper,
         OrderResource $orderResource,
         \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig,
-        Renderer $addressRenderer,
         ManagerInterface $eventManager
     ) {
-        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger);
+        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger, $addressRenderer);
         $this->paymentHelper = $paymentHelper;
         $this->orderResource = $orderResource;
         $this->globalConfig = $globalConfig;
@@ -119,25 +119,21 @@ class OrderSender extends Sender
      */
     protected function prepareTemplate(Order $order)
     {
-        $transport = new \Magento\Framework\Object(
-            ['template_vars' =>
-                 [
-                     'order'                    => $order,
-                     'billing'                  => $order->getBillingAddress(),
-                     'payment_html'             => $this->getPaymentHtml($order),
-                     'store'                    => $order->getStore(),
-                     'formattedShippingAddress' => $this->addressRenderer->format($order->getShippingAddress(), 'html'),
-                     'formattedBillingAddress'  => $this->addressRenderer->format($order->getBillingAddress(), 'html'),
-                 ]
-            ]
-        );
+        $transport = [
+            'order' => $order,
+            'billing' => $order->getBillingAddress(),
+            'payment_html' => $this->getPaymentHtml($order),
+            'store' => $order->getStore(),
+            'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
+            'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
+        ];
 
         $this->eventManager->dispatch(
             'email_order_set_template_vars_before',
             ['sender' => $this, 'transport' => $transport]
         );
 
-        $this->templateContainer->setTemplateVars($transport->getTemplateVars());
+        $this->templateContainer->setTemplateVars($transport);
 
         parent::prepareTemplate($order);
     }
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentCommentSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentCommentSender.php
index d3555b8240b9a27934f0bbc6144d64db0a2ba563..c0e2b7b785661a5dfb154cd1a47a9c3f390760e2 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentCommentSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentCommentSender.php
@@ -46,7 +46,7 @@ class ShipmentCommentSender extends NotifySender
         Renderer $addressRenderer,
         ManagerInterface $eventManager
     ) {
-        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger);
+        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger, $addressRenderer);
         $this->addressRenderer = $addressRenderer;
         $this->eventManager = $eventManager;
     }
@@ -62,33 +62,22 @@ class ShipmentCommentSender extends NotifySender
     public function send(Shipment $shipment, $notify = true, $comment = '')
     {
         $order = $shipment->getOrder();
-        if ($order->getShippingAddress()) {
-            $formattedShippingAddress = $this->addressRenderer->format($order->getShippingAddress(), 'html');
-        } else {
-            $formattedShippingAddress = '';
-        }
-        $formattedBillingAddress = $this->addressRenderer->format($order->getBillingAddress(), 'html');
-
-        $transport = new \Magento\Framework\Object(
-            ['template_vars' =>
-                 [
-                     'order'                    => $order,
-                     'shipment'                 => $shipment,
-                     'comment'                  => $comment,
-                     'billing'                  => $order->getBillingAddress(),
-                     'store'                    => $order->getStore(),
-                     'formattedShippingAddress' => $formattedShippingAddress,
-                     'formattedBillingAddress'  => $formattedBillingAddress,
-                 ]
-            ]
-        );
+        $transport = [
+            'order' => $order,
+            'shipment' => $shipment,
+            'comment' => $comment,
+            'billing' => $order->getBillingAddress(),
+            'store' => $order->getStore(),
+            'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
+            'formattedBillingAddress' => $this->getFormattedBillingAddress($order),
+        ];
 
         $this->eventManager->dispatch(
             'email_shipment_comment_set_template_vars_before',
             ['sender' => $this, 'transport' => $transport]
         );
 
-        $this->templateContainer->setTemplateVars($transport->getTemplateVars());
+        $this->templateContainer->setTemplateVars($transport);
 
         return $this->checkAndSend($order, $notify);
     }
diff --git a/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentSender.php b/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentSender.php
index 96a62f88588435d2695a8e97c1a466aa161d4986..960e29028f6d15fbd1390227d1f179b628d74a3d 100644
--- a/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentSender.php
+++ b/app/code/Magento/Sales/Model/Order/Email/Sender/ShipmentSender.php
@@ -67,13 +67,13 @@ class ShipmentSender extends Sender
         ShipmentIdentity $identityContainer,
         \Magento\Sales\Model\Order\Email\SenderBuilderFactory $senderBuilderFactory,
         \Psr\Log\LoggerInterface $logger,
+        Renderer $addressRenderer,
         PaymentHelper $paymentHelper,
         ShipmentResource $shipmentResource,
         \Magento\Framework\App\Config\ScopeConfigInterface $globalConfig,
-        Renderer $addressRenderer,
         ManagerInterface $eventManager
     ) {
-        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger);
+        parent::__construct($templateContainer, $identityContainer, $senderBuilderFactory, $logger, $addressRenderer);
         $this->paymentHelper = $paymentHelper;
         $this->shipmentResource = $shipmentResource;
         $this->globalConfig = $globalConfig;
@@ -102,37 +102,24 @@ class ShipmentSender extends Sender
 
         if (!$this->globalConfig->getValue('sales_email/general/async_sending') || $forceSyncMode) {
             $order = $shipment->getOrder();
-
-            if ($order->getShippingAddress()) {
-                $formattedShippingAddress = $this->addressRenderer->format($order->getShippingAddress(), 'html');
-            } else {
-                $formattedShippingAddress = '';
-            }
-            $formattedBillingAddress = $this->addressRenderer->format($order->getBillingAddress(), 'html');
-
-            $transport = new \Magento\Framework\Object(
-                ['template_vars' =>
-                     [
-                         'order'                    => $order,
-                         'shipment'                 => $shipment,
-                         'comment'                  => $shipment->getCustomerNoteNotify()
-                             ? $shipment->getCustomerNote()
-                             : '',
-                         'billing'                  => $order->getBillingAddress(),
-                         'payment_html'             => $this->getPaymentHtml($order),
-                         'store'                    => $order->getStore(),
-                         'formattedShippingAddress' => $formattedShippingAddress,
-                         'formattedBillingAddress'  => $formattedBillingAddress
-                     ]
-                ]
-            );
+            
+            $transport = [
+                'order' => $order,
+                'shipment' => $shipment,
+                'comment' => $shipment->getCustomerNoteNotify() ? $shipment->getCustomerNote() : '',
+                'billing' => $order->getBillingAddress(),
+                'payment_html' => $this->getPaymentHtml($order),
+                'store' => $order->getStore(),
+                'formattedShippingAddress' => $this->getFormattedShippingAddress($order),
+                'formattedBillingAddress' => $this->getFormattedBillingAddress($order)
+            ];
 
             $this->eventManager->dispatch(
                 'email_shipment_set_template_vars_before',
                 ['sender' => $this, 'transport' => $transport]
             );
 
-            $this->templateContainer->setTemplateVars($transport->getTemplateVars());
+            $this->templateContainer->setTemplateVars($transport);
 
             if ($this->checkAndSend($order)) {
                 $shipment->setEmailSent(true);
diff --git a/app/code/Magento/Sales/Model/Order/Invoice.php b/app/code/Magento/Sales/Model/Order/Invoice.php
index 8317b7041d61f3e747af2b644050854b3b55174d..036aec685121162933181a05e6c66af57af6d58c 100644
--- a/app/code/Magento/Sales/Model/Order/Invoice.php
+++ b/app/code/Magento/Sales/Model/Order/Invoice.php
@@ -11,7 +11,6 @@ use Magento\Sales\Model\AbstractModel;
 use Magento\Sales\Model\EntityInterface;
 
 /**
- * @method \Magento\Sales\Model\Order\Invoice setCreatedAt(string $value)
  * @method \Magento\Sales\Model\Order\Invoice setSendEmail(bool $value)
  * @method \Magento\Sales\Model\Order\Invoice setCustomerNote(string $value)
  * @method string getCustomerNote()
@@ -969,6 +968,14 @@ class Invoice extends AbstractModel implements EntityInterface, InvoiceInterface
         return $this->getData(InvoiceInterface::CREATED_AT);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(InvoiceInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * Returns discount_amount
      *
diff --git a/app/code/Magento/Sales/Model/Order/Invoice/Comment.php b/app/code/Magento/Sales/Model/Order/Invoice/Comment.php
index 074e77b3638e656906f3da22e3727cea61423e98..e7b99dea1593ed699d4f76e6f745256f780e8075 100644
--- a/app/code/Magento/Sales/Model/Order/Invoice/Comment.php
+++ b/app/code/Magento/Sales/Model/Order/Invoice/Comment.php
@@ -12,7 +12,6 @@ use Magento\Sales\Model\AbstractModel;
 /**
  * @method \Magento\Sales\Model\Resource\Order\Invoice\Comment _getResource()
  * @method \Magento\Sales\Model\Resource\Order\Invoice\Comment getResource()
- * @method \Magento\Sales\Model\Order\Invoice\Comment setCreatedAt(string $value)
  */
 class Comment extends AbstractModel implements InvoiceCommentInterface
 {
@@ -126,6 +125,14 @@ class Comment extends AbstractModel implements InvoiceCommentInterface
         return $this->getData(InvoiceCommentInterface::CREATED_AT);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(InvoiceCommentInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * Returns is_customer_notified
      *
diff --git a/app/code/Magento/Sales/Model/Order/Item.php b/app/code/Magento/Sales/Model/Order/Item.php
index b23a34296c690d5584dc2a6e314401669981bd3a..602cde0a32e3ccbbc03195aa4933e4fdb81b3079 100644
--- a/app/code/Magento/Sales/Model/Order/Item.php
+++ b/app/code/Magento/Sales/Model/Order/Item.php
@@ -14,7 +14,6 @@ use Magento\Sales\Api\Data\OrderItemInterface;
  *
  * @method \Magento\Sales\Model\Resource\Order\Item _getResource()
  * @method \Magento\Sales\Model\Resource\Order\Item getResource()
- * @method \Magento\Sales\Model\Order\Item setCreatedAt(string $value)
  * @method int getGiftMessageId()
  * @method \Magento\Sales\Model\Order\Item setGiftMessageId(int $value)
  * @method int getGiftMessageAvailable()
@@ -949,6 +948,14 @@ class Item extends AbstractModel implements OrderItemInterface
         return $this->getData(OrderItemInterface::CREATED_AT);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(OrderItemInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * Returns description
      *
diff --git a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php
index 3c0d281f3e27cd8630d0471e6e8f505c29f6b10c..16cc9b45365adec1da8225d0c7ef6cd27ba813f1 100644
--- a/app/code/Magento/Sales/Model/Order/Payment/Transaction.php
+++ b/app/code/Magento/Sales/Model/Order/Payment/Transaction.php
@@ -19,7 +19,6 @@ use Magento\Sales\Model\AbstractModel;
  *
  * @method \Magento\Sales\Model\Resource\Order\Payment\Transaction _getResource()
  * @method \Magento\Sales\Model\Resource\Order\Payment\Transaction getResource()
- * @method \Magento\Sales\Model\Order\Payment\Transaction setCreatedAt(string $value)
 
  * @author      Magento Core Team <core@magentocommerce.com>
  * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
@@ -922,6 +921,14 @@ class Transaction extends AbstractModel implements TransactionInterface
         return $this->getData(TransactionInterface::TRANSACTION_ID);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setTransactionId($id)
+    {
+        return $this->setData(TransactionInterface::TRANSACTION_ID, $id);
+    }
+
     /**
      * Returns method
      *
@@ -1002,8 +1009,9 @@ class Transaction extends AbstractModel implements TransactionInterface
         return $this->getData(TransactionInterface::IS_CLOSED);
     }
 
+    //@codeCoverageIgnoreStart
     /**
-     * Returns created_at
+     * Gets the created-at timestamp for the transaction.
      *
      * @return string
      */
@@ -1012,7 +1020,14 @@ class Transaction extends AbstractModel implements TransactionInterface
         return $this->getData(TransactionInterface::CREATED_AT);
     }
 
-    //@codeCoverageIgnoreStart
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(TransactionInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * {@inheritdoc}
      */
diff --git a/app/code/Magento/Sales/Model/Order/Shipment.php b/app/code/Magento/Sales/Model/Order/Shipment.php
index 3472e9663ad337ceb64c7399b06a60e389883708..6763a4895dfe30891530cdeb2c25a61e47047c14 100644
--- a/app/code/Magento/Sales/Model/Order/Shipment.php
+++ b/app/code/Magento/Sales/Model/Order/Shipment.php
@@ -15,7 +15,6 @@ use Magento\Sales\Model\EntityInterface;
  *
  * @method \Magento\Sales\Model\Resource\Order\Shipment _getResource()
  * @method \Magento\Sales\Model\Resource\Order\Shipment getResource()
- * @method \Magento\Sales\Model\Order\Shipment setCreatedAt(string $value)
  * @method \Magento\Sales\Model\Order\Invoice setSendEmail(bool $value)
  * @method \Magento\Sales\Model\Order\Invoice setCustomerNote(string $value)
  * @method string getCustomerNote()
@@ -626,6 +625,14 @@ class Shipment extends AbstractModel implements EntityInterface, ShipmentInterfa
         return $this->getData(ShipmentInterface::CREATED_AT);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(ShipmentInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * Returns customer_id
      *
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Comment.php b/app/code/Magento/Sales/Model/Order/Shipment/Comment.php
index 43361d79d59c4a4b6e403a7b0c7677ba1dbc1784..d1e9a5ac880bce77a0cef548f077e6e09ce754e7 100644
--- a/app/code/Magento/Sales/Model/Order/Shipment/Comment.php
+++ b/app/code/Magento/Sales/Model/Order/Shipment/Comment.php
@@ -12,7 +12,6 @@ use Magento\Sales\Model\AbstractModel;
 /**
  * @method \Magento\Sales\Model\Resource\Order\Shipment\Comment _getResource()
  * @method \Magento\Sales\Model\Resource\Order\Shipment\Comment getResource()
- * @method \Magento\Sales\Model\Order\Shipment\Comment setCreatedAt(string $value)
  */
 class Comment extends AbstractModel implements ShipmentCommentInterface
 {
@@ -126,6 +125,14 @@ class Comment extends AbstractModel implements ShipmentCommentInterface
         return $this->getData(ShipmentCommentInterface::CREATED_AT);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(ShipmentCommentInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * Returns is_customer_notified
      *
diff --git a/app/code/Magento/Sales/Model/Order/Shipment/Track.php b/app/code/Magento/Sales/Model/Order/Shipment/Track.php
index 325c9837bee51bc906c55afdc3d172c9da8966f3..f5b15181cb8fcb89a5ddb301b28a4290573010ec 100644
--- a/app/code/Magento/Sales/Model/Order/Shipment/Track.php
+++ b/app/code/Magento/Sales/Model/Order/Shipment/Track.php
@@ -12,7 +12,6 @@ use Magento\Sales\Model\AbstractModel;
 /**
  * @method \Magento\Sales\Model\Resource\Order\Shipment\Track _getResource()
  * @method \Magento\Sales\Model\Resource\Order\Shipment\Track getResource()
- * @method \Magento\Sales\Model\Order\Shipment\Track setCreatedAt(string $value)
  *
  * @author      Magento Core Team <core@magentocommerce.com>
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -232,6 +231,14 @@ class Track extends AbstractModel implements ShipmentTrackInterface
         return $this->getData(ShipmentTrackInterface::CREATED_AT);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(ShipmentTrackInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * Returns description
      *
diff --git a/app/code/Magento/Sales/Model/Order/Status/History.php b/app/code/Magento/Sales/Model/Order/Status/History.php
index edd828956c8241f11fcc8d929f4618a36d75e858..b442ebba05f7df7af8691e42949e79c174b0cb74 100644
--- a/app/code/Magento/Sales/Model/Order/Status/History.php
+++ b/app/code/Magento/Sales/Model/Order/Status/History.php
@@ -14,7 +14,6 @@ use Magento\Sales\Model\AbstractModel;
  *
  * @method \Magento\Sales\Model\Resource\Order\Status\History _getResource()
  * @method \Magento\Sales\Model\Resource\Order\Status\History getResource()
- * @method \Magento\Sales\Model\Order\Status\History setCreatedAt(string $value)
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class History extends AbstractModel implements OrderStatusHistoryInterface
@@ -196,6 +195,14 @@ class History extends AbstractModel implements OrderStatusHistoryInterface
         return $this->getData(OrderStatusHistoryInterface::CREATED_AT);
     }
 
+    /**
+     * {@inheritdoc}
+     */
+    public function setCreatedAt($createdAt)
+    {
+        return $this->setData(OrderStatusHistoryInterface::CREATED_AT, $createdAt);
+    }
+
     /**
      * Returns entity_id
      *
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Config/Backend/Email/AsyncSendingTest.php b/app/code/Magento/Sales/Test/Unit/Model/Config/Backend/Email/AsyncSendingTest.php
index 69f3f6e0df310d27dc7c7c6774ad5a62ca1e82cb..9359af03ee68dfcb020c7e7ed1a9923bd4d456ec 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Config/Backend/Email/AsyncSendingTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Config/Backend/Email/AsyncSendingTest.php
@@ -63,7 +63,7 @@ class AsyncSendingTest extends \PHPUnit_Framework_TestCase
     public function testAfterSave($value, $oldValue, $eventName)
     {
         $path = 'sales_email/general/async_sending';
-        $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT;
+        $scope = \Magento\Framework\App\Config\ScopeConfigInterface::SCOPE_TYPE_DEFAULT;
 
         $this->object->setData(['value' => $value, 'path' => $path, 'scope' => $scope]);
 
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Config/Backend/Grid/AsyncIndexingTest.php b/app/code/Magento/Sales/Test/Unit/Model/Config/Backend/Grid/AsyncIndexingTest.php
index 972cfae38e2ae4273235a2c7a7d1ac260b4f45a3..729c19940ccff8b5f464eeeb895bc74e5aeafa16 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Config/Backend/Grid/AsyncIndexingTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Config/Backend/Grid/AsyncIndexingTest.php
@@ -63,7 +63,7 @@ class AsyncIndexingTest extends \PHPUnit_Framework_TestCase
     public function testAfterSave($value, $oldValue, $eventName)
     {
         $path = 'dev/grid/async_indexing';
-        $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT;
+        $scope = \Magento\Framework\App\Config\ScopeConfigInterface::SCOPE_TYPE_DEFAULT;
 
         $this->object->setData(['value' => $value, 'path' => $path, 'scope' => $scope]);
 
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/AbstractSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/AbstractSenderTest.php
index 63ef953d756f00967ade66140431bef520989812..9c53a0c259652bf65b4f4d89f33e99c7cd9ef018 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/AbstractSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/AbstractSenderTest.php
@@ -157,14 +157,20 @@ abstract class AbstractSenderTest extends \PHPUnit_Framework_TestCase
         );
     }
 
-    public function stepAddressFormat($billingAddress)
+    public function stepAddressFormat($billingAddress, $isVirtual = false)
     {
         $this->orderMock->expects($this->any())
             ->method('getBillingAddress')
             ->will($this->returnValue($billingAddress));
-        $this->orderMock->expects($this->any())
-            ->method('getShippingAddress')
-            ->will($this->returnValue($billingAddress));
+        if ($isVirtual) {
+            $this->orderMock->expects($this->never())
+                ->method('getShippingAddress');
+        } else {
+            $this->orderMock->expects($this->once())
+                ->method('getShippingAddress')
+                ->will($this->returnValue($billingAddress));
+        }
+
     }
 
     public function stepSendWithoutSendCopy()
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoCommentSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoCommentSenderTest.php
index fe968f3f76438091ba4fb4d99e0901c0c1d6ebc1..5b836126a46526e5815f2b9ab575c6497dc52f71 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoCommentSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoCommentSenderTest.php
@@ -58,6 +58,30 @@ class CreditmemoCommentSenderTest extends AbstractSenderTest
         $this->assertFalse($result);
     }
 
+    public function testSendVirtualOrder()
+    {
+        $this->orderMock->setData(\Magento\Sales\Api\Data\OrderInterface::IS_VIRTUAL, true);
+        $billingAddress = $this->addressMock;
+        $this->templateContainerMock->expects($this->once())
+            ->method('setTemplateVars')
+            ->with(
+                $this->equalTo(
+                    [
+                        'order' => $this->orderMock,
+                        'creditmemo' => $this->creditmemoMock,
+                        'comment' => '',
+                        'billing' => $billingAddress,
+                        'store' => $this->storeMock,
+                        'formattedShippingAddress' => null,
+                        'formattedBillingAddress' => 1
+                    ]
+                )
+            );
+        $this->stepAddressFormat($billingAddress, true);
+        $result = $this->sender->send($this->creditmemoMock);
+        $this->assertFalse($result);
+    }
+
     public function testSendTrueWithCustomerCopy()
     {
         $billingAddress = $this->addressMock;
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoSenderTest.php
index c42216226dae0a6f5fe4df3b75de089ff8229532..1c7f98c3a1228dfed39e86762608cb04025f0732 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/CreditmemoSenderTest.php
@@ -70,10 +70,10 @@ class CreditmemoSenderTest extends AbstractSenderTest
             $this->identityContainerMock,
             $this->senderBuilderFactoryMock,
             $this->loggerMock,
+            $this->addressRenderer,
             $this->paymentHelper,
             $this->creditmemoResourceMock,
             $this->globalConfig,
-            $this->addressRenderer,
             $this->eventManagerMock
         );
     }
@@ -111,18 +111,13 @@ class CreditmemoSenderTest extends AbstractSenderTest
                 false
             );
 
-            $this->addressRenderer->expects($this->any())
+            $this->addressRenderer->expects($this->exactly(2))
                 ->method('format')
                 ->with($addressMock, 'html')
                 ->willReturn($address);
 
-            $this->orderMock->expects($this->any())
-                ->method('getBillingAddress')
-                ->willReturn($addressMock);
 
-            $this->orderMock->expects($this->any())
-                ->method('getShippingAddress')
-                ->willReturn($addressMock);
+            $this->stepAddressFormat($addressMock);
 
             $this->creditmemoMock->expects($this->once())
                 ->method('getCustomerNoteNotify')
@@ -206,4 +201,75 @@ class CreditmemoSenderTest extends AbstractSenderTest
             [1, null, null, null]
         ];
     }
+
+    /**
+     * @param bool $isVirtualOrder
+     * @param int $formatCallCount
+     * @param string|null $expectedShippingAddress
+     * @dataProvider sendVirtualOrderDataProvider
+     */
+    public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expectedShippingAddress)
+    {
+        $billingAddress = 'address_test';
+
+        $this->orderMock->setData(\Magento\Sales\Api\Data\OrderInterface::IS_VIRTUAL, $isVirtualOrder);
+
+        $this->creditmemoMock->expects($this->once())
+            ->method('setSendEmail')
+            ->with(true);
+
+        $this->globalConfig->expects($this->once())
+            ->method('getValue')
+            ->with('sales_email/general/async_sending')
+            ->willReturn(false);
+
+        $addressMock = $this->getMock('Magento\Sales\Model\Order\Address', [], [], '', false);
+
+        $this->addressRenderer->expects($this->exactly($formatCallCount))
+            ->method('format')
+            ->with($addressMock, 'html')
+            ->willReturn($billingAddress);
+
+        $this->stepAddressFormat($addressMock, $isVirtualOrder);
+
+        $this->creditmemoMock->expects($this->once())
+            ->method('getCustomerNoteNotify')
+            ->willReturn(true);
+
+        $this->templateContainerMock->expects($this->once())
+            ->method('setTemplateVars')
+            ->with(
+                [
+                    'order' => $this->orderMock,
+                    'creditmemo' => $this->creditmemoMock,
+                    'comment' => '',
+                    'billing' => $addressMock,
+                    'payment_html' => 'payment',
+                    'store' => $this->storeMock,
+                    'formattedShippingAddress' => $expectedShippingAddress,
+                    'formattedBillingAddress' => $billingAddress
+                ]
+            );
+
+        $this->identityContainerMock->expects($this->once())
+            ->method('isEnabled')
+            ->willReturn(false);
+
+        $this->creditmemoResourceMock->expects($this->once())
+            ->method('saveAttribute')
+            ->with($this->creditmemoMock, 'send_email');
+
+        $this->assertFalse($this->sender->send($this->creditmemoMock));
+    }
+
+    /**
+     * @return array
+     */
+    public function sendVirtualOrderDataProvider()
+    {
+        return [
+            [true, 1, null],
+            [false, 2, 'address_test']
+        ];
+    }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceCommentSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceCommentSenderTest.php
index 4670ec2824ecb03e26ba446871b1cb7e24c0c28d..0e44676e83d84a3c00820fa5e4cb1031d0fa8a10 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceCommentSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceCommentSenderTest.php
@@ -136,4 +136,31 @@ class InvoiceCommentSenderTest extends AbstractSenderTest
         $result = $this->sender->send($this->invoiceMock, false, $comment);
         $this->assertTrue($result);
     }
+
+    public function testSendVirtualOrder()
+    {
+        $isVirtualOrder = true;
+        $this->orderMock->setData(\Magento\Sales\Api\Data\OrderInterface::IS_VIRTUAL, $isVirtualOrder);
+        $this->stepAddressFormat($this->addressMock, $isVirtualOrder);
+
+        $this->identityContainerMock->expects($this->once())
+            ->method('isEnabled')
+            ->will($this->returnValue(false));
+        $this->templateContainerMock->expects($this->once())
+            ->method('setTemplateVars')
+            ->with(
+                $this->equalTo(
+                    [
+                        'order' => $this->orderMock,
+                        'invoice' => $this->invoiceMock,
+                        'billing' => $this->addressMock,
+                        'comment' => '',
+                        'store' => $this->storeMock,
+                        'formattedShippingAddress' => null,
+                        'formattedBillingAddress' => 1
+                    ]
+                )
+            );
+        $this->assertFalse($this->sender->send($this->invoiceMock));
+    }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceSenderTest.php
index 8ca7f14f25b291edbd91de51f28540ea4a48c8db..af477dce80a846e014d8559d1f290dea2ead066d 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/InvoiceSenderTest.php
@@ -70,10 +70,10 @@ class InvoiceSenderTest extends AbstractSenderTest
             $this->identityContainerMock,
             $this->senderBuilderFactoryMock,
             $this->loggerMock,
+            $this->addressRenderer,
             $this->paymentHelper,
             $this->invoiceResourceMock,
             $this->globalConfig,
-            $this->addressRenderer,
             $this->eventManagerMock
         );
     }
@@ -206,4 +206,75 @@ class InvoiceSenderTest extends AbstractSenderTest
             [1, null, null, null]
         ];
     }
+
+    /**
+     * @param bool $isVirtualOrder
+     * @param int $formatCallCount
+     * @param string|null $expectedShippingAddress
+     * @dataProvider sendVirtualOrderDataProvider
+     */
+    public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expectedShippingAddress)
+    {
+        $billingAddress = 'address_test';
+        $this->orderMock->setData(\Magento\Sales\Api\Data\OrderInterface::IS_VIRTUAL, $isVirtualOrder);
+
+        $this->invoiceMock->expects($this->once())
+            ->method('setSendEmail')
+            ->with(true);
+
+        $this->globalConfig->expects($this->once())
+            ->method('getValue')
+            ->with('sales_email/general/async_sending')
+            ->willReturn(false);
+
+        $addressMock = $this->getMock('Magento\Sales\Model\Order\Address', [], [], '', false);
+
+        $this->addressRenderer->expects($this->exactly($formatCallCount))
+            ->method('format')
+            ->with($addressMock, 'html')
+            ->willReturn($billingAddress);
+
+        $this->stepAddressFormat($addressMock, $isVirtualOrder);
+
+        $this->invoiceMock->expects($this->once())
+            ->method('getCustomerNoteNotify')
+            ->willReturn(false);
+
+        $this->templateContainerMock->expects($this->once())
+            ->method('setTemplateVars')
+            ->with(
+                [
+                    'order' => $this->orderMock,
+                    'invoice' => $this->invoiceMock,
+                    'comment' => '',
+                    'billing' => $addressMock,
+                    'payment_html' => 'payment',
+                    'store' => $this->storeMock,
+                    'formattedShippingAddress' => $expectedShippingAddress,
+                    'formattedBillingAddress' => $billingAddress
+                ]
+            );
+
+        $this->identityContainerMock->expects($this->once())
+            ->method('isEnabled')
+            ->willReturn(false);
+
+
+        $this->invoiceResourceMock->expects($this->once())
+            ->method('saveAttribute')
+            ->with($this->invoiceMock, 'send_email');
+
+        $this->assertFalse($this->sender->send($this->invoiceMock));
+    }
+
+    /**
+     * @return array
+     */
+    public function sendVirtualOrderDataProvider()
+    {
+        return [
+            [true, 1, null],
+            [false, 2, 'address_test']
+        ];
+    }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderCommentSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderCommentSenderTest.php
index 3b7c92d55986fb7f5435f7210c25b0d412b85e5e..f27d9663b624ef5962ef8bb49e8e4ba8b0941266 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderCommentSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderCommentSenderTest.php
@@ -67,4 +67,30 @@ class OrderCommentSenderTest extends AbstractSenderTest
         $result = $this->sender->send($this->orderMock, true, $comment);
         $this->assertTrue($result);
     }
+
+    public function testSendVirtualOrder()
+    {
+        $isVirtualOrder = true;
+        $this->orderMock->setData(\Magento\Sales\Api\Data\OrderInterface::IS_VIRTUAL, $isVirtualOrder);
+        $this->stepAddressFormat($this->addressMock, $isVirtualOrder);
+
+        $this->identityContainerMock->expects($this->once())
+            ->method('isEnabled')
+            ->will($this->returnValue(false));
+        $this->templateContainerMock->expects($this->once())
+            ->method('setTemplateVars')
+            ->with(
+                $this->equalTo(
+                    [
+                        'order' => $this->orderMock,
+                        'comment' => '',
+                        'billing' => $this->addressMock,
+                        'store' => $this->storeMock,
+                        'formattedShippingAddress' => null,
+                        'formattedBillingAddress' => 1
+                    ]
+                )
+            );
+        $this->assertFalse($this->sender->send($this->orderMock));
+    }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderSenderTest.php
index 7de676a36f9281413f0d008e44de723d0de385f5..2e692ca7dc6cc602040988ebb805e8507c266671 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/OrderSenderTest.php
@@ -47,10 +47,10 @@ class OrderSenderTest extends AbstractSenderTest
             $this->identityContainerMock,
             $this->senderBuilderFactoryMock,
             $this->loggerMock,
+            $this->addressRenderer,
             $this->paymentHelper,
             $this->orderResourceMock,
             $this->globalConfig,
-            $this->addressRenderer,
             $this->eventManagerMock
         );
     }
@@ -170,4 +170,80 @@ class OrderSenderTest extends AbstractSenderTest
             [1, null, null, null]
         ];
     }
+
+    /**
+     * @param bool $isVirtualOrder
+     * @param int $formatCallCount
+     * @param string|null $expectedShippingAddress
+     * @dataProvider sendVirtualOrderDataProvider
+     */
+    public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expectedShippingAddress)
+    {
+        $address = 'address_test';
+        $this->orderMock->setData(\Magento\Sales\Api\Data\OrderInterface::IS_VIRTUAL, $isVirtualOrder);
+
+        $this->orderMock->expects($this->once())
+            ->method('setSendEmail')
+            ->with(true);
+
+        $this->globalConfig->expects($this->once())
+            ->method('getValue')
+            ->with('sales_email/general/async_sending')
+            ->willReturn(false);
+
+        $this->identityContainerMock->expects($this->once())
+            ->method('isEnabled')
+            ->willReturn(true);
+
+        $addressMock = $this->getMock('Magento\Sales\Model\Order\Address', [], [], '', false);
+
+        $this->addressRenderer->expects($this->exactly($formatCallCount))
+            ->method('format')
+            ->with($addressMock, 'html')
+            ->willReturn($address);
+
+        $this->stepAddressFormat($addressMock, $isVirtualOrder);
+
+        $this->templateContainerMock->expects($this->once())
+            ->method('setTemplateVars')
+            ->with(
+                [
+                    'order' => $this->orderMock,
+                    'billing' => $addressMock,
+                    'payment_html' => 'payment',
+                    'store' => $this->storeMock,
+                    'formattedShippingAddress' => $expectedShippingAddress,
+                    'formattedBillingAddress' => $address
+                ]
+            );
+
+        $this->senderBuilderFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($this->senderMock);
+
+        $this->senderMock->expects($this->once())->method('send');
+
+        $this->senderMock->expects($this->once())->method('sendCopyTo');
+
+        $this->orderMock->expects($this->once())
+            ->method('setEmailSent')
+            ->with(true);
+
+        $this->orderResourceMock->expects($this->once())
+            ->method('saveAttribute')
+            ->with($this->orderMock, ['send_email', 'email_sent']);
+
+        $this->assertTrue($this->sender->send($this->orderMock));
+    }
+
+    /**
+     * @return array
+     */
+    public function sendVirtualOrderDataProvider()
+    {
+        return [
+            [true, 1, null],
+            [false, 2, 'address_test']
+        ];
+    }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentCommentSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentCommentSenderTest.php
index 7351b1444b6691440f087a99ed05fdb2db6b00e8..c5bf14edaad133f2162a683a8575550bc3ba634c 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentCommentSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentCommentSenderTest.php
@@ -120,4 +120,31 @@ class ShipmentCommentSenderTest extends AbstractSenderTest
         $result = $this->sender->send($this->shipmentMock, false, $comment);
         $this->assertTrue($result);
     }
+
+    public function testSendVirtualOrder()
+    {
+        $isVirtualOrder = true;
+        $this->orderMock->setData(\Magento\Sales\Api\Data\OrderInterface::IS_VIRTUAL, $isVirtualOrder);
+        $this->stepAddressFormat($this->addressMock, $isVirtualOrder);
+
+        $this->identityContainerMock->expects($this->once())
+            ->method('isEnabled')
+            ->will($this->returnValue(false));
+        $this->templateContainerMock->expects($this->once())
+            ->method('setTemplateVars')
+            ->with(
+                $this->equalTo(
+                    [
+                        'order' => $this->orderMock,
+                        'shipment' => $this->shipmentMock,
+                        'billing' => $this->addressMock,
+                        'comment' => '',
+                        'store' => $this->storeMock,
+                        'formattedShippingAddress' => null,
+                        'formattedBillingAddress' => 1
+                    ]
+                )
+            );
+        $this->assertFalse($this->sender->send($this->shipmentMock));
+    }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentSenderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentSenderTest.php
index 89fab376003d21eb36bf6c702785584abab2a861..19572f23533a6bdefba08194271576a8b9050d4c 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentSenderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Order/Email/Sender/ShipmentSenderTest.php
@@ -70,10 +70,10 @@ class ShipmentSenderTest extends AbstractSenderTest
             $this->identityContainerMock,
             $this->senderBuilderFactoryMock,
             $this->loggerMock,
+            $this->addressRenderer,
             $this->paymentHelper,
             $this->shipmentResourceMock,
             $this->globalConfig,
-            $this->addressRenderer,
             $this->eventManagerMock
         );
     }
@@ -206,4 +206,73 @@ class ShipmentSenderTest extends AbstractSenderTest
             [1, null, null, null]
         ];
     }
+
+    /**
+     * @param bool $isVirtualOrder
+     * @param int $formatCallCount
+     * @param string|null $expectedShippingAddress
+     * @dataProvider sendVirtualOrderDataProvider
+     */
+    public function testSendVirtualOrder($isVirtualOrder, $formatCallCount, $expectedShippingAddress)
+    {
+        $address = 'address_test';
+        $this->orderMock->setData(\Magento\Sales\Api\Data\OrderInterface::IS_VIRTUAL, $isVirtualOrder);
+
+        $this->shipmentMock->expects($this->once())
+            ->method('setSendEmail')
+            ->with(true);
+
+        $this->globalConfig->expects($this->once())
+            ->method('getValue')
+            ->with('sales_email/general/async_sending')
+            ->willReturn(false);
+
+        $addressMock = $this->getMock('Magento\Sales\Model\Order\Address', [], [], '', false);
+
+        $this->addressRenderer->expects($this->exactly($formatCallCount))
+            ->method('format')
+            ->with($addressMock, 'html')
+            ->willReturn($address);
+
+        $this->stepAddressFormat($addressMock, $isVirtualOrder);
+
+        $this->shipmentMock->expects($this->once())
+            ->method('getCustomerNoteNotify')
+            ->willReturn(false);
+
+        $this->templateContainerMock->expects($this->once())
+            ->method('setTemplateVars')
+            ->with(
+                [
+                    'order' => $this->orderMock,
+                    'shipment' => $this->shipmentMock,
+                    'comment' => '',
+                    'billing' => $addressMock,
+                    'payment_html' => 'payment',
+                    'store' => $this->storeMock,
+                    'formattedShippingAddress' => $expectedShippingAddress,
+                    'formattedBillingAddress' => $address
+                ]
+            );
+
+        $this->identityContainerMock->expects($this->once())
+            ->method('isEnabled')
+            ->willReturn(false);
+        $this->shipmentResourceMock->expects($this->once())
+            ->method('saveAttribute')
+            ->with($this->shipmentMock, 'send_email');
+
+        $this->assertFalse($this->sender->send($this->shipmentMock));
+    }
+
+    /**
+     * @return array
+     */
+    public function sendVirtualOrderDataProvider()
+    {
+        return [
+            [true, 1, null],
+            [false, 2, 'address_test']
+        ];
+    }
 }
diff --git a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js
index 029a93e92456b0468571bb146a49c3aff2cc7ad0..f936da5c2516adf5ef34db62f334d811daf07adb 100644
--- a/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js
+++ b/app/code/Magento/Sales/view/adminhtml/web/order/create/scripts.js
@@ -32,6 +32,7 @@ AdminOrder.prototype = {
         this.productPriceBase = {};
         this.collectElementsValue = true;
         this.isOnlyVirtualProduct = false;
+        this.excludedPaymentMethods = [];
         Event.observe(window, 'load',  (function(){
             this.dataArea = new OrderFormArea('data', $(this.getAreaId('data')), this);
             this.itemsArea = Object.extend(new OrderFormArea('items', $(this.getAreaId('items')), this), {
@@ -74,6 +75,13 @@ AdminOrder.prototype = {
             this.areasLoaded();
             this.itemsArea.onLoad();
         }).bind(this));
+
+        jQuery('#edit_form')
+            .on('submitOrder', function(){
+                jQuery(this).trigger('realOrder');
+            })
+            .on('realOrder', this._realSubmit.bind(this));
+
     },
 
     areasLoaded: function(){
@@ -94,6 +102,10 @@ AdminOrder.prototype = {
         this.addresses = addresses;
     },
 
+    addExcludedPaymentMethod : function(method){
+        this.excludedPaymentMethods.push(method);
+    },
+
     setCustomerId : function(id){
         this.customerId = id;
         this.loadArea('header', true);
@@ -327,6 +339,7 @@ AdminOrder.prototype = {
     },
 
     switchPaymentMethod : function(method){
+        jQuery('#edit_form').trigger('changePaymentMethod', [method]);
         this.setPaymentMethod(method);
         var data = {};
         data['order[payment_method]'] = method;
@@ -354,6 +367,7 @@ AdminOrder.prototype = {
         }
 
         if ($('payment_form_'+method)){
+            jQuery('#' + this.getAreaId('billing_method')).trigger('contentUpdated');
             this.paymentMethod = method;
             var form = 'payment_form_'+method;
             [form + '_before', form, form + '_after'].each(function(el) {
@@ -394,6 +408,9 @@ AdminOrder.prototype = {
                 return false;
             }
         }
+        if (this.isPaymentValidationAvailable() == false) {
+            return false;
+        }
         var data = {};
         var fields = $('payment_form_' + currentMethod).select('input', 'select');
         for(var i=0;i<fields.length;i++){
@@ -1037,15 +1054,30 @@ AdminOrder.prototype = {
         if (!params.form_key) {
             params.form_key = FORM_KEY;
         }
-        var data = this.serializeData('order-billing_method');
-        if (data) {
-            data.each(function(value) {
-                params[value[0]] = value[1];
-            });
+
+        if (this.isPaymentValidationAvailable()) {
+            var data = this.serializeData('order-billing_method');
+            if (data) {
+                data.each(function(value) {
+                    params[value[0]] = value[1];
+                });
+            }
+        } else {
+            params['payment[method]'] = this.paymentMethod;
         }
         return params;
     },
 
+    /**
+     * Prevent from sending credit card information to server for some payment methods
+     *
+     * @returns {boolean}
+     */
+    isPaymentValidationAvailable : function(){
+        return ((typeof this.paymentMethod) == 'undefined'
+            || this.excludedPaymentMethods.indexOf(this.paymentMethod) == -1);
+    },
+
     serializeData : function(container){
         var fields = $(container).select('input', 'select', 'textarea');
         var data = Form.serializeElements(fields, true);
@@ -1068,7 +1100,11 @@ AdminOrder.prototype = {
 
     submit : function()
     {
-        // Temporary solution will be replaced after refactoring order functionality
+        jQuery('#edit_form').trigger('processStart');
+        jQuery('#edit_form').trigger('submitOrder');
+    },
+
+    _realSubmit: function () {
         var disableAndSave = function() {
             disableElements('save');
             jQuery('#edit_form').on('invalid-form.validate', function() {
@@ -1308,4 +1344,4 @@ ControlButton.prototype = {
     }
 };
 
-});
\ No newline at end of file
+});
diff --git a/app/code/Magento/Sales/view/frontend/layout/sales_order_print.xml b/app/code/Magento/Sales/view/frontend/layout/sales_order_print.xml
index d0b200edd474c325a3eb00217da3f9473c53783a..ef7f10aaacd09d308f802c733ad728880d3919b3 100644
--- a/app/code/Magento/Sales/view/frontend/layout/sales_order_print.xml
+++ b/app/code/Magento/Sales/view/frontend/layout/sales_order_print.xml
@@ -32,7 +32,7 @@
                     </block>
                 </block>
             </block>
-            <block class="Magento\Sales\Block\Order\PrintShipment" as="sales.order.print.info" name="sales.order.print.info" template="order/info.phtml"/>
+            <block class="Magento\Sales\Block\Order\Info" as="sales.order.print.info" name="sales.order.print.info" template="order/info.phtml"/>
         </referenceContainer>
         <block class="Magento\Framework\View\Element\Template" name="additional.product.info" template="Magento_Theme::template.phtml"/>
     </body>
diff --git a/app/code/Magento/Search/Model/SearchEngine.php b/app/code/Magento/Search/Model/SearchEngine.php
index c4d5c4787a17af5dbfd7f042da520650493642c3..f80e6bfd8796f2d6e2dae2901f27028964c97b6c 100644
--- a/app/code/Magento/Search/Model/SearchEngine.php
+++ b/app/code/Magento/Search/Model/SearchEngine.php
@@ -17,14 +17,21 @@ class SearchEngine implements SearchEngineInterface
     /**
      * @var AdapterInterface
      */
-    protected $adapter;
+    private $adapter = null;
+
+    /**
+     * Adapter factory
+     *
+     * @var AdapterFactory
+     */
+    private $adapterFactory;
 
     /**
      * @param AdapterFactory $adapterFactory
      */
     public function __construct(AdapterFactory $adapterFactory)
     {
-        $this->adapter = $adapterFactory->create();
+        $this->adapterFactory = $adapterFactory;
     }
 
     /**
@@ -32,6 +39,19 @@ class SearchEngine implements SearchEngineInterface
      */
     public function search(RequestInterface $request)
     {
-        return $this->adapter->query($request);
+        return $this->getAdapter()->query($request);
+    }
+
+    /**
+     * Get adapter
+     *
+     * @return AdapterInterface
+     */
+    protected function getAdapter()
+    {
+        if ($this->adapter === null) {
+            $this->adapter = $this->adapterFactory->create();
+        }
+        return $this->adapter;
     }
 }
diff --git a/app/code/Magento/Shipping/Model/Order/Track.php b/app/code/Magento/Shipping/Model/Order/Track.php
index 81b506a7d10d9a821df999357d74a3c914feb8a9..9763f2bdb6e49035dd9b5d16b0677b635b6dd39b 100644
--- a/app/code/Magento/Shipping/Model/Order/Track.php
+++ b/app/code/Magento/Shipping/Model/Order/Track.php
@@ -19,7 +19,6 @@ use Magento\Framework\Api\AttributeValueFactory;
  * @method string getTitle()
  * @method string getCarrierCode()
  * @method string getCreatedAt()
- * @method \Magento\Sales\Model\Order\Shipment\Track setCreatedAt(string $value)
  * @method string getUpdatedAt()
  * @method \Magento\Sales\Api\Data\ShipmentTrackExtensionInterface getExtensionAttributes()
  */
diff --git a/app/code/Magento/Store/Model/Config/Reader/DefaultReader.php b/app/code/Magento/Store/Model/Config/Reader/DefaultReader.php
index 4f03885e8cd7a910cb35abf05970bd86deb5a790..7bb9981369440c9c8062ffe6308376c8b089a05f 100644
--- a/app/code/Magento/Store/Model/Config/Reader/DefaultReader.php
+++ b/app/code/Magento/Store/Model/Config/Reader/DefaultReader.php
@@ -7,6 +7,9 @@
  */
 namespace Magento\Store\Model\Config\Reader;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Framework\Exception\LocalizedException;
+
 class DefaultReader implements \Magento\Framework\App\Config\Scope\ReaderInterface
 {
     /**
@@ -42,14 +45,21 @@ class DefaultReader implements \Magento\Framework\App\Config\Scope\ReaderInterfa
     /**
      * Read configuration data
      *
+     * @param null|string $scope
+     * @throws LocalizedException Exception is thrown when scope other than default is given
      * @return array
      */
-    public function read()
+    public function read($scope = null)
     {
-        $config = $this->_initialConfig->getData(\Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT);
+        $scope = $scope === null ? ScopeConfigInterface::SCOPE_TYPE_DEFAULT : $scope;
+        if ($scope !== ScopeConfigInterface::SCOPE_TYPE_DEFAULT) {
+            throw new \Magento\Framework\Exception\LocalizedException(__("Only default scope allowed"));
+        }
+
+        $config = $this->_initialConfig->getData($scope);
 
         $collection = $this->_collectionFactory->create(
-            ['scope' => \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT]
+            ['scope' => $scope]
         );
         $dbDefaultConfig = [];
         foreach ($collection as $item) {
diff --git a/app/code/Magento/Store/Model/Config/Reader/Store.php b/app/code/Magento/Store/Model/Config/Reader/Store.php
index c5456bcb102f9ad2952c17f33ac41f48c1ae777a..151c3625f2b1dbf596d222eaf10b3f7c9e07ce5e 100644
--- a/app/code/Magento/Store/Model/Config/Reader/Store.php
+++ b/app/code/Magento/Store/Model/Config/Reader/Store.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Store\Model\Config\Reader;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\Exception\NoSuchEntityException;
 
 class Store implements \Magento\Framework\App\Config\Scope\ReaderInterface
@@ -66,7 +67,7 @@ class Store implements \Magento\Framework\App\Config\Scope\ReaderInterface
     /**
      * Read configuration by code
      *
-     * @param string $code
+     * @param null|string $code
      * @return array
      * @throws NoSuchEntityException
      */
@@ -74,7 +75,7 @@ class Store implements \Magento\Framework\App\Config\Scope\ReaderInterface
     {
         if (empty($code)) {
             $store = $this->_storeManager->getStore();
-        } elseif (($code == \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT)) {
+        } elseif (($code == ScopeConfigInterface::SCOPE_TYPE_DEFAULT)) {
             $store = $this->_storeManager->getDefaultStoreView();
         } else {
             $store = $this->_storeFactory->create();
diff --git a/app/code/Magento/Store/Model/Config/Reader/Website.php b/app/code/Magento/Store/Model/Config/Reader/Website.php
index 1448b04bf9afbf5e6b49b5e223f53b9ec2a52f69..7971deb6c9713199cfe7c85617ebe767556edb18 100644
--- a/app/code/Magento/Store/Model/Config/Reader/Website.php
+++ b/app/code/Magento/Store/Model/Config/Reader/Website.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Store\Model\Config\Reader;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 class Website implements \Magento\Framework\App\Config\Scope\ReaderInterface
 {
     /**
@@ -62,7 +64,7 @@ class Website implements \Magento\Framework\App\Config\Scope\ReaderInterface
     public function read($code = null)
     {
         $config = array_replace_recursive(
-            $this->_scopePool->getScope(\Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT)->getSource(),
+            $this->_scopePool->getScope(ScopeConfigInterface::SCOPE_TYPE_DEFAULT)->getSource(),
             $this->_initialConfig->getData("websites|{$code}")
         );
 
diff --git a/app/code/Magento/Store/Model/Store.php b/app/code/Magento/Store/Model/Store.php
index 1da41cae73e20593dcdc498b6b4a1bc94bb5a0b6..494d1c129254154208d81e6956d72027003f9dc4 100644
--- a/app/code/Magento/Store/Model/Store.php
+++ b/app/code/Magento/Store/Model/Store.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Store\Model;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\App\Filesystem\DirectoryList;
 use Magento\Framework\App\Http\Context;
 use Magento\Framework\Model\AbstractModel;
@@ -55,7 +56,7 @@ class Store extends AbstractModel implements
     const XML_PATH_UNSECURE_BASE_URL = 'web/unsecure/base_url';
 
     const XML_PATH_SECURE_BASE_URL = 'web/secure/base_url';
-    
+
     const XML_PATH_SECURE_IN_FRONTEND = 'web/secure/use_in_frontend';
 
     const XML_PATH_SECURE_IN_ADMINHTML = 'web/secure/use_in_adminhtml';
@@ -479,7 +480,7 @@ class Store extends AbstractModel implements
     {
         $data = $this->_config->getValue($path, ScopeInterface::SCOPE_STORE, $this->getCode());
         if (!$data) {
-            $data = $this->_config->getValue($path, \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT);
+            $data = $this->_config->getValue($path, ScopeConfigInterface::SCOPE_TYPE_DEFAULT);
         }
         return $data === false ? null : $data;
     }
@@ -788,7 +789,7 @@ class Store extends AbstractModel implements
         if ($configValue == self::PRICE_SCOPE_GLOBAL) {
             return $this->_config->getValue(
                 \Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE,
-                \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+                ScopeConfigInterface::SCOPE_TYPE_DEFAULT
             );
         } else {
             return $this->_getConfig(\Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE);
diff --git a/app/code/Magento/Store/Test/Unit/Model/Config/Reader/DefaultReaderTest.php b/app/code/Magento/Store/Test/Unit/Model/Config/Reader/DefaultReaderTest.php
index 9e91f4b43281522ac0a2d3688167488893df43e3..25875ae67dd5973525a0a59cbf7e2c1635c58691 100644
--- a/app/code/Magento/Store/Test/Unit/Model/Config/Reader/DefaultReaderTest.php
+++ b/app/code/Magento/Store/Test/Unit/Model/Config/Reader/DefaultReaderTest.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Store\Test\Unit\Model\Config\Reader;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 class DefaultReaderTest extends \PHPUnit_Framework_TestCase
 {
     /**
@@ -46,7 +48,7 @@ class DefaultReaderTest extends \PHPUnit_Framework_TestCase
         )->method(
             'getData'
         )->with(
-            \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+            ScopeConfigInterface::SCOPE_TYPE_DEFAULT
         )->will(
             $this->returnValue(['config' => ['key1' => 'default_value1', 'key2' => 'default_value2']])
         );
diff --git a/app/code/Magento/Store/Test/Unit/Model/StoreTest.php b/app/code/Magento/Store/Test/Unit/Model/StoreTest.php
index e9a6f8ecf7207c03889a4043d02168d18e6e5b72..8d305848c554f900bd521f04490c7b8f18fca6a4 100644
--- a/app/code/Magento/Store/Test/Unit/Model/StoreTest.php
+++ b/app/code/Magento/Store/Test/Unit/Model/StoreTest.php
@@ -8,6 +8,7 @@
 
 namespace Magento\Store\Test\Unit\Model;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Store\Model\ScopeInterface;
 use Magento\Framework\App\Config\ReinitableConfigInterface;
 use Magento\Store\Model\Store;
@@ -399,7 +400,7 @@ class StoreTest extends \PHPUnit_Framework_TestCase
                 ['catalog/price/scope', ScopeInterface::SCOPE_STORE, 'scope_code', $priceScope],
                 [
                     \Magento\Directory\Model\Currency::XML_PATH_CURRENCY_BASE,
-                    \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT,
+                    ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
                     null,
                     'USD'
                 ],
diff --git a/app/code/Magento/Store/etc/di.xml b/app/code/Magento/Store/etc/di.xml
index ebbc61f6036c8723c1fe943e07795097b63f1f6d..c1584145c2d3db3ad86924dd7ac6b0099155aa18 100644
--- a/app/code/Magento/Store/etc/di.xml
+++ b/app/code/Magento/Store/etc/di.xml
@@ -79,7 +79,7 @@
         <arguments>
             <argument name="session" xsi:type="object" shared="false">Magento\Framework\Session\Generic\Proxy</argument>
             <argument name="isCustomEntryPoint" xsi:type="init_parameter">Magento\Store\Model\Store::CUSTOM_ENTRY_POINT_PARAM</argument>
-            <argument name="url" xsi:type="object" shared="false">Magento\Framework\UrlInterface</argument>
+            <argument name="url" xsi:type="object" shared="false">Magento\Framework\UrlInterface\Proxy</argument>
         </arguments>
     </type>
     <type name="Magento\Store\Model\StoreManager">
diff --git a/app/code/Magento/Tax/Api/Data/AppliedTaxInterface.php b/app/code/Magento/Tax/Api/Data/AppliedTaxInterface.php
index 356d39d0bc106519315c3fa76da8321931c116fd..a5865871a5f59f25f9d72d624d277088d5f4ae41 100644
--- a/app/code/Magento/Tax/Api/Data/AppliedTaxInterface.php
+++ b/app/code/Magento/Tax/Api/Data/AppliedTaxInterface.php
@@ -7,18 +7,6 @@ namespace Magento\Tax\Api\Data;
 
 interface AppliedTaxInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     * Constants defined for keys of array, makes typos less likely
-     */
-    const KEY_TAX_RATE_KEY = 'tax_rate_key';
-
-    const KEY_PERCENT = 'percent';
-
-    const KEY_AMOUNT = 'amount';
-
-    const KEY_RATES = 'rates';
-    /**#@-*/
-
     /**
      * Get tax rate key
      *
diff --git a/app/code/Magento/Tax/Api/Data/AppliedTaxRateInterface.php b/app/code/Magento/Tax/Api/Data/AppliedTaxRateInterface.php
index cee4ab16fd1f0acdde90bd353b3d264e4ba52b11..afd3231335ea011e6daed2e0fa5537849c376362 100644
--- a/app/code/Magento/Tax/Api/Data/AppliedTaxRateInterface.php
+++ b/app/code/Magento/Tax/Api/Data/AppliedTaxRateInterface.php
@@ -8,16 +8,6 @@ namespace Magento\Tax\Api\Data;
 
 interface AppliedTaxRateInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     * Constants defined for keys of array, makes typos less likely
-     */
-    const KEY_CODE = 'code';
-
-    const KEY_TITLE = 'title';
-
-    const KEY_PERCENT = 'percent';
-    /**#@-*/
-
     /**
      * Get code
      *
diff --git a/app/code/Magento/Tax/Api/Data/OrderTaxDetailsAppliedTaxInterface.php b/app/code/Magento/Tax/Api/Data/OrderTaxDetailsAppliedTaxInterface.php
index 7123087eacf565f0341178e6f9643c9a98bf7036..603d287eabff739644b9ed7ada2d397b4c59d857 100644
--- a/app/code/Magento/Tax/Api/Data/OrderTaxDetailsAppliedTaxInterface.php
+++ b/app/code/Magento/Tax/Api/Data/OrderTaxDetailsAppliedTaxInterface.php
@@ -9,20 +9,6 @@ namespace Magento\Tax\Api\Data;
 
 interface OrderTaxDetailsAppliedTaxInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     * Constants defined for keys of array, makes typos less likely
-     */
-    const KEY_CODE = 'code';
-
-    const KEY_TITLE = 'title';
-
-    const KEY_PERCENT = 'percent';
-
-    const KEY_AMOUNT = 'amount';
-
-    const KEY_BASE_AMOUNT = 'base_amount';
-    /**#@-*/
-
     /**
      * Get code
      *
diff --git a/app/code/Magento/Tax/Api/Data/OrderTaxDetailsInterface.php b/app/code/Magento/Tax/Api/Data/OrderTaxDetailsInterface.php
index d68de6f5858aab5c3362c60d62a1d006bc22c42d..d57fb6ba5194faac79dbcddd4e0269adb81c6dae 100644
--- a/app/code/Magento/Tax/Api/Data/OrderTaxDetailsInterface.php
+++ b/app/code/Magento/Tax/Api/Data/OrderTaxDetailsInterface.php
@@ -9,10 +9,6 @@ namespace Magento\Tax\Api\Data;
 
 interface OrderTaxDetailsInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    const KEY_APPLIED_TAXES = 'applied_taxes';
-
-    const KEY_ITEMS = 'items';
-
     /**
      * Get applied taxes at order level
      *
diff --git a/app/code/Magento/Tax/Api/Data/OrderTaxDetailsItemInterface.php b/app/code/Magento/Tax/Api/Data/OrderTaxDetailsItemInterface.php
index 905a0aa203594097e5377130679dfb4e5bb18a92..a43d4ccd7dfc4b5f1f95ed1fbf29527bdea40e89 100644
--- a/app/code/Magento/Tax/Api/Data/OrderTaxDetailsItemInterface.php
+++ b/app/code/Magento/Tax/Api/Data/OrderTaxDetailsItemInterface.php
@@ -9,18 +9,6 @@ namespace Magento\Tax\Api\Data;
 
 interface OrderTaxDetailsItemInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     * Constants defined for keys of array, makes typos less likely
-     */
-    const KEY_TYPE = 'type';
-
-    const KEY_ITEM_ID = 'item_id';
-
-    const KEY_ASSOCIATED_ITEM_ID = 'associated_item_id';
-
-    const KEY_APPLIED_TAXES = 'applied_taxes';
-    /**#@-*/
-
     /**
      * Get type (shipping, product, weee, gift wrapping, etc)
      *
diff --git a/app/code/Magento/Tax/Api/Data/QuoteDetailsInterface.php b/app/code/Magento/Tax/Api/Data/QuoteDetailsInterface.php
index f7d69e1572f86eaecfad263eeeb026ebe8f280bc..b3250a1f7caa09419ffc35169ac0362ffdc2ef2a 100644
--- a/app/code/Magento/Tax/Api/Data/QuoteDetailsInterface.php
+++ b/app/code/Magento/Tax/Api/Data/QuoteDetailsInterface.php
@@ -9,22 +9,6 @@ namespace Magento\Tax\Api\Data;
 
 interface QuoteDetailsInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     * Constants defined for keys of array, makes typos less likely
-     */
-    const KEY_BILLING_ADDRESS = 'billing_address';
-
-    const KEY_SHIPPING_ADDRESS = 'shipping_address';
-
-    const KEY_CUSTOMER_TAX_CLASS_KEY = 'customer_tax_class_key';
-
-    const KEY_ITEMS = 'items';
-
-    const CUSTOMER_TAX_CLASS_ID = 'customer_tax_class_id';
-
-    const KEY_CUSTOMER_ID = 'customer_id';
-    /**#@-*/
-
     /**
      * Get customer billing address
      *
diff --git a/app/code/Magento/Tax/Api/Data/QuoteDetailsItemInterface.php b/app/code/Magento/Tax/Api/Data/QuoteDetailsItemInterface.php
index ea3e57327f3115581853572e3159628b600c31cd..daffa01d4f87651346965eab83a723e7f806df28 100644
--- a/app/code/Magento/Tax/Api/Data/QuoteDetailsItemInterface.php
+++ b/app/code/Magento/Tax/Api/Data/QuoteDetailsItemInterface.php
@@ -7,32 +7,6 @@ namespace Magento\Tax\Api\Data;
 
 interface QuoteDetailsItemInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     * Constants defined for keys of array, makes typos less likely
-     */
-    const KEY_CODE = 'code';
-
-    const KEY_TYPE = 'type';
-
-    const KEY_TAX_CLASS_KEY = 'tax_class_key';
-
-    const KEY_UNIT_PRICE = 'unit_price';
-
-    const KEY_QUANTITY = 'quantity';
-
-    const KEY_TAX_INCLUDED = 'tax_included';
-
-    const KEY_SHORT_DESCRIPTION = 'short_description';
-
-    const KEY_DISCOUNT_AMOUNT = 'discount_amount';
-
-    const KEY_PARENT_CODE = 'parent_code';
-
-    const KEY_ASSOCIATED_ITEM_CODE = 'associated_item_code';
-
-    const KEY_TAX_CLASS_ID = 'tax_class_id';
-    /**#@-*/
-
     /**
      * Get code (sku or shipping code)
      *
@@ -172,7 +146,7 @@ interface QuoteDetailsItemInterface extends \Magento\Framework\Api\ExtensibleDat
     /**
      * Get associated item code if this item is associated with another item, null otherwise
      *
-     * @return mixed|null
+     * @return int|null
      */
     public function getAssociatedItemCode();
 
diff --git a/app/code/Magento/Tax/Api/Data/TaxClassInterface.php b/app/code/Magento/Tax/Api/Data/TaxClassInterface.php
index 80774ef47c646bed3cb54e3813b7968c37536adc..632219c6ad66986690b0655198feceb4f271b0a5 100644
--- a/app/code/Magento/Tax/Api/Data/TaxClassInterface.php
+++ b/app/code/Magento/Tax/Api/Data/TaxClassInterface.php
@@ -9,15 +9,6 @@ namespace Magento\Tax\Api\Data;
 
 interface TaxClassInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     *
-     * Tax class field key.
-     */
-    const KEY_ID = 'class_id';
-    const KEY_NAME = 'class_name';
-    const KEY_TYPE = 'class_type';
-    /**#@-*/
-
     /**
      * Get tax class ID.
      *
diff --git a/app/code/Magento/Tax/Api/Data/TaxClassKeyInterface.php b/app/code/Magento/Tax/Api/Data/TaxClassKeyInterface.php
index 9f0a25a170cbadbd71ad8e1c1e7d7cd6de7d0c27..d6f5d742ad88069a9810c5f815a3a0ac8668f18a 100644
--- a/app/code/Magento/Tax/Api/Data/TaxClassKeyInterface.php
+++ b/app/code/Magento/Tax/Api/Data/TaxClassKeyInterface.php
@@ -10,19 +10,10 @@ use Magento\Framework\Api\ExtensibleDataInterface;
 
 interface TaxClassKeyInterface extends ExtensibleDataInterface
 {
-    /**#@+
-     * Constants defined for keys of array, makes typos less likely
-     */
-    const KEY_TYPE = 'type';
-
-    const KEY_VALUE = 'value';
-    /**#@-*/
-
     /**#@+
      * Constants defined for type of tax class key
      */
-    const TYPE_ID = 'id';
-
+    const TYPE_ID   = 'id';
     const TYPE_NAME = 'name';
     /**#@-*/
 
diff --git a/app/code/Magento/Tax/Api/Data/TaxDetailsInterface.php b/app/code/Magento/Tax/Api/Data/TaxDetailsInterface.php
index f06ba96bc54ca28a6ed4e167d48bbc4e553dcd15..ce0ae30e69e15cf434a0e034be6d913afc9cc245 100644
--- a/app/code/Magento/Tax/Api/Data/TaxDetailsInterface.php
+++ b/app/code/Magento/Tax/Api/Data/TaxDetailsInterface.php
@@ -8,21 +8,6 @@ namespace Magento\Tax\Api\Data;
 
 interface TaxDetailsInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     * Constants defined for keys of array, makes typos less likely
-     */
-    const KEY_SUBTOTAL = 'subtotal';
-
-    const KEY_TAX_AMOUNT = 'tax_amount';
-
-    const KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT = 'discount_tax_compensation_amount';
-
-    const KEY_APPLIED_TAXES = 'applied_taxes';
-
-    const KEY_ITEMS = 'items';
-
-    /**#@-*/
-
     /**
      * Get subtotal
      *
diff --git a/app/code/Magento/Tax/Api/Data/TaxDetailsItemInterface.php b/app/code/Magento/Tax/Api/Data/TaxDetailsItemInterface.php
index fad3229d7076a589363cbabf9f5bcb064984e04f..0550b6614dfc76ef111e29179a96551e476a831b 100644
--- a/app/code/Magento/Tax/Api/Data/TaxDetailsItemInterface.php
+++ b/app/code/Magento/Tax/Api/Data/TaxDetailsItemInterface.php
@@ -8,36 +8,6 @@ namespace Magento\Tax\Api\Data;
 
 interface TaxDetailsItemInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     * Constants defined for keys of array, makes typos less likely
-     */
-    const KEY_CODE = 'code';
-
-    const KEY_TYPE = 'type';
-
-    const KEY_TAX_PERCENT = 'tax_percent';
-
-    const KEY_PRICE = 'price';
-
-    const KEY_PRICE_INCL_TAX = 'price_incl_tax';
-
-    const KEY_ROW_TOTAL = 'row_total';
-
-    const KEY_ROW_TOTAL_INCL_TAX = 'row_total_incl_tax';
-
-    const KEY_ROW_TAX = 'row_tax';
-
-    const KEY_TAXABLE_AMOUNT = 'taxable_amount';
-
-    const KEY_DISCOUNT_AMOUNT = 'discount_amount';
-
-    const KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT = 'discount_tax_compensation_amount';
-
-    const KEY_APPLIED_TAXES = 'applied_taxes';
-
-    const KEY_ASSOCIATED_ITEM_CODE = 'associated_item_code';
-    /**#@-*/
-
     /**
      * Get code (sku or shipping code)
      *
@@ -221,7 +191,7 @@ interface TaxDetailsItemInterface extends \Magento\Framework\Api\ExtensibleDataI
     /**
      * Return associated item code if this item is associated with another item, null otherwise
      *
-     * @return mixed|null
+     * @return int|null
      */
     public function getAssociatedItemCode();
 
diff --git a/app/code/Magento/Tax/Api/Data/TaxRateInterface.php b/app/code/Magento/Tax/Api/Data/TaxRateInterface.php
index 881bb7fa7e013838c558f5514af373dcbe6fceaa..34cf62414862a644f928531ce9fafe996648c32e 100644
--- a/app/code/Magento/Tax/Api/Data/TaxRateInterface.php
+++ b/app/code/Magento/Tax/Api/Data/TaxRateInterface.php
@@ -9,22 +9,6 @@ namespace Magento\Tax\Api\Data;
 
 interface TaxRateInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     * Constants defined for keys of array, makes typos less likely
-     */
-    const KEY_ID = 'id';
-    const KEY_COUNTRY_ID = 'tax_country_id';
-    const KEY_REGION_ID = 'tax_region_id';
-    const KEY_REGION_NAME = 'region_name';
-    const KEY_POSTCODE = 'tax_postcode';
-    const KEY_ZIP_IS_RANGE = 'zip_is_range';
-    const KEY_ZIP_RANGE_FROM = 'zip_from';
-    const KEY_ZIP_RANGE_TO = 'zip_to';
-    const KEY_PERCENTAGE_RATE = 'rate';
-    const KEY_CODE = 'code';
-    const KEY_TITLES = 'titles';
-    /**#@-*/
-
     /**
      * Get id
      *
diff --git a/app/code/Magento/Tax/Api/Data/TaxRateTitleInterface.php b/app/code/Magento/Tax/Api/Data/TaxRateTitleInterface.php
index 8d3991070b9565d9527c7c036aca9e45864d15f4..7dcfd2413759636b184d8e6cac0a789d6ecfacee 100644
--- a/app/code/Magento/Tax/Api/Data/TaxRateTitleInterface.php
+++ b/app/code/Magento/Tax/Api/Data/TaxRateTitleInterface.php
@@ -9,15 +9,6 @@ namespace Magento\Tax\Api\Data;
 
 interface TaxRateTitleInterface extends \Magento\Framework\Api\ExtensibleDataInterface
 {
-    /**#@+
-     *
-     * Tax rate field key.
-     */
-    const KEY_STORE_ID = 'store_id';
-
-    const KEY_VALUE_ID = 'value';
-    /**#@-*/
-
     /**
      * Get store id
      *
diff --git a/app/code/Magento/Tax/Block/Adminhtml/Rate/Form.php b/app/code/Magento/Tax/Block/Adminhtml/Rate/Form.php
index 08a7803aa85474510a9135d22b7819dd4122c03c..84e32da4ae97439c3fbc7d8e8fccefc364b9f6cc 100644
--- a/app/code/Magento/Tax/Block/Adminhtml/Rate/Form.php
+++ b/app/code/Magento/Tax/Block/Adminhtml/Rate/Form.php
@@ -65,6 +65,11 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
      */
     protected $_taxRateCollection;
 
+    /**
+     * @var \Magento\Tax\Model\Calculation\Rate\Converter
+     */
+    protected $_taxRateConverter;
+
     /**
      * @param \Magento\Backend\Block\Template\Context $context
      * @param \Magento\Framework\Registry $registry
@@ -75,6 +80,7 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
      * @param \Magento\Tax\Helper\Data $taxData
      * @param \Magento\Tax\Api\TaxRateRepositoryInterface $taxRateRepository
      * @param \Magento\Tax\Model\TaxRateCollection $taxRateCollection
+     * @param \Magento\Tax\Model\Calculation\Rate\Converter $taxRateConverter
      * @param array $data
      * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
@@ -88,6 +94,7 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
         \Magento\Tax\Helper\Data $taxData,
         \Magento\Tax\Api\TaxRateRepositoryInterface $taxRateRepository,
         \Magento\Tax\Model\TaxRateCollection $taxRateCollection,
+        \Magento\Tax\Model\Calculation\Rate\Converter $taxRateConverter,
         array $data = []
     ) {
         $this->_regionFactory = $regionFactory;
@@ -96,6 +103,7 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
         $this->_taxData = $taxData;
         $this->_taxRateRepository = $taxRateRepository;
         $this->_taxRateCollection = $taxRateCollection;
+        $this->_taxRateConverter = $taxRateConverter;
         parent::__construct($context, $registry, $formFactory, $data);
     }
 
@@ -127,7 +135,7 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
         }
 
         $sessionFormValues = (array)$this->_coreRegistry->registry(RegistryConstants::CURRENT_TAX_RATE_FORM_DATA);
-        $formData = isset($taxRateDataObject) ? $this->extractTaxRateData($taxRateDataObject) : [];
+        $formData = isset($taxRateDataObject) ? $this->_taxRateConverter->createArrayFromServiceObject($taxRateDataObject) : [];
         $formData = array_merge($formData, $sessionFormValues);
 
         if (isset($formData['zip_is_range']) && $formData['zip_is_range'] && !isset($formData['tax_postcode'])) {
@@ -286,65 +294,4 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
 
         return parent::_prepareForm();
     }
-
-    /**
-     * Get Tax Rates Collection
-     *
-     * @return mixed
-     */
-    public function getRateCollection()
-    {
-        if ($this->getData('rate_collection') == null) {
-            $items = $this->_taxRateCollection->getItems();
-            $rates = [];
-            foreach ($items as $rate) {
-                $rateData = $rate->getData();
-                if (isset($rateData['titles'])) {
-                    foreach ($rateData['titles'] as $storeId => $value) {
-                        $rateData['title[' . $storeId . ']'] = $value;
-                    }
-                }
-                unset($rateData['titles']);
-                $rates[] = $rateData;
-            }
-
-            $this->setRateCollection($rates);
-        }
-        return $this->getData('rate_collection');
-    }
-
-    /**
-     * Extract tax rate data in a format which is
-     *
-     * @param \Magento\Tax\Api\Data\TaxRateInterface $taxRate
-     * @return array
-     */
-    protected function extractTaxRateData($taxRate)
-    {
-        $formData = [
-            'tax_calculation_rate_id' => $taxRate->getId(),
-            'tax_country_id' => $taxRate->getTaxCountryId(),
-            'tax_region_id' => $taxRate->getTaxRegionId(),
-            'tax_postcode' => $taxRate->getTaxPostcode(),
-            'code' => $taxRate->getCode(),
-            'rate' => $taxRate->getRate(),
-            'zip_is_range' => false,
-        ];
-
-        if ($taxRate->getZipFrom() && $taxRate->getZipTo()) {
-            $formData['zip_is_range'] = true;
-            $formData['zip_from'] = $taxRate->getZipFrom();
-            $formData['zip_to'] = $taxRate->getZipTo();
-        }
-
-        if ($taxRate->getTitles()) {
-            $titleData = [];
-            foreach ($taxRate->getTitles() as $title) {
-                $titleData[] = [$title->getStoreId() => $title->getValue()];
-            }
-            $formData['title'] = $titleData;
-        }
-
-        return $formData;
-    }
 }
diff --git a/app/code/Magento/Tax/Block/Adminhtml/Rule/Edit/Form.php b/app/code/Magento/Tax/Block/Adminhtml/Rule/Edit/Form.php
index 0d2b16bee6f0dff1154bba3c025f3a0f9b0b541a..fb434ca6dd3092395c7df36a0f4cd1dfa0fdd222 100644
--- a/app/code/Magento/Tax/Block/Adminhtml/Rule/Edit/Form.php
+++ b/app/code/Magento/Tax/Block/Adminhtml/Rule/Edit/Form.php
@@ -297,6 +297,16 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
         return $this->getUrl('tax/rate/ajaxSave/');
     }
 
+    /**
+     * Retrieve Tax Rate load URL
+     *
+     * @return string
+     */
+    public function getTaxRateLoadUrl()
+    {
+        return $this->getUrl('tax/rate/ajaxLoad/');
+    }
+
     /**
      * Extract tax rule data in a format which is
      *
diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Rate.php b/app/code/Magento/Tax/Controller/Adminhtml/Rate.php
index 21a165edf65bf48964f43da33811e285fcbdfffe..e25e0a19a87a2752204de23adc90e6106e6c559e 100644
--- a/app/code/Magento/Tax/Controller/Adminhtml/Rate.php
+++ b/app/code/Magento/Tax/Controller/Adminhtml/Rate.php
@@ -21,38 +21,30 @@ class Rate extends \Magento\Backend\App\Action
     protected $_coreRegistry;
 
     /**
-     * @var \Magento\Tax\Api\TaxRateRepositoryInterface
+     * @var \Magento\Tax\Model\Calculation\Rate\Converter
      */
-    protected $_taxRateRepository;
+    protected $_taxRateConverter;
 
     /**
-     * @var \Magento\Tax\Api\Data\TaxRateInterfaceFactory
-     */
-    protected $_taxRateDataObjectFactory;
-
-    /**
-     * @var \Magento\Tax\Api\Data\TaxRateTitleInterfaceFactory
+     * @var \Magento\Tax\Api\TaxRateRepositoryInterface
      */
-    protected $_taxRateTitleDataObjectFactory;
+    protected $_taxRateRepository;
 
     /**
      * @param \Magento\Backend\App\Action\Context $context
      * @param \Magento\Framework\Registry $coreRegistry
+     * @param \Magento\Tax\Model\Calculation\Rate\Converter $taxRateConverter
      * @param \Magento\Tax\Api\TaxRateRepositoryInterface $taxRateRepository
-     * @param \Magento\Tax\Api\Data\TaxRateInterfaceFactory $taxRateDataObjectFactory
-     * @param \Magento\Tax\Api\Data\TaxRateTitleInterfaceFactory $taxRateTitleDataObjectFactory
      */
     public function __construct(
         \Magento\Backend\App\Action\Context $context,
         \Magento\Framework\Registry $coreRegistry,
-        \Magento\Tax\Api\TaxRateRepositoryInterface $taxRateRepository,
-        \Magento\Tax\Api\Data\TaxRateInterfaceFactory $taxRateDataObjectFactory,
-        \Magento\Tax\Api\Data\TaxRateTitleInterfaceFactory $taxRateTitleDataObjectFactory
+        \Magento\Tax\Model\Calculation\Rate\Converter $taxRateConverter,
+        \Magento\Tax\Api\TaxRateRepositoryInterface $taxRateRepository
     ) {
         $this->_coreRegistry = $coreRegistry;
+        $this->_taxRateConverter = $taxRateConverter;
         $this->_taxRateRepository = $taxRateRepository;
-        $this->_taxRateDataObjectFactory = $taxRateDataObjectFactory;
-        $this->_taxRateTitleDataObjectFactory = $taxRateTitleDataObjectFactory;
         parent::__construct($context);
     }
 
@@ -96,50 +88,4 @@ class Rate extends \Magento\Backend\App\Action
     {
         return $this->_authorization->isAllowed('Magento_Tax::manage_tax');
     }
-
-    /**
-     * Populate a tax rate data object
-     *
-     * @param array $formData
-     * @return \Magento\Tax\Api\Data\TaxRateInterface
-     */
-    protected function populateTaxRateData($formData)
-    {
-        $taxRate = $this->_taxRateDataObjectFactory->create();
-        $taxRate->setId($this->extractFormData($formData, 'tax_calculation_rate_id'))
-            ->setTaxCountryId($this->extractFormData($formData, 'tax_country_id'))
-            ->setTaxRegionId($this->extractFormData($formData, 'tax_region_id'))
-            ->setTaxPostcode($this->extractFormData($formData, 'tax_postcode'))
-            ->setCode($this->extractFormData($formData, 'code'))
-            ->setRate($this->extractFormData($formData, 'rate'));
-        if (isset($formData['zip_is_range']) && $formData['zip_is_range']) {
-            $taxRate->setZipFrom($this->extractFormData($formData, 'zip_from'))
-                ->setZipTo($this->extractFormData($formData, 'zip_to'))->setZipIsRange(1);
-        }
-
-        if (isset($formData['title'])) {
-            $titles = [];
-            foreach ($formData['title'] as $storeId => $value) {
-                $titles[] = $this->_taxRateTitleDataObjectFactory->create()->setStoreId($storeId)->setValue($value);
-            }
-            $taxRate->setTitles($titles);
-        }
-
-        return $taxRate;
-    }
-
-    /**
-     * Determines if an array value is set in the form data array and returns it.
-     *
-     * @param array $formData the form to get data from
-     * @param string $fieldName the key
-     * @return null|string
-     */
-    protected function extractFormData($formData, $fieldName)
-    {
-        if (isset($formData[$fieldName])) {
-            return $formData[$fieldName];
-        }
-        return null;
-    }
 }
diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Rate/AjaxLoad.php b/app/code/Magento/Tax/Controller/Adminhtml/Rate/AjaxLoad.php
new file mode 100755
index 0000000000000000000000000000000000000000..673ea280bab25ed504a240bfcddb25d1e2cbadfe
--- /dev/null
+++ b/app/code/Magento/Tax/Controller/Adminhtml/Rate/AjaxLoad.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Tax\Controller\Adminhtml\Rate;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Framework\Controller\ResultFactory;
+
+class AjaxLoad extends \Magento\Tax\Controller\Adminhtml\Rate
+{
+    /**
+     * Json needed for the Ajax Edit Form
+     *
+     * @return void
+     */
+    public function execute()
+    {
+        $rateId = (int)$this->getRequest()->getParam('id');
+        try {
+            /* @var \Magento\Tax\Api\Data\TaxRateInterface */
+            $taxRateDataObject = $this->_taxRateRepository->get($rateId);
+            /* @var array */
+            $resultArray= $this->_taxRateConverter->createArrayFromServiceObject($taxRateDataObject, true);
+
+            $responseContent = [
+                'success' => true,
+                'error_message' => '',
+                'result'=>$resultArray,
+                ];
+        } catch (NoSuchEntityException $e) {
+            $responseContent = [
+                'success' => false,
+                'error_message' => $e->getMessage(),
+            ];
+        } catch (\Exception $e) {
+            $responseContent = [
+                'success' => false,
+                'error_message' => __('An error occurred while loading this tax rate.'),
+            ];
+        }
+
+        /** @var \Magento\Framework\Controller\Result\Json $resultJson */
+        $resultJson = $this->resultFactory->create(ResultFactory::TYPE_JSON);
+        $resultJson->setData($responseContent);
+        return $resultJson;
+    }
+}
diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Rate/AjaxSave.php b/app/code/Magento/Tax/Controller/Adminhtml/Rate/AjaxSave.php
index fd5471314d2d7066ae4462d3276dfcf0c55bb193..32ba0758fbd58b291e036ec525b06c6c3c3242c4 100644
--- a/app/code/Magento/Tax/Controller/Adminhtml/Rate/AjaxSave.php
+++ b/app/code/Magento/Tax/Controller/Adminhtml/Rate/AjaxSave.php
@@ -20,7 +20,7 @@ class AjaxSave extends \Magento\Tax\Controller\Adminhtml\Rate
         try {
             $rateData = $this->_processRateData($this->getRequest()->getPostValue());
             /** @var \Magento\Tax\Api\Data\TaxRateInterface  $taxRate */
-            $taxRate = $this->populateTaxRateData($rateData);
+            $taxRate = $this->_taxRateConverter->populateTaxRateData($rateData);
             $this->_taxRateRepository->save($taxRate);
             $responseContent = [
                 'success' => true,
diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Rate/Save.php b/app/code/Magento/Tax/Controller/Adminhtml/Rate/Save.php
index e56a31a4d348942962cb96a04f4f598bbbdaf4f3..36dbcc284eabb831c206477b1da004c886686429 100644
--- a/app/code/Magento/Tax/Controller/Adminhtml/Rate/Save.php
+++ b/app/code/Magento/Tax/Controller/Adminhtml/Rate/Save.php
@@ -32,7 +32,7 @@ class Save extends \Magento\Tax\Controller\Adminhtml\Rate
             }
 
             try {
-                $taxData = $this->populateTaxRateData($ratePost);
+                $taxData = $this->_taxRateConverter->populateTaxRateData($ratePost);
                 $this->_taxRateRepository->save($taxData);
 
                 $this->messageManager->addSuccess(__('The tax rate has been saved.'));
diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php b/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php
index d84a09825b08fb4391830a6ec8261b24d152557a..9fede0b0238787abcc72a691b7473f588a90434b 100644
--- a/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php
+++ b/app/code/Magento/Tax/Controller/Adminhtml/Tax/IgnoreTaxNotification.php
@@ -6,6 +6,7 @@
  */
 namespace Magento\Tax\Controller\Adminhtml\Tax;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\Controller\ResultFactory;
 
 class IgnoreTaxNotification extends \Magento\Tax\Controller\Adminhtml\Tax
@@ -43,7 +44,7 @@ class IgnoreTaxNotification extends \Magento\Tax\Controller\Adminhtml\Tax
             try {
                 $path = 'tax/notification/ignore_' . $section;
                 $this->_objectManager->get('Magento\Config\Model\Resource\Config')
-                    ->saveConfig($path, 1, \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, 0);
+                    ->saveConfig($path, 1, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 0);
             } catch (\Exception $e) {
                 $this->messageManager->addError($e->getMessage());
             }
diff --git a/app/code/Magento/Tax/Model/Calculation/Rate.php b/app/code/Magento/Tax/Model/Calculation/Rate.php
index 18dde7c54f14d54945d1625e034e07ce7833f502..fae528a7d943f8b48b5023d3aaf2ad468a62bb98 100644
--- a/app/code/Magento/Tax/Model/Calculation/Rate.php
+++ b/app/code/Magento/Tax/Model/Calculation/Rate.php
@@ -20,8 +20,24 @@ use Magento\Tax\Api\Data\TaxRateInterface;
  * @method \Magento\Tax\Model\Resource\Calculation\Rate getResource()
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
-class Rate extends \Magento\Framework\Model\AbstractExtensibleModel implements \Magento\Tax\Api\Data\TaxRateInterface
+class Rate extends \Magento\Framework\Model\AbstractExtensibleModel implements TaxRateInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_ID              = 'id';
+    const KEY_COUNTRY_ID      = 'tax_country_id';
+    const KEY_REGION_ID       = 'tax_region_id';
+    const KEY_REGION_NAME     = 'region_name';
+    const KEY_POSTCODE        = 'tax_postcode';
+    const KEY_ZIP_IS_RANGE    = 'zip_is_range';
+    const KEY_ZIP_RANGE_FROM  = 'zip_from';
+    const KEY_ZIP_RANGE_TO    = 'zip_to';
+    const KEY_PERCENTAGE_RATE = 'rate';
+    const KEY_CODE            = 'code';
+    const KEY_TITLES          = 'titles';
+    /**#@-*/
+
     /**
      * List of tax titles
      *
diff --git a/app/code/Magento/Tax/Model/Calculation/Rate/Converter.php b/app/code/Magento/Tax/Model/Calculation/Rate/Converter.php
index 7a407da4de340f4d8a8c82bc2df877786ecdcc3a..5fd8da907a5d8b81a297511758895d0dfa2156bd 100644
--- a/app/code/Magento/Tax/Model/Calculation/Rate/Converter.php
+++ b/app/code/Magento/Tax/Model/Calculation/Rate/Converter.php
@@ -12,6 +12,27 @@ namespace Magento\Tax\Model\Calculation\Rate;
  */
 class Converter
 {
+    /**
+     * @var \Magento\Tax\Api\Data\TaxRateInterfaceFactory
+     */
+    protected $taxRateDataObjectFactory;
+
+    /**
+     * @var \Magento\Tax\Api\Data\TaxRateTitleInterfaceFactory
+     */
+    protected $taxRateTitleDataObjectFactory;
+
+    /**
+     * @param \Magento\Tax\Api\Data\TaxRateInterfaceFactory $taxRateDataObjectFactory
+     * @param \Magento\Tax\Api\Data\TaxRateTitleInterfaceFactory $taxRateTitleDataObjectFactory,
+     */
+    public function __construct(
+        \Magento\Tax\Api\Data\TaxRateInterfaceFactory $taxRateDataObjectFactory,
+        \Magento\Tax\Api\Data\TaxRateTitleInterfaceFactory $taxRateTitleDataObjectFactory
+    ) {
+        $this->taxRateDataObjectFactory = $taxRateDataObjectFactory;
+        $this->taxRateTitleDataObjectFactory = $taxRateTitleDataObjectFactory;
+    }
     /**
      * Convert a tax rate data object to an array of associated titles
      *
@@ -29,4 +50,105 @@ class Converter
         }
         return $titleData;
     }
+
+    /**
+     * Extract tax rate data in a format which is
+     *
+     * @param \Magento\Tax\Api\Data\TaxRateInterface $taxRate
+     * @param Boolean $returnNumericLogic
+     * @return array
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    public function createArrayFromServiceObject(
+        \Magento\Tax\Api\Data\TaxRateInterface $taxRate,
+        $returnNumericLogic = false
+    ) {
+        $taxRateFormData = [
+            'tax_calculation_rate_id' => $taxRate->getId(),
+            'tax_country_id' => $taxRate->getTaxCountryId(),
+            'tax_region_id' => $taxRate->getTaxRegionId(),
+            'tax_postcode' => $taxRate->getTaxPostcode(),
+            'code' => $taxRate->getCode(),
+            'rate' => $taxRate->getRate(),
+            'zip_is_range' => $returnNumericLogic?0:false,
+        ];
+
+        if ($taxRate->getZipFrom() && $taxRate->getZipTo()) {
+            $taxRateFormData['zip_is_range'] = $returnNumericLogic?1:true;
+            $taxRateFormData['zip_from'] = $taxRate->getZipFrom();
+            $taxRateFormData['zip_to'] = $taxRate->getZipTo();
+        }
+
+        if ($returnNumericLogic) {
+            //format for the ajax on multiple sites titles
+            $titleArray=($this->createTitleArrayFromServiceObject($taxRate));
+            if (is_array($titleArray)) {
+                foreach ($titleArray as $storeId => $title) {
+                    $taxRateFormData['title[' . $storeId . ']']=$title;
+                }
+            }
+        } else {
+            //format for the form array on multiple sites titles
+            $titleArray=($this->createTitleArrayFromServiceObject($taxRate));
+            if (is_array($titleArray)) {
+                $titleData = [];
+                foreach ($titleArray as $storeId => $title) {
+                    $titleData[] = [$storeId => $title];
+                }
+                if (count($titleArray)>0) {
+                    $taxRateFormData['title'] = $titleData;
+                }
+            }
+        }
+
+        return $taxRateFormData;
+    }
+
+
+    /**
+     * Convert an array to a tax rate data object
+     *
+     * @param array $formData
+     * @return \Magento\Tax\Api\Data\TaxRateInterface
+     */
+    public function populateTaxRateData($formData)
+    {
+        $taxRate = $this->taxRateDataObjectFactory->create();
+        $taxRate->setId($this->extractFormData($formData, 'tax_calculation_rate_id'))
+            ->setTaxCountryId($this->extractFormData($formData, 'tax_country_id'))
+            ->setTaxRegionId($this->extractFormData($formData, 'tax_region_id'))
+            ->setTaxPostcode($this->extractFormData($formData, 'tax_postcode'))
+            ->setCode($this->extractFormData($formData, 'code'))
+            ->setRate($this->extractFormData($formData, 'rate'));
+        if (isset($formData['zip_is_range']) && $formData['zip_is_range']) {
+            $taxRate->setZipFrom($this->extractFormData($formData, 'zip_from'))
+                ->setZipTo($this->extractFormData($formData, 'zip_to'))->setZipIsRange(1);
+        }
+
+        if (isset($formData['title'])) {
+            $titles = [];
+            foreach ($formData['title'] as $storeId => $value) {
+                $titles[] = $this->taxRateTitleDataObjectFactory->create()->setStoreId($storeId)->setValue($value);
+            }
+            $taxRate->setTitles($titles);
+        }
+
+        return $taxRate;
+    }
+
+    /**
+     * Determines if an array value is set in the form data array and returns it.
+     *
+     * @param array $formData the form to get data from
+     * @param string $fieldName the key
+     * @return null|string
+     */
+    protected function extractFormData($formData, $fieldName)
+    {
+        if (isset($formData[$fieldName])) {
+            return $formData[$fieldName];
+        }
+        return null;
+    }
 }
diff --git a/app/code/Magento/Tax/Model/Calculation/Rate/Title.php b/app/code/Magento/Tax/Model/Calculation/Rate/Title.php
index a98b220548940e240774250f868c8b1abb8c4f1d..141e62435538b94a97d91671966161b6bf174b7c 100644
--- a/app/code/Magento/Tax/Model/Calculation/Rate/Title.php
+++ b/app/code/Magento/Tax/Model/Calculation/Rate/Title.php
@@ -17,9 +17,16 @@ namespace Magento\Tax\Model\Calculation\Rate;
 
 use Magento\Tax\Api\Data\TaxRateTitleInterface;
 
-class Title extends \Magento\Framework\Model\AbstractExtensibleModel implements
-    \Magento\Tax\Api\Data\TaxRateTitleInterface
+class Title extends \Magento\Framework\Model\AbstractExtensibleModel implements TaxRateTitleInterface
 {
+    /**#@+
+     *
+     * Tax rate field key.
+     */
+    const KEY_STORE_ID = 'store_id';
+    const KEY_VALUE_ID = 'value';
+    /**#@-*/
+
     /**
      * @return void
      */
diff --git a/app/code/Magento/Tax/Model/Calculation/RateRepository.php b/app/code/Magento/Tax/Model/Calculation/RateRepository.php
index a185acd15844412198f779b0efd4dc58e224a7fa..6f099ea27ae35038fac754ea19d97066355c7b47 100644
--- a/app/code/Magento/Tax/Model/Calculation/RateRepository.php
+++ b/app/code/Magento/Tax/Model/Calculation/RateRepository.php
@@ -15,7 +15,7 @@ use Magento\Framework\Api\SortOrder;
 use Magento\Framework\Exception\InputException;
 use Magento\Framework\Exception\LocalizedException;
 use Magento\Framework\Exception\AlreadyExistsException;
-use Magento\Tax\Api\Data\TaxRateInterface as TaxRateDataObject;
+use Magento\Tax\Model\Calculation\Rate;
 use Magento\Tax\Model\Calculation\Rate\Converter;
 use Magento\Tax\Model\Resource\Calculation\Rate\Collection;
 
@@ -210,7 +210,7 @@ class RateRepository implements \Magento\Tax\Api\TaxRateRepositoryInterface
     protected function translateField($field)
     {
         switch ($field) {
-            case TaxRateDataObject::KEY_REGION_NAME:
+            case Rate::KEY_REGION_NAME:
                 return 'region_table.code';
             default:
                 return "main_table." . $field;
diff --git a/app/code/Magento/Tax/Model/Calculation/Rule.php b/app/code/Magento/Tax/Model/Calculation/Rule.php
index 13d287ce5da36b67ece5d16a634a1ba3a743ca44..dc7e0cfac6f2c4932e6c1515b277483e78e88a7c 100644
--- a/app/code/Magento/Tax/Model/Calculation/Rule.php
+++ b/app/code/Magento/Tax/Model/Calculation/Rule.php
@@ -21,21 +21,14 @@ class Rule extends \Magento\Framework\Model\AbstractExtensibleModel implements T
      *
      * Tax rule field key.
      */
-    const KEY_ID = 'id';
-
-    const KEY_CODE = 'code';
-
+    const KEY_ID       = 'id';
+    const KEY_CODE     = 'code';
     const KEY_PRIORITY = 'priority';
-
     const KEY_POSITION = 'position';
-
     const KEY_CUSTOMER_TAX_CLASS_IDS = 'customer_tax_class_ids';
-
-    const KEY_PRODUCT_TAX_CLASS_IDS = 'product_tax_class_ids';
-
-    const KEY_TAX_RATE_IDS = 'tax_rate_ids';
-
-    const KEY_CALCULATE_SUBTOTAL = 'calculate_subtotal';
+    const KEY_PRODUCT_TAX_CLASS_IDS  = 'product_tax_class_ids';
+    const KEY_TAX_RATE_IDS           = 'tax_rate_ids';
+    const KEY_CALCULATE_SUBTOTAL     = 'calculate_subtotal';
     /**#@-*/
 
     /**
diff --git a/app/code/Magento/Tax/Model/ClassModel.php b/app/code/Magento/Tax/Model/ClassModel.php
index 603fc708d47286e0dffdd25f8724756445f6cac1..610527d58eb625ed32510e99dabbb11d58af3bc8 100644
--- a/app/code/Magento/Tax/Model/ClassModel.php
+++ b/app/code/Magento/Tax/Model/ClassModel.php
@@ -19,6 +19,14 @@ use Magento\Tax\Api\Data\TaxClassInterface;
 class ClassModel extends \Magento\Framework\Model\AbstractExtensibleModel implements
     \Magento\Tax\Api\Data\TaxClassInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_ID   = 'class_id';
+    const KEY_NAME = 'class_name';
+    const KEY_TYPE = 'class_type';
+    /**#@-*/
+
     /**
      * Defines Customer Tax Class string
      */
diff --git a/app/code/Magento/Tax/Model/ClassModelRegistry.php b/app/code/Magento/Tax/Model/ClassModelRegistry.php
index e4667c061776813e7fa833bae372904527505eb5..da438fcbdf3d55ddb4d5127a36b89d402ec2e4cc 100644
--- a/app/code/Magento/Tax/Model/ClassModelRegistry.php
+++ b/app/code/Magento/Tax/Model/ClassModelRegistry.php
@@ -7,7 +7,6 @@
 namespace Magento\Tax\Model;
 
 use Magento\Framework\Exception\NoSuchEntityException;
-use Magento\Tax\Api\Data\TaxClassInterface;
 use Magento\Tax\Model\ClassModel as TaxClassModel;
 use Magento\Tax\Model\ClassModelFactory as TaxClassModelFactory;
 
@@ -67,7 +66,7 @@ class ClassModelRegistry
         $taxClassModel = $this->taxClassModelFactory->create()->load($taxClassId);
         if (!$taxClassModel->getId()) {
             // tax class does not exist
-            throw NoSuchEntityException::singleField(TaxClassInterface::KEY_ID, $taxClassId);
+            throw NoSuchEntityException::singleField(TaxClassModel::KEY_ID, $taxClassId);
         }
         $this->taxClassRegistryById[$taxClassModel->getId()] = $taxClassModel;
         return $taxClassModel;
diff --git a/app/code/Magento/Tax/Model/Config/Notification.php b/app/code/Magento/Tax/Model/Config/Notification.php
index c886452442406056cb369dd15210a1c32b0c9829..f4b395a290856cf26c36fae743ac7a3ce9797c9b 100644
--- a/app/code/Magento/Tax/Model/Config/Notification.php
+++ b/app/code/Magento/Tax/Model/Config/Notification.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Tax\Model\Config;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 /**
  * Tax Config Notification
  */
@@ -59,7 +61,7 @@ class Notification extends \Magento\Framework\App\Config\Value
      */
     protected function _resetNotificationFlag($path)
     {
-        $this->resourceConfig->saveConfig($path, 0, \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, 0);
+        $this->resourceConfig->saveConfig($path, 0, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 0);
         return $this;
     }
 }
diff --git a/app/code/Magento/Tax/Model/Rate/Source.php b/app/code/Magento/Tax/Model/Rate/Source.php
index 8e4342ca28f161887bfc6aecf3e1d1f6ccb41b44..0d999d6698b6ba76630b3d81a815c8649e466cb5 100644
--- a/app/code/Magento/Tax/Model/Rate/Source.php
+++ b/app/code/Magento/Tax/Model/Rate/Source.php
@@ -8,8 +8,8 @@ namespace Magento\Tax\Model\Rate;
 
 use Magento\Framework\Api\SearchCriteriaBuilder;
 use Magento\Framework\Convert\Object as Converter;
-use Magento\Tax\Api\Data\TaxRateInterface as TaxRate;
 use Magento\Tax\Api\TaxRateRepositoryInterface;
+use Magento\Tax\Model\Calculation\Rate;
 
 /**
  * Tax rate source model.
@@ -57,8 +57,8 @@ class Source implements \Magento\Framework\Data\OptionSourceInterface
             $searchResults = $this->taxRateRepository->getList($searchCriteria);
             $this->options = $this->converter->toOptionArray(
                 $searchResults->getItems(),
-                TaxRate::KEY_ID,
-                TaxRate::KEY_CODE
+                Rate::KEY_ID,
+                Rate::KEY_CODE
             );
         }
         return $this->options;
diff --git a/app/code/Magento/Tax/Model/Sales/Order/Details.php b/app/code/Magento/Tax/Model/Sales/Order/Details.php
index 5161ab9fe6f7397f08cb88972033a8a6be6f6ef4..0294aff0f68eeef1f3e903a3ecbc85246d4fd3c9 100644
--- a/app/code/Magento/Tax/Model/Sales/Order/Details.php
+++ b/app/code/Magento/Tax/Model/Sales/Order/Details.php
@@ -13,6 +13,13 @@ namespace Magento\Tax\Model\Sales\Order;
 class Details extends \Magento\Framework\Model\AbstractExtensibleModel implements
     \Magento\Tax\Api\Data\OrderTaxDetailsInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_APPLIED_TAXES = 'applied_taxes';
+    const KEY_ITEMS         = 'items';
+    /**#@-*/
+
     /**
      * {@inheritdoc}
      */
diff --git a/app/code/Magento/Tax/Model/Sales/Order/Tax.php b/app/code/Magento/Tax/Model/Sales/Order/Tax.php
index 29ce7e404f5696bcff549d3b276f6b14f6aea1d2..3b67f9222800f2f55585bff22409966003799d2e 100644
--- a/app/code/Magento/Tax/Model/Sales/Order/Tax.php
+++ b/app/code/Magento/Tax/Model/Sales/Order/Tax.php
@@ -25,6 +25,16 @@ namespace Magento\Tax\Model\Sales\Order;
 class Tax extends \Magento\Framework\Model\AbstractExtensibleModel implements
     \Magento\Tax\Api\Data\OrderTaxDetailsAppliedTaxInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_CODE        = 'code';
+    const KEY_TITLE       = 'title';
+    const KEY_PERCENT     = 'percent';
+    const KEY_AMOUNT      = 'amount';
+    const KEY_BASE_AMOUNT = 'base_amount';
+    /**#@-*/
+
     /**
      * @return void
      */
diff --git a/app/code/Magento/Tax/Model/Sales/Order/Tax/Item.php b/app/code/Magento/Tax/Model/Sales/Order/Tax/Item.php
index a6b6148ed0c9eaca83d07b74c4d32f53ce3a1e74..8ecadf3eec08696f763a1f72ea1bbfa256dcd575 100644
--- a/app/code/Magento/Tax/Model/Sales/Order/Tax/Item.php
+++ b/app/code/Magento/Tax/Model/Sales/Order/Tax/Item.php
@@ -11,6 +11,15 @@ namespace Magento\Tax\Model\Sales\Order\Tax;
 class Item extends \Magento\Framework\Model\AbstractExtensibleModel implements
     \Magento\Tax\Api\Data\OrderTaxDetailsItemInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_TYPE               = 'type';
+    const KEY_ITEM_ID            = 'item_id';
+    const KEY_ASSOCIATED_ITEM_ID = 'associated_item_id';
+    const KEY_APPLIED_TAXES      = 'applied_taxes';
+    /**#@-*/
+
     /**
      * {@inheritdoc}
      */
diff --git a/app/code/Magento/Tax/Model/Sales/Order/TaxManagement.php b/app/code/Magento/Tax/Model/Sales/Order/TaxManagement.php
index c665dfd00e8f8a65f487faacb618c1475991b10b..fed06b4dd1983da04c39ff4625bf22c0626a4707 100644
--- a/app/code/Magento/Tax/Model/Sales/Order/TaxManagement.php
+++ b/app/code/Magento/Tax/Model/Sales/Order/TaxManagement.php
@@ -10,7 +10,8 @@ namespace Magento\Tax\Model\Sales\Order;
 use Magento\Framework\Exception\NoSuchEntityException;
 use Magento\Tax\Api\Data\OrderTaxDetailsAppliedTaxInterfaceFactory as TaxDetailsDataObjectFactory;
 use Magento\Tax\Api\Data\OrderTaxDetailsAppliedTaxInterface as AppliedTax;
-use Magento\Tax\Api\Data\OrderTaxDetailsItemInterface as Item;
+use Magento\Tax\Model\Sales\Order\Tax;
+use Magento\Tax\Model\Sales\Order\Tax\Item;
 
 class TaxManagement implements \Magento\Tax\Api\OrderTaxManagementInterface
 {
@@ -83,7 +84,7 @@ class TaxManagement implements \Magento\Tax\Api\OrderTaxManagementInterface
      * Aggregate item applied taxes to get order applied taxes
      *
      * @param TaxDetailsDataObjectFactory $appliedTaxDataObjectFactory
-     * @param Item[] $items
+     * @param \Magento\Tax\Api\Data\OrderTaxDetailsItemInterface[] $items
      * @return AppliedTax[]
      */
     protected function aggregateAppliedTaxes(TaxDetailsDataObjectFactory $appliedTaxDataObjectFactory, $items)
@@ -96,25 +97,25 @@ class TaxManagement implements \Magento\Tax\Api\OrderTaxManagementInterface
                 $code = $itemAppliedTax->getCode();
                 if (!isset($orderAppliedTaxesData[$code])) {
                     $orderAppliedTaxesData[$code] = [
-                        AppliedTax::KEY_CODE => $code,
-                        AppliedTax::KEY_TITLE => $itemAppliedTax->getTitle(),
-                        AppliedTax::KEY_PERCENT => $itemAppliedTax->getPercent(),
-                        AppliedTax::KEY_AMOUNT => $itemAppliedTax->getAmount(),
-                        AppliedTax::KEY_BASE_AMOUNT => $itemAppliedTax->getBaseAmount(),
+                        Tax::KEY_CODE => $code,
+                        Tax::KEY_TITLE => $itemAppliedTax->getTitle(),
+                        Tax::KEY_PERCENT => $itemAppliedTax->getPercent(),
+                        Tax::KEY_AMOUNT => $itemAppliedTax->getAmount(),
+                        Tax::KEY_BASE_AMOUNT => $itemAppliedTax->getBaseAmount(),
                     ];
                 } else {
-                    $orderAppliedTaxesData[$code][AppliedTax::KEY_AMOUNT] += $itemAppliedTax->getAmount();
-                    $orderAppliedTaxesData[$code][AppliedTax::KEY_BASE_AMOUNT] += $itemAppliedTax->getBaseAmount();
+                    $orderAppliedTaxesData[$code][Tax::KEY_AMOUNT] += $itemAppliedTax->getAmount();
+                    $orderAppliedTaxesData[$code][Tax::KEY_BASE_AMOUNT] += $itemAppliedTax->getBaseAmount();
                 }
             }
         }
         foreach ($orderAppliedTaxesData as $orderAppliedTaxData) {
             $orderAppliedTaxes[] = $appliedTaxDataObjectFactory->create()
-                ->setCode($orderAppliedTaxData[AppliedTax::KEY_CODE])
-                ->setTitle($orderAppliedTaxData[AppliedTax::KEY_TITLE])
-                ->setPercent($orderAppliedTaxData[AppliedTax::KEY_PERCENT])
-                ->setAmount($orderAppliedTaxData[AppliedTax::KEY_AMOUNT])
-                ->setBaseAmount($orderAppliedTaxData[AppliedTax::KEY_BASE_AMOUNT]);
+                ->setCode($orderAppliedTaxData[Tax::KEY_CODE])
+                ->setTitle($orderAppliedTaxData[Tax::KEY_TITLE])
+                ->setPercent($orderAppliedTaxData[Tax::KEY_PERCENT])
+                ->setAmount($orderAppliedTaxData[Tax::KEY_AMOUNT])
+                ->setBaseAmount($orderAppliedTaxData[Tax::KEY_BASE_AMOUNT]);
         }
         return $orderAppliedTaxes;
     }
diff --git a/app/code/Magento/Tax/Model/Sales/Quote/ItemDetails.php b/app/code/Magento/Tax/Model/Sales/Quote/ItemDetails.php
index 71d18024ea5f1a199b99ff3811fa4d82d7009ed7..cd893b122f89381b05baa4b5cc41e59d120bd40b 100644
--- a/app/code/Magento/Tax/Model/Sales/Quote/ItemDetails.php
+++ b/app/code/Magento/Tax/Model/Sales/Quote/ItemDetails.php
@@ -13,12 +13,28 @@ use Magento\Tax\Api\Data\QuoteDetailsItemInterface;
  */
 class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_CODE                 = 'code';
+    const KEY_TYPE                 = 'type';
+    const KEY_TAX_CLASS_KEY        = 'tax_class_key';
+    const KEY_UNIT_PRICE           = 'unit_price';
+    const KEY_QUANTITY             = 'quantity';
+    const KEY_TAX_INCLUDED         = 'tax_included';
+    const KEY_SHORT_DESCRIPTION    = 'short_description';
+    const KEY_DISCOUNT_AMOUNT      = 'discount_amount';
+    const KEY_PARENT_CODE          = 'parent_code';
+    const KEY_ASSOCIATED_ITEM_CODE = 'associated_item_code';
+    const KEY_TAX_CLASS_ID         = 'tax_class_id';
+    /**#@-*/
+
     /**
      * {@inheritdoc}
      */
     public function getCode()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_CODE);
+        return $this->getData(self::KEY_CODE);
     }
 
     /**
@@ -26,7 +42,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function getType()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_TYPE);
+        return $this->getData(self::KEY_TYPE);
     }
 
     /**
@@ -34,7 +50,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function getTaxClassKey()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_TAX_CLASS_KEY);
+        return $this->getData(self::KEY_TAX_CLASS_KEY);
     }
 
     /**
@@ -42,7 +58,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function getUnitPrice()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_UNIT_PRICE);
+        return $this->getData(self::KEY_UNIT_PRICE);
     }
 
     /**
@@ -50,7 +66,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function getQuantity()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_QUANTITY);
+        return $this->getData(self::KEY_QUANTITY);
     }
 
     /**
@@ -58,7 +74,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function getTaxIncluded()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_TAX_INCLUDED);
+        return $this->getData(self::KEY_TAX_INCLUDED);
     }
 
     /**
@@ -66,7 +82,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function getShortDescription()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_SHORT_DESCRIPTION);
+        return $this->getData(self::KEY_SHORT_DESCRIPTION);
     }
 
     /**
@@ -74,7 +90,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function getDiscountAmount()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_DISCOUNT_AMOUNT);
+        return $this->getData(self::KEY_DISCOUNT_AMOUNT);
     }
 
     /**
@@ -82,7 +98,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function getParentCode()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_PARENT_CODE);
+        return $this->getData(self::KEY_PARENT_CODE);
     }
 
     /**
@@ -90,7 +106,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function getAssociatedItemCode()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_ASSOCIATED_ITEM_CODE);
+        return $this->getData(self::KEY_ASSOCIATED_ITEM_CODE);
     }
 
     /**
@@ -98,7 +114,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function getTaxClassId()
     {
-        return $this->getData(QuoteDetailsItemInterface::KEY_TAX_CLASS_ID);
+        return $this->getData(self::KEY_TAX_CLASS_ID);
     }
 
     /**
@@ -109,7 +125,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setCode($code)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_CODE, $code);
+        return $this->setData(self::KEY_CODE, $code);
     }
 
     /**
@@ -120,7 +136,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setType($type)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_TYPE, $type);
+        return $this->setData(self::KEY_TYPE, $type);
     }
 
     /**
@@ -131,7 +147,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setTaxClassKey(\Magento\Tax\Api\Data\TaxClassKeyInterface $taxClassKey = null)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_TAX_CLASS_KEY, $taxClassKey);
+        return $this->setData(self::KEY_TAX_CLASS_KEY, $taxClassKey);
     }
 
     /**
@@ -142,7 +158,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setUnitPrice($unitPrice)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_UNIT_PRICE, $unitPrice);
+        return $this->setData(self::KEY_UNIT_PRICE, $unitPrice);
     }
 
     /**
@@ -153,7 +169,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setQuantity($quantity)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_QUANTITY, $quantity);
+        return $this->setData(self::KEY_QUANTITY, $quantity);
     }
 
     /**
@@ -164,7 +180,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setIsTaxIncluded($isTaxIncluded)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_TAX_INCLUDED, $isTaxIncluded);
+        return $this->setData(self::KEY_TAX_INCLUDED, $isTaxIncluded);
     }
 
     /**
@@ -175,7 +191,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setShortDescription($shortDescription)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_SHORT_DESCRIPTION, $shortDescription);
+        return $this->setData(self::KEY_SHORT_DESCRIPTION, $shortDescription);
     }
 
     /**
@@ -186,7 +202,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setDiscountAmount($discountAmount)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_DISCOUNT_AMOUNT, $discountAmount);
+        return $this->setData(self::KEY_DISCOUNT_AMOUNT, $discountAmount);
     }
 
     /**
@@ -197,7 +213,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setParentCode($parentCode)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_PARENT_CODE, $parentCode);
+        return $this->setData(self::KEY_PARENT_CODE, $parentCode);
     }
 
     /**
@@ -208,7 +224,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setAssociatedItemCode($associatedItemCode)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_ASSOCIATED_ITEM_CODE, $associatedItemCode);
+        return $this->setData(self::KEY_ASSOCIATED_ITEM_CODE, $associatedItemCode);
     }
 
     /**
@@ -219,7 +235,7 @@ class ItemDetails extends AbstractExtensibleModel implements QuoteDetailsItemInt
      */
     public function setTaxClassId($taxClassId)
     {
-        return $this->setData(QuoteDetailsItemInterface::KEY_TAX_CLASS_ID, $taxClassId);
+        return $this->setData(self::KEY_TAX_CLASS_ID, $taxClassId);
     }
 
     /**
diff --git a/app/code/Magento/Tax/Model/Sales/Quote/QuoteDetails.php b/app/code/Magento/Tax/Model/Sales/Quote/QuoteDetails.php
index 1ef369ba40d82dfb3655926be7970e003892a152..1569e8496bd0cb9417b6f0609df658f06f21a0ed 100644
--- a/app/code/Magento/Tax/Model/Sales/Quote/QuoteDetails.php
+++ b/app/code/Magento/Tax/Model/Sales/Quote/QuoteDetails.php
@@ -13,12 +13,23 @@ use Magento\Tax\Api\Data\QuoteDetailsInterface;
  */
 class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_BILLING_ADDRESS        = 'billing_address';
+    const KEY_SHIPPING_ADDRESS       = 'shipping_address';
+    const KEY_CUSTOMER_TAX_CLASS_KEY = 'customer_tax_class_key';
+    const KEY_ITEMS                  = 'items';
+    const KEY_CUSTOMER_TAX_CLASS_ID  = 'customer_tax_class_id';
+    const KEY_CUSTOMER_ID            = 'customer_id';
+    /**#@-*/
+
     /**
      * {@inheritdoc}
      */
     public function getBillingAddress()
     {
-        return $this->getData(QuoteDetailsInterface::KEY_BILLING_ADDRESS);
+        return $this->getData(self::KEY_BILLING_ADDRESS);
     }
 
     /**
@@ -26,7 +37,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function getShippingAddress()
     {
-        return $this->getData(QuoteDetailsInterface::KEY_SHIPPING_ADDRESS);
+        return $this->getData(self::KEY_SHIPPING_ADDRESS);
     }
 
     /**
@@ -34,7 +45,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function getCustomerTaxClassKey()
     {
-        return $this->getData(QuoteDetailsInterface::KEY_CUSTOMER_TAX_CLASS_KEY);
+        return $this->getData(self::KEY_CUSTOMER_TAX_CLASS_KEY);
     }
 
     /**
@@ -42,7 +53,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function getCustomerId()
     {
-        return $this->getData(QuoteDetailsInterface::KEY_CUSTOMER_ID);
+        return $this->getData(self::KEY_CUSTOMER_ID);
     }
 
     /**
@@ -50,7 +61,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function getItems()
     {
-        return $this->getData(QuoteDetailsInterface::KEY_ITEMS);
+        return $this->getData(self::KEY_ITEMS);
     }
 
     /**
@@ -58,7 +69,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function getCustomerTaxClassId()
     {
-        return $this->getData(QuoteDetailsInterface::CUSTOMER_TAX_CLASS_ID);
+        return $this->getData(self::KEY_CUSTOMER_TAX_CLASS_ID);
     }
 
     /**
@@ -69,7 +80,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function setBillingAddress(\Magento\Customer\Api\Data\AddressInterface $billingAddress = null)
     {
-        return $this->setData(QuoteDetailsInterface::KEY_BILLING_ADDRESS, $billingAddress);
+        return $this->setData(self::KEY_BILLING_ADDRESS, $billingAddress);
     }
 
     /**
@@ -80,7 +91,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function setShippingAddress(\Magento\Customer\Api\Data\AddressInterface $shippingAddress = null)
     {
-        return $this->setData(QuoteDetailsInterface::KEY_SHIPPING_ADDRESS, $shippingAddress);
+        return $this->setData(self::KEY_SHIPPING_ADDRESS, $shippingAddress);
     }
 
     /**
@@ -91,7 +102,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function setCustomerTaxClassKey(\Magento\Tax\Api\Data\TaxClassKeyInterface $customerTaxClassKey = null)
     {
-        return $this->setData(QuoteDetailsInterface::KEY_CUSTOMER_TAX_CLASS_KEY, $customerTaxClassKey);
+        return $this->setData(self::KEY_CUSTOMER_TAX_CLASS_KEY, $customerTaxClassKey);
     }
 
     /**
@@ -102,7 +113,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function setCustomerId($customerId)
     {
-        return $this->setData(QuoteDetailsInterface::KEY_CUSTOMER_ID, $customerId);
+        return $this->setData(self::KEY_CUSTOMER_ID, $customerId);
     }
 
     /**
@@ -113,7 +124,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function setItems(array $items = null)
     {
-        return $this->setData(QuoteDetailsInterface::KEY_ITEMS, $items);
+        return $this->setData(self::KEY_ITEMS, $items);
     }
 
     /**
@@ -124,7 +135,7 @@ class QuoteDetails extends AbstractExtensibleModel implements QuoteDetailsInterf
      */
     public function setCustomerTaxClassId($customerTaxClassId)
     {
-        return $this->setData(QuoteDetailsInterface::CUSTOMER_TAX_CLASS_ID, $customerTaxClassId);
+        return $this->setData(self::KEY_CUSTOMER_TAX_CLASS_ID, $customerTaxClassId);
     }
 
     /**
diff --git a/app/code/Magento/Tax/Model/TaxCalculation.php b/app/code/Magento/Tax/Model/TaxCalculation.php
index fdbc6cb724bfe1bf27df13375ba11d8ff29af87e..579ee5519899603976a08b1aeb874a59f1f8d774 100644
--- a/app/code/Magento/Tax/Model/TaxCalculation.php
+++ b/app/code/Magento/Tax/Model/TaxCalculation.php
@@ -6,19 +6,19 @@
 
 namespace Magento\Tax\Model;
 
-use Magento\Tax\Api\Data\TaxDetailsInterface;
+use Magento\Tax\Api\TaxCalculationInterface;
+use Magento\Tax\Api\TaxClassManagementInterface;
 use Magento\Tax\Api\Data\TaxDetailsItemInterface;
 use Magento\Tax\Api\Data\QuoteDetailsItemInterface;
 use Magento\Tax\Api\Data\TaxDetailsInterfaceFactory;
 use Magento\Tax\Api\Data\TaxDetailsItemInterfaceFactory;
-use Magento\Tax\Api\Data\AppliedTaxRateInterface;
-use Magento\Tax\Api\Data\AppliedTaxInterface;
-use Magento\Tax\Api\TaxClassManagementInterface;
+use Magento\Tax\Model\Calculation\AbstractCalculator;
 use Magento\Tax\Model\Calculation\CalculatorFactory;
 use Magento\Tax\Model\Config;
-use Magento\Tax\Model\Calculation\AbstractCalculator;
+use Magento\Tax\Model\TaxDetails\AppliedTax;
+use Magento\Tax\Model\TaxDetails\AppliedTaxRate;
+use Magento\Tax\Model\TaxDetails\TaxDetails;
 use Magento\Store\Model\StoreManagerInterface;
-use Magento\Tax\Api\TaxCalculationInterface;
 
 /**
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
@@ -142,11 +142,11 @@ class TaxCalculation implements TaxCalculationInterface
 
         // initial TaxDetails data
         $taxDetailsData = [
-            TaxDetailsInterface::KEY_SUBTOTAL => 0.0,
-            TaxDetailsInterface::KEY_TAX_AMOUNT => 0.0,
-            TaxDetailsInterface::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT => 0.0,
-            TaxDetailsInterface::KEY_APPLIED_TAXES => [],
-            TaxDetailsInterface::KEY_ITEMS => [],
+            TaxDetails::KEY_SUBTOTAL => 0.0,
+            TaxDetails::KEY_TAX_AMOUNT => 0.0,
+            TaxDetails::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT => 0.0,
+            TaxDetails::KEY_APPLIED_TAXES => [],
+            TaxDetails::KEY_ITEMS => [],
         ];
         $items = $quoteDetails->getItems();
         if (empty($items)) {
@@ -327,21 +327,21 @@ class TaxCalculation implements TaxCalculationInterface
      */
     protected function aggregateItemData($taxDetailsData, TaxDetailsItemInterface $item)
     {
-        $taxDetailsData[TaxDetailsInterface::KEY_SUBTOTAL]
-            = $taxDetailsData[TaxDetailsInterface::KEY_SUBTOTAL] + $item->getRowTotal();
+        $taxDetailsData[TaxDetails::KEY_SUBTOTAL]
+            = $taxDetailsData[TaxDetails::KEY_SUBTOTAL] + $item->getRowTotal();
 
-        $taxDetailsData[TaxDetailsInterface::KEY_TAX_AMOUNT]
-            = $taxDetailsData[TaxDetailsInterface::KEY_TAX_AMOUNT] + $item->getRowTax();
+        $taxDetailsData[TaxDetails::KEY_TAX_AMOUNT]
+            = $taxDetailsData[TaxDetails::KEY_TAX_AMOUNT] + $item->getRowTax();
 
-        $taxDetailsData[TaxDetailsInterface::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT] =
-            $taxDetailsData[TaxDetailsInterface::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT]
+        $taxDetailsData[TaxDetails::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT] =
+            $taxDetailsData[TaxDetails::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT]
             + $item->getDiscountTaxCompensationAmount();
 
         $itemAppliedTaxes = $item->getAppliedTaxes();
         if ($itemAppliedTaxes === null) {
             return $taxDetailsData;
         }
-        $appliedTaxes = $taxDetailsData[TaxDetailsInterface::KEY_APPLIED_TAXES];
+        $appliedTaxes = $taxDetailsData[TaxDetails::KEY_APPLIED_TAXES];
         foreach ($itemAppliedTaxes as $taxId => $itemAppliedTax) {
             if (!isset($appliedTaxes[$taxId])) {
                 //convert rate data object to array
@@ -349,23 +349,23 @@ class TaxCalculation implements TaxCalculationInterface
                 $rateDataObjects = $itemAppliedTax->getRates();
                 foreach ($rateDataObjects as $rateDataObject) {
                     $rates[$rateDataObject->getCode()] = [
-                        AppliedTaxRateInterface::KEY_CODE => $rateDataObject->getCode(),
-                        AppliedTaxRateInterface::KEY_TITLE => $rateDataObject->getTitle(),
-                        AppliedTaxRateInterface::KEY_PERCENT => $rateDataObject->getPercent(),
+                        AppliedTaxRate::KEY_CODE => $rateDataObject->getCode(),
+                        AppliedTaxRate::KEY_TITLE => $rateDataObject->getTitle(),
+                        AppliedTaxRate::KEY_PERCENT => $rateDataObject->getPercent(),
                     ];
                 }
                 $appliedTaxes[$taxId] = [
-                    AppliedTaxInterface::KEY_AMOUNT => $itemAppliedTax->getAmount(),
-                    AppliedTaxInterface::KEY_PERCENT => $itemAppliedTax->getPercent(),
-                    AppliedTaxInterface::KEY_RATES => $rates,
-                    AppliedTaxInterface::KEY_TAX_RATE_KEY => $itemAppliedTax->getTaxRateKey(),
+                    AppliedTax::KEY_AMOUNT => $itemAppliedTax->getAmount(),
+                    AppliedTax::KEY_PERCENT => $itemAppliedTax->getPercent(),
+                    AppliedTax::KEY_RATES => $rates,
+                    AppliedTax::KEY_TAX_RATE_KEY => $itemAppliedTax->getTaxRateKey(),
                 ];
             } else {
-                $appliedTaxes[$taxId][AppliedTaxInterface::KEY_AMOUNT] += $itemAppliedTax->getAmount();
+                $appliedTaxes[$taxId][AppliedTax::KEY_AMOUNT] += $itemAppliedTax->getAmount();
             }
         }
 
-        $taxDetailsData[TaxDetailsInterface::KEY_APPLIED_TAXES] = $appliedTaxes;
+        $taxDetailsData[TaxDetails::KEY_APPLIED_TAXES] = $appliedTaxes;
         return $taxDetailsData;
     }
 
diff --git a/app/code/Magento/Tax/Model/TaxClass/Key.php b/app/code/Magento/Tax/Model/TaxClass/Key.php
index 085b018aa88f7ad8ba4ef5a36fea99c31f6ded54..c882d2dae170cfa9589909859f8b0eb995a41d01 100644
--- a/app/code/Magento/Tax/Model/TaxClass/Key.php
+++ b/app/code/Magento/Tax/Model/TaxClass/Key.php
@@ -13,12 +13,19 @@ use Magento\Tax\Api\Data\TaxClassKeyInterface;
  */
 class Key extends AbstractExtensibleModel implements TaxClassKeyInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_TYPE  = 'type';
+    const KEY_VALUE = 'value';
+    /**#@-*/
+
     /**
      * {@inheritdoc}
      */
     public function getType()
     {
-        return $this->getData(TaxClassKeyInterface::KEY_TYPE);
+        return $this->getData(self::KEY_TYPE);
     }
 
     /**
@@ -26,7 +33,7 @@ class Key extends AbstractExtensibleModel implements TaxClassKeyInterface
      */
     public function getValue()
     {
-        return $this->getData(TaxClassKeyInterface::KEY_VALUE);
+        return $this->getData(self::KEY_VALUE);
     }
 
     /**
@@ -37,7 +44,7 @@ class Key extends AbstractExtensibleModel implements TaxClassKeyInterface
      */
     public function setType($type)
     {
-        return $this->setData(TaxClassKeyInterface::KEY_TYPE, $type);
+        return $this->setData(self::KEY_TYPE, $type);
     }
 
     /**
@@ -48,7 +55,7 @@ class Key extends AbstractExtensibleModel implements TaxClassKeyInterface
      */
     public function setValue($value)
     {
-        return $this->setData(TaxClassKeyInterface::KEY_VALUE, $value);
+        return $this->setData(self::KEY_VALUE, $value);
     }
 
     /**
diff --git a/app/code/Magento/Tax/Model/TaxClass/Management.php b/app/code/Magento/Tax/Model/TaxClass/Management.php
index 679a054b62314f379cfbc94ec0b0633a1142c059..eb7871c1086c22efe4e988254490bf02abdebf48 100644
--- a/app/code/Magento/Tax/Model/TaxClass/Management.php
+++ b/app/code/Magento/Tax/Model/TaxClass/Management.php
@@ -9,8 +9,8 @@ namespace Magento\Tax\Model\TaxClass;
 
 use Magento\Framework\Api\FilterBuilder;
 use Magento\Framework\Api\SearchCriteriaBuilder;
-use Magento\Tax\Api\Data\TaxClassInterface;
 use Magento\Tax\Api\Data\TaxClassKeyInterface;
+use Magento\Tax\Model\ClassModel;
 
 class Management implements \Magento\Tax\Api\TaxClassManagementInterface
 {
@@ -61,10 +61,10 @@ class Management implements \Magento\Tax\Api\TaxClassManagementInterface
                     return $taxClassKey->getValue();
                 case TaxClassKeyInterface::TYPE_NAME:
                     $searchCriteria = $this->searchCriteriaBuilder->addFilter(
-                        [$this->filterBuilder->setField(TaxClassInterface::KEY_TYPE)->setValue($taxClassType)->create()]
+                        [$this->filterBuilder->setField(ClassModel::KEY_TYPE)->setValue($taxClassType)->create()]
                     )->addFilter(
                         [
-                            $this->filterBuilder->setField(TaxClassInterface::KEY_NAME)
+                            $this->filterBuilder->setField(ClassModel::KEY_NAME)
                                 ->setValue($taxClassKey->getValue())
                                 ->create(),
                         ]
diff --git a/app/code/Magento/Tax/Model/TaxClass/Repository.php b/app/code/Magento/Tax/Model/TaxClass/Repository.php
index a0fc6fe76d46ec8718a7cccf2af8a44068b73425..01dd656b0d5e51d5b64e22c8fd4d80e937d19e2b 100644
--- a/app/code/Magento/Tax/Model/TaxClass/Repository.php
+++ b/app/code/Magento/Tax/Model/TaxClass/Repository.php
@@ -15,8 +15,8 @@ use Magento\Framework\Api\SortOrder;
 use Magento\Framework\Exception\CouldNotDeleteException;
 use Magento\Framework\Exception\InputException;
 use Magento\Framework\Exception\LocalizedException as ModelException;
-use Magento\Tax\Api\Data\TaxClassInterface;
 use Magento\Tax\Api\TaxClassManagementInterface;
+use Magento\Tax\Model\ClassModel;
 use Magento\Tax\Model\ClassModelRegistry;
 use Magento\Tax\Model\Resource\TaxClass\Collection as TaxClassCollection;
 use Magento\Tax\Model\Resource\TaxClass\CollectionFactory as TaxClassCollectionFactory;
@@ -164,19 +164,19 @@ class Repository implements \Magento\Tax\Api\TaxClassRepositoryInterface
         $exception = new InputException();
 
         if (!\Zend_Validate::is(trim($taxClass->getClassName()), 'NotEmpty')) {
-            $exception->addError(__(InputException::REQUIRED_FIELD, ['fieldName' => TaxClassInterface::KEY_NAME]));
+            $exception->addError(__(InputException::REQUIRED_FIELD, ['fieldName' => ClassModel::KEY_NAME]));
         }
 
         $classType = $taxClass->getClassType();
         if (!\Zend_Validate::is(trim($classType), 'NotEmpty')) {
-            $exception->addError(__(InputException::REQUIRED_FIELD, ['fieldName' => TaxClassInterface::KEY_TYPE]));
+            $exception->addError(__(InputException::REQUIRED_FIELD, ['fieldName' => ClassModel::KEY_TYPE]));
         } elseif ($classType !== TaxClassManagementInterface::TYPE_CUSTOMER
             && $classType !== TaxClassManagementInterface::TYPE_PRODUCT
         ) {
             $exception->addError(
                 __(
                     InputException::INVALID_FIELD_VALUE,
-                    ['fieldName' => TaxClassInterface::KEY_TYPE, 'value' => $classType]
+                    ['fieldName' => ClassModel::KEY_TYPE, 'value' => $classType]
                 )
             );
         }
diff --git a/app/code/Magento/Tax/Model/TaxClass/Source/Customer.php b/app/code/Magento/Tax/Model/TaxClass/Source/Customer.php
index 4a52c81b669fb5a3a13b775ab60686f18ecb5c99..ca0dd21abdd84a2714adf6c8eb26aa89c83584de 100644
--- a/app/code/Magento/Tax/Model/TaxClass/Source/Customer.php
+++ b/app/code/Magento/Tax/Model/TaxClass/Source/Customer.php
@@ -8,7 +8,7 @@ namespace Magento\Tax\Model\TaxClass\Source;
 
 use Magento\Framework\Exception\StateException;
 use Magento\Tax\Api\TaxClassManagementInterface;
-use Magento\Tax\Api\Data\TaxClassInterface as TaxClass;
+use Magento\Tax\Model\ClassModel;
 
 /**
  * Customer tax class source model.
@@ -57,7 +57,7 @@ class Customer extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
     {
         if (empty($this->_options)) {
             $options = [];
-            $filter = $this->filterBuilder->setField(TaxClass::KEY_TYPE)
+            $filter = $this->filterBuilder->setField(ClassModel::KEY_TYPE)
                 ->setValue(TaxClassManagementInterface::TYPE_CUSTOMER)
                 ->create();
             $searchCriteria = $this->searchCriteriaBuilder->addFilter([$filter])->create();
diff --git a/app/code/Magento/Tax/Model/TaxClass/Source/Product.php b/app/code/Magento/Tax/Model/TaxClass/Source/Product.php
index bf8711f93228abcfec3c8c6836ff0dd3847a4b23..37844ab57076c71cfc5fb8c57010de4db1fe5444 100644
--- a/app/code/Magento/Tax/Model/TaxClass/Source/Product.php
+++ b/app/code/Magento/Tax/Model/TaxClass/Source/Product.php
@@ -7,8 +7,8 @@
 namespace Magento\Tax\Model\TaxClass\Source;
 
 use Magento\Framework\DB\Ddl\Table;
-use Magento\Tax\Api\Data\TaxClassInterface as TaxClass;
 use Magento\Tax\Api\TaxClassManagementInterface;
+use Magento\Tax\Model\ClassModel;
 
 /**
  * Product tax class source model.
@@ -68,7 +68,7 @@ class Product extends \Magento\Eav\Model\Entity\Attribute\Source\AbstractSource
     {
         if (!$this->_options) {
             $filter = $this->_filterBuilder
-                ->setField(TaxClass::KEY_TYPE)
+                ->setField(ClassModel::KEY_TYPE)
                 ->setValue(TaxClassManagementInterface::TYPE_PRODUCT)
                 ->create();
             $searchCriteria = $this->_searchCriteriaBuilder->addFilter([$filter])->create();
diff --git a/app/code/Magento/Tax/Model/TaxDetails/AppliedTax.php b/app/code/Magento/Tax/Model/TaxDetails/AppliedTax.php
index 79265cacbc0c8615b0989d9deae57cb4ab6ee405..c5857168feddd83a0280449aadd5bc05c831838e 100644
--- a/app/code/Magento/Tax/Model/TaxDetails/AppliedTax.php
+++ b/app/code/Magento/Tax/Model/TaxDetails/AppliedTax.php
@@ -13,12 +13,21 @@ use Magento\Tax\Api\Data\AppliedTaxInterface;
  */
 class AppliedTax extends AbstractExtensibleModel implements AppliedTaxInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_TAX_RATE_KEY = 'tax_rate_key';
+    const KEY_PERCENT      = 'percent';
+    const KEY_AMOUNT       = 'amount';
+    const KEY_RATES        = 'rates';
+    /**#@-*/
+
     /**
      * {@inheritdoc}
      */
     public function getTaxRateKey()
     {
-        return $this->getData(AppliedTaxInterface::KEY_TAX_RATE_KEY);
+        return $this->getData(self::KEY_TAX_RATE_KEY);
     }
 
     /**
@@ -26,7 +35,7 @@ class AppliedTax extends AbstractExtensibleModel implements AppliedTaxInterface
      */
     public function getPercent()
     {
-        return $this->getData(AppliedTaxInterface::KEY_PERCENT);
+        return $this->getData(self::KEY_PERCENT);
     }
 
     /**
@@ -34,7 +43,7 @@ class AppliedTax extends AbstractExtensibleModel implements AppliedTaxInterface
      */
     public function getAmount()
     {
-        return $this->getData(AppliedTaxInterface::KEY_AMOUNT);
+        return $this->getData(self::KEY_AMOUNT);
     }
 
     /**
@@ -42,7 +51,7 @@ class AppliedTax extends AbstractExtensibleModel implements AppliedTaxInterface
      */
     public function getRates()
     {
-        return $this->getData(AppliedTaxInterface::KEY_RATES);
+        return $this->getData(self::KEY_RATES);
     }
 
     /**
@@ -53,7 +62,7 @@ class AppliedTax extends AbstractExtensibleModel implements AppliedTaxInterface
      */
     public function setTaxRateKey($taxRateKey)
     {
-        return $this->setData(AppliedTaxInterface::KEY_TAX_RATE_KEY, $taxRateKey);
+        return $this->setData(self::KEY_TAX_RATE_KEY, $taxRateKey);
     }
 
     /**
@@ -64,7 +73,7 @@ class AppliedTax extends AbstractExtensibleModel implements AppliedTaxInterface
      */
     public function setPercent($percent)
     {
-        return $this->setData(AppliedTaxInterface::KEY_PERCENT, $percent);
+        return $this->setData(self::KEY_PERCENT, $percent);
     }
 
     /**
@@ -75,7 +84,7 @@ class AppliedTax extends AbstractExtensibleModel implements AppliedTaxInterface
      */
     public function setAmount($amount)
     {
-        return $this->setData(AppliedTaxInterface::KEY_AMOUNT, $amount);
+        return $this->setData(self::KEY_AMOUNT, $amount);
     }
 
     /**
@@ -86,7 +95,7 @@ class AppliedTax extends AbstractExtensibleModel implements AppliedTaxInterface
      */
     public function setRates(array $rates = null)
     {
-        return $this->setData(AppliedTaxInterface::KEY_RATES, $rates);
+        return $this->setData(self::KEY_RATES, $rates);
     }
 
     /**
diff --git a/app/code/Magento/Tax/Model/TaxDetails/AppliedTaxRate.php b/app/code/Magento/Tax/Model/TaxDetails/AppliedTaxRate.php
index 8cd44cb70e0e36de4ebe281b05e439e18be8312d..a04aed56a7f4a8b6224f628d9786d98a136821f3 100644
--- a/app/code/Magento/Tax/Model/TaxDetails/AppliedTaxRate.php
+++ b/app/code/Magento/Tax/Model/TaxDetails/AppliedTaxRate.php
@@ -13,12 +13,20 @@ use Magento\Tax\Api\Data\AppliedTaxRateInterface;
  */
 class AppliedTaxRate extends AbstractExtensibleModel implements AppliedTaxRateInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_CODE    = 'code';
+    const KEY_TITLE   = 'title';
+    const KEY_PERCENT = 'percent';
+    /**#@-*/
+
     /**
      * {@inheritdoc}
      */
     public function getCode()
     {
-        return $this->getData(AppliedTaxRateInterface::KEY_CODE);
+        return $this->getData(self::KEY_CODE);
     }
 
     /**
@@ -26,7 +34,7 @@ class AppliedTaxRate extends AbstractExtensibleModel implements AppliedTaxRateIn
      */
     public function getTitle()
     {
-        return $this->getData(AppliedTaxRateInterface::KEY_TITLE);
+        return $this->getData(self::KEY_TITLE);
     }
 
     /**
@@ -34,7 +42,7 @@ class AppliedTaxRate extends AbstractExtensibleModel implements AppliedTaxRateIn
      */
     public function getPercent()
     {
-        return $this->getData(AppliedTaxRateInterface::KEY_PERCENT);
+        return $this->getData(self::KEY_PERCENT);
     }
 
     /**
@@ -45,7 +53,7 @@ class AppliedTaxRate extends AbstractExtensibleModel implements AppliedTaxRateIn
      */
     public function setCode($code)
     {
-        return $this->setData(AppliedTaxRateInterface::KEY_CODE, $code);
+        return $this->setData(self::KEY_CODE, $code);
     }
 
     /**
@@ -56,7 +64,7 @@ class AppliedTaxRate extends AbstractExtensibleModel implements AppliedTaxRateIn
      */
     public function setTitle($title)
     {
-        return $this->setData(AppliedTaxRateInterface::KEY_TITLE, $title);
+        return $this->setData(self::KEY_TITLE, $title);
     }
 
     /**
@@ -67,7 +75,7 @@ class AppliedTaxRate extends AbstractExtensibleModel implements AppliedTaxRateIn
      */
     public function setPercent($percent)
     {
-        return $this->setData(AppliedTaxRateInterface::KEY_PERCENT, $percent);
+        return $this->setData(self::KEY_PERCENT, $percent);
     }
 
     /**
diff --git a/app/code/Magento/Tax/Model/TaxDetails/ItemDetails.php b/app/code/Magento/Tax/Model/TaxDetails/ItemDetails.php
index 9ba71b43dedf1c2bf676436e6a3754e4f168d69f..d4f1628fbdbb8f4921e1162f01e23bd68aa94223 100644
--- a/app/code/Magento/Tax/Model/TaxDetails/ItemDetails.php
+++ b/app/code/Magento/Tax/Model/TaxDetails/ItemDetails.php
@@ -13,12 +13,30 @@ use Magento\Tax\Api\Data\TaxDetailsItemInterface;
  */
 class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_CODE                 = 'code';
+    const KEY_TYPE                 = 'type';
+    const KEY_TAX_PERCENT          = 'tax_percent';
+    const KEY_PRICE                = 'price';
+    const KEY_PRICE_INCL_TAX       = 'price_incl_tax';
+    const KEY_ROW_TOTAL            = 'row_total';
+    const KEY_ROW_TOTAL_INCL_TAX   = 'row_total_incl_tax';
+    const KEY_ROW_TAX              = 'row_tax';
+    const KEY_TAXABLE_AMOUNT       = 'taxable_amount';
+    const KEY_DISCOUNT_AMOUNT      = 'discount_amount';
+    const KEY_APPLIED_TAXES        = 'applied_taxes';
+    const KEY_ASSOCIATED_ITEM_CODE = 'associated_item_code';
+    const KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT = 'discount_tax_compensation_amount';
+    /**#@-*/
+
     /**
      * {@inheritdoc}
      */
     public function getCode()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_CODE);
+        return $this->getData(self::KEY_CODE);
     }
 
     /**
@@ -26,7 +44,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getType()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_TYPE);
+        return $this->getData(self::KEY_TYPE);
     }
 
     /**
@@ -34,7 +52,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getTaxPercent()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_TAX_PERCENT);
+        return $this->getData(self::KEY_TAX_PERCENT);
     }
 
     /**
@@ -42,7 +60,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getPrice()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_PRICE);
+        return $this->getData(self::KEY_PRICE);
     }
 
     /**
@@ -50,7 +68,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getPriceInclTax()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_PRICE_INCL_TAX);
+        return $this->getData(self::KEY_PRICE_INCL_TAX);
     }
 
     /**
@@ -58,7 +76,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getRowTotal()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_ROW_TOTAL);
+        return $this->getData(self::KEY_ROW_TOTAL);
     }
 
     /**
@@ -66,7 +84,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getRowTotalInclTax()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_ROW_TOTAL_INCL_TAX);
+        return $this->getData(self::KEY_ROW_TOTAL_INCL_TAX);
     }
 
     /**
@@ -74,7 +92,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getRowTax()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_ROW_TAX);
+        return $this->getData(self::KEY_ROW_TAX);
     }
 
     /**
@@ -82,7 +100,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getTaxableAmount()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_TAXABLE_AMOUNT);
+        return $this->getData(self::KEY_TAXABLE_AMOUNT);
     }
 
     /**
@@ -90,7 +108,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getDiscountAmount()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_DISCOUNT_AMOUNT);
+        return $this->getData(self::KEY_DISCOUNT_AMOUNT);
     }
 
     /**
@@ -98,7 +116,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getDiscountTaxCompensationAmount()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT);
+        return $this->getData(self::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT);
     }
 
     /**
@@ -106,7 +124,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getAppliedTaxes()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_APPLIED_TAXES);
+        return $this->getData(self::KEY_APPLIED_TAXES);
     }
 
     /**
@@ -114,7 +132,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function getAssociatedItemCode()
     {
-        return $this->getData(TaxDetailsItemInterface::KEY_ASSOCIATED_ITEM_CODE);
+        return $this->getData(self::KEY_ASSOCIATED_ITEM_CODE);
     }
 
     /**
@@ -125,7 +143,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setCode($code)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_CODE, $code);
+        return $this->setData(self::KEY_CODE, $code);
     }
 
     /**
@@ -136,7 +154,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setType($type)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_TYPE, $type);
+        return $this->setData(self::KEY_TYPE, $type);
     }
 
     /**
@@ -147,7 +165,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setTaxPercent($taxPercent)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_TAX_PERCENT, $taxPercent);
+        return $this->setData(self::KEY_TAX_PERCENT, $taxPercent);
     }
 
     /**
@@ -158,7 +176,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setPrice($price)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_PRICE, $price);
+        return $this->setData(self::KEY_PRICE, $price);
     }
 
     /**
@@ -169,7 +187,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setPriceInclTax($priceInclTax)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_PRICE_INCL_TAX, $priceInclTax);
+        return $this->setData(self::KEY_PRICE_INCL_TAX, $priceInclTax);
     }
 
     /**
@@ -180,7 +198,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setRowTotal($rowTotal)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_ROW_TOTAL, $rowTotal);
+        return $this->setData(self::KEY_ROW_TOTAL, $rowTotal);
     }
 
     /**
@@ -191,7 +209,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setRowTotalInclTax($rowTotalInclTax)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_ROW_TOTAL_INCL_TAX, $rowTotalInclTax);
+        return $this->setData(self::KEY_ROW_TOTAL_INCL_TAX, $rowTotalInclTax);
     }
 
     /**
@@ -202,7 +220,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setRowTax($rowTax)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_ROW_TAX, $rowTax);
+        return $this->setData(self::KEY_ROW_TAX, $rowTax);
     }
 
     /**
@@ -213,7 +231,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setTaxableAmount($taxableAmount)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_TAXABLE_AMOUNT, $taxableAmount);
+        return $this->setData(self::KEY_TAXABLE_AMOUNT, $taxableAmount);
     }
 
     /**
@@ -224,7 +242,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setDiscountAmount($discountAmount)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_DISCOUNT_AMOUNT, $discountAmount);
+        return $this->setData(self::KEY_DISCOUNT_AMOUNT, $discountAmount);
     }
 
     /**
@@ -236,7 +254,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
     public function setDiscountTaxCompensationAmount($discountTaxCompensationAmount)
     {
         return $this->setData(
-            TaxDetailsItemInterface::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT,
+            self::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT,
             $discountTaxCompensationAmount
         );
     }
@@ -249,7 +267,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setAppliedTaxes(array $appliedTaxes = null)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_APPLIED_TAXES, $appliedTaxes);
+        return $this->setData(self::KEY_APPLIED_TAXES, $appliedTaxes);
     }
 
     /**
@@ -260,7 +278,7 @@ class ItemDetails extends AbstractExtensibleModel implements TaxDetailsItemInter
      */
     public function setAssociatedItemCode($associatedItemCode)
     {
-        return $this->setData(TaxDetailsItemInterface::KEY_ASSOCIATED_ITEM_CODE, $associatedItemCode);
+        return $this->setData(self::KEY_ASSOCIATED_ITEM_CODE, $associatedItemCode);
     }
 
     /**
diff --git a/app/code/Magento/Tax/Model/TaxDetails/TaxDetails.php b/app/code/Magento/Tax/Model/TaxDetails/TaxDetails.php
index 91f1587c8b575ce08e5f52a0196c724f40917a36..721dedffeb29e43cb8433b1222e9e0059e8a4f7a 100644
--- a/app/code/Magento/Tax/Model/TaxDetails/TaxDetails.php
+++ b/app/code/Magento/Tax/Model/TaxDetails/TaxDetails.php
@@ -13,12 +13,22 @@ use Magento\Tax\Api\Data\TaxDetailsInterface;
  */
 class TaxDetails extends AbstractExtensibleModel implements TaxDetailsInterface
 {
+    /**#@+
+     * Constants defined for keys of array, makes typos less likely
+     */
+    const KEY_SUBTOTAL      = 'subtotal';
+    const KEY_TAX_AMOUNT    = 'tax_amount';
+    const KEY_APPLIED_TAXES = 'applied_taxes';
+    const KEY_ITEMS         = 'items';
+    const KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT = 'discount_tax_compensation_amount';
+    /**#@-*/
+
     /**
      * {@inheritdoc}
      */
     public function getSubtotal()
     {
-        return $this->getData(TaxDetailsInterface::KEY_SUBTOTAL);
+        return $this->getData(self::KEY_SUBTOTAL);
     }
 
     /**
@@ -26,7 +36,7 @@ class TaxDetails extends AbstractExtensibleModel implements TaxDetailsInterface
      */
     public function getTaxAmount()
     {
-        return $this->getData(TaxDetailsInterface::KEY_TAX_AMOUNT);
+        return $this->getData(self::KEY_TAX_AMOUNT);
     }
 
     /**
@@ -34,7 +44,7 @@ class TaxDetails extends AbstractExtensibleModel implements TaxDetailsInterface
      */
     public function getDiscountTaxCompensationAmount()
     {
-        return $this->getData(TaxDetailsInterface::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT);
+        return $this->getData(self::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT);
     }
 
     /**
@@ -42,7 +52,7 @@ class TaxDetails extends AbstractExtensibleModel implements TaxDetailsInterface
      */
     public function getAppliedTaxes()
     {
-        return $this->getData(TaxDetailsInterface::KEY_APPLIED_TAXES);
+        return $this->getData(self::KEY_APPLIED_TAXES);
     }
 
     /**
@@ -50,7 +60,7 @@ class TaxDetails extends AbstractExtensibleModel implements TaxDetailsInterface
      */
     public function getItems()
     {
-        return $this->getData(TaxDetailsInterface::KEY_ITEMS);
+        return $this->getData(self::KEY_ITEMS);
     }
 
     /**
@@ -61,7 +71,7 @@ class TaxDetails extends AbstractExtensibleModel implements TaxDetailsInterface
      */
     public function setSubtotal($subtotal)
     {
-        return $this->setData(TaxDetailsInterface::KEY_SUBTOTAL, $subtotal);
+        return $this->setData(self::KEY_SUBTOTAL, $subtotal);
     }
 
     /**
@@ -72,7 +82,7 @@ class TaxDetails extends AbstractExtensibleModel implements TaxDetailsInterface
      */
     public function setTaxAmount($taxAmount)
     {
-        return $this->setData(TaxDetailsInterface::KEY_TAX_AMOUNT, $taxAmount);
+        return $this->setData(self::KEY_TAX_AMOUNT, $taxAmount);
     }
 
     /**
@@ -84,7 +94,7 @@ class TaxDetails extends AbstractExtensibleModel implements TaxDetailsInterface
     public function setDiscountTaxCompensationAmount($discountTaxCompensationAmount)
     {
         return $this->setData(
-            TaxDetailsInterface::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT,
+            self::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT,
             $discountTaxCompensationAmount
         );
     }
@@ -97,7 +107,7 @@ class TaxDetails extends AbstractExtensibleModel implements TaxDetailsInterface
      */
     public function setAppliedTaxes(array $appliedTaxes = null)
     {
-        return $this->setData(TaxDetailsInterface::KEY_APPLIED_TAXES, $appliedTaxes);
+        return $this->setData(self::KEY_APPLIED_TAXES, $appliedTaxes);
     }
 
     /**
@@ -108,7 +118,7 @@ class TaxDetails extends AbstractExtensibleModel implements TaxDetailsInterface
      */
     public function setItems(array $items = null)
     {
-        return $this->setData(TaxDetailsInterface::KEY_ITEMS, $items);
+        return $this->setData(self::KEY_ITEMS, $items);
     }
 
     /**
diff --git a/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Rate/AjaxLoadTest.php b/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Rate/AjaxLoadTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6373e5aa514bf11a2d6174c78e64489bd7d558b0
--- /dev/null
+++ b/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Rate/AjaxLoadTest.php
@@ -0,0 +1,238 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Tax\Test\Unit\Controller\Adminhtml\Rate;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+use Magento\Framework\Exception\NoSuchEntityException;
+
+/**
+ * Test for AjaxLoadTest
+ */
+class AjaxLoadTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\Request\Http
+     */
+    private $request;
+
+    /**
+     * @var \Magento\Framework\App\Response\Http
+     */
+    private $resultFactory;
+
+    /**
+     * @var \Magento\Tax\Model\Calculation\RateRepository
+     */
+    private $taxRateRepository;
+
+    /*
+     * test setup
+     */
+    public function setUp()
+    {
+        $this->request = $this->getMockBuilder('\Magento\Framework\App\Request\Http')
+            ->disableOriginalConstructor()
+            ->setMethods(['getParam'])
+            ->getMock();
+
+        $this->resultFactory = $this->getMockBuilder('Magento\Framework\Controller\ResultFactory')
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->taxRateRepository = $this->getMockBuilder('\Magento\Tax\Model\Calculation\RateRepository')
+            ->disableOriginalConstructor()
+            ->setMethods(['get'])
+            ->getMock();
+    }
+
+    /**
+     * Executes the controller action and asserts non exception logic
+     */
+    public function testExecute()
+    {
+        $taxRateId=1;
+        $returnArray=[
+        'tax_calculation_rate_id' => null,
+                    'tax_country_id' => 'US',
+                    'tax_region_id' => 2,
+                    'tax_postcode' => null,
+                    'code' => 'Tax Rate Code',
+                    'rate' => 7.5,
+                    'zip_is_range'=> 0,
+                    'title[1]' => 'texas',
+                ];
+        $objectManager = new ObjectManager($this);
+        $rateTitles = [$objectManager->getObject(
+            '\Magento\Tax\Model\Calculation\Rate\Title',
+            ['data' => ['store_id' => 1, 'value' => 'texas']]
+        )
+        ];
+        $rateMock = $objectManager->getObject(
+            'Magento\Tax\Model\Calculation\Rate',
+            [
+                'data' =>
+                    [
+                        'tax_country_id' => 'US',
+                        'tax_region_id' => 2,
+                        'tax_postcode' => null,
+                        'rate' => 7.5,
+                        'code' => 'Tax Rate Code',
+                        'titles' => $rateTitles,
+                    ],
+            ]
+        );
+
+        $this->request->expects($this->any())
+            ->method('getParam')
+            ->will($this->returnValue($taxRateId));
+
+        $this->taxRateRepository->expects($this->any())
+            ->method('get')
+            ->with($taxRateId)
+            ->will($this->returnValue($rateMock));
+
+        $taxRateConverter = $this->getMockBuilder('\Magento\Tax\Model\Calculation\Rate\Converter')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $taxRateConverter->expects($this->any())
+            ->method('createArrayFromServiceObject')
+            ->with($rateMock, true)
+            ->willReturn($returnArray);
+
+        $jsonObject= $this->getMockBuilder('Magento\Framework\Controller\Result\Json')
+            ->disableOriginalConstructor()
+            ->setMethods(['setData'])
+            ->getMock();
+
+        $jsonObject->expects($this->once())
+            ->method('setData')
+            ->with(['success' => true, 'error_message' => '', 'result'=>
+                $returnArray,
+            ]);
+
+        $this->resultFactory->expects($this->any())
+            ->method('create')
+            ->with(\Magento\Framework\Controller\ResultFactory::TYPE_JSON)
+            ->willReturn($jsonObject);
+
+        $notification = $objectManager->getObject(
+            'Magento\Tax\Controller\Adminhtml\Rate\AjaxLoad',
+            [
+                'taxRateRepository' => $this->taxRateRepository,
+                'taxRateConverter' => $taxRateConverter,
+                'request' => $this->request,
+                'resultFactory' => $this->resultFactory,
+            ]
+        );
+
+
+        // No exception thrown
+        $this->assertSame($jsonObject, $notification->execute());
+
+    }
+
+    /**
+     * Check if validation throws a localized catched exception in case of incorrect id
+     */
+    public function testExecuteLocalizedException()
+    {
+        $taxRateId=999;
+        $exceptionMessage='No such entity with taxRateId = '.$taxRateId;
+        $noSuchEntityEx= new NoSuchEntityException(__($exceptionMessage));
+
+        $objectManager = new ObjectManager($this);
+
+        $this->request->expects($this->any())
+            ->method('getParam')
+            ->will($this->returnValue($taxRateId));
+
+        $this->taxRateRepository->expects($this->any())
+            ->method('get')
+            ->with($taxRateId)
+            ->willThrowException($noSuchEntityEx);
+
+        $jsonObject= $this->getMockBuilder('Magento\Framework\Controller\Result\Json')
+            ->disableOriginalConstructor()
+            ->setMethods(['setData'])
+            ->getMock();
+
+        $jsonObject->expects($this->once())
+            ->method('setData')
+            ->with([
+                'success' => false,
+                'error_message' => $exceptionMessage,
+            ]);
+
+        $this->resultFactory->expects($this->any())
+            ->method('create')
+            ->with(\Magento\Framework\Controller\ResultFactory::TYPE_JSON)
+            ->willReturn($jsonObject);
+
+        $notification = $objectManager->getObject(
+            'Magento\Tax\Controller\Adminhtml\Rate\AjaxLoad',
+            [
+                'taxRateRepository' => $this->taxRateRepository,
+                'request' => $this->request,
+                'resultFactory' => $this->resultFactory,
+            ]
+        );
+
+        //exception thrown with catch
+        $this->assertSame($jsonObject, $notification->execute());
+    }
+
+    /**
+     * Check if validation throws a localized catched exception in case of incorrect id
+     */
+    public function testExecuteException()
+    {
+        $taxRateId=999;
+        $exceptionMessage=__('An error occurred while loading this tax rate.');
+        $noSuchEntityEx= new \Exception();
+
+        $objectManager = new ObjectManager($this);
+
+        $this->request->expects($this->any())
+            ->method('getParam')
+            ->will($this->returnValue($taxRateId));
+
+        $this->taxRateRepository->expects($this->any())
+            ->method('get')
+            ->with($taxRateId)
+            ->willThrowException($noSuchEntityEx);
+
+        $jsonObject= $this->getMockBuilder('Magento\Framework\Controller\Result\Json')
+            ->disableOriginalConstructor()
+            ->setMethods(['setData'])
+            ->getMock();
+
+        $jsonObject->expects($this->once())
+            ->method('setData')
+            ->with([
+                'success' => false,
+                'error_message' => $exceptionMessage,
+            ]);
+
+        $this->resultFactory->expects($this->any())
+            ->method('create')
+            ->with(\Magento\Framework\Controller\ResultFactory::TYPE_JSON)
+            ->willReturn($jsonObject);
+
+        $notification = $objectManager->getObject(
+            'Magento\Tax\Controller\Adminhtml\Rate\AjaxLoad',
+            [
+                'taxRateRepository' => $this->taxRateRepository,
+                'request' => $this->request,
+                'resultFactory' => $this->resultFactory,
+            ]
+        );
+
+        //exception thrown with catch
+        $this->assertSame($jsonObject, $notification->execute());
+    }
+}
diff --git a/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php b/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php
index 2f2a823d5f64d3cb8c3b00a4c864a7108e181c32..8714905efc56bc118efd516eb8346ec1e2045ad6 100644
--- a/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php
+++ b/app/code/Magento/Tax/Test/Unit/Controller/Adminhtml/Tax/IgnoreTaxNotificationTest.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Tax\Test\Unit\Controller\Adminhtml\Tax;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 class IgnoreTaxNotificationTest extends \PHPUnit_Framework_TestCase
@@ -51,7 +52,7 @@ class IgnoreTaxNotificationTest extends \PHPUnit_Framework_TestCase
             ->getMock();
         $config->expects($this->once())
             ->method('saveConfig')
-            ->with('tax/notification/ignore_tax', 1, \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, 0)
+            ->with('tax/notification/ignore_tax', 1, ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 0)
             ->willReturn(null);
 
         $manager = $this->getMockBuilder('\Magento\Framework\ObjectManagerInterface')
diff --git a/app/code/Magento/Tax/Test/Unit/Model/Calculation/Rate/ConverterTest.php b/app/code/Magento/Tax/Test/Unit/Model/Calculation/Rate/ConverterTest.php
index 7fa4b63e75e603558c6a26fe028472552f58fd72..dc4dfcf84c4a377205e513c526e15c427018307c 100644
--- a/app/code/Magento/Tax/Test/Unit/Model/Calculation/Rate/ConverterTest.php
+++ b/app/code/Magento/Tax/Test/Unit/Model/Calculation/Rate/ConverterTest.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Tax\Test\Unit\Model\Calculation\Rate;
 
-use \Magento\Tax\Model\Calculation\Rate\Converter;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 class ConverterTest extends \PHPUnit_Framework_TestCase
 {
@@ -14,9 +14,45 @@ class ConverterTest extends \PHPUnit_Framework_TestCase
      */
     protected $converter;
 
+    /**
+     * @var \Magento\Tax\Api\Data\TaxRateInterfaceFactory
+     */
+    protected $taxRateDataObjectFactory;
+
+    /**
+     * @var \Magento\Tax\Api\Data\TaxRateTitleInterfaceFactory
+     */
+    protected $taxRateTitleDataObjectFactory;
+
+    /**
+     * @var \Magento\Framework\TestFramework\Unit\Helper
+     */
+    protected $objectManager;
+
     public function setUp()
     {
-        $this->converter = new Converter();
+        $this->taxRateDataObjectFactory = $this->getMockBuilder(
+            '\Magento\Tax\Api\Data\TaxRateInterfaceFactory'
+        )
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->taxRateTitleDataObjectFactory = $this->getMockBuilder(
+            '\Magento\Tax\Api\Data\TaxRateTitleInterfaceFactory'
+        )
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+
+        $this->objectManager = new ObjectManager($this);
+        $this->converter =  $this->objectManager->getObject(
+            'Magento\Tax\Model\Calculation\Rate\Converter',
+            [
+                'taxRateDataObjectFactory' =>  $this->taxRateDataObjectFactory,
+                'taxRateTitleDataObjectFactory' => $this->taxRateTitleDataObjectFactory,
+            ]
+        );
     }
 
     public function testCreateTitlesFromServiceObject()
@@ -39,4 +75,48 @@ class ConverterTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals([], $this->converter->createTitleArrayFromServiceObject($taxRateMock));
     }
+
+
+    public function testCreateArrayFromServiceObject()
+    {
+        $taxRateMock = $this->getMock('Magento\Tax\Api\Data\TaxRateInterface');
+        $titlesMock = $this->getMock('Magento\Tax\Api\Data\TaxRateTitleInterface');
+
+        $taxRateMock->expects($this->atLeastOnce())->method('getTitles')->willReturn([$titlesMock]);
+        $titlesMock->expects($this->atLeastOnce())->method('getStoreId')->willReturn(1);
+        $titlesMock->expects($this->atLeastOnce())->method('getValue')->willReturn('Value');
+
+        $this->assertArrayHasKey('title[1]', $this->converter->createArrayFromServiceObject($taxRateMock, true));
+        $this->assertArrayHasKey('title', $this->converter->createArrayFromServiceObject($taxRateMock));
+        $this->assertTrue(is_array($this->converter->createArrayFromServiceObject($taxRateMock)));
+    }
+
+    public function testPopulateTaxRateData()
+    {
+        $rateTitles = [$this->objectManager->getObject(
+            '\Magento\Tax\Model\Calculation\Rate\Title',
+            ['data' => ['store_id' => 1, 'value' => 'texas']]
+        )
+        ];
+        $dataArray=[
+            'tax_country_id' => 'US',
+            'tax_region_id' => 2,
+            'tax_postcode' => null,
+            'rate' => 7.5,
+            'code' => 'Tax Rate Code',
+            'titles' => $rateTitles,
+        ];
+
+        $taxRate = $this->objectManager->getObject(
+            'Magento\Tax\Model\Calculation\Rate',
+            [
+                'data' =>$dataArray,
+            ]
+        );
+
+        $this->taxRateDataObjectFactory->expects($this->once())->method('create')->willReturn($taxRate);
+
+        $this->assertSame($taxRate, $this->converter->populateTaxRateData($dataArray));
+        $this->assertEquals($taxRate->getTitles(), $rateTitles);
+    }
 }
diff --git a/app/code/Magento/Tax/Test/Unit/Model/TaxCalculationTest.php b/app/code/Magento/Tax/Test/Unit/Model/TaxCalculationTest.php
index f4bd04f1adf82bf8c77346c6ead678e85bb99f2c..d88ea2756c2e95330fc1a520c2d2a42c8744b259 100644
--- a/app/code/Magento/Tax/Test/Unit/Model/TaxCalculationTest.php
+++ b/app/code/Magento/Tax/Test/Unit/Model/TaxCalculationTest.php
@@ -199,11 +199,11 @@ class TaxCalculationTest extends \PHPUnit_Framework_TestCase
         $customerId = 100;
         $taxClassId = 200;
         $taxDetailsData = [
-            \Magento\Tax\Api\Data\TaxDetailsInterface::KEY_SUBTOTAL => 0.0,
-            \Magento\Tax\Api\Data\TaxDetailsInterface::KEY_TAX_AMOUNT => 0.0,
-            \Magento\Tax\Api\Data\TaxDetailsInterface::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT => 0.0,
-            \Magento\Tax\Api\Data\TaxDetailsInterface::KEY_APPLIED_TAXES => [],
-            \Magento\Tax\Api\Data\TaxDetailsInterface::KEY_ITEMS => [],
+            \Magento\Tax\Model\TaxDetails\TaxDetails::KEY_SUBTOTAL => 0.0,
+            \Magento\Tax\Model\TaxDetails\TaxDetails::KEY_TAX_AMOUNT => 0.0,
+            \Magento\Tax\Model\TaxDetails\TaxDetails::KEY_DISCOUNT_TAX_COMPENSATION_AMOUNT => 0.0,
+            \Magento\Tax\Model\TaxDetails\TaxDetails::KEY_APPLIED_TAXES => [],
+            \Magento\Tax\Model\TaxDetails\TaxDetails::KEY_ITEMS => [],
         ];
 
         $quoteDetailsMock = $this->getMock('\Magento\Tax\Api\Data\QuoteDetailsInterface');
diff --git a/app/code/Magento/Tax/Test/Unit/Model/TaxClass/ManagementTest.php b/app/code/Magento/Tax/Test/Unit/Model/TaxClass/ManagementTest.php
index 3ceefb565192b79193555b490f15d159f414024b..de391779d3ec915a2796f3404b84206c024cbdbb 100644
--- a/app/code/Magento/Tax/Test/Unit/Model/TaxClass/ManagementTest.php
+++ b/app/code/Magento/Tax/Test/Unit/Model/TaxClass/ManagementTest.php
@@ -79,8 +79,8 @@ class ManagementTest extends \PHPUnit_Framework_TestCase
             ->method('setField')
             ->with(
                 $this->logicalOr(
-                    \Magento\Tax\Api\Data\TaxClassInterface::KEY_TYPE,
-                    \Magento\Tax\Api\Data\TaxClassInterface::KEY_NAME
+                    \Magento\Tax\Model\ClassModel::KEY_TYPE,
+                    \Magento\Tax\Model\ClassModel::KEY_NAME
                 )
             )->willReturnSelf();
 
diff --git a/app/code/Magento/Tax/Test/Unit/Model/TaxClass/Source/CustomerTest.php b/app/code/Magento/Tax/Test/Unit/Model/TaxClass/Source/CustomerTest.php
index 6adec4612fe7b22e96f97bba7dd73119d4a4449c..c36618f8faf5c2a7cdc68b9aab3a16fbe274a5d9 100644
--- a/app/code/Magento/Tax/Test/Unit/Model/TaxClass/Source/CustomerTest.php
+++ b/app/code/Magento/Tax/Test/Unit/Model/TaxClass/Source/CustomerTest.php
@@ -120,7 +120,7 @@ class CustomerTest extends \PHPUnit_Framework_TestCase
 
         $this->filterBuilderMock->expects($this->once())
             ->method('setField')
-            ->with(\Magento\Tax\Api\Data\TaxClassInterface::KEY_TYPE)
+            ->with(\Magento\Tax\Model\ClassModel::KEY_TYPE)
             ->willReturnSelf();
         $this->filterBuilderMock->expects($this->once())
             ->method('setValue')
diff --git a/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml b/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml
index e1941d06d1d4973744aa9e6cc415e282cc799780..4861e4b3bdc539fe555e6eefa3eaad39a489ecdb 100644
--- a/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml
+++ b/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml
@@ -73,16 +73,33 @@ require([
                 id = select.find('option').eq(index).attr('value'),
                 item;
 
-            for(var i = 0, c = taxRateCollection.length; i < c; i++) {
-                if (taxRateCollection[i].tax_calculation_rate_id == id) {
-                    item = taxRateCollection[i];
-                    break;
-                }
-            }
-            item.itemElement = that.prev();
-            $('#tax-rate-form')
-                    .dialogRates({itemRate: item})
-                    .dialogRates('open');
+            $('body').trigger('processStart')
+            $.ajax({
+                type: "POST",
+                data: {id:id},
+                url: '<?php echo $block->getTaxRateLoadUrl()?>',
+                success: function(result, status) {
+                    $('body').trigger('processStop');
+                    if (result.success) {
+                        item=result.result;
+                        item.itemElement = that.prev();
+                        $('#tax-rate-form')
+                            .dialogRates({itemRate: item})
+                            .dialogRates('open');
+
+                    } else {
+                        if (result.error_message)
+                            alert(result.error_message);
+                        else
+                            alert('<?php echo __('An error occurred'); ?>');
+                    }
+                },
+                error: function () {
+                    $('body').trigger('processStop');
+                    alert('<?php echo __('An error occurred'); ?>');
+                },
+                dataType: "json"
+            });
         };
 
         TaxRateEditableMultiselect.prototype.init = function () {
@@ -142,6 +159,7 @@ require([
                                 index = that.parent().index(),
                                 select = that.closest('.mselect-list').prev();
 
+                        $('body').trigger('processStart')
                         var ajaxOptions = {
                             type: 'POST',
                             data: {
@@ -151,12 +169,20 @@ require([
                             dataType: 'json',
                             url: '<?php echo $block->getTaxRateDeleteUrl()?>',
                             success: function(result, status) {
+                                $('body').trigger('processStop');
                                 if (result.success) {
                                     that.parent().remove();
                                     select.find('option').eq(index).remove();
                                 } else {
-                                    alert(result.error_message);
+                                    if (result.error_message)
+                                        alert(result.error_message);
+                                    else
+                                        alert('<?php echo __('An error occurred'); ?>');
                                 }
+                            },
+                            error: function () {
+                                $('body').trigger('processStop');
+                                alert('<?php echo __('An error occurred'); ?>');
                             }
                         };
                         $.ajax(ajaxOptions);
@@ -215,13 +241,15 @@ require([
                         if (!taxRateFormElement.validation().valid()) {
                             return;
                         }
-
+                        $('.tax-rate-popup').trigger('processStart');
+                        $('.loading-mask').css('z-index','1004');
                         var ajaxOptions = {
                             type: 'POST',
                             data: itemRateData,
                             dataType: 'json',
                             url: '<?php echo $block->getTaxRateSaveUrl()?>',
                             success: function(result, status) {
+                                $('body').trigger('processStop');
                                 if (result.success) {
                                     itemRate.code = result.code;
                                     if (itemRate.tax_calculation_rate_id) {
@@ -238,10 +266,16 @@ require([
                                             .val(itemRate.tax_calculation_rate_id);
                                     }
                                     taxRateForm.dialogRates("close");
-                                    taxRateCollection.push(itemRate);
                                 } else {
-                                    alert(result.error_message);
+                                    if (result.error_message)
+                                        alert(result.error_message);
+                                    else
+                                        alert('<?php echo __('An error occurred'); ?>');
                                 }
+                            },
+                            error: function () {
+                                $('body').trigger('processStop');
+                                alert('<?php echo __('An error occurred'); ?>');
                             }
                         };
                         $.ajax(ajaxOptions);
@@ -256,6 +290,7 @@ require([
                     }
                 }]
             });
+            $('.grid-loading-mask').hide();
         }
     };
 
diff --git a/app/code/Magento/Tax/view/adminhtml/templates/rule/rate/form.phtml b/app/code/Magento/Tax/view/adminhtml/templates/rule/rate/form.phtml
index eae01d9d0b302c71017afb3571349eb82bcc6043..d5c0d8aee3b6a8f84af22f3fd90f2c2afde1f0f5 100644
--- a/app/code/Magento/Tax/view/adminhtml/templates/rule/rate/form.phtml
+++ b/app/code/Magento/Tax/view/adminhtml/templates/rule/rate/form.phtml
@@ -5,14 +5,13 @@
  */
 /* @var $block \Magento\Tax\Block\Adminhtml\Rate\Form */
 ?>
+
+<div data-role="spinner" class="grid-loading-mask">
+    <div class="grid-loader"></div>
+</div>
+
 <div class="form-inline" id="<?php echo $block->getNameInLayout() ?>" style="display:none">
     <?php echo $block->getFormHtml();?>
     <?php echo $block->getChildHtml('form_after');?>
 </div>
 
-<script>
-
-
-    var taxRateCollection = <?php echo json_encode($block->getRateCollection());?>;
-
-</script>
diff --git a/app/code/Magento/Theme/Model/Config.php b/app/code/Magento/Theme/Model/Config.php
index 5993e9bf010d5586384e03bdc4df50010f882547..39332cc9a0b7b7705db033cb7996e0fd3c482e90 100644
--- a/app/code/Magento/Theme/Model/Config.php
+++ b/app/code/Magento/Theme/Model/Config.php
@@ -9,6 +9,8 @@
  */
 namespace Magento\Theme\Model;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 class Config
 {
     /**
@@ -173,7 +175,7 @@ class Config
     protected function _assignThemeToDefaultScope($themeId, &$isReassigned)
     {
         $configPath = \Magento\Framework\View\DesignInterface::XML_PATH_THEME_ID;
-        $this->_configWriter->save($configPath, $themeId, \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT);
+        $this->_configWriter->save($configPath, $themeId, ScopeConfigInterface::SCOPE_TYPE_DEFAULT);
         $isReassigned = true;
         return $this;
     }
diff --git a/app/code/Magento/Theme/Model/View/Design.php b/app/code/Magento/Theme/Model/View/Design.php
index f839d6ba900f71e2998634aa9e36776bcd863105..f0cf795f6b4482b9c8ac59bc444e62f4af24f14c 100644
--- a/app/code/Magento/Theme/Model/View/Design.php
+++ b/app/code/Magento/Theme/Model/View/Design.php
@@ -6,6 +6,8 @@
 
 namespace Magento\Theme\Model\View;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 /**
  * Keeps design settings for current request
  */
@@ -167,7 +169,7 @@ class Design implements \Magento\Framework\View\DesignInterface
             if ($this->_storeManager->isSingleStoreMode()) {
                 $theme = $this->_scopeConfig->getValue(
                     self::XML_PATH_THEME_ID,
-                    \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+                    ScopeConfigInterface::SCOPE_TYPE_DEFAULT
                 );
             } else {
                 $theme = (string) $this->_scopeConfig->getValue(
diff --git a/app/code/Magento/User/Controller/Adminhtml/User/Edit.php b/app/code/Magento/User/Controller/Adminhtml/User/Edit.php
index 3d3ad64cd201a0bf5cc7eb3691852ab451317e21..39ac43d55391ba02f47089b28233a7f13e791d86 100644
--- a/app/code/Magento/User/Controller/Adminhtml/User/Edit.php
+++ b/app/code/Magento/User/Controller/Adminhtml/User/Edit.php
@@ -6,6 +6,8 @@
  */
 namespace Magento\User\Controller\Adminhtml\User;
 
+use Magento\Framework\Locale\Resolver;
+
 class Edit extends \Magento\User\Controller\Adminhtml\User
 {
     /**
@@ -25,7 +27,7 @@ class Edit extends \Magento\User\Controller\Adminhtml\User
                 return;
             }
         } else {
-            $model->setInterfaceLocale(\Magento\Framework\Locale\ResolverInterface::DEFAULT_LOCALE);
+            $model->setInterfaceLocale(Resolver::DEFAULT_LOCALE);
         }
 
         // Restore previously entered form data from session
diff --git a/app/code/Magento/Weee/Model/Observer.php b/app/code/Magento/Weee/Model/Observer.php
index daca840e903b7e2e8c0f11390a84c259a66ff837..08831d28845bc7fb62e842af1178310da6208160 100644
--- a/app/code/Magento/Weee/Model/Observer.php
+++ b/app/code/Magento/Weee/Model/Observer.php
@@ -194,4 +194,37 @@ class Observer extends \Magento\Framework\Model\AbstractModel
         $response->setTypes($types);
         return $this;
     }
+
+    /**
+     * Modify the options config for the front end to resemble the weee final price
+     *
+     * @param   \Magento\Framework\Event\Observer $observer
+     * @return  $this
+     */
+    public function getPriceConfiguration(\Magento\Framework\Event\Observer $observer)
+    {
+        if ($this->_weeeData->isEnabled()) {
+            $priceConfigObj=$observer->getData('configObj');
+            $priceConfig=$priceConfigObj->getConfig();
+            if (is_array($priceConfig)) {
+                foreach ($priceConfig as $keyConfigs => $configs) {
+                    if (is_array($configs)) {
+                        if (array_key_exists('prices', $configs)) {
+                            $priceConfig[$keyConfigs]['prices']['weeePrice'] = [
+                                'amount' => $configs['prices']['finalPrice']['amount'],
+                            ];
+                        } else {
+                            foreach ($configs as $keyConfig => $config) {
+                                $priceConfig[$keyConfigs][$keyConfig]['prices']['weeePrice'] = [
+                                    'amount' => $config['prices']['finalPrice']['amount'],
+                                ];
+                            }
+                        }
+                    }
+                }
+            }
+            $priceConfigObj->setConfig($priceConfig);
+        }
+        return $this;
+    }
 }
diff --git a/app/code/Magento/Weee/Pricing/Render/Adjustment.php b/app/code/Magento/Weee/Pricing/Render/Adjustment.php
index 2272c719cb94c6b6196e023f0540071693975efb..f13c044532f0514e0c230b8f51ae88b045d060b1 100644
--- a/app/code/Magento/Weee/Pricing/Render/Adjustment.php
+++ b/app/code/Magento/Weee/Pricing/Render/Adjustment.php
@@ -61,6 +61,14 @@ class Adjustment extends AbstractAdjustment
         return $this->toHtml();
     }
 
+    /**
+     * @return float
+     */
+    public function getRawFinalAmount()
+    {
+        return $this->finalAmount;
+    }
+
     /**
      * Obtain adjustment code
      *
diff --git a/app/code/Magento/Weee/Test/Unit/Model/ObserverTest.php b/app/code/Magento/Weee/Test/Unit/Model/ObserverTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..63a13abb53622e5f93590a1586d695fb17e18707
--- /dev/null
+++ b/app/code/Magento/Weee/Test/Unit/Model/ObserverTest.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/**
+ * Test class for \Magento\Weee\Model\Observer
+ */
+namespace Magento\Weee\Test\Unit\Model;
+
+use \Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class ObserverTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Tests the methods that rely on the ScopeConfigInterface object to provide their return values
+     *
+     */
+    public function testGetPriceConfiguration()
+    {
+        $testArray=[
+            [
+                [
+                    'prices' =>
+                        [
+                            'finalPrice' => [
+                                    'amount' => 31.50,
+                            ],
+                        ],
+                ],
+                [
+                    'prices' =>
+                        [
+                            'finalPrice' =>[
+                                'amount' => 31.50,
+                            ],
+                        ],
+                ],
+            ],
+        ];
+
+        $configObj = new \Magento\Framework\Object(
+            [
+                'config' => $testArray,
+            ]
+        );
+
+        $testArrayWithWeee=$testArray;
+        $testArrayWithWeee[0][0]['prices']['weeePrice']= [
+            'amount' => $testArray[0][0]['prices']['finalPrice']['amount'],
+        ];
+        $testArrayWithWeee[0][1]['prices']['weeePrice']= [
+            'amount' => $testArray[0][1]['prices']['finalPrice']['amount'],
+        ];
+
+        $weeHelper=$this->getMock('Magento\Weee\Helper\Data', [], [], '', false);
+        $weeHelper->expects($this->any())
+            ->method('isEnabled')
+            ->will($this->returnValue(true));
+
+        $observerObject=$this->getMock('Magento\Framework\Event\Observer', [], [], '', false);
+
+        $observerObject->expects($this->any())
+            ->method('getData')
+            ->with('configObj')
+            ->will($this->returnValue($configObj));
+
+         $objectManager = new ObjectManager($this);
+         $weeeObserverObject = $objectManager->getObject(
+             'Magento\Weee\Model\Observer',
+             [
+                 'weeeData' => $weeHelper,
+             ]
+         );
+         $weeeObserverObject->getPriceConfiguration($observerObject);
+
+         $this->assertEquals($testArrayWithWeee, $configObj->getData('config'));
+    }
+}
diff --git a/app/code/Magento/Weee/etc/events.xml b/app/code/Magento/Weee/etc/events.xml
index b6ef0f804b1fd72258baff580d5257b90dd1a31e..f4300f38b2369817d96c1902c29c57d378676f17 100644
--- a/app/code/Magento/Weee/etc/events.xml
+++ b/app/code/Magento/Weee/etc/events.xml
@@ -9,4 +9,7 @@
     <event name="catalog_entity_attribute_save_before">
         <observer name="weee" instance="Magento\Weee\Model\Observer" method="assignBackendModelToAttribute" shared="false" />
     </event>
+    <event name="catalog_product_option_price_configuration_after">
+        <observer name="weee" instance="Magento\Weee\Model\Observer" method="getPriceConfiguration" shared="false" />
+    </event>
 </config>
diff --git a/app/code/Magento/Weee/view/base/templates/pricing/adjustment.phtml b/app/code/Magento/Weee/view/base/templates/pricing/adjustment.phtml
index 86267dea51a757c481bff1d110c6ce121cd41a5e..f8a77699ff4d9356fa99cf9eed5925efbc1b3a3d 100644
--- a/app/code/Magento/Weee/view/base/templates/pricing/adjustment.phtml
+++ b/app/code/Magento/Weee/view/base/templates/pricing/adjustment.phtml
@@ -28,5 +28,7 @@ $closeBrace = ')';
               data-label="<?php echo $block->renderWeeeTaxAttributeName($weeeTaxAttribute); ?>"><?php echo $block->renderWeeeTaxAttribute($weeeTaxAttribute); ?></span>
     <?php endforeach; ?>
     <span class="price-final_price"
+          data-price-type="weeePrice"
+          data-price-amount="<?php echo $block->getRawFinalAmount(); ?>"
           data-label="<?php echo __('Final Price'); ?>"><?php echo $block->getFinalAmount(); ?></span>
 <?php endif; ?>
diff --git a/app/etc/di.xml b/app/etc/di.xml
index c461dc254c841721a21146ff4010a00f848f1124..7ffd8702c787b917c82fb2073953559106c98119 100755
--- a/app/etc/di.xml
+++ b/app/etc/di.xml
@@ -964,6 +964,11 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\Object\Copy\Config">
+        <arguments>
+            <argument name="dataStorage" xsi:type="object">Magento\Framework\Object\Copy\Config\Data\Proxy</argument>
+        </arguments>
+    </type>
     <type name="Magento\Framework\Object\Copy\Config\Reader">
         <arguments>
             <argument name="fileName" xsi:type="string">fieldset.xml</argument>
@@ -1101,4 +1106,9 @@
             </argument>
         </arguments>
     </type>
+    <type name="Magento\Framework\Url\Decoder">
+        <arguments>
+            <argument name="urlBuilder" xsi:type="object">Magento\Framework\UrlInterface\Proxy</argument>
+        </arguments>
+    </type>
 </config>
diff --git a/dev/shell/cache.php b/dev/shell/cache.php
deleted file mode 100644
index 9c44a5914daa6e255fe74d66ca587da01cd4ed35..0000000000000000000000000000000000000000
--- a/dev/shell/cache.php
+++ /dev/null
@@ -1,52 +0,0 @@
-<?php
-/**
- * A CLI tool for managing Magento application caches
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Framework\App;
-
-use Magento\Framework\App\Cache\ManagerApp;
-use Magento\Framework\Shell\ComplexParameter;
-
-require __DIR__ . '/../../app/bootstrap.php';
-
-$usage = 'Usage: php -f cache.php -- [--' . ManagerApp::KEY_SET . '=1|0]'
-    . ' [--' . ManagerApp::KEY_CLEAN . ']'
-    . ' [--' . ManagerApp::KEY_STATUS . ']'
-    . ' [--' . ManagerApp::KEY_FLUSH . ']'
-    . ' [--' . ManagerApp::KEY_TYPES . '=<type1>,<type2>,...]'
-    . ' [--bootstrap=' . escapeshellarg('INIT_PARAM=foo&ANOTHER_PARAM[key]=bar') . ']
-    --' . ManagerApp::KEY_TYPES . ' - list of cache types, comma-separated. If omitted, all caches will be affected
-    --' . ManagerApp::KEY_SET . ' - enable or disable the specified cache types
-    --' . ManagerApp::KEY_CLEAN . ' - clean data of the specified cache types
-    --' . ManagerApp::KEY_STATUS . ' - display current status for each cache type
-    --' . ManagerApp::KEY_FLUSH . ' - destroy all data in storage that the specified cache types reside on
-    --bootstrap - add or override parameters of the bootstrap' . PHP_EOL;
-$longOpts = [
-    ManagerApp::KEY_SET . '::',
-    ManagerApp::KEY_CLEAN,
-    ManagerApp::KEY_STATUS,
-    ManagerApp::KEY_FLUSH,
-    ManagerApp::KEY_TYPES . '::',
-    'bootstrap::',
-];
-$opt = getopt('', $longOpts);
-if (empty($opt)) {
-    echo $usage;
-}
-
-try {
-    $bootstrapParam = new ComplexParameter('bootstrap');
-    $params = $bootstrapParam->mergeFromArgv($_SERVER, $_SERVER);
-    $params[Bootstrap::PARAM_REQUIRE_MAINTENANCE] = null;
-    $bootstrap = Bootstrap::create(BP, $params);
-    /** @var ManagerApp $app */
-    $app = $bootstrap->createApplication('Magento\Framework\App\Cache\ManagerApp', ['requestArgs' => $opt]);
-    $bootstrap->run($app);
-} catch (\Exception $e) {
-    echo $e;
-    exit(1);
-}
diff --git a/dev/shell/indexer.php b/dev/shell/indexer.php
deleted file mode 100644
index 08c6cbe77d70f0f9ef0cebc7cd720f91fa74d669..0000000000000000000000000000000000000000
--- a/dev/shell/indexer.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-use Magento\Framework\App\Bootstrap;
-use Magento\Store\Model\StoreManager;
-
-require __DIR__ . '/../../app/bootstrap.php';
-$params = $_SERVER;
-$params[StoreManager::PARAM_RUN_CODE] = 'admin';
-$params[StoreManager::PARAM_RUN_TYPE] = 'store';
-$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params);
-/** @var \Magento\Indexer\App\Shell $application */
-$app = $bootstrap->createApplication('Magento\Indexer\App\Shell', ['entryFileName' => basename(__FILE__)]);
-$bootstrap->run($app);
diff --git a/dev/shell/log.php b/dev/shell/log.php
deleted file mode 100644
index 181b07ac06f9f1444d5527d4d0c34ddd143f44b1..0000000000000000000000000000000000000000
--- a/dev/shell/log.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-use Magento\Framework\App\Bootstrap;
-use Magento\Store\Model\StoreManager;
-
-require __DIR__ . '/../../app/bootstrap.php';
-$params = $_SERVER;
-$params[StoreManager::PARAM_RUN_CODE] = 'admin';
-$params[StoreManager::PARAM_RUN_TYPE] = 'store';
-$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $params);
-/** @var \Magento\Log\App\Shell $app */
-$app = $bootstrap->createApplication('Magento\Log\App\Shell', ['entryFileName' => basename(__FILE__)]);
-$bootstrap->run($app);
diff --git a/dev/tools/Magento/Tools/I18n/bootstrap.php b/dev/tests/api-functional/config/config-global.php.dist
similarity index 64%
rename from dev/tools/Magento/Tools/I18n/bootstrap.php
rename to dev/tests/api-functional/config/config-global.php.dist
index 61706a7fde27c998109e16d10734951523a7deee..f24e2ce9ccae044dda5ccadb9ccc4e54946558e2 100644
--- a/dev/tools/Magento/Tools/I18n/bootstrap.php
+++ b/dev/tests/api-functional/config/config-global.php.dist
@@ -3,4 +3,5 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-require_once __DIR__ . '/../../../../../app/autoload.php';
+
+return [];
\ No newline at end of file
diff --git a/dev/tests/api-functional/framework/bootstrap.php b/dev/tests/api-functional/framework/bootstrap.php
index 27a9b855d69497ab089aafde2c1615e81ca85965..2df18e828bfa8d9b759d1b4ff75867aa82f84ba6 100644
--- a/dev/tests/api-functional/framework/bootstrap.php
+++ b/dev/tests/api-functional/framework/bootstrap.php
@@ -44,11 +44,16 @@ $installConfigFile = $settings->getAsConfigFile('TESTS_INSTALL_CONFIG_FILE');
 if (!file_exists($installConfigFile)) {
     $installConfigFile = $installConfigFile . '.dist';
 }
+$globalConfigFile = $settings->getAsConfigFile('TESTS_GLOBAL_CONFIG_FILE');
+if (!file_exists($installConfigFile)) {
+    $installConfigFile = $installConfigFile . '.dist';
+}
 $dirList = new \Magento\Framework\App\Filesystem\DirectoryList(BP);
 $application =  new \Magento\TestFramework\WebApiApplication(
     $shell,
     $dirList->getPath(DirectoryList::VAR_DIR),
     $installConfigFile,
+    $globalConfigFile,
     BP . '/app/etc/',
     $settings->get('TESTS_MAGENTO_MODE'),
     AutoloaderRegistry::getAutoloader()
diff --git a/dev/tests/api-functional/phpunit.xml.dist b/dev/tests/api-functional/phpunit.xml.dist
index ad98d96c2ab49ee5e1028123de6deadc82ad82af..5138d64ee83540d375a91bc64ee35f72a3b7cf53 100644
--- a/dev/tests/api-functional/phpunit.xml.dist
+++ b/dev/tests/api-functional/phpunit.xml.dist
@@ -31,6 +31,7 @@
     <php>
         <includePath>./testsuite</includePath>
         <const name="TESTS_INSTALL_CONFIG_FILE" value="config/install-config-mysql.php"/>
+        <const name="TESTS_GLOBAL_CONFIG_FILE" value="config/config-global.php"/>
         <!-- WebSerivice Type. Possible values: soap, rest -->
         <const name="TESTS_WEB_API_ADAPTER" value="rest"/>
         <!-- Webserver URL -->
diff --git a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
index fb6588a7f4107cf2ff07095ff3820e442ee10a87..a0f06e0ce7aac3fa6752c18a2adb47af1ba2e544 100644
--- a/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Catalog/Api/ProductRepositoryInterfaceTest.php
@@ -126,7 +126,6 @@ class ProductRepositoryInterfaceTest extends WebapiAbstract
 
     public function testProductLinks()
     {
-        $this->markTestSkipped('Skipped until MAGETWO-35458 is ready');
         // Create simple product
         $productData =  [
             ProductInterface::SKU => "product_simple_500",
@@ -140,9 +139,10 @@ class ProductRepositoryInterfaceTest extends WebapiAbstract
         ];
 
         $this->saveProduct($productData);
+
         $productLinkData = ["product_sku" => "product_simple_with_related_500", "link_type" => "related",
                             "linked_product_sku" => "product_simple_500", "linked_product_type" => "simple",
-                            "position" => 0];
+                            "position" => 0, "extension_attributes" => []];
         $productWithRelatedData =  [
             ProductInterface::SKU => "product_simple_with_related_500",
             ProductInterface::NAME => "Product Simple with Related 500",
@@ -166,7 +166,7 @@ class ProductRepositoryInterfaceTest extends WebapiAbstract
         // update link information
         $productLinkData = ["product_sku" => "product_simple_with_related_500", "link_type" => "upsell",
                             "linked_product_sku" => "product_simple_500", "linked_product_type" => "simple",
-                            "position" => 0];
+                            "position" => 0, "extension_attributes" => []];
         $productWithUpsellData =  [
             ProductInterface::SKU => "product_simple_with_related_500",
             ProductInterface::NAME => "Product Simple with Related 500",
@@ -174,7 +174,6 @@ class ProductRepositoryInterfaceTest extends WebapiAbstract
             ProductInterface::TYPE_ID => 'simple',
             ProductInterface::PRICE => 100,
             ProductInterface::STATUS => 1,
-            ProductInterface::TYPE_ID => 'simple',
             ProductInterface::ATTRIBUTE_SET_ID => 4,
             "product_links" => [$productLinkData]
         ];
@@ -195,18 +194,15 @@ class ProductRepositoryInterfaceTest extends WebapiAbstract
             ProductInterface::TYPE_ID => 'simple',
             ProductInterface::PRICE => 100,
             ProductInterface::STATUS => 1,
-            ProductInterface::TYPE_ID => 'simple',
             ProductInterface::ATTRIBUTE_SET_ID => 4,
             "product_links" => []
         ];
 
         $this->saveProduct($productWithNoLinkData);
         $response = $this->getProduct("product_simple_with_related_500");
-
         $this->assertArrayHasKey('product_links', $response);
         $links = $response['product_links'];
-        $this->assertEquals(1, count($links));
-        $this->assertEquals([], $links[0]);
+        $this->assertEquals([], $links);
 
         $this->deleteProduct("product_simple_500");
         $this->deleteProduct("product_simple_with_related_500");
diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/ProductRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/ProductRepositoryInterfaceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0a5a6a9faa72c64b8ceb5dcce87fd81f55ec92f3
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/ProductRepositoryInterfaceTest.php
@@ -0,0 +1,398 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\CatalogInventory\Api;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\CatalogInventory\Api\Data\StockStatusInterface;
+use Magento\Framework\Api\ExtensibleDataInterface;
+use Magento\TestFramework\TestCase\WebapiAbstract;
+
+class ProductRepositoryInterfaceTest extends WebapiAbstract
+{
+    const SERVICE_NAME = 'catalogProductRepositoryV1';
+    const SERVICE_VERSION = 'V1';
+    const RESOURCE_PATH = '/V1/products';
+
+    const KEY_EXTENSION_ATTRIBUTES = ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY;
+    const KEY_STOCK_ITEM = StockStatusInterface::STOCK_ITEM;
+    const KEY_QTY = StockStatusInterface::QTY;
+    const KEY_ITEM_ID = 'item_id';
+    const KEY_PRODUCT_ID = StockStatusInterface::PRODUCT_ID;
+    const KEY_WEBSITE_ID = StockStatusInterface::WEBSITE_ID;
+    const KEY_CUSTOM_ATTRIBUTES = 'custom_attributes';
+    const KEY_ATTRIBUTE_CODE = \Magento\Eav\Api\Data\AttributeInterface::ATTRIBUTE_CODE;
+    const CODE_QUANTITY_AND_STOCK_STATUS = 'quantity_and_stock_status';
+
+    const PRODUCT_SKU = 'sku-test-catalog-inventory';
+
+    /**
+     * Tests the 'happy path'
+     */
+    public function testCatalogInventory()
+    {
+        // create a simple product with catalog inventory
+        $qty = 1234;
+        $productData = $this->getSimpleProductData($qty);
+        $stockItemData = $this->getStockItemData($qty);
+        $this->assertArrayNotHasKey(self::KEY_ITEM_ID, $stockItemData);
+        $this->assertArrayNotHasKey(self::KEY_WEBSITE_ID, $stockItemData);
+        $this->assertArrayNotHasKey(self::KEY_PRODUCT_ID, $stockItemData);
+        $productData[self::KEY_EXTENSION_ATTRIBUTES] = $stockItemData;
+
+        $response = $this->saveProduct($productData);
+
+        $this->assertArrayHasKey(self::KEY_EXTENSION_ATTRIBUTES, $response);
+        $this->assertTrue(isset($response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM]));
+        $stockItemData = $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM];
+        $returnedQty = $stockItemData[self::KEY_QTY];
+        $this->assertEquals($qty, $returnedQty, 'CREATE: Expected qty to be same: ' . $qty .', '. $returnedQty);
+        $this->assertArrayHasKey(self::KEY_ITEM_ID, $stockItemData);
+        $this->assertArrayHasKey(self::KEY_PRODUCT_ID, $stockItemData);
+        $this->assertArrayHasKey(self::KEY_WEBSITE_ID, $stockItemData);
+
+        // officially get the product
+        $response = $this->getProduct($productData[ProductInterface::SKU]);
+
+        $stockItemData = $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM];
+        $returnedQty = $stockItemData[self::KEY_QTY];
+        $this->assertEquals($qty, $returnedQty, 'GET: Expected qty to be same: ' . $qty .', '. $returnedQty);
+
+        // update the catalog inventory
+        $qty = $this->getDifferent($qty);  // update the quantity
+        $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM][self::KEY_QTY] = $qty;
+
+        $response = $this->updateProduct($response);
+
+        $stockItemData = $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM];
+        $returnedQty = $stockItemData[self::KEY_QTY];
+        $this->assertEquals($qty, $returnedQty, 'UPDATE 1: Expected qty to be same: ' . $qty .', '. $returnedQty);
+
+        $customAttributeQty = $this->findCustomAttributeQty($response[self::KEY_CUSTOM_ATTRIBUTES]);
+        $this->assertTrue(!is_bool($customAttributeQty), 'Expected to find a quantity in the custom attributes');
+        $this->assertEquals(
+            $qty,
+            $customAttributeQty,
+            'UPDATE 1: Expected custom attribute qty to be updated: ' . $qty .', '. $customAttributeQty
+        );
+
+        // update the product without any mention of catalog inventory; no change expected for catalog inventory
+        // note: $qty expected to be the same as previously set, above
+        $newPrice = $this->getDifferent($response[ProductInterface::PRICE]);
+        $response[ProductInterface::PRICE] = $newPrice;
+        unset($response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM]);
+
+        $response = $this->updateProduct($response);
+
+        $this->assertArrayHasKey(self::KEY_EXTENSION_ATTRIBUTES, $response);
+        $this->assertTrue(isset($response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM]));
+        $stockItemData = $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM];
+        $returnedQty = $stockItemData[self::KEY_QTY];
+        $this->assertEquals($qty, $returnedQty, 'UPDATE 2: Expected qty to be same: ' . $qty .', '. $returnedQty);
+        $this->assertEquals($newPrice, $response[ProductInterface::PRICE]);
+
+        // delete the product; expect that all goes well
+        $response = $this->deleteProduct($productData[ProductInterface::SKU]);
+        $this->assertTrue($response);
+    }
+
+    /**
+     * Tests conditions that stray from the 'happy path'
+     */
+    public function testCatalogInventoryWithBogusData()
+    {
+        // create a simple product with catalog inventory
+        $qty = 666;
+        $productData = $this->getSimpleProductData($qty);
+        $stockItemData = $this->getStockItemData($qty);
+        $this->assertArrayNotHasKey(self::KEY_ITEM_ID, $stockItemData);
+        $this->assertArrayNotHasKey(self::KEY_WEBSITE_ID, $stockItemData);
+        $this->assertArrayNotHasKey(self::KEY_PRODUCT_ID, $stockItemData);
+        $productData[self::KEY_EXTENSION_ATTRIBUTES] = $stockItemData;
+
+        $response = $this->saveProduct($productData);
+
+        $this->assertArrayHasKey(self::KEY_EXTENSION_ATTRIBUTES, $response);
+        $this->assertTrue(isset($response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM]));
+        $stockItemData = $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM];
+        $returnedQty = $stockItemData[self::KEY_QTY];
+        $this->assertEquals($qty, $returnedQty, 'POST 1: Expected qty to be same: ' . $qty .', '. $returnedQty);
+        $this->assertArrayHasKey(self::KEY_ITEM_ID, $stockItemData);
+        $this->assertArrayHasKey(self::KEY_PRODUCT_ID, $stockItemData);
+        $this->assertArrayHasKey(self::KEY_WEBSITE_ID, $stockItemData);
+
+        // re-save the catalog inventory:
+        // -- update quantity (which should be honored)
+        // -- supply an incorrect product id (which should be ignored, and be replaced with the actual one)
+        // -- supply an incorrect website id (which should be ignored, and be replaced with the actual one)
+        $qty = 777;  // update the quantity
+        $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM][self::KEY_QTY] = $qty;
+
+        $originalProductId = $stockItemData[self::KEY_PRODUCT_ID];
+        $bogusProductId = $this->getDifferent($originalProductId);
+        $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM][self::KEY_PRODUCT_ID] = $bogusProductId;
+
+        $originalWebsiteId = $stockItemData[self::KEY_WEBSITE_ID];
+        $bogusWebsiteId = $this->getDifferent($originalWebsiteId);
+        $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM][self::KEY_WEBSITE_ID] = $bogusWebsiteId;
+
+        $response = $this->saveProduct($response);
+
+        $stockItemData = $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM];
+        $returnedQty = $stockItemData[self::KEY_QTY];
+        $this->assertEquals($qty, $returnedQty, 'POST 2: Expected qty to be same: ' . $qty .', '. $returnedQty);
+
+        $returnedProductId = $stockItemData[self::KEY_PRODUCT_ID];
+        $this->assertEquals($originalProductId, $returnedProductId);
+
+        $returnedWebsiteId = $stockItemData[self::KEY_WEBSITE_ID];
+        $this->assertEquals($originalWebsiteId, $returnedWebsiteId);
+
+        // delete the product; expect that all goes well
+        $response = $this->deleteProduct($productData[ProductInterface::SKU]);
+        $this->assertTrue($response);
+    }
+
+    /**
+     * Tests that creating a simple product has a side-effect of creating catalog inventory
+     */
+    public function testSimpleProductCreationWithoutSpecifyingCatalogInventory()
+    {
+        // create a simple product with catalog inventory
+        $qty = null;
+        $productData = $this->getSimpleProductData($qty);
+        $this->assertArrayNotHasKey(self::KEY_CUSTOM_ATTRIBUTES, $productData);
+        $this->assertArrayNotHasKey(self::KEY_EXTENSION_ATTRIBUTES, $productData);
+
+        $response = $this->saveProduct($productData);
+
+        $this->assertArrayHasKey(self::KEY_EXTENSION_ATTRIBUTES, $response);
+        $this->assertTrue(isset($response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM]));
+        $stockItemData = $response[self::KEY_EXTENSION_ATTRIBUTES][self::KEY_STOCK_ITEM];
+        $this->assertArrayHasKey(self::KEY_ITEM_ID, $stockItemData);
+        $this->assertArrayHasKey(self::KEY_PRODUCT_ID, $stockItemData);
+        $this->assertArrayHasKey(self::KEY_WEBSITE_ID, $stockItemData);
+
+        // delete the product; expect that all goes well
+        $response = $this->deleteProduct($productData[ProductInterface::SKU]);
+        $this->assertTrue($response);
+    }
+
+    // --- my helpers -----------------------------------------------------------------------------
+
+    /**
+     * Return a value that is different than the original one
+     *
+     * @param int $original
+     * @return int
+     */
+    protected function getDifferent($original)
+    {
+        return 1 + $original * $original;
+    }
+
+    /**
+     * Returns the product's quantity from the array of custom attributes.
+     * If no quantity can be found, will return false.
+     *
+     * @param array $customAttributes
+     * @return int|bool
+     */
+    protected function findCustomAttributeQty($customAttributes)
+    {
+        $qty = false;
+        $qtyAndStockStatus = [];
+        foreach ($customAttributes as $customAttribute) {
+            if ($customAttribute[self::KEY_ATTRIBUTE_CODE] == self::CODE_QUANTITY_AND_STOCK_STATUS) {
+                $qtyAndStockStatus = $customAttribute['value'];
+                break;
+            }
+        }
+        if (!empty($qtyAndStockStatus) && is_array($qtyAndStockStatus)) {
+
+            if (array_key_exists('any_type', $qtyAndStockStatus)) {
+                // for SOAP, need to use the inner array
+                $qtyAndStockStatus = $qtyAndStockStatus['any_type'];
+            }
+
+            // ex: [true, 1234]
+            if (is_bool($qtyAndStockStatus[0]) || is_string($qtyAndStockStatus[0])) {
+                $qty = $qtyAndStockStatus[1];
+            } else {
+                $qty = $qtyAndStockStatus[0];
+            }
+        }
+        return $qty;
+    }
+
+    /**
+     * Get Simple Product Data
+     *
+     * @param int $qty
+     * @return array
+     */
+    protected function getSimpleProductData($qty = 1000)
+    {
+        $productData = [
+            ProductInterface::SKU => self::PRODUCT_SKU,
+            ProductInterface::NAME => self::PRODUCT_SKU,
+            ProductInterface::VISIBILITY => 4,
+            ProductInterface::TYPE_ID => 'simple',
+            ProductInterface::PRICE => 10,
+            ProductInterface::STATUS => 1,
+            ProductInterface::ATTRIBUTE_SET_ID => 4,
+        ];
+
+        if ($qty != null) {
+            $productData[self::KEY_CUSTOM_ATTRIBUTES] = [
+                [self::KEY_ATTRIBUTE_CODE => 'description', 'value' => 'My Product Description'],
+                [self::KEY_ATTRIBUTE_CODE => self::CODE_QUANTITY_AND_STOCK_STATUS, 'value' => [true, $qty]],
+            ];
+        }
+
+        return $productData;
+    }
+
+    /**
+     * Get sample Stock Item data
+     *
+     * @param int $qty
+     * @return array
+     */
+    protected function getStockItemData($qty = 1000)
+    {
+        return [
+            self::KEY_STOCK_ITEM => [
+                self::KEY_QTY => $qty,
+                'is_in_stock' => true,
+                'is_qty_decimal' => false,
+                'show_default_notification_message' => false,
+                'use_config_min_qty' => true,
+                'min_qty' => 0,
+                'use_config_min_sale_qty' => 1,
+                'min_sale_qty' => 1,
+                'use_config_max_sale_qty' => true,
+                'max_sale_qty' => 10000,
+                'use_config_backorders' => true,
+                'backorders' => 0,
+                'use_config_notify_stock_qty' => true,
+                'notify_stock_qty' => 1,
+                'use_config_qty_increments' => true,
+                'qty_increments' => 0,
+                'use_config_enable_qty_inc' => false,
+                'enable_qty_increments' => false,
+                'use_config_manage_stock' => false,
+                'manage_stock' => true,
+                'low_stock_date' => "0",
+                'is_decimal_divided' => false,
+                'stock_status_changed_auto' => 0,
+            ]
+        ];
+    }
+
+    // --- common REST helpers --------------------------------------------------------------------
+
+    /**
+     * Get a product via its sku
+     *
+     * @param string $sku
+     * @return array the product data
+     */
+    protected function getProduct($sku)
+    {
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH . '/' . $sku,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Get',
+            ],
+        ];
+
+        $response = $this->_webApiCall($serviceInfo, ['sku' => $sku]);
+        return $response;
+    }
+
+    /**
+     * Save a product
+     *
+     * @param array $product
+     * @return array the created product data
+     */
+    protected function saveProduct($product)
+    {
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Save',
+            ],
+        ];
+        $requestData = ['product' => $product];
+        $response = $this->_webApiCall($serviceInfo, $requestData);
+        return $response;
+    }
+
+    /**
+     * Update an existing product via its sku
+     *
+     * @param array $product
+     * @return array the product data, including any updates
+     */
+    protected function updateProduct($product)
+    {
+        $sku = $product[ProductInterface::SKU];
+        if (TESTS_WEB_API_ADAPTER == self::ADAPTER_REST) {
+            $product[ProductInterface::SKU] = null;
+        }
+
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH . '/' . $sku,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Save',
+            ],
+        ];
+        $requestData = ['product' => $product];
+        $response =  $this->_webApiCall($serviceInfo, $requestData);
+        return $response;
+    }
+
+    /**
+     * Delete a product via its sku
+     *
+     * @param string $sku
+     * @return bool
+     */
+    protected function deleteProduct($sku)
+    {
+        $resourcePath = self::RESOURCE_PATH . '/' . $sku;
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => $resourcePath,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'deleteById',
+            ],
+        ];
+        $requestData = ['sku' => $sku];
+        $response = $this->_webApiCall($serviceInfo, $requestData);
+        return $response;
+    }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php
index 0513f5e68abfdbe603bb5972604abb8d21453165..f8ef77f8e297b3bdf6a41c501c70adb40d31db99 100644
--- a/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/CatalogInventory/Api/StockItemTest.php
@@ -223,7 +223,7 @@ class StockItemTest extends WebapiAbstract
                     'enable_qty_increments' => '',
                     'use_config_manage_stock' => 1,
                     'manage_stock' => 1,
-                    'low_stock_date' => 0,
+                    'low_stock_date' => '',
                     'is_decimal_divided' => '',
                     'stock_status_changed_auto' => 0
                 ],
diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php
index 4551eaa3e45e2d713487938cf485344c5ff10b5c..bf9607d24969cae9ad70a61e46973c1ce2d95fb3 100644
--- a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionRepositoryTest.php
@@ -166,7 +166,6 @@ class OptionRepositoryTest extends \Magento\TestFramework\TestCase\WebapiAbstrac
         ];
         $option = [
             'attribute_id' => 'test_configurable',
-            'type' => 'select',
             'label' => 'Test',
             'values' => [
                 [
diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionTypesListTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionTypesListTest.php
deleted file mode 100644
index a96d5ca79a5cb22ccf148210a39a37f0b545ba81..0000000000000000000000000000000000000000
--- a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/OptionTypesListTest.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\ConfigurableProduct\Api;
-
-class OptionTypesListTest extends \Magento\TestFramework\TestCase\WebapiAbstract
-{
-    const SERVICE_READ_NAME = 'configurableProductOptionTypesListV1';
-    const SERVICE_VERSION = 'V1';
-    const RESOURCE_PATH = '/V1/configurable-products/:sku/options/';
-
-    public function testGetTypes()
-    {
-        $expectedTypes = ['multiselect', 'select'];
-        $result = $this->getTypes();
-        $this->assertEquals($expectedTypes, $result);
-    }
-
-    /**
-     * @return array
-     */
-    protected function getTypes()
-    {
-        $serviceInfo = [
-            'rest' => [
-                'resourcePath' => str_replace(':sku/', '', self::RESOURCE_PATH) . 'types',
-                'httpMethod'   => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET
-            ],
-            'soap' => [
-                'service'        => self::SERVICE_READ_NAME,
-                'serviceVersion' => self::SERVICE_VERSION,
-                'operation'      => self::SERVICE_READ_NAME . 'GetItems'
-            ]
-        ];
-        return $this->_webApiCall($serviceInfo);
-    }
-}
diff --git a/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/ProductRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/ProductRepositoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b9a2c658dfa3bd771656523fa6a3669ec2eaf411
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/ConfigurableProduct/Api/ProductRepositoryTest.php
@@ -0,0 +1,486 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\ConfigurableProduct\Api;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Framework\Api\ExtensibleDataInterface;
+use Magento\TestFramework\Helper\Bootstrap;
+use Magento\TestFramework\TestCase\WebapiAbstract;
+
+/**
+ * Class ProductRepositoryTest for testing ConfigurableProduct integration
+ */
+class ProductRepositoryTest extends WebapiAbstract
+{
+    const SERVICE_NAME = 'catalogProductRepositoryV1';
+    const SERVICE_VERSION = 'V1';
+    const RESOURCE_PATH = '/V1/products';
+    const CONFIGURABLE_PRODUCT_SKU = 'configurable-product-sku';
+
+    /**
+     * @var \Magento\Eav\Model\Config
+     */
+    protected $eavConfig;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $objectManager;
+
+    /**
+     * @var \Magento\Catalog\Model\Entity\Attribute
+     */
+    protected $configurableAttribute;
+
+    /**
+     * Execute per test initialization
+     */
+    public function setUp()
+    {
+        $this->objectManager = Bootstrap::getObjectManager();
+        $this->eavConfig = $this->objectManager->get('Magento\Eav\Model\Config');
+    }
+
+    /**
+     * Execute per test cleanup
+     */
+    public function tearDown()
+    {
+        $this->deleteProductBySku(self::CONFIGURABLE_PRODUCT_SKU);
+        parent::tearDown();
+    }
+
+    protected function getConfigurableAttributeOptions()
+    {
+        /** @var \Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection $optionCollection */
+        $optionCollection = $this->objectManager->create(
+            'Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection'
+        );
+        $options = $optionCollection->setAttributeFilter($this->configurableAttribute->getId())->getData();
+        return $options;
+    }
+
+    protected function createConfigurableProduct()
+    {
+        $productId1 = 10;
+        $productId2 = 20;
+
+        $label = "color";
+
+        $this->configurableAttribute = $this->eavConfig->getAttribute('catalog_product', 'test_configurable');
+        $this->assertNotNull($this->configurableAttribute);
+
+        $options = $this->getConfigurableAttributeOptions();
+        $this->assertEquals(2, count($options));
+
+        $configurableProductOptions = [
+            [
+                "attribute_id" =>  $this->configurableAttribute->getId(),
+                "label" => $label,
+                "position" => 0,
+                "values" => [
+                    [
+                        "pricing_value" => 10,
+                        "is_percent" =>  0,
+                        "value_index" =>  $options[0]['option_id'],
+                    ],
+                    [
+                        "pricing_value" => 5,
+                        "is_percent" =>  1,
+                        "value_index" =>  $options[1]['option_id'],
+                    ]
+                ],
+            ]
+        ];
+
+        $product = [
+            "sku" => self::CONFIGURABLE_PRODUCT_SKU,
+            "name" => self::CONFIGURABLE_PRODUCT_SKU,
+            "type_id" => "configurable",
+            "price" => 50,
+            'attribute_set_id' => 4,
+            "custom_attributes" => [
+                [
+                    "attribute_code" => $this->configurableAttribute->getAttributeCode(),
+                    "value" => $options[0]['option_id'],
+                ],
+            ],
+            "extension_attributes" => [
+                "configurable_product_options" => $configurableProductOptions,
+                "configurable_product_links" => [$productId1, $productId2],
+            ],
+        ];
+
+        $response = $this->createProduct($product);
+        return $response;
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     */
+    public function testCreateConfigurableProduct()
+    {
+        $productId1 = 10;
+        $productId2 = 20;
+        $label = "color";
+
+        $response = $this->createConfigurableProduct();
+        $this->assertEquals(self::CONFIGURABLE_PRODUCT_SKU, $response[ProductInterface::SKU]);
+        $this->assertEquals(50, $response['price']);
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_options"])
+        );
+        $resultConfigurableProductOptions
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_options"];
+        $this->assertEquals(1, count($resultConfigurableProductOptions));
+        $this->assertTrue(isset($resultConfigurableProductOptions[0]['label']));
+        $this->assertTrue(isset($resultConfigurableProductOptions[0]['id']));
+        $this->assertEquals($label, $resultConfigurableProductOptions[0]['label']);
+        $this->assertTrue(
+            isset($resultConfigurableProductOptions[0]['values'])
+        );
+        $this->assertEquals(2, count($resultConfigurableProductOptions[0]['values']));
+
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_links"])
+        );
+        $resultConfigurableProductLinks
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_links"];
+        $this->assertEquals(2, count($resultConfigurableProductLinks));
+
+        $this->assertEquals([$productId1, $productId2], $resultConfigurableProductLinks);
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     */
+    public function testDeleteConfigurableProductOption()
+    {
+        $productId1 = 10;
+        $productId2 = 20;
+
+        $response = $this->createConfigurableProduct();
+        //delete existing option
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_options'] = [];
+        //leave the product links unchanged
+        unset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_links']);
+        $response = $this->saveProduct($response);
+
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_options"])
+        );
+        $resultConfigurableProductOptions
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_options"];
+        $this->assertEquals(0, count($resultConfigurableProductOptions));
+
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_links"])
+        );
+        $resultConfigurableProductLinks
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_links"];
+        $this->assertEquals(2, count($resultConfigurableProductLinks));
+
+        $this->assertEquals([$productId1, $productId2], $resultConfigurableProductLinks);
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     */
+    public function testUpdateConfigurableProductOption()
+    {
+        $productId1 = 10;
+        $newLabel = 'size';
+
+        $response = $this->createConfigurableProduct();
+        $option = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_options"][0];
+
+        $optionId = $option['id'];
+        $updatedOption = [
+            'id' => $optionId,
+            'attribute_id' => $option['attribute_id'],
+            'label' => $newLabel,
+            'position' => 1,
+            'values' => [
+                [
+                    'pricing_value' => 15,
+                    'is_percent' => 1,
+                    'value_index' => $option['values'][0]['value_index'],
+                ],
+            ],
+        ];
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_options'][0] =
+            $updatedOption;
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_links'] = [$productId1];
+        $response = $this->saveProduct($response);
+
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_options"])
+        );
+        $resultConfigurableProductOptions
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_options"];
+        $this->assertEquals(1, count($resultConfigurableProductOptions));
+
+        $this->assertEquals($updatedOption, $resultConfigurableProductOptions[0]);
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     */
+    public function testUpdateConfigurableProductLinks()
+    {
+        $productId1 = 10;
+        $productId2 = 20;
+
+        $response = $this->createConfigurableProduct();
+        $options = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_options'];
+        //leave existing option untouched
+        unset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_options']);
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_links'] = [$productId1];
+        $response = $this->saveProduct($response);
+
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_options"])
+        );
+        $resultConfigurableProductOptions
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_options"];
+        $this->assertEquals(1, count($resultConfigurableProductOptions));
+        //Since one product is removed, the available values for the option is reduced
+        $this->assertEquals(1, count($resultConfigurableProductOptions[0]['values']));
+
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_links"])
+        );
+        $resultConfigurableProductLinks
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["configurable_product_links"];
+        $this->assertEquals(1, count($resultConfigurableProductLinks));
+        $this->assertEquals([$productId1], $resultConfigurableProductLinks);
+
+        //adding back the product links, the option value should be restored
+        unset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_options']);
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_links']
+            = [$productId1, $productId2];
+        //set the value for required attribute
+        $response["custom_attributes"][] =
+        [
+            "attribute_code" => $this->configurableAttribute->getAttributeCode(),
+            "value" => $resultConfigurableProductOptions[0]['values'][0]['value_index'],
+        ];
+
+        $response = $this->saveProduct($response);
+        $currentOptions = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_options'];
+
+        $this->assertEquals($options, $currentOptions);
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     */
+    public function testUpdateConfigurableProductLinksWithNonExistingProduct()
+    {
+        $productId1 = 10;
+        $nonExistingId = 999;
+
+        $response = $this->createConfigurableProduct();
+        //leave existing option untouched
+        unset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_options']);
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_links'] = [
+            $productId1, $nonExistingId
+        ];
+
+        $expectedMessage = 'Product with id "%1" does not exist.';
+        try {
+            $this->saveProduct($response);
+            $this->fail("Expected exception");
+        } catch (\SoapFault $e) {
+            $this->assertContains(
+                $expectedMessage,
+                $e->getMessage(),
+                "SoapFault does not contain expected message."
+            );
+        } catch (\Exception $e) {
+            $errorObj = $this->processRestExceptionResult($e);
+            $this->assertEquals($expectedMessage, $errorObj['message']);
+            $this->assertEquals(['0' => '999'], $errorObj['parameters']);
+        }
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     */
+    public function testUpdateConfigurableProductLinksWithDuplicateAttributes()
+    {
+        $productId1 = 10;
+        $productId2 = 20;
+
+        $response = $this->createConfigurableProduct();
+        $options = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_options'];
+        //make product2 and product1 have the same value for the configurable attribute
+        $optionValue1 = $options[0]['values'][0]['value_index'];
+        $product2 = $this->getProduct('simple_' . $productId2);
+        $product2['custom_attributes'] = [
+            [
+                'attribute_code' => 'test_configurable',
+                'value' => $optionValue1,
+            ]
+        ];
+        $this->saveProduct($product2);
+
+        //leave existing option untouched
+        unset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_options']);
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_links'] = [
+            $productId1, $productId2
+        ];
+
+        $expectedMessage = 'Products "%1" and %2 have the same set of attribute values.';
+        try {
+            $this->saveProduct($response);
+            $this->fail("Expected exception");
+        } catch (\SoapFault $e) {
+            $this->assertContains(
+                $expectedMessage,
+                $e->getMessage(),
+                "SoapFault does not contain expected message."
+            );
+        } catch (\Exception $e) {
+            $errorObj = $this->processRestExceptionResult($e);
+            $this->assertEquals($expectedMessage, $errorObj['message']);
+            $this->assertEquals(['0' => 20, '1' => 10], $errorObj['parameters']);
+        }
+    }
+
+    /**
+     * @magentoApiDataFixture Magento/ConfigurableProduct/_files/product_configurable.php
+     */
+    public function testUpdateConfigurableProductLinksWithWithoutVariationAttributes()
+    {
+        $productId1 = 10;
+        $productId2 = 20;
+
+        $response = $this->createConfigurableProduct();
+
+        /** delete all variation attribute */
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_options'] = [];
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]['configurable_product_links'] = [
+            $productId1, $productId2
+        ];
+
+        $expectedMessage = 'The configurable product does not have any variation attribute.';
+        try {
+            $this->saveProduct($response);
+            $this->fail("Expected exception");
+        } catch (\SoapFault $e) {
+            $this->assertContains(
+                $expectedMessage,
+                $e->getMessage(),
+                "SoapFault does not contain expected message."
+            );
+        } catch (\Exception $e) {
+            $errorObj = $this->processRestExceptionResult($e);
+            $this->assertEquals($expectedMessage, $errorObj['message']);
+        }
+    }
+
+    /**
+     * Get product
+     *
+     * @param string $productSku
+     * @return array the product data
+     */
+    protected function getProduct($productSku)
+    {
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH . '/' . $productSku,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Get',
+            ],
+        ];
+
+        $response = (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) ?
+            $this->_webApiCall($serviceInfo, ['sku' => $productSku]) : $this->_webApiCall($serviceInfo);
+
+        return $response;
+    }
+
+    /**
+     * Create product
+     *
+     * @param array $product
+     * @return array the created product data
+     */
+    protected function createProduct($product)
+    {
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Save',
+            ],
+        ];
+        $requestData = ['product' => $product];
+        $response = $this->_webApiCall($serviceInfo, $requestData);
+        return $response;
+    }
+
+    /**
+     * Delete a product by sku
+     *
+     * @param $productSku
+     * @return bool
+     */
+    protected function deleteProductBySku($productSku)
+    {
+        $resourcePath = self::RESOURCE_PATH . '/' . $productSku;
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => $resourcePath,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'deleteById',
+            ],
+        ];
+        $requestData = ["sku" => $productSku];
+        $response = $this->_webApiCall($serviceInfo, $requestData);
+        return $response;
+    }
+
+    /**
+     * Save product
+     *
+     * @param array $product
+     * @return array the created product data
+     */
+    protected function saveProduct($product)
+    {
+        $resourcePath = self::RESOURCE_PATH . '/' . $product['sku'];
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => $resourcePath,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Save',
+            ],
+        ];
+        $requestData = ['product' => $product];
+        $response = $this->_webApiCall($serviceInfo, $requestData);
+        return $response;
+    }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/LinkRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/LinkRepositoryTest.php
index 4234afc66f27883af89395192189e18bf3c154e0..656da53f38e842a1f3122b6fd35fbd87cdb24c05 100644
--- a/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/LinkRepositoryTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/LinkRepositoryTest.php
@@ -80,9 +80,10 @@ class LinkRepositoryTest extends WebapiAbstract
     protected function getTargetProduct($isScopeGlobal = false)
     {
         $objectManager = Bootstrap::getObjectManager();
-        $product = $objectManager->get('Magento\Catalog\Model\ProductFactory')->create()->load(1);
         if ($isScopeGlobal) {
-            $product->setStoreId(0);
+            $product = $objectManager->get('Magento\Catalog\Model\ProductFactory')->create()->setStoreId(0)->load(1);
+        } else {
+            $product = $objectManager->get('Magento\Catalog\Model\ProductFactory')->create()->load(1);
         }
 
         return $product;
@@ -114,18 +115,18 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => true,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Title',
                 'sort_order' => 1,
                 'price' => 10.1,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 100,
                 'link_type' => 'file',
-                'link_file' => [
+                'link_file_content' => [
                     'file_data' => base64_encode(file_get_contents($this->testImagePath)),
                     'name' => 'image.jpg',
                 ],
-                'sample_file' => [
+                'sample_file_content' => [
                     'file_data' => base64_encode(file_get_contents($this->testImagePath)),
                     'name' => 'image.jpg',
                 ],
@@ -137,15 +138,15 @@ class LinkRepositoryTest extends WebapiAbstract
         $globalScopeLink = $this->getTargetLink($this->getTargetProduct(true), $newLinkId);
         $link = $this->getTargetLink($this->getTargetProduct(), $newLinkId);
         $this->assertNotNull($link);
-        $this->assertEquals($requestData['linkContent']['title'], $link->getTitle());
-        $this->assertEquals($requestData['linkContent']['title'], $globalScopeLink->getTitle());
-        $this->assertEquals($requestData['linkContent']['sort_order'], $link->getSortOrder());
-        $this->assertEquals($requestData['linkContent']['price'], $link->getPrice());
-        $this->assertEquals($requestData['linkContent']['price'], $globalScopeLink->getPrice());
-        $this->assertEquals($requestData['linkContent']['shareable'], $link->getIsShareable());
-        $this->assertEquals($requestData['linkContent']['number_of_downloads'], $link->getNumberOfDownloads());
-        $this->assertEquals($requestData['linkContent']['link_type'], $link->getLinkType());
-        $this->assertEquals($requestData['linkContent']['sample_type'], $link->getSampleType());
+        $this->assertEquals($requestData['link']['title'], $link->getTitle());
+        $this->assertEquals($requestData['link']['title'], $globalScopeLink->getTitle());
+        $this->assertEquals($requestData['link']['sort_order'], $link->getSortOrder());
+        $this->assertEquals($requestData['link']['price'], $link->getPrice());
+        $this->assertEquals($requestData['link']['price'], $globalScopeLink->getPrice());
+        $this->assertEquals($requestData['link']['is_shareable'], $link->getIsShareable());
+        $this->assertEquals($requestData['link']['number_of_downloads'], $link->getNumberOfDownloads());
+        $this->assertEquals($requestData['link']['link_type'], $link->getLinkType());
+        $this->assertEquals($requestData['link']['sample_type'], $link->getSampleType());
         $this->assertStringEndsWith('.jpg', $link->getSampleFile());
         $this->assertStringEndsWith('.jpg', $link->getLinkFile());
         $this->assertNull($link->getLinkUrl());
@@ -160,11 +161,11 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Store View Title',
                 'sort_order' => 1,
                 'price' => 150,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 100,
                 'link_url' => 'http://www.example.com/',
                 'link_type' => 'url',
@@ -177,15 +178,15 @@ class LinkRepositoryTest extends WebapiAbstract
         $link = $this->getTargetLink($this->getTargetProduct(), $newLinkId);
         $globalScopeLink = $this->getTargetLink($this->getTargetProduct(true), $newLinkId);
         $this->assertNotNull($link);
-        $this->assertEquals($requestData['linkContent']['title'], $link->getTitle());
-        $this->assertEquals($requestData['linkContent']['sort_order'], $link->getSortOrder());
-        $this->assertEquals($requestData['linkContent']['price'], $link->getPrice());
-        $this->assertEquals($requestData['linkContent']['shareable'], $link->getIsShareable());
-        $this->assertEquals($requestData['linkContent']['number_of_downloads'], $link->getNumberOfDownloads());
-        $this->assertEquals($requestData['linkContent']['link_url'], $link->getLinkUrl());
-        $this->assertEquals($requestData['linkContent']['link_type'], $link->getLinkType());
-        $this->assertEquals($requestData['linkContent']['sample_url'], $link->getSampleUrl());
-        $this->assertEquals($requestData['linkContent']['sample_type'], $link->getSampleType());
+        $this->assertEquals($requestData['link']['title'], $link->getTitle());
+        $this->assertEquals($requestData['link']['sort_order'], $link->getSortOrder());
+        $this->assertEquals($requestData['link']['price'], $link->getPrice());
+        $this->assertEquals($requestData['link']['is_shareable'], $link->getIsShareable());
+        $this->assertEquals($requestData['link']['number_of_downloads'], $link->getNumberOfDownloads());
+        $this->assertEquals($requestData['link']['link_url'], $link->getLinkUrl());
+        $this->assertEquals($requestData['link']['link_type'], $link->getLinkType());
+        $this->assertEquals($requestData['link']['sample_url'], $link->getSampleUrl());
+        $this->assertEquals($requestData['link']['sample_type'], $link->getSampleType());
         $this->assertEmpty($globalScopeLink->getTitle());
         $this->assertEmpty($globalScopeLink->getPrice());
     }
@@ -198,11 +199,11 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link with URL resources',
                 'sort_order' => 1,
                 'price' => 10.1,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 100,
                 'link_url' => 'http://www.example.com/',
                 'link_type' => 'url',
@@ -214,15 +215,15 @@ class LinkRepositoryTest extends WebapiAbstract
         $newLinkId = $this->_webApiCall($this->createServiceInfo, $requestData);
         $link = $this->getTargetLink($this->getTargetProduct(), $newLinkId);
         $this->assertNotNull($link);
-        $this->assertEquals($requestData['linkContent']['title'], $link->getTitle());
-        $this->assertEquals($requestData['linkContent']['sort_order'], $link->getSortOrder());
-        $this->assertEquals($requestData['linkContent']['price'], $link->getPrice());
-        $this->assertEquals($requestData['linkContent']['shareable'], $link->getIsShareable());
-        $this->assertEquals($requestData['linkContent']['number_of_downloads'], $link->getNumberOfDownloads());
-        $this->assertEquals($requestData['linkContent']['link_url'], $link->getLinkUrl());
-        $this->assertEquals($requestData['linkContent']['link_type'], $link->getLinkType());
-        $this->assertEquals($requestData['linkContent']['sample_type'], $link->getSampleType());
-        $this->assertEquals($requestData['linkContent']['sample_url'], $link->getSampleUrl());
+        $this->assertEquals($requestData['link']['title'], $link->getTitle());
+        $this->assertEquals($requestData['link']['sort_order'], $link->getSortOrder());
+        $this->assertEquals($requestData['link']['price'], $link->getPrice());
+        $this->assertEquals($requestData['link']['is_shareable'], $link->getIsShareable());
+        $this->assertEquals($requestData['link']['number_of_downloads'], $link->getNumberOfDownloads());
+        $this->assertEquals($requestData['link']['link_url'], $link->getLinkUrl());
+        $this->assertEquals($requestData['link']['link_type'], $link->getLinkType());
+        $this->assertEquals($requestData['link']['sample_type'], $link->getSampleType());
+        $this->assertEquals($requestData['link']['sample_url'], $link->getSampleUrl());
     }
 
     /**
@@ -235,12 +236,15 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link with URL resources',
                 'sort_order' => 1,
                 'price' => 10.1,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 100,
+                'link_type' => 'invalid',
+                'sample_type' => 'url',
+                'sample_url' => 'http://www.example.com',
             ],
         ];
 
@@ -257,16 +261,16 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link Title',
                 'sort_order' => 1,
                 'price' => 10,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 100,
                 'link_type' => 'url',
                 'link_url' => 'http://www.example.com/',
                 'sample_type' => 'file',
-                'sample_file' => [
+                'sample_file_content' => [
                     'file_data' => 'not_a_base64_encoded_content',
                     'name' => 'image.jpg',
                 ],
@@ -286,17 +290,19 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link Title',
                 'sort_order' => 1,
                 'price' => 10,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 100,
                 'link_type' => 'file',
-                'link_file' => [
+                'link_file_content' => [
                     'file_data' => 'not_a_base64_encoded_content',
                     'name' => 'image.jpg',
                 ],
+                'sample_type' => 'url',
+                'sample_url' => 'http://www.example.com/',
             ],
         ];
 
@@ -313,17 +319,19 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Title',
                 'sort_order' => 15,
                 'price' => 10,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 100,
                 'link_type' => 'file',
-                'link_file' => [
+                'link_file_content' => [
                     'file_data' => base64_encode(file_get_contents($this->testImagePath)),
                     'name' => 'name/with|forbidden{characters',
                 ],
+                'sample_type' => 'url',
+                'sample_url' => 'http://www.example.com/',
             ],
         ];
 
@@ -340,16 +348,16 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link Title',
                 'sort_order' => 1,
                 'price' => 10,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 100,
                 'link_type' => 'url',
                 'link_url' => 'http://www.example.com/',
                 'sample_type' => 'file',
-                'sample_file' => [
+                'sample_file_content' => [
                     'file_data' => base64_encode(file_get_contents($this->testImagePath)),
                     'name' => 'name/with|forbidden{characters',
                 ],
@@ -369,14 +377,16 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link Title',
                 'sort_order' => 1,
                 'price' => 10,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 100,
                 'link_type' => 'url',
                 'link_url' => 'http://example<.>com/',
+                'sample_type' => 'url',
+                'sample_url' => 'http://www.example.com/',
             ],
         ];
 
@@ -393,11 +403,11 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link Title',
                 'sort_order' => 1,
                 'price' => 150,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 0,
                 'sample_type' => 'url',
                 'sample_url' => 'http://example<.>com/',
@@ -420,11 +430,11 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link Title',
                 'sort_order' => 1,
                 'price' => $linkPrice,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 0,
                 'sample_type' => 'url',
                 'sample_url' => 'http://example.com/',
@@ -442,7 +452,6 @@ class LinkRepositoryTest extends WebapiAbstract
     public function getInvalidLinkPrice()
     {
         return [
-            ['string_value'],
             [-1.5],
         ];
     }
@@ -458,11 +467,11 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link Title',
                 'sort_order' => $sortOrder,
                 'price' => 10,
-                'shareable' => false,
+                'is_shareable' => false,
                 'number_of_downloads' => 0,
                 'sample_type' => 'url',
                 'sample_url' => 'http://example.com/',
@@ -494,11 +503,11 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link Title',
                 'sort_order' => 0,
                 'price' => 10,
-                'shareable' => false,
+                'is_shareable' => false,
                 'number_of_downloads' => $numberOfDownloads,
                 'sample_type' => 'url',
                 'sample_url' => 'http://example.com/',
@@ -530,11 +539,11 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'simple',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link Title',
                 'sort_order' => 50,
                 'price' => 200,
-                'shareable' => false,
+                'is_shareable' => false,
                 'number_of_downloads' => 10,
                 'sample_type' => 'url',
                 'sample_url' => 'http://example.com/',
@@ -555,11 +564,11 @@ class LinkRepositoryTest extends WebapiAbstract
         $requestData = [
             'isGlobalScopeContent' => false,
             'sku' => 'wrong-sku',
-            'linkContent' => [
+            'link' => [
                 'title' => 'Link Title',
                 'sort_order' => 15,
                 'price' => 200,
-                'shareable' => true,
+                'is_shareable' => true,
                 'number_of_downloads' => 100,
                 'sample_type' => 'url',
                 'sample_url' => 'http://example.com/',
@@ -580,24 +589,26 @@ class LinkRepositoryTest extends WebapiAbstract
             = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
         $requestData = [
             'isGlobalScopeContent' => false,
-            'linkId' => $linkId,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
+                'id' => $linkId,
                 'title' => 'Updated Title',
                 'sort_order' => 2,
                 'price' => 100.10,
-                'shareable' => false,
+                'is_shareable' => false,
                 'number_of_downloads' => 50,
+                'link_type' => 'url',
+                'sample_type' => 'url',
             ],
         ];
         $this->assertEquals($linkId, $this->_webApiCall($this->updateServiceInfo, $requestData));
         $link = $this->getTargetLink($this->getTargetProduct(), $linkId);
         $this->assertNotNull($link);
-        $this->assertEquals($requestData['linkContent']['title'], $link->getTitle());
-        $this->assertEquals($requestData['linkContent']['sort_order'], $link->getSortOrder());
-        $this->assertEquals($requestData['linkContent']['price'], $link->getPrice());
-        $this->assertEquals($requestData['linkContent']['shareable'], (bool)$link->getIsShareable());
-        $this->assertEquals($requestData['linkContent']['number_of_downloads'], $link->getNumberOfDownloads());
+        $this->assertEquals($requestData['link']['title'], $link->getTitle());
+        $this->assertEquals($requestData['link']['sort_order'], $link->getSortOrder());
+        $this->assertEquals($requestData['link']['price'], $link->getPrice());
+        $this->assertEquals($requestData['link']['is_shareable'], (bool)$link->getIsShareable());
+        $this->assertEquals($requestData['link']['number_of_downloads'], $link->getNumberOfDownloads());
     }
 
     /**
@@ -611,14 +622,16 @@ class LinkRepositoryTest extends WebapiAbstract
             = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
         $requestData = [
             'isGlobalScopeContent' => true,
-            'linkId' => $linkId,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
+                'id' => $linkId,
                 'title' => 'Updated Title',
                 'sort_order' => 2,
                 'price' => 100.10,
-                'shareable' => false,
+                'is_shareable' => false,
                 'number_of_downloads' => 50,
+                'link_type' => 'url',
+                'sample_type' => 'url',
             ],
         ];
 
@@ -629,11 +642,11 @@ class LinkRepositoryTest extends WebapiAbstract
         // Title and price were set on store view level in fixture so they must be the same
         $this->assertEquals($originalLink->getTitle(), $link->getTitle());
         $this->assertEquals($originalLink->getPrice(), $link->getPrice());
-        $this->assertEquals($requestData['linkContent']['title'], $globalScopeLink->getTitle());
-        $this->assertEquals($requestData['linkContent']['price'], $globalScopeLink->getPrice());
-        $this->assertEquals($requestData['linkContent']['sort_order'], $link->getSortOrder());
-        $this->assertEquals($requestData['linkContent']['shareable'], (bool)$link->getIsShareable());
-        $this->assertEquals($requestData['linkContent']['number_of_downloads'], $link->getNumberOfDownloads());
+        $this->assertEquals($requestData['link']['title'], $globalScopeLink->getTitle());
+        $this->assertEquals($requestData['link']['price'], $globalScopeLink->getPrice());
+        $this->assertEquals($requestData['link']['sort_order'], $link->getSortOrder());
+        $this->assertEquals($requestData['link']['is_shareable'], (bool)$link->getIsShareable());
+        $this->assertEquals($requestData['link']['number_of_downloads'], $link->getNumberOfDownloads());
     }
 
     /**
@@ -645,14 +658,16 @@ class LinkRepositoryTest extends WebapiAbstract
         $this->updateServiceInfo['rest']['resourcePath'] = '/V1/products/wrong-sku/downloadable-links/1';
         $requestData = [
             'isGlobalScopeContent' => true,
-            'linkId' => 1,
             'sku' => 'wrong-sku',
-            'linkContent' => [
+            'link' => [
+                'id' => 1,
                 'title' => 'Updated Title',
                 'sort_order' => 2,
                 'price' => 100.10,
-                'shareable' => false,
+                'is_shareable' => false,
                 'number_of_downloads' => 50,
+                'link_type' => 'url',
+                'sample_type' => 'url',
             ],
         ];
         $this->_webApiCall($this->updateServiceInfo, $requestData);
@@ -670,14 +685,16 @@ class LinkRepositoryTest extends WebapiAbstract
             = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
         $requestData = [
             'isGlobalScopeContent' => true,
-            'linkId' => 9999,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
+                'id' => $linkId,
                 'title' => 'Title',
                 'sort_order' => 2,
                 'price' => 100.10,
-                'shareable' => false,
+                'is_shareable' => false,
                 'number_of_downloads' => 50,
+                'link_type' => 'url',
+                'sample_type' => 'url',
             ],
         ];
 
@@ -697,14 +714,16 @@ class LinkRepositoryTest extends WebapiAbstract
             = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
         $requestData = [
             'isGlobalScopeContent' => false,
-            'linkId' => $linkId,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
+                'id' => $linkId,
                 'title' => 'Updated Link Title',
                 'sort_order' => 2,
                 'price' => $linkPrice,
-                'shareable' => false,
+                'is_shareable' => false,
                 'number_of_downloads' => 50,
+                'link_type' => 'url',
+                'sample_type' => 'url',
             ],
         ];
 
@@ -724,14 +743,16 @@ class LinkRepositoryTest extends WebapiAbstract
             = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
         $requestData = [
             'isGlobalScopeContent' => false,
-            'linkId' => $linkId,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
+                'id' => $linkId,
                 'title' => 'Updated Link Title',
                 'sort_order' => $sortOrder,
                 'price' => 100.50,
-                'shareable' => false,
+                'is_shareable' => false,
                 'number_of_downloads' => 50,
+                'link_type' => 'url',
+                'sample_type' => 'url',
             ],
         ];
         $this->_webApiCall($this->updateServiceInfo, $requestData);
@@ -750,14 +771,16 @@ class LinkRepositoryTest extends WebapiAbstract
             = "/V1/products/downloadable-product/downloadable-links/{$linkId}";
         $requestData = [
             'isGlobalScopeContent' => false,
-            'linkId' => $linkId,
             'sku' => 'downloadable-product',
-            'linkContent' => [
+            'link' => [
+                'id' => $linkId,
                 'title' => 'Updated Link Title',
                 'sort_order' => 200,
                 'price' => 100.50,
-                'shareable' => false,
+                'is_shareable' => false,
                 'number_of_downloads' => $numberOfDownloads,
+                'link_type' => 'url',
+                'sample_type' => 'url',
             ],
         ];
         $this->_webApiCall($this->updateServiceInfo, $requestData);
@@ -771,7 +794,7 @@ class LinkRepositoryTest extends WebapiAbstract
         $linkId = $this->getTargetLink($this->getTargetProduct())->getId();
         $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/{$linkId}";
         $requestData = [
-            'linkId' => $linkId,
+            'id' => $linkId,
         ];
 
         $this->assertTrue($this->_webApiCall($this->deleteServiceInfo, $requestData));
@@ -788,7 +811,7 @@ class LinkRepositoryTest extends WebapiAbstract
         $linkId = 9999;
         $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/{$linkId}";
         $requestData = [
-            'linkId' => $linkId,
+            'id' => $linkId,
         ];
 
         $this->_webApiCall($this->deleteServiceInfo, $requestData);
diff --git a/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/ProductRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/ProductRepositoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a079eb6d4b6bfa58256a646f396a535c91a0e0cc
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/ProductRepositoryTest.php
@@ -0,0 +1,627 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Downloadable\Api;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\Framework\Api\ExtensibleDataInterface;
+use Magento\TestFramework\Helper\Bootstrap;
+use Magento\TestFramework\TestCase\WebapiAbstract;
+use Magento\Bundle\Api\Data\LinkInterface;
+
+/**
+ * Class ProductRepositoryTest for testing ProductRepository interface with Downloadable Product
+ */
+class ProductRepositoryTest extends WebapiAbstract
+{
+    const SERVICE_NAME = 'catalogProductRepositoryV1';
+    const SERVICE_VERSION = 'V1';
+    const RESOURCE_PATH = '/V1/products';
+    const PRODUCT_SKU = 'sku-test-product-downloadable';
+
+    /**
+     * @var string
+     */
+    protected $testImagePath;
+
+    protected function setUp()
+    {
+        $this->testImagePath = __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'test_image.jpg';
+    }
+
+    /**
+     * Execute per test cleanup
+     */
+    public function tearDown()
+    {
+        $this->deleteProductBySku(self::PRODUCT_SKU);
+        parent::tearDown();
+    }
+
+    protected function getLinkData()
+    {
+        return [
+            'link1' => [
+                'title' => "link1",
+                'sort_order'=> 10,
+                'is_shareable' => 1,
+                'price' => 2.0,
+                'number_of_downloads' => 0,
+                'link_type' => 'file',
+                'link_file_content' => [
+                    'name' => 'link1_content.jpg',
+                    'file_data' => base64_encode(file_get_contents($this->testImagePath)),
+                ],
+                'sample_type' => 'file',
+                'sample_file_content' => [
+                    'name' => 'link1_sample.jpg',
+                    'file_data' => base64_encode(file_get_contents($this->testImagePath)),
+                ],
+            ],
+            'link2' => [
+                'title' => 'link2',
+                'sort_order'=> 20,
+                'is_shareable' => 0,
+                'price' => 3.0,
+                'number_of_downloads' => 100,
+                'link_type' => "url",
+                'link_url' => 'http://www.example.com/link2.jpg',
+                'sample_type' => 'url',
+                'sample_url' => 'http://www.example.com/link2.jpg',
+            ],
+        ];
+    }
+
+    protected function getExpectedLinkData()
+    {
+        return [
+            [
+                'title' => 'link1',
+                'sort_order' => 10,
+                'is_shareable' => 1,
+                'price' => 2,
+                'number_of_downloads' => 0,
+                'link_type' => 'file',
+                'sample_type' => 'file',
+            ],
+            [
+                'title' => 'link2',
+                'sort_order' => 20,
+                'is_shareable' => 0,
+                'price' => 3,
+                'number_of_downloads' => 100,
+                'link_type' => 'url',
+                'link_url' => 'http://www.example.com/link2.jpg',
+                'sample_type' => 'url',
+                'sample_url' => 'http://www.example.com/link2.jpg',
+            ],
+        ];
+    }
+
+    protected function getSampleData()
+    {
+        return [
+            'sample1' => [
+                'title' => 'sample1',
+                'sort_order' => 10,
+                'sample_type' => 'url',
+                'sample_url' => 'http://www.example.com/sample1.jpg',
+            ],
+            'sample2' => [
+                'title' => 'sample2',
+                'sort_order' => 20,
+                'sample_type' => 'file',
+                'sample_file_content' => [
+                    'name' => 'sample2.jpg',
+                    'file_data' => base64_encode(file_get_contents($this->testImagePath)),
+                ],
+            ],
+        ];
+    }
+
+    protected function getExpectedSampleData()
+    {
+        return [
+            [
+                'title' => 'sample1',
+                'sort_order' => 10,
+                'sample_type' => 'url',
+                'sample_url' => 'http://www.example.com/sample1.jpg',
+            ],
+            [
+                'title' => 'sample2',
+                'sort_order' => 20,
+                'sample_type' => 'file',
+            ],
+        ];
+    }
+
+    protected function createDownloadableProduct()
+    {
+        $product = [
+            "sku" => self::PRODUCT_SKU,
+            "name" => self::PRODUCT_SKU,
+            "type_id" => \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE,
+            "price" => 10,
+            'attribute_set_id' => 4,
+            "extension_attributes" => [
+                "downloadable_product_links" => array_values($this->getLinkData()),
+                "downloadable_product_samples" => array_values($this->getSampleData()),
+            ],
+        ];
+
+        $response =  $this->createProduct($product);
+        $this->assertEquals(self::PRODUCT_SKU, $response[ProductInterface::SKU]);
+        $this->assertEquals(10, $response['price']);
+        $this->assertEquals(
+            \Magento\Downloadable\Model\Product\Type::TYPE_DOWNLOADABLE,
+            $response['type_id']
+        );
+        return $response;
+    }
+
+    /**
+     * Create a downloadable product with two links and two samples
+     */
+    public function testCreateDownloadableProduct()
+    {
+        $response = $this->createDownloadableProduct();
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"])
+        );
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"])
+        );
+        $resultLinks
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"];
+        $this->assertEquals(2, count($resultLinks));
+        $this->assertTrue(isset($resultLinks[0]['id']));
+        $this->assertTrue(isset($resultLinks[0]['link_file']));
+        $this->assertTrue(isset($resultLinks[0]['sample_file']));
+        unset($resultLinks[0]['id']);
+        unset($resultLinks[0]['link_file']);
+        unset($resultLinks[0]['sample_file']);
+        $this->assertTrue(isset($resultLinks[1]['id']));
+        unset($resultLinks[1]['id']);
+
+        $expectedLinkData = $this->getExpectedLinkData();
+        $this->assertEquals($expectedLinkData, $resultLinks);
+
+        $resultSamples = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"];
+        $this->assertEquals(2, count($resultSamples));
+        $this->assertTrue(isset($resultSamples[0]['id']));
+        unset($resultSamples[0]['id']);
+        $this->assertTrue(isset($resultSamples[1]['id']));
+        $this->assertTrue(isset($resultSamples[1]['sample_file']));
+        unset($resultSamples[1]['sample_file']);
+        unset($resultSamples[1]['id']);
+
+        $expectedSampleData = $this->getExpectedSampleData();
+        $this->assertEquals($expectedSampleData, $resultSamples);
+    }
+
+    /**
+     * Update downloadable product, update a link, add two link, delete a link
+     */
+    public function testUpdateDownloadableProductLinks()
+    {
+        $response = $this->createDownloadableProduct();
+        $resultLinks
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"];
+        $link1Id = $resultLinks[0]['id'];
+        $link2Id = $resultLinks[1]['id'];
+
+        $linkFile = $resultLinks[0]['link_file'];
+        $sampleFile = $resultLinks[0]['sample_file'];
+        $updatedLink1Data = [
+            'id' => $link1Id,
+            'title' => 'link1_updated',
+            'sort_order' => 1, //the sort order needs to be smaller than 10
+            'is_shareable' => 0,
+            'price' => 5.0,
+            'number_of_downloads' => 999,
+            'link_type' => 'file',
+            'sample_type' => 'file',
+            'link_file' =>  'http://www.example.com/invalid', //this field will be overridden
+            'sample_file' => 'http://www.example.com/invalid', //this field will be overridden
+        ];
+        $linkData = $this->getLinkData();
+
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"] =
+            [$updatedLink1Data, $linkData['link1'], $linkData['link2']];
+        unset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"]);
+
+        $response = $this->saveProduct($response);
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"])
+        );
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"])
+        );
+        $resultLinks
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"];
+
+        $this->assertEquals(3, count($resultLinks));
+        $this->assertTrue(isset($resultLinks[0]['id']));
+        $this->assertEquals($link1Id, $resultLinks[0]['id']);
+        $this->assertTrue(isset($resultLinks[0]['link_file']));
+        $this->assertEquals($linkFile, $resultLinks[0]['link_file']);
+        $this->assertTrue(isset($resultLinks[0]['sample_file']));
+        $this->assertEquals($sampleFile, $resultLinks[0]['sample_file']);
+        unset($resultLinks[0]['id']);
+        unset($resultLinks[0]['link_file']);
+        unset($resultLinks[0]['sample_file']);
+        $this->assertTrue(isset($resultLinks[1]['id']));
+        $this->assertGreaterThan($link2Id, $resultLinks[1]['id']);
+        $this->assertTrue(isset($resultLinks[1]['link_file']));
+        $this->assertTrue(isset($resultLinks[1]['sample_file']));
+        unset($resultLinks[1]['id']);
+        unset($resultLinks[1]['link_file']);
+        unset($resultLinks[1]['sample_file']);
+        $this->assertTrue(isset($resultLinks[2]['id']));
+        $this->assertGreaterThan($link2Id, $resultLinks[2]['id']);
+        unset($resultLinks[2]['id']);
+
+        $expectedLinkData[] = [
+            'title' => 'link1_updated',
+            'sort_order' => 1, //the sort order needs to be smaller than 10
+            'is_shareable' => 0,
+            'price' => 5.0,
+            'number_of_downloads' => 999,
+            'link_type' => 'file',
+            'sample_type' => 'file',
+        ];
+        $expectedLinkData = array_merge($expectedLinkData, $this->getExpectedLinkData());
+        $this->assertEquals($expectedLinkData, $resultLinks);
+
+        $resultSamples = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"];
+        $this->assertEquals(2, count($resultSamples));
+    }
+
+    /**
+     * Update downloadable product, update two links and change file content
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function testUpdateDownloadableProductLinksWithNewFile()
+    {
+        $response = $this->createDownloadableProduct();
+        $resultLinks
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"];
+        $link1Id = $resultLinks[0]['id'];
+        $link2Id = $resultLinks[1]['id'];
+
+        $linkFile = 'link1_content_updated.jpg';
+        $sampleFile = 'link1_sample_updated.jpg';
+        $updatedLink1Data = [
+            'id' => $link1Id,
+            'title' => 'link1_updated',
+            'sort_order' => 1, //the sort order needs to be smaller than 10
+            'is_shareable' => 0,
+            'price' => 5.0,
+            'number_of_downloads' => 999,
+            'link_type' => 'file',
+            'link_file_content' => [
+                'name' => $linkFile,
+                'file_data' => base64_encode(file_get_contents($this->testImagePath)),
+            ],
+            'sample_type' => 'file',
+            'sample_file_content' => [
+                'name' => $sampleFile,
+                'file_data' => base64_encode(file_get_contents($this->testImagePath)),
+            ],
+        ];
+        $updatedLink2Data = [
+            'id' => $link2Id,
+            'title' => 'link2_updated',
+            'sort_order' => 2,
+            'is_shareable' => 0,
+            'price' => 6.0,
+            'number_of_downloads' => 0,
+            'link_type' => 'file',
+            'link_file_content' => [
+                'name' => 'link2_content.jpg',
+                'file_data' => base64_encode(file_get_contents($this->testImagePath)),
+            ],
+            'sample_type' => 'file',
+            'sample_file_content' => [
+                'name' => 'link2_sample.jpg',
+                'file_data' => base64_encode(file_get_contents($this->testImagePath)),
+            ],
+        ];
+
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"] =
+            [$updatedLink1Data, $updatedLink2Data];
+        unset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"]);
+
+        $response = $this->saveProduct($response);
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"])
+        );
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"])
+        );
+        $resultLinks
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"];
+
+        $this->assertEquals(2, count($resultLinks));
+        $this->assertTrue(isset($resultLinks[0]['id']));
+        $this->assertEquals($link1Id, $resultLinks[0]['id']);
+        $this->assertTrue(isset($resultLinks[0]['link_file']));
+        $this->assertGreaterThan(0, strpos($resultLinks[0]['link_file'], $linkFile));
+        $this->assertTrue(isset($resultLinks[0]['sample_file']));
+        $this->assertGreaterThan(0, strpos($resultLinks[0]['sample_file'], $sampleFile));
+        unset($resultLinks[0]['id']);
+        unset($resultLinks[0]['link_file']);
+        unset($resultLinks[0]['sample_file']);
+        $this->assertTrue(isset($resultLinks[1]['id']));
+        $this->assertEquals($link2Id, $resultLinks[1]['id']);
+        $this->assertTrue(isset($resultLinks[1]['link_file']));
+        $this->assertTrue(isset($resultLinks[1]['sample_file']));
+        unset($resultLinks[1]['id']);
+        unset($resultLinks[1]['link_file']);
+        unset($resultLinks[1]['sample_file']);
+
+        $expectedLinkData = [
+            [
+                'title' => 'link1_updated',
+                'sort_order' => 1, //the sort order needs to be smaller than 10
+                'is_shareable' => 0,
+                'price' => 5.0,
+                'number_of_downloads' => 999,
+                'link_type' => 'file',
+                'sample_type' => 'file',
+            ],
+            [
+                'title' => 'link2_updated',
+                'sort_order' => 2,
+                'is_shareable' => 0,
+                'price' => 6.0,
+                'number_of_downloads' => 0,
+                'link_type' => 'file',
+                'sample_type' => 'file',
+                'link_url' => 'http://www.example.com/link2.jpg', //urls are still saved, just not used
+                'sample_url' => 'http://www.example.com/link2.jpg',
+            ]
+        ];
+        $this->assertEquals($expectedLinkData, $resultLinks);
+
+        $resultSamples = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"];
+        $this->assertEquals(2, count($resultSamples));
+    }
+
+    public function testUpdateDownloadableProductSamples()
+    {
+        $response = $this->createDownloadableProduct();
+
+        $resultSample
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"];
+        $sample1Id = $resultSample[0]['id'];
+        $sample2Id = $resultSample[1]['id'];
+
+        $updatedSample1Data = [
+            'id' => $sample1Id,
+            'title' => 'sample1_updated',
+            'sort_order' => 1,
+            'sample_type' => 'url',
+            'sample_url' => 'http://www.example.com/sample1.jpg',
+        ];
+        $sampleData = $this->getSampleData();
+
+        unset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"]);
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"] =
+            [$updatedSample1Data, $sampleData['sample1'], $sampleData['sample2']];
+
+        $response = $this->saveProduct($response);
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"])
+        );
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"])
+        );
+        $resultLinks
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"];
+
+        $this->assertEquals(2, count($resultLinks));
+
+        $resultSamples = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"];
+        $this->assertEquals(3, count($resultSamples));
+        $this->assertTrue(isset($resultSamples[0]['id']));
+        $this->assertEquals($sample1Id, $resultSamples[0]['id']);
+        unset($resultSamples[0]['id']);
+        $this->assertTrue(isset($resultSamples[1]['id']));
+        $this->assertGreaterThan($sample2Id, $resultSamples[1]['id']);
+        unset($resultSamples[1]['id']);
+        $this->assertTrue(isset($resultSamples[2]['id']));
+        $this->assertGreaterThan($sample2Id, $resultSamples[2]['id']);
+        $this->assertTrue(isset($resultSamples[2]['sample_file']));
+        unset($resultSamples[2]['sample_file']);
+        unset($resultSamples[2]['id']);
+
+        $expectedSampleData[] = [
+            'title' => 'sample1_updated',
+            'sort_order' => 1,
+            'sample_type' => 'url',
+            'sample_url' => 'http://www.example.com/sample1.jpg',
+        ];
+        $expectedSampleData = array_merge($expectedSampleData, $this->getExpectedSampleData());
+        $this->assertEquals($expectedSampleData, $resultSamples);
+    }
+
+    public function testUpdateDownloadableProductSamplesWithNewFile()
+    {
+        $response = $this->createDownloadableProduct();
+
+        $resultSample
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"];
+        $sample1Id = $resultSample[0]['id'];
+        $sample2Id = $resultSample[1]['id'];
+
+        //upload a file for sample 1
+        $updatedSample1Data = [
+            'id' => $sample1Id,
+            'title' => 'sample1_updated',
+            'sort_order' => 1,
+            'sample_type' => 'file',
+            'sample_file_content' => [
+                'name' => 'sample1.jpg',
+                'file_data' => base64_encode(file_get_contents($this->testImagePath)),
+            ],
+        ];
+        //change title for sample 2
+        $updatedSamp2e1Data = [
+            'id' => $sample2Id,
+            'title' => 'sample2_updated',
+            'sort_order' => 2,
+            'sample_type' => 'file',
+        ];
+
+        unset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"]);
+        $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"] =
+            [$updatedSample1Data, $updatedSamp2e1Data];
+
+        $response = $this->saveProduct($response);
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"])
+        );
+        $this->assertTrue(
+            isset($response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"])
+        );
+        $resultLinks
+            = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_links"];
+
+        $this->assertEquals(2, count($resultLinks));
+
+        $resultSamples = $response[ExtensibleDataInterface::EXTENSION_ATTRIBUTES_KEY]["downloadable_product_samples"];
+        $this->assertEquals(2, count($resultSamples));
+        $this->assertTrue(isset($resultSamples[0]['id']));
+        $this->assertEquals($sample1Id, $resultSamples[0]['id']);
+        unset($resultSamples[0]['id']);
+        $this->assertTrue(isset($resultSamples[0]['sample_file']));
+        $this->assertContains('sample1.jpg', $resultSamples[0]['sample_file']);
+        unset($resultSamples[0]['sample_file']);
+        $this->assertTrue(isset($resultSamples[1]['id']));
+        $this->assertEquals($sample2Id, $resultSamples[1]['id']);
+        unset($resultSamples[1]['id']);
+        $this->assertTrue(isset($resultSamples[1]['sample_file']));
+        $this->assertContains('sample2.jpg', $resultSamples[1]['sample_file']);
+        unset($resultSamples[1]['sample_file']);
+
+        $expectedSampleData = [
+            [
+                'title' => 'sample1_updated',
+                'sort_order' => 1,
+                'sample_type' => 'file',
+                'sample_url' => 'http://www.example.com/sample1.jpg',
+            ],
+            [
+                'title' => 'sample2_updated',
+                'sort_order' => 2,
+                'sample_type' => 'file',
+            ],
+        ];
+        $this->assertEquals($expectedSampleData, $resultSamples);
+    }
+
+    /**
+     * Get product
+     *
+     * @param string $productSku
+     * @return array the product data
+     */
+    protected function getProduct($productSku)
+    {
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH . '/' . $productSku,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Get',
+            ],
+        ];
+
+        $response = (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) ?
+            $this->_webApiCall($serviceInfo, ['sku' => $productSku]) : $this->_webApiCall($serviceInfo);
+
+        return $response;
+    }
+
+    /**
+     * Create product
+     *
+     * @param array $product
+     * @return array the created product data
+     */
+    protected function createProduct($product)
+    {
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Save',
+            ],
+        ];
+        $requestData = ['product' => $product];
+        $response = $this->_webApiCall($serviceInfo, $requestData);
+        return $response;
+    }
+
+    /**
+     * Delete a product by sku
+     *
+     * @param $productSku
+     * @return bool
+     */
+    protected function deleteProductBySku($productSku)
+    {
+        $resourcePath = self::RESOURCE_PATH . '/' . $productSku;
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => $resourcePath,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'deleteById',
+            ],
+        ];
+        $requestData = ["sku" => $productSku];
+        $response = $this->_webApiCall($serviceInfo, $requestData);
+        return $response;
+    }
+
+    /**
+     * Save product
+     *
+     * @param array $product
+     * @return array the created product data
+     */
+    protected function saveProduct($product)
+    {
+        $resourcePath = self::RESOURCE_PATH . '/' . $product['sku'];
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => $resourcePath,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Save',
+            ],
+        ];
+        $requestData = ['product' => $product];
+        $response = $this->_webApiCall($serviceInfo, $requestData);
+        return $response;
+    }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/SampleRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/SampleRepositoryTest.php
index c4fe8606cb8bc9f680e3db3da0bdc4061941a05c..0a1bba69a89890b7feeec2afd84a793181e2d239 100644
--- a/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/SampleRepositoryTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Downloadable/Api/SampleRepositoryTest.php
@@ -79,9 +79,11 @@ class SampleRepositoryTest extends WebapiAbstract
      */
     protected function getTargetProduct($isScopeGlobal = false)
     {
-        $product = Bootstrap::getObjectManager()->get('Magento\Catalog\Model\ProductFactory')->create()->load(1);
         if ($isScopeGlobal) {
-            $product->setStoreId(0);
+            $product = Bootstrap::getObjectManager()->get('Magento\Catalog\Model\ProductFactory')
+                ->create()->setStoreId(0)->load(1);
+        } else {
+            $product = Bootstrap::getObjectManager()->get('Magento\Catalog\Model\ProductFactory')->create()->load(1);
         }
 
         return $product;
@@ -120,11 +122,11 @@ class SampleRepositoryTest extends WebapiAbstract
     {
         $requestData = [
             'isGlobalScopeContent' => true,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
                 'title' => 'Title',
                 'sort_order' => 1,
-                'sample_file' => [
+                'sample_file_content' => [
                     'file_data' => base64_encode(file_get_contents($this->testImagePath)),
                     'name' => 'image.jpg',
                 ],
@@ -136,10 +138,11 @@ class SampleRepositoryTest extends WebapiAbstract
         $globalScopeSample = $this->getTargetSample($this->getTargetProduct(true), $newSampleId);
         $sample = $this->getTargetSample($this->getTargetProduct(), $newSampleId);
         $this->assertNotNull($sample);
-        $this->assertEquals($requestData['sampleContent']['title'], $sample->getTitle());
-        $this->assertEquals($requestData['sampleContent']['title'], $globalScopeSample->getTitle());
-        $this->assertEquals($requestData['sampleContent']['sort_order'], $sample->getSortOrder());
-        $this->assertEquals($requestData['sampleContent']['sample_type'], $sample->getSampleType());
+        $this->assertNotNull($sample->getId());
+        $this->assertEquals($requestData['sample']['title'], $sample->getTitle());
+        $this->assertEquals($requestData['sample']['title'], $globalScopeSample->getTitle());
+        $this->assertEquals($requestData['sample']['sort_order'], $sample->getSortOrder());
+        $this->assertEquals($requestData['sample']['sample_type'], $sample->getSampleType());
         $this->assertStringEndsWith('.jpg', $sample->getSampleFile());
         $this->assertNull($sample->getSampleUrl());
     }
@@ -151,8 +154,8 @@ class SampleRepositoryTest extends WebapiAbstract
     {
         $requestData = [
             'isGlobalScopeContent' => false,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
                 'title' => 'Store View Title',
                 'sort_order' => 1,
                 'sample_url' => 'http://www.sample.example.com/',
@@ -164,10 +167,10 @@ class SampleRepositoryTest extends WebapiAbstract
         $sample = $this->getTargetSample($this->getTargetProduct(), $newSampleId);
         $globalScopeSample = $this->getTargetSample($this->getTargetProduct(true), $newSampleId);
         $this->assertNotNull($sample);
-        $this->assertEquals($requestData['sampleContent']['title'], $sample->getTitle());
-        $this->assertEquals($requestData['sampleContent']['sort_order'], $sample->getSortOrder());
-        $this->assertEquals($requestData['sampleContent']['sample_url'], $sample->getSampleUrl());
-        $this->assertEquals($requestData['sampleContent']['sample_type'], $sample->getSampleType());
+        $this->assertEquals($requestData['sample']['title'], $sample->getTitle());
+        $this->assertEquals($requestData['sample']['sort_order'], $sample->getSortOrder());
+        $this->assertEquals($requestData['sample']['sample_url'], $sample->getSampleUrl());
+        $this->assertEquals($requestData['sample']['sample_type'], $sample->getSampleType());
         $this->assertEmpty($globalScopeSample->getTitle());
     }
 
@@ -178,8 +181,8 @@ class SampleRepositoryTest extends WebapiAbstract
     {
         $requestData = [
             'isGlobalScopeContent' => false,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
                 'title' => 'Sample with URL resource',
                 'sort_order' => 1,
                 'sample_url' => 'http://www.sample.example.com/',
@@ -190,10 +193,10 @@ class SampleRepositoryTest extends WebapiAbstract
         $newSampleId = $this->_webApiCall($this->createServiceInfo, $requestData);
         $sample = $this->getTargetSample($this->getTargetProduct(), $newSampleId);
         $this->assertNotNull($sample);
-        $this->assertEquals($requestData['sampleContent']['title'], $sample->getTitle());
-        $this->assertEquals($requestData['sampleContent']['sort_order'], $sample->getSortOrder());
-        $this->assertEquals($requestData['sampleContent']['sample_type'], $sample->getSampleType());
-        $this->assertEquals($requestData['sampleContent']['sample_url'], $sample->getSampleUrl());
+        $this->assertEquals($requestData['sample']['title'], $sample->getTitle());
+        $this->assertEquals($requestData['sample']['sort_order'], $sample->getSortOrder());
+        $this->assertEquals($requestData['sample']['sample_type'], $sample->getSampleType());
+        $this->assertEquals($requestData['sample']['sample_url'], $sample->getSampleUrl());
     }
 
     /**
@@ -201,14 +204,15 @@ class SampleRepositoryTest extends WebapiAbstract
      * @expectedException \Exception
      * @expectedExceptionMessage Invalid sample type.
      */
-    public function testCreateThrowsExceptionIfSampleTypeIsNotSpecified()
+    public function testCreateThrowsExceptionIfSampleTypeIsInvalid()
     {
         $requestData = [
             'isGlobalScopeContent' => false,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
                 'title' => 'Sample with URL resource',
                 'sort_order' => 1,
+                'sample_type' => 'invalid',
             ],
         ];
 
@@ -224,12 +228,12 @@ class SampleRepositoryTest extends WebapiAbstract
     {
         $requestData = [
             'isGlobalScopeContent' => false,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
                 'title' => 'Sample Title',
                 'sort_order' => 1,
                 'sample_type' => 'file',
-                'sample_file' => [
+                'sample_file_content' => [
                     'file_data' => 'not_a_base64_encoded_content',
                     'name' => 'image.jpg',
                 ],
@@ -248,12 +252,12 @@ class SampleRepositoryTest extends WebapiAbstract
     {
         $requestData = [
             'isGlobalScopeContent' => false,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
                 'title' => 'Title',
                 'sort_order' => 15,
                 'sample_type' => 'file',
-                'sample_file' => [
+                'sample_file_content' => [
                     'file_data' => base64_encode(file_get_contents($this->testImagePath)),
                     'name' => 'name/with|forbidden{characters',
                 ],
@@ -272,8 +276,8 @@ class SampleRepositoryTest extends WebapiAbstract
     {
         $requestData = [
             'isGlobalScopeContent' => false,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
                 'title' => 'Sample Title',
                 'sort_order' => 1,
                 'sample_type' => 'url',
@@ -294,8 +298,8 @@ class SampleRepositoryTest extends WebapiAbstract
     {
         $requestData = [
             'isGlobalScopeContent' => false,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
                 'title' => 'Sample Title',
                 'sort_order' => $sortOrder,
                 'sample_type' => 'url',
@@ -325,8 +329,8 @@ class SampleRepositoryTest extends WebapiAbstract
         $this->createServiceInfo['rest']['resourcePath'] = '/V1/products/simple/downloadable-links/samples';
         $requestData = [
             'isGlobalScopeContent' => false,
-            'productSku' => 'simple',
-            'sampleContent' => [
+            'sku' => 'simple',
+            'sample' => [
                 'title' => 'Sample Title',
                 'sort_order' => 50,
                 'sample_type' => 'url',
@@ -345,8 +349,8 @@ class SampleRepositoryTest extends WebapiAbstract
         $this->createServiceInfo['rest']['resourcePath'] = '/V1/products/wrong-sku/downloadable-links/samples';
         $requestData = [
             'isGlobalScopeContent' => false,
-            'productSku' => 'wrong-sku',
-            'sampleContent' => [
+            'sku' => 'wrong-sku',
+            'sample' => [
                 'title' => 'Title',
                 'sort_order' => 15,
                 'sample_type' => 'url',
@@ -366,19 +370,21 @@ class SampleRepositoryTest extends WebapiAbstract
             = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}";
         $requestData = [
             'isGlobalScopeContent' => false,
-            'sampleId' => $sampleId,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
+                'id' => $sampleId,
                 'title' => 'Updated Title',
                 'sort_order' => 2,
+                'sample_type' => 'url',
             ],
         ];
 
         $this->assertEquals($sampleId, $this->_webApiCall($this->updateServiceInfo, $requestData));
         $sample = $this->getTargetSample($this->getTargetProduct(), $sampleId);
         $this->assertNotNull($sample);
-        $this->assertEquals($requestData['sampleContent']['title'], $sample->getTitle());
-        $this->assertEquals($requestData['sampleContent']['sort_order'], $sample->getSortOrder());
+        $this->assertEquals($requestData['sample']['id'], $sample->getId());
+        $this->assertEquals($requestData['sample']['title'], $sample->getTitle());
+        $this->assertEquals($requestData['sample']['sort_order'], $sample->getSortOrder());
     }
 
     /**
@@ -392,11 +398,12 @@ class SampleRepositoryTest extends WebapiAbstract
             = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}";
         $requestData = [
             'isGlobalScopeContent' => true,
-            'sampleId' => $sampleId,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
+                'id' => $sampleId,
                 'title' => 'Updated Title',
                 'sort_order' => 2,
+                'sample_type' => 'url',
             ],
         ];
 
@@ -406,8 +413,8 @@ class SampleRepositoryTest extends WebapiAbstract
         $this->assertNotNull($sample);
         // Title was set on store view level in fixture so it must be the same
         $this->assertEquals($originalSample->getTitle(), $sample->getTitle());
-        $this->assertEquals($requestData['sampleContent']['title'], $globalScopeSample->getTitle());
-        $this->assertEquals($requestData['sampleContent']['sort_order'], $sample->getSortOrder());
+        $this->assertEquals($requestData['sample']['title'], $globalScopeSample->getTitle());
+        $this->assertEquals($requestData['sample']['sort_order'], $sample->getSortOrder());
     }
 
     /**
@@ -419,11 +426,12 @@ class SampleRepositoryTest extends WebapiAbstract
         $this->updateServiceInfo['rest']['resourcePath'] = '/V1/products/wrong-sku/downloadable-links/samples/1';
         $requestData = [
             'isGlobalScopeContent' => true,
-            'sampleId' => 1,
-            'productSku' => 'wrong-sku',
-            'sampleContent' => [
+            'sku' => 'wrong-sku',
+            'sample' => [
+                'id' => 1,
                 'title' => 'Updated Title',
                 'sort_order' => 2,
+                'sample_type' => 'url',
             ],
         ];
         $this->_webApiCall($this->updateServiceInfo, $requestData);
@@ -441,11 +449,12 @@ class SampleRepositoryTest extends WebapiAbstract
             = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}";
         $requestData = [
             'isGlobalScopeContent' => true,
-            'sampleId' => 9999,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
+                'id' => $sampleId,
                 'title' => 'Title',
                 'sort_order' => 2,
+                'sample_type' => 'url',
             ],
         ];
 
@@ -465,11 +474,12 @@ class SampleRepositoryTest extends WebapiAbstract
             = "/V1/products/downloadable-product/downloadable-links/samples/{$sampleId}";
         $requestData = [
             'isGlobalScopeContent' => false,
-            'sampleId' => $sampleId,
-            'productSku' => 'downloadable-product',
-            'sampleContent' => [
+            'sku' => 'downloadable-product',
+            'sample' => [
+                'id' => $sampleId,
                 'title' => 'Updated Sample Title',
                 'sort_order' => $sortOrder,
+                'sample_type' => 'url',
             ],
         ];
         $this->_webApiCall($this->updateServiceInfo, $requestData);
@@ -483,7 +493,7 @@ class SampleRepositoryTest extends WebapiAbstract
         $sampleId = $this->getTargetSample($this->getTargetProduct())->getId();
         $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/samples/{$sampleId}";
         $requestData = [
-            'sampleId' => $sampleId,
+            'id' => $sampleId,
         ];
 
         $this->assertTrue($this->_webApiCall($this->deleteServiceInfo, $requestData));
@@ -500,7 +510,7 @@ class SampleRepositoryTest extends WebapiAbstract
         $sampleId = 9999;
         $this->deleteServiceInfo['rest']['resourcePath'] = "/V1/products/downloadable-links/samples/{$sampleId}";
         $requestData = [
-            'sampleId' => $sampleId,
+            'id' => $sampleId,
         ];
 
         $this->_webApiCall($this->deleteServiceInfo, $requestData);
diff --git a/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductRepositoryInterfaceTest.php b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductRepositoryInterfaceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c8ab24527c633a12fd46442a9528570a4586e458
--- /dev/null
+++ b/dev/tests/api-functional/testsuite/Magento/GroupedProduct/Api/ProductRepositoryInterfaceTest.php
@@ -0,0 +1,203 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\GroupedProduct\Api;
+
+use Magento\Catalog\Api\Data\ProductInterface;
+use Magento\TestFramework\TestCase\WebapiAbstract;
+
+class ProductRepositoryInterfaceTest extends WebapiAbstract
+{
+    const SERVICE_NAME = 'catalogProductRepositoryV1';
+    const SERVICE_VERSION = 'V1';
+    const RESOURCE_PATH = '/V1/products';
+
+    /**
+     * Get Product
+     *
+     * @param $sku
+     * @return ProductInterface
+     */
+    protected function getProduct($sku)
+    {
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH . '/' . $sku,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_GET,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Get',
+            ],
+        ];
+
+        $response = $this->_webApiCall($serviceInfo, ['sku' => $sku]);
+        return $response;
+    }
+
+    /**
+     * Update Product
+     *
+     * @param $product
+     * @return mixed
+     */
+    protected function updateProduct($product)
+    {
+        $sku = $product[ProductInterface::SKU];
+        if (TESTS_WEB_API_ADAPTER == self::ADAPTER_REST) {
+            $product[ProductInterface::SKU] = null;
+        }
+
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH . '/' . $sku,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_PUT,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Save',
+            ],
+        ];
+        $requestData = ['product' => $product];
+        $response =  $this->_webApiCall($serviceInfo, $requestData);
+        return $response;
+    }
+
+    /**
+     * Save Product
+     *
+     * @param $product
+     * @return mixed
+     */
+    protected function saveProduct($product)
+    {
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_POST,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'Save',
+            ],
+        ];
+        $requestData = ['product' => $product];
+        return $this->_webApiCall($serviceInfo, $requestData);
+    }
+
+    /**
+     * Delete Product
+     *
+     * @param string $sku
+     * @return boolean
+     */
+    protected function deleteProduct($sku)
+    {
+        $serviceInfo = [
+            'rest' => [
+                'resourcePath' => self::RESOURCE_PATH . '/' . $sku,
+                'httpMethod' => \Magento\Framework\Webapi\Rest\Request::HTTP_METHOD_DELETE,
+            ],
+            'soap' => [
+                'service' => self::SERVICE_NAME,
+                'serviceVersion' => self::SERVICE_VERSION,
+                'operation' => self::SERVICE_NAME . 'DeleteById',
+            ],
+        ];
+
+        return (TESTS_WEB_API_ADAPTER == self::ADAPTER_SOAP) ?
+            $this->_webApiCall($serviceInfo, ['sku' => $sku]) : $this->_webApiCall($serviceInfo);
+    }
+
+    public function testProductLinks()
+    {
+        // Create simple product
+        $productData =  [
+            ProductInterface::SKU => "product_simple_500",
+            ProductInterface::NAME => "Product Simple 500",
+            ProductInterface::VISIBILITY => 4,
+            ProductInterface::TYPE_ID => 'simple',
+            ProductInterface::PRICE => 100,
+            ProductInterface::STATUS => 1,
+            ProductInterface::TYPE_ID => 'simple',
+            ProductInterface::ATTRIBUTE_SET_ID => 4,
+        ];
+
+        $this->saveProduct($productData);
+
+        // Create a group product
+        $productLinkData = ["product_sku" => "group_product_500", "link_type" => "associated",
+                            "linked_product_sku" => "product_simple_500", "linked_product_type" => "simple",
+                            "position" => 0, "extension_attributes" => ["qty" => 1]];
+        $productWithGroupData =  [
+            ProductInterface::SKU => "group_product_500",
+            ProductInterface::NAME => "Group Product 500",
+            ProductInterface::VISIBILITY => 4,
+            ProductInterface::TYPE_ID => 'grouped',
+            ProductInterface::PRICE => 300,
+            ProductInterface::STATUS => 1,
+            ProductInterface::ATTRIBUTE_SET_ID => 4,
+            "product_links" => [$productLinkData]
+        ];
+
+        $this->saveProduct($productWithGroupData);
+        $response = $this->getProduct("group_product_500");
+        $this->assertArrayHasKey('product_links', $response);
+        $links = $response['product_links'];
+        $this->assertEquals(1, count($links));
+        $this->assertEquals($productLinkData, $links[0]);
+
+        // update link information for Group Product
+        $productLinkData1 = ["product_sku" => "group_product_500", "link_type" => "associated",
+                            "linked_product_sku" => "product_simple_500", "linked_product_type" => "simple",
+                            "position" => 0, "extension_attributes" => ["qty" => 4]];
+        $productLinkData2 = ["product_sku" => "group_product_500", "link_type" => "upsell",
+                             "linked_product_sku" => "product_simple_500", "linked_product_type" => "simple",
+                             "position" => 0, "extension_attributes" => []];
+        $productWithGroupData =  [
+            ProductInterface::SKU => "group_product_500",
+            ProductInterface::NAME => "Group Product 500",
+            ProductInterface::VISIBILITY => 4,
+            ProductInterface::TYPE_ID => 'grouped',
+            ProductInterface::PRICE => 300,
+            ProductInterface::STATUS => 1,
+            ProductInterface::ATTRIBUTE_SET_ID => 4,
+            "product_links" => [$productLinkData1, $productLinkData2]
+        ];
+
+        $this->saveProduct($productWithGroupData);
+        $response = $this->getProduct("group_product_500");
+
+        $this->assertArrayHasKey('product_links', $response);
+        $links = $response['product_links'];
+        $this->assertEquals(2, count($links));
+        $this->assertEquals($productLinkData1, $links[1]);
+        $this->assertEquals($productLinkData2, $links[0]);
+
+        // Remove link
+        $productWithNoLinkData =  [
+            ProductInterface::SKU => "group_product_500",
+            ProductInterface::NAME => "Group Product 500",
+            ProductInterface::VISIBILITY => 4,
+            ProductInterface::TYPE_ID => 'grouped',
+            ProductInterface::PRICE => 300,
+            ProductInterface::STATUS => 1,
+            ProductInterface::ATTRIBUTE_SET_ID => 4,
+            "product_links" => []
+        ];
+
+        $this->saveProduct($productWithNoLinkData);
+        $response = $this->getProduct("group_product_500");
+        $this->assertArrayHasKey('product_links', $response);
+        $links = $response['product_links'];
+        $this->assertEquals([], $links);
+
+        $this->deleteProduct("product_simple_500");
+        $this->deleteProduct("group_product_500");
+    }
+}
diff --git a/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxClassRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxClassRepositoryTest.php
index 1557278ce1bb31a76ac96d90a90c57b6bada4d21..2d20a4e9110939aa3c8298b8eb6e317436bf2454 100644
--- a/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxClassRepositoryTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxClassRepositoryTest.php
@@ -12,6 +12,7 @@ use Magento\Framework\Api\FilterBuilder;
 use Magento\Framework\Api\SearchCriteriaBuilder;
 use Magento\Framework\Exception\NoSuchEntityException;
 use Magento\Tax\Api\Data\TaxClassInterfaceFactory;
+use Magento\Tax\Model\ClassModel;
 use Magento\Tax\Model\ClassModelRegistry;
 use Magento\TestFramework\Helper\Bootstrap;
 use Magento\TestFramework\TestCase\WebapiAbstract;
@@ -171,9 +172,9 @@ class TaxClassRepositoryTest extends WebapiAbstract
         ];
         $requestData = ['taxClassId' => $taxClassId];
         $taxClassData = $this->_webApiCall($serviceInfo, $requestData);
-        $this->assertEquals($taxClassData[Data\TaxClassInterface::KEY_NAME], $taxClassName);
+        $this->assertEquals($taxClassData[ClassModel::KEY_NAME], $taxClassName);
         $this->assertEquals(
-            $taxClassData[Data\TaxClassInterface::KEY_TYPE],
+            $taxClassData[ClassModel::KEY_TYPE],
             TaxClassManagementInterface::TYPE_CUSTOMER
         );
     }
@@ -220,7 +221,7 @@ class TaxClassRepositoryTest extends WebapiAbstract
     public function testSearchTaxClass()
     {
         $taxClassName = 'Retail Customer';
-        $taxClassNameField = Data\TaxClassInterface::KEY_NAME;
+        $taxClassNameField = ClassModel::KEY_NAME;
         $filter = $this->filterBuilder->setField($taxClassNameField)
             ->setValue($taxClassName)
             ->create();
@@ -249,23 +250,23 @@ class TaxClassRepositoryTest extends WebapiAbstract
     public function testSearchTaxClassMultipleFilterGroups()
     {
         $productTaxClass = [
-            Data\TaxClassInterface::KEY_NAME => 'Taxable Goods',
-            Data\TaxClassInterface::KEY_TYPE => 'PRODUCT',
+            ClassModel::KEY_NAME => 'Taxable Goods',
+            ClassModel::KEY_TYPE => 'PRODUCT',
         ];
-        $customerTaxClass = [Data\TaxClassInterface::KEY_NAME => 'Retail Customer',
-            Data\TaxClassInterface::KEY_TYPE => 'CUSTOMER', ];
+        $customerTaxClass = [ClassModel::KEY_NAME => 'Retail Customer',
+            ClassModel::KEY_TYPE => 'CUSTOMER', ];
 
-        $filter1 = $this->filterBuilder->setField(Data\TaxClassInterface::KEY_NAME)
-            ->setValue($productTaxClass[Data\TaxClassInterface::KEY_NAME])
+        $filter1 = $this->filterBuilder->setField(ClassModel::KEY_NAME)
+            ->setValue($productTaxClass[ClassModel::KEY_NAME])
             ->create();
-        $filter2 = $this->filterBuilder->setField(Data\TaxClassInterface::KEY_NAME)
-            ->setValue($customerTaxClass[Data\TaxClassInterface::KEY_NAME])
+        $filter2 = $this->filterBuilder->setField(ClassModel::KEY_NAME)
+            ->setValue($customerTaxClass[ClassModel::KEY_NAME])
             ->create();
-        $filter3 = $this->filterBuilder->setField(Data\TaxClassInterface::KEY_TYPE)
-            ->setValue($productTaxClass[Data\TaxClassInterface::KEY_TYPE])
+        $filter3 = $this->filterBuilder->setField(ClassModel::KEY_TYPE)
+            ->setValue($productTaxClass[ClassModel::KEY_TYPE])
             ->create();
-        $filter4 = $this->filterBuilder->setField(Data\TaxClassInterface::KEY_TYPE)
-            ->setValue($customerTaxClass[Data\TaxClassInterface::KEY_TYPE])
+        $filter4 = $this->filterBuilder->setField(ClassModel::KEY_TYPE)
+            ->setValue($customerTaxClass[ClassModel::KEY_TYPE])
             ->create();
 
         /**
@@ -291,12 +292,12 @@ class TaxClassRepositoryTest extends WebapiAbstract
         $searchResults = $this->_webApiCall($serviceInfo, $requestData);
         $this->assertEquals(2, $searchResults['total_count']);
         $this->assertEquals(
-            $productTaxClass[Data\TaxClassInterface::KEY_NAME],
-            $searchResults['items'][0][Data\TaxClassInterface::KEY_NAME]
+            $productTaxClass[ClassModel::KEY_NAME],
+            $searchResults['items'][0][ClassModel::KEY_NAME]
         );
         $this->assertEquals(
-            $customerTaxClass[Data\TaxClassInterface::KEY_NAME],
-            $searchResults['items'][1][Data\TaxClassInterface::KEY_NAME]
+            $customerTaxClass[ClassModel::KEY_NAME],
+            $searchResults['items'][1][ClassModel::KEY_NAME]
         );
 
         /** class_name == 'Retail Customer' && ( class_type == 'CUSTOMER' || class_type == 'PRODUCT') */
@@ -309,8 +310,8 @@ class TaxClassRepositoryTest extends WebapiAbstract
         $searchResults = $this->_webApiCall($serviceInfo, $requestData);
         $this->assertEquals(1, $searchResults['total_count']);
         $this->assertEquals(
-            $customerTaxClass[Data\TaxClassInterface::KEY_NAME],
-            $searchResults['items'][0][Data\TaxClassInterface::KEY_NAME]
+            $customerTaxClass[ClassModel::KEY_NAME],
+            $searchResults['items'][0][ClassModel::KEY_NAME]
         );
     }
 }
diff --git a/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxRateRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxRateRepositoryTest.php
index 9f47505721b8f6bb1e4b403e6b2f56b861fd3668..a140347e2498fe75163c9822a4f5f8eb80fd9506 100644
--- a/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxRateRepositoryTest.php
+++ b/dev/tests/api-functional/testsuite/Magento/Tax/Api/TaxRateRepositoryTest.php
@@ -10,7 +10,7 @@ use Magento\Framework\Api\FilterBuilder;
 use Magento\Framework\Api\SearchCriteria;
 use Magento\Framework\Api\SearchCriteriaBuilder;
 use Magento\Framework\Api\SortOrderBuilder;
-use Magento\Tax\Api\Data\TaxRateInterface as TaxRate;
+use Magento\Tax\Model\Calculation\Rate;
 use Magento\TestFramework\Helper\Bootstrap;
 use Magento\TestFramework\TestCase\WebapiAbstract;
 
@@ -433,7 +433,7 @@ class TaxRateRepositoryTest extends WebapiAbstract
         $rates = $this->setupTaxRatesForSearch();
 
         // Find rates whose code is 'codeUs12'
-        $filter = $this->filterBuilder->setField(TaxRate::KEY_CODE)
+        $filter = $this->filterBuilder->setField(Rate::KEY_CODE)
             ->setValue('codeUs12')
             ->create();
 
@@ -480,11 +480,11 @@ class TaxRateRepositoryTest extends WebapiAbstract
         $rates = $this->setupTaxRatesForSearch();
 
         // Find rates which country id 'CZ'
-        $filter = $this->filterBuilder->setField(TaxRate::KEY_COUNTRY_ID)
+        $filter = $this->filterBuilder->setField(Rate::KEY_COUNTRY_ID)
             ->setValue('CZ')
             ->create();
         $sortOrder = $this->sortOrderBuilder
-            ->setField(TaxRate::KEY_POSTCODE)
+            ->setField(Rate::KEY_POSTCODE)
             ->setDirection(SearchCriteria::SORT_DESC)
             ->create();
         // Order them by descending postcode (not the default order)
diff --git a/dev/tests/integration/etc/config-global.php.dist b/dev/tests/integration/etc/config-global.php.dist
new file mode 100644
index 0000000000000000000000000000000000000000..f24e2ce9ccae044dda5ccadb9ccc4e54946558e2
--- /dev/null
+++ b/dev/tests/integration/etc/config-global.php.dist
@@ -0,0 +1,7 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+return [];
\ No newline at end of file
diff --git a/dev/tests/integration/framework/Magento/TestFramework/Annotation/ConfigFixture.php b/dev/tests/integration/framework/Magento/TestFramework/Annotation/ConfigFixture.php
index 9854602a507fcc0045fcc2f5be86a85f96073b0d..3809d7f293849488c696e4631c03e6ed34e0de02 100644
--- a/dev/tests/integration/framework/Magento/TestFramework/Annotation/ConfigFixture.php
+++ b/dev/tests/integration/framework/Magento/TestFramework/Annotation/ConfigFixture.php
@@ -9,6 +9,8 @@
  */
 namespace Magento\TestFramework\Annotation;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 class ConfigFixture
 {
     /**
@@ -73,7 +75,7 @@ class ConfigFixture
                 )->setValue(
                     $configPath,
                     $value,
-                    \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+                    ScopeConfigInterface::SCOPE_TYPE_DEFAULT
                 );
             }
         } else {
diff --git a/dev/tests/integration/framework/Magento/TestFramework/Application.php b/dev/tests/integration/framework/Magento/TestFramework/Application.php
index d8aee09eb186a8a531ec1fb6f49790fc770d038d..41e57ac4359e8c8547ba425e15b15c8ba514571a 100644
--- a/dev/tests/integration/framework/Magento/TestFramework/Application.php
+++ b/dev/tests/integration/framework/Magento/TestFramework/Application.php
@@ -116,12 +116,20 @@ class Application
      */
     protected $dirList;
 
+    /**
+     * Config file for integration tests
+     *
+     * @var string
+     */
+    private $globalConfigFile;
+
     /**
      * Constructor
      *
      * @param \Magento\Framework\Shell $shell
      * @param string $installDir
      * @param array $installConfigFile
+     * @param string $globalConfigFile
      * @param string $globalConfigDir
      * @param string $appMode
      * @param AutoloaderInterface $autoloadWrapper
@@ -130,6 +138,7 @@ class Application
         \Magento\Framework\Shell $shell,
         $installDir,
         $installConfigFile,
+        $globalConfigFile,
         $globalConfigDir,
         $appMode,
         AutoloaderInterface $autoloadWrapper
@@ -151,6 +160,7 @@ class Application
         $this->_factory = new \Magento\TestFramework\ObjectManagerFactory($this->dirList, $driverPool);
 
         $this->_configDir = $this->dirList->getPath(DirectoryList::CONFIG);
+        $this->globalConfigFile = $globalConfigFile;
     }
 
     /**
@@ -336,6 +346,8 @@ class Application
         /** @var \Magento\TestFramework\Db\Sequence $sequence */
         $sequence = $objectManager->get('Magento\TestFramework\Db\Sequence');
         $sequence->generateSequences();
+        $objectManager->create('Magento\TestFramework\Config', ['configPath' => $this->globalConfigFile])
+            ->rewriteAdditionalConfig();
     }
 
     /**
@@ -416,18 +428,18 @@ class Application
         );
 
         // enable only specified list of caches
-        $cacheScript = BP . '/dev/shell/cache.php';
         $initParamsQuery = $this->getInitParamsQuery();
-        $this->_shell->execute('php -f %s -- --set=0 --bootstrap=%s', [$cacheScript, $initParamsQuery]);
-        $cacheTypes = [
-            \Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER,
-            \Magento\Framework\App\Cache\Type\Layout::TYPE_IDENTIFIER,
-            \Magento\Framework\App\Cache\Type\Translate::TYPE_IDENTIFIER,
-            \Magento\Eav\Model\Cache\Type::TYPE_IDENTIFIER,
-        ];
+        $this->_shell->execute('php -f %s cache:disable --all --bootstrap=%s', [BP . '/bin/magento', $initParamsQuery]);
         $this->_shell->execute(
-            'php -f %s -- --set=1 --types=%s --bootstrap=%s',
-            [$cacheScript, implode(',', $cacheTypes), $initParamsQuery]
+            'php -f %s cache:enable %s %s %s %s --bootstrap=%s',
+            [
+                BP . '/bin/magento',
+                \Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER,
+                \Magento\Framework\App\Cache\Type\Layout::TYPE_IDENTIFIER,
+                \Magento\Framework\App\Cache\Type\Translate::TYPE_IDENTIFIER,
+                \Magento\Eav\Model\Cache\Type::TYPE_IDENTIFIER,
+                $initParamsQuery,
+            ]
         );
 
         // right after a clean installation, store DB dump for future reuse in tests or running the test suite again
diff --git a/dev/tests/integration/framework/Magento/TestFramework/Config.php b/dev/tests/integration/framework/Magento/TestFramework/Config.php
new file mode 100644
index 0000000000000000000000000000000000000000..3160918f29c5cffb6b456ff69b30ad6554b728a6
--- /dev/null
+++ b/dev/tests/integration/framework/Magento/TestFramework/Config.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\TestFramework;
+
+use Magento\Framework\App\Config\MutableScopeConfigInterface;
+
+class Config
+{
+    /**
+     * @var MutableScopeConfigInterface
+     */
+    private $mutableScopeConfig;
+
+    /**
+     * @var array
+     */
+    private $configData;
+
+    /**
+     * @param MutableScopeConfigInterface $mutableScopeConfig
+     * @param string $configPath
+     */
+    public function __construct(MutableScopeConfigInterface $mutableScopeConfig, $configPath)
+    {
+        $this->mutableScopeConfig = $mutableScopeConfig;
+        $this->configData = $this->readFile($configPath);
+    }
+
+    /**
+     * Rewrite config from integration config to global config
+     */
+    public function rewriteAdditionalConfig()
+    {
+        foreach ($this->configData as $path => $value) {
+            $this->mutableScopeConfig->setValue($path, $value, \Magento\Store\Model\ScopeInterface::SCOPE_STORE);
+        }
+    }
+
+    /**
+     * @param string $configPath
+     * @return array
+     */
+    private function readFile($configPath)
+    {
+        /** @var array $config */
+        $config = require $configPath;
+
+        return $config;
+    }
+}
diff --git a/dev/tests/integration/framework/bootstrap.php b/dev/tests/integration/framework/bootstrap.php
index b71bb17d945ccd42f693ed57588116e05c474dbb..32fabb2269a4453e5762790ea11c61d0a0c60ae0 100644
--- a/dev/tests/integration/framework/bootstrap.php
+++ b/dev/tests/integration/framework/bootstrap.php
@@ -34,7 +34,11 @@ try {
 
     $installConfigFile = $settings->getAsConfigFile('TESTS_INSTALL_CONFIG_FILE');
     if (!file_exists($installConfigFile)) {
-        $installConfigFile = $installConfigFile . '.dist';
+        $installConfigFile .= '.dist';
+    }
+    $globalConfigFile = $settings->getAsConfigFile('TESTS_GLOBAL_CONFIG_FILE');
+    if (!file_exists($globalConfigFile)) {
+        $globalConfigFile .= '.dist';
     }
     $sandboxUniqueId = md5(sha1_file($installConfigFile));
     $installDir = "{$testsTmpDir}/sandbox-{$settings->get('TESTS_PARALLEL_THREAD', 0)}-{$sandboxUniqueId}";
@@ -42,6 +46,7 @@ try {
         $shell,
         $installDir,
         $installConfigFile,
+        $globalConfigFile,
         $settings->get('TESTS_GLOBAL_CONFIG_DIR'),
         $settings->get('TESTS_MAGENTO_MODE'),
         AutoloaderRegistry::getAutoloader()
diff --git a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ApplicationTest.php b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ApplicationTest.php
index ce5f9d12c00bccf6eef1323270c0fe71dbf685b8..b24467937d35cb3291ed18a10eef2390c6d71a09 100644
--- a/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ApplicationTest.php
+++ b/dev/tests/integration/framework/tests/unit/testsuite/Magento/Test/ApplicationTest.php
@@ -27,6 +27,7 @@ class ApplicationTest extends \PHPUnit_Framework_TestCase
             $shell,
             $tempDir,
             'config.php',
+            'global-config.php',
             '',
             $appMode,
             $autoloadWrapper
diff --git a/dev/tests/integration/testsuite/Magento/Backend/Model/Locale/ResolverTest.php b/dev/tests/integration/testsuite/Magento/Backend/Model/Locale/ResolverTest.php
index 09c21758cba336cbd15982d610875cbc0aa19117..c0cc101fd36bfe94dd5dcc19481d81d14b926132 100644
--- a/dev/tests/integration/testsuite/Magento/Backend/Model/Locale/ResolverTest.php
+++ b/dev/tests/integration/testsuite/Magento/Backend/Model/Locale/ResolverTest.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Backend\Model\Locale;
 
+use Magento\Framework\Locale\Resolver;
+
 /**
  * @magentoAppArea adminhtml
  */
@@ -28,7 +30,7 @@ class ResolverTest extends \PHPUnit_Framework_TestCase
      */
     public function testSetLocaleWithDefaultLocale()
     {
-        $this->_checkSetLocale(\Magento\Framework\Locale\ResolverInterface::DEFAULT_LOCALE);
+        $this->_checkSetLocale(Resolver::DEFAULT_LOCALE);
     }
 
     /**
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
index 2a99dede484227e4b7bc38fd9040e78573584869..ab40348430e024c0d58e42d8ee649321c0ec754b 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/Model/Product/Type/ConfigurableTest.php
@@ -79,7 +79,6 @@ class ConfigurableTest extends \PHPUnit_Framework_TestCase
     public function testSetUsedProductAttributeIds()
     {
         $testConfigurable = $this->_getAttributeByCode('test_configurable');
-        $this->assertEmpty($this->_product->getData('_cache_instance_configurable_attributes'));
         $this->_model->setUsedProductAttributeIds([$testConfigurable->getId()], $this->_product);
         $attributes = $this->_product->getData('_cache_instance_configurable_attributes');
         $this->assertArrayHasKey(0, $attributes);
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute_rollback.php
new file mode 100644
index 0000000000000000000000000000000000000000..5772edc9317ae5a0a41a9d4aafd419ea982e53fa
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/configurable_attribute_rollback.php
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+/** @var \Magento\Framework\Registry $registry */
+$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry');
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+$eavConfig = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Eav\Model\Config');
+$attribute = $eavConfig->getAttribute('catalog_product', 'test_configurable');
+if ($attribute instanceof \Magento\Eav\Model\Entity\Attribute\AbstractAttribute
+    && $attribute->getId()
+) {
+    $attribute->delete();
+}
+$eavConfig->clear();
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php
index b083d7e52dfb293b687d837f145b54909240e617..cc615bf03ea85243af323bf7844bc3d33acac7c9 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable.php
@@ -12,17 +12,16 @@ $installer = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create
     ['resourceName' => 'catalog_setup']
 );
 
-/* Create simple products per each option */
-/** @var $options \Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection */
-$options = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-    'Magento\Eav\Model\Resource\Entity\Attribute\Option\Collection'
-);
-$options->setAttributeFilter($attribute->getId());
+/* Create simple products per each option value*/
+
+/** @var \Magento\Eav\Api\Data\AttributeOptionInterface[] $options */
+$options = $attribute->getOptions();
 
 $attributeValues = [];
 $productIds = [];
 $attributeSetId = $installer->getAttributeSetId('catalog_product', 'Default');
 $productIds = [10, 20];
+array_shift($options); //remove the first option which is empty
 foreach ($options as $option) {
     /** @var $product \Magento\Catalog\Model\Product */
     $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
@@ -36,13 +35,13 @@ foreach ($options as $option) {
     )->setWebsiteIds(
         [1]
     )->setName(
-        'Configurable Option' . $option->getId()
+        'Configurable Option' . $option->getLabel()
     )->setSku(
         'simple_' . $productId
     )->setPrice(
         10
     )->setTestConfigurable(
-        $option->getId()
+        $option->getValue()
     )->setVisibility(
         \Magento\Catalog\Model\Product\Visibility::VISIBILITY_NOT_VISIBLE
     )->setStatus(
@@ -54,7 +53,7 @@ foreach ($options as $option) {
     $attributeValues[] = [
         'label' => 'test',
         'attribute_id' => $attribute->getId(),
-        'value_index' => $option->getId(),
+        'value_index' => $option->getValue(),
         'is_percent' => false,
         'pricing_value' => 5,
     ];
diff --git a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_rollback.php b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_rollback.php
index c1b23ce233c9e09240533d5bc7ee97f90a7510da..f1e17b724c8b476f76a622837d2120b0df1c96cd 100644
--- a/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_rollback.php
+++ b/dev/tests/integration/testsuite/Magento/ConfigurableProduct/_files/product_configurable_rollback.php
@@ -26,6 +26,11 @@ $product->load(1);
 if ($product->getId()) {
     $product->delete();
 }
+\Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+    ->get('Magento\ConfigurableProduct\Model\Resource\Product\Type\Configurable\Attribute\Price\Data')
+    ->setProductPrice(1, null);
+
+require __DIR__ . '/configurable_attribute_rollback.php';
 
 $registry->unregister('isSecureArea');
 $registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php
index c8379e5e9c39f37bb5d4edd46ed4720aa250b788..18a4314710c3d9a19f51bf5688afcc7087b90f93 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/Session/SessionManagerTest.php
@@ -3,153 +3,214 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Framework\Session;
-
-class SessionManagerTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \Magento\Framework\Session\SessionManagerInterface
-     */
-    protected $_model;
-
-    /**
-     * @var \Magento\Framework\Session\SidResolverInterface
-     */
-    protected $_sidResolver;
-
-    /**
-     * @var string
-     */
-    protected $sessionName;
-
-    /**
-     * @var \Magento\Framework\App\RequestInterface
-     */
-    protected $request;
-
-    protected function setUp()
-    {
-        $this->sessionName = 'frontEndSession';
-
-        ini_set('session.use_only_cookies', '0');
-        ini_set('session.name', $this->sessionName);
-
-        $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
-
-        /** @var \Magento\Framework\Session\SidResolverInterface $sidResolver */
-        $this->_sidResolver = $objectManager->get('Magento\Framework\Session\SidResolverInterface');
-
-        $this->request = $objectManager->get('Magento\Framework\App\RequestInterface');
-
-        /** @var \Magento\Framework\Session\SessionManager _model */
-        $this->_model = $objectManager->create(
-            'Magento\Framework\Session\SessionManager',
-            [
-                $this->request,
-                $this->_sidResolver,
-                $objectManager->get('Magento\Framework\Session\Config\ConfigInterface'),
-                $objectManager->get('Magento\Framework\Session\SaveHandlerInterface'),
-                $objectManager->get('Magento\Framework\Session\ValidatorInterface'),
-                $objectManager->get('Magento\Framework\Session\StorageInterface')
-            ]
-        );
-    }
-
-    public function testSessionNameFromIni()
-    {
-        $this->_model->start();
-        $this->assertSame($this->sessionName, $this->_model->getName());
-        $this->_model->destroy();
-    }
-
-    public function testSessionUseOnlyCookies()
-    {
-        $expectedValue = '1';
-        $sessionUseOnlyCookies = ini_get('session.use_only_cookies');
-        $this->assertSame($expectedValue, $sessionUseOnlyCookies);
-    }
-
-    public function testGetData()
-    {
-        $this->_model->setData(['test_key' => 'test_value']);
-        $this->assertEquals('test_value', $this->_model->getData('test_key', true));
-        $this->assertNull($this->_model->getData('test_key'));
-    }
-
-    public function testGetSessionId()
-    {
-        $this->assertEquals(session_id(), $this->_model->getSessionId());
-    }
-
-    public function testGetName()
-    {
-        $this->assertEquals(session_name(), $this->_model->getName());
-    }
-
-    public function testSetName()
-    {
-        $this->_model->setName('test');
-        $this->assertEquals('test', $this->_model->getName());
-    }
-
-    public function testDestroy()
-    {
-        $data = ['key' => 'value'];
-        $this->_model->setData($data);
-
-        $this->assertEquals($data, $this->_model->getData());
-        $this->_model->destroy();
-
-        $this->assertEquals([], $this->_model->getData());
-    }
+// @codingStandardsIgnoreStart
+namespace {
+    $mockPHPFunctions = false;
+}
 
-    public function testSetSessionId()
-    {
-        $sessionId = $this->_model->getSessionId();
-        $this->_model->setSessionId($this->_sidResolver->getSid($this->_model));
-        $this->assertEquals($sessionId, $this->_model->getSessionId());
-
-        $this->_model->setSessionId('test');
-        $this->assertEquals('test', $this->_model->getSessionId());
-    }
+namespace Magento\Framework\Session {
+    // @codingStandardsIgnoreEnd
 
     /**
-     * @magentoConfigFixture current_store web/session/use_frontend_sid 1
+     * Mock session_status if in test mode, or continue normal execution otherwise
+     *
+     * @return int Session status code
      */
-    public function testSetSessionIdFromParam()
+    function session_status()
     {
-        $this->assertNotEquals('test_id', $this->_model->getSessionId());
-        $this->request->getQuery()->set($this->_sidResolver->getSessionIdQueryParam($this->_model), 'test-id');
-        $this->_model->setSessionId($this->_sidResolver->getSid($this->_model));
-
-        $this->assertEquals('test-id', $this->_model->getSessionId());
-
-        /* Use not valid identifier */
-        $this->request->getQuery()->set($this->_sidResolver->getSessionIdQueryParam($this->_model), 'test_id');
-        $this->_model->setSessionId($this->_sidResolver->getSid($this->_model));
-        $this->assertEquals('test-id', $this->_model->getSessionId());
+        global $mockPHPFunctions;
+        if ($mockPHPFunctions) {
+            return PHP_SESSION_NONE;
+        }
+        return call_user_func_array('\session_status', func_get_args());
     }
 
-    public function testGetSessionIdForHost()
+    function headers_sent()
     {
-        $this->request->getServer()->set('HTTP_HOST', 'localhost');
-        $this->_model->start();
-        $this->assertEmpty($this->_model->getSessionIdForHost('localhost'));
-        $this->assertNotEmpty($this->_model->getSessionIdForHost('test'));
-        $this->_model->destroy();
+        global $mockPHPFunctions;
+        if ($mockPHPFunctions) {
+            return false;
+        }
+        return call_user_func_array('\headers_sent', func_get_args());
     }
 
-    public function testIsValidForHost()
+    class SessionManagerTest extends \PHPUnit_Framework_TestCase
     {
-        $this->request->getServer()->set('HTTP_HOST', 'localhost');
-        $this->_model->start();
-
-        $reflection = new \ReflectionMethod($this->_model, '_addHost');
-        $reflection->setAccessible(true);
-        $reflection->invoke($this->_model);
-
-        $this->assertFalse($this->_model->isValidForHost('test.com'));
-        $this->assertTrue($this->_model->isValidForHost('localhost'));
-        $this->_model->destroy();
+        /**
+         * @var \Magento\Framework\Session\SessionManagerInterface
+         */
+        protected $_model;
+
+        /**
+         * @var \Magento\Framework\Session\SidResolverInterface
+         */
+        protected $_sidResolver;
+
+        /**
+         * @var string
+         */
+        protected $sessionName;
+
+        /**
+         * @var \Magento\Framework\ObjectManagerInterface
+         */
+        protected $objectManager;
+
+        protected function setUp()
+        {
+            $this->sessionName = 'frontEndSession';
+
+            ini_set('session.use_only_cookies', '0');
+            ini_set('session.name', $this->sessionName);
+
+            $this->objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+
+            /** @var \Magento\Framework\Session\SidResolverInterface $sidResolver */
+            $this->_sidResolver = $this->objectManager->get('Magento\Framework\Session\SidResolverInterface');
+
+            $this->request = $this->objectManager->get('Magento\Framework\App\RequestInterface');
+
+            /** @var \Magento\Framework\Session\SessionManager _model */
+            $this->_model = $this->objectManager->create(
+                'Magento\Framework\Session\SessionManager',
+                [
+                    $this->objectManager->get('Magento\Framework\App\Request\Http'),
+                    $this->_sidResolver,
+                    $this->objectManager->get('Magento\Framework\Session\Config\ConfigInterface'),
+                    $this->objectManager->get('Magento\Framework\Session\SaveHandlerInterface'),
+                    $this->objectManager->get('Magento\Framework\Session\ValidatorInterface'),
+                    $this->objectManager->get('Magento\Framework\Session\StorageInterface')
+                ]
+            );
+        }
+
+        public function testSessionNameFromIni()
+        {
+            $this->_model->start();
+            $this->assertSame($this->sessionName, $this->_model->getName());
+            $this->_model->destroy();
+        }
+
+        public function testSessionUseOnlyCookies()
+        {
+            $expectedValue = '1';
+            $sessionUseOnlyCookies = ini_get('session.use_only_cookies');
+            $this->assertSame($expectedValue, $sessionUseOnlyCookies);
+        }
+
+        public function testGetData()
+        {
+            $this->_model->setData(['test_key' => 'test_value']);
+            $this->assertEquals('test_value', $this->_model->getData('test_key', true));
+            $this->assertNull($this->_model->getData('test_key'));
+        }
+
+        public function testGetSessionId()
+        {
+            $this->assertEquals(session_id(), $this->_model->getSessionId());
+        }
+
+        public function testGetName()
+        {
+            $this->assertEquals(session_name(), $this->_model->getName());
+        }
+
+        public function testSetName()
+        {
+            $this->_model->setName('test');
+            $this->assertEquals('test', $this->_model->getName());
+        }
+
+        public function testDestroy()
+        {
+            $data = ['key' => 'value'];
+            $this->_model->setData($data);
+
+            $this->assertEquals($data, $this->_model->getData());
+            $this->_model->destroy();
+
+            $this->assertEquals([], $this->_model->getData());
+        }
+
+        public function testSetSessionId()
+        {
+            $sessionId = $this->_model->getSessionId();
+            $this->_model->setSessionId($this->_sidResolver->getSid($this->_model));
+            $this->assertEquals($sessionId, $this->_model->getSessionId());
+
+            $this->_model->setSessionId('test');
+            $this->assertEquals('test', $this->_model->getSessionId());
+        }
+
+        /**
+         * @magentoConfigFixture current_store web/session/use_frontend_sid 1
+         */
+        public function testSetSessionIdFromParam()
+        {
+            $this->assertNotEquals('test_id', $this->_model->getSessionId());
+            $this->request->getQuery()->set($this->_sidResolver->getSessionIdQueryParam($this->_model), 'test-id');
+            $this->_model->setSessionId($this->_sidResolver->getSid($this->_model));
+            $this->assertEquals('test-id', $this->_model->getSessionId());
+            /* Use not valid identifier */
+            $this->request->getQuery()->set($this->_sidResolver->getSessionIdQueryParam($this->_model), 'test_id');
+            $this->_model->setSessionId($this->_sidResolver->getSid($this->_model));
+            $this->assertEquals('test-id', $this->_model->getSessionId());
+        }
+
+        public function testGetSessionIdForHost()
+        {
+            $_SERVER['HTTP_HOST'] = 'localhost';
+            $this->_model->start();
+            $this->assertEmpty($this->_model->getSessionIdForHost('localhost'));
+            $this->assertNotEmpty($this->_model->getSessionIdForHost('test'));
+            $this->_model->destroy();
+        }
+
+        public function testIsValidForHost()
+        {
+            $_SERVER['HTTP_HOST'] = 'localhost';
+            $this->_model->start();
+
+            $reflection = new \ReflectionMethod($this->_model, '_addHost');
+            $reflection->setAccessible(true);
+            $reflection->invoke($this->_model);
+
+            $this->assertFalse($this->_model->isValidForHost('test.com'));
+            $this->assertTrue($this->_model->isValidForHost('localhost'));
+            $this->_model->destroy();
+        }
+
+
+        /**
+         * @expectedException \Magento\Framework\Exception\SessionException
+         * @expectedExceptionMessage Area code not set: Area code must be set before starting a session.
+         */
+        public function testStartAreaNotSet()
+        {
+            $scope = $this->objectManager->get('Magento\Framework\Config\ScopeInterface');
+            $appState = new \Magento\Framework\App\State($scope);
+
+            /**
+             * Must be created by "new" in order to get a real Magento\Framework\App\State object that
+             * is not overridden in the TestFramework
+             *
+             * @var \Magento\Framework\Session\SessionManager _model
+             */
+            $this->_model = new \Magento\Framework\Session\SessionManager(
+                $this->objectManager->get('Magento\Framework\App\Request\Http'),
+                $this->_sidResolver,
+                $this->objectManager->get('Magento\Framework\Session\Config\ConfigInterface'),
+                $this->objectManager->get('Magento\Framework\Session\SaveHandlerInterface'),
+                $this->objectManager->get('Magento\Framework\Session\ValidatorInterface'),
+                $this->objectManager->get('Magento\Framework\Session\StorageInterface'),
+                $this->objectManager->get('Magento\Framework\Stdlib\CookieManagerInterface'),
+                $this->objectManager->get('Magento\Framework\Stdlib\Cookie\CookieMetadataFactory'),
+                $appState
+            );
+
+            global $mockPHPFunctions;
+            $mockPHPFunctions = true;
+            $this->_model->start();
+        }
     }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Framework/View/Asset/MinifierTest.php b/dev/tests/integration/testsuite/Magento/Framework/View/Asset/MinifierTest.php
index da5a86c47a1496652cf53df739c93389f1c1e58c..9e64e9345c6fa2d84885c4ec01e469ed1df7277c 100644
--- a/dev/tests/integration/testsuite/Magento/Framework/View/Asset/MinifierTest.php
+++ b/dev/tests/integration/testsuite/Magento/Framework/View/Asset/MinifierTest.php
@@ -208,9 +208,8 @@ class MinifierTest extends \PHPUnit_Framework_TestCase
             ->method('create')
             ->will($this->returnValue($this->objectManager));
 
-        $logger = $this->objectManager->create(
-            'Magento\Tools\View\Deployer\Log',
-            ['verbosity' => \Magento\Tools\View\Deployer\Log::SILENT]
+        $output = $this->objectManager->create(
+            'Symfony\Component\Console\Output\ConsoleOutput'
         );
 
         $filesUtil = $this->getMock('\Magento\Framework\App\Utility\Files', [], [], '', false);
@@ -230,10 +229,10 @@ class MinifierTest extends \PHPUnit_Framework_TestCase
                 ]
             ));
 
-        /** @var \Magento\Tools\View\Deployer $deployer */
+        /** @var \Magento\Setup\ModelDeployer $deployer */
         $deployer = $this->objectManager->create(
-            'Magento\Tools\View\Deployer',
-            ['filesUtil' => $filesUtil, 'logger' => $logger, 'isDryRun' => false]
+            'Magento\Setup\Model\Deployer',
+            ['filesUtil' => $filesUtil, 'output' => $output, 'isDryRun' => false]
         );
 
         $deployer->deploy($omFactory, ['en_US']);
diff --git a/dev/tests/integration/testsuite/Magento/Indexer/Model/ShellTest.php b/dev/tests/integration/testsuite/Magento/Indexer/Model/ShellTest.php
deleted file mode 100644
index 9d2a1e7d0e183992397f5fa7dba6d1354dc6b1de..0000000000000000000000000000000000000000
--- a/dev/tests/integration/testsuite/Magento/Indexer/Model/ShellTest.php
+++ /dev/null
@@ -1,97 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Indexer\Model;
-
-class ShellTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * Returns prepared model
-     *
-     * @param string $entryPoint
-     * @return \Magento\Indexer\Model\Shell
-     */
-    protected function getModel($entryPoint = 'fake.php')
-    {
-        return \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Indexer\Model\Shell',
-            ['entryPoint' => $entryPoint]
-        );
-    }
-
-    /**
-     * Returns result of running model - can be real model or mocked one
-     *
-     * @param \Magento\Indexer\Model\Shell $model Can be mock
-     * @return string
-     */
-    protected function runModel($model)
-    {
-        ob_start();
-        $model->run();
-        $result = ob_get_contents();
-        ob_end_clean();
-        return $result;
-    }
-
-    public function testGetUsageHelp()
-    {
-        $model = $this->getModel('testme.php');
-        $this->assertContains('testme.php', $model->getUsageHelp());
-    }
-
-    public function testRunWithoutParams()
-    {
-        $model = $this->getModel('testme.php');
-        $result = $this->runModel($model);
-        $this->assertContains('testme.php', $result);
-        $this->assertContains('index', $result); // Something about indexes
-    }
-
-    public function testRunIndexList()
-    {
-        $model = $this->getModel('testme.php');
-        $model->setRawArgs(['testme.php', '--', 'status']);
-        $result = $this->runModel($model);
-
-        $this->assertNotContains('testme.php', $result);
-        $this->assertNotContains('Usage:', $result);
-
-        /** @var \Magento\Indexer\Model\Indexer\Collection $indexerCollection */
-        $indexerCollection = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
-            'Magento\Indexer\Model\Indexer\Collection'
-        );
-        foreach ($indexerCollection->getItems() as $indexer) {
-            /** @var \Magento\Indexer\Model\IndexerInterface $indexer */
-            $this->assertContains((string)$indexer->getTitle(), $result);
-        }
-    }
-
-    /**
-     * @param string $param
-     * @param bool $expectedHasErrors
-     *
-     * @dataProvider hasErrorsDataProvider
-     */
-    public function testHasErrors($param, $expectedHasErrors)
-    {
-        $model = $this->getModel('testme.php');
-        $model->setRawArgs(['testme.php', '--', $param]);
-        $this->runModel($model);
-
-        $this->assertEquals($expectedHasErrors, $model->hasErrors());
-    }
-
-    /**
-     * @return array
-     */
-    public function hasErrorsDataProvider()
-    {
-        return [
-            'execution without issues' => ['info', false],
-            'issue with wrong index' => ['--reindex=wrong_index_code', true]
-        ];
-    }
-}
diff --git a/dev/tests/integration/testsuite/Magento/Log/Model/ShellTest.php b/dev/tests/integration/testsuite/Magento/Log/Model/ShellTest.php
deleted file mode 100644
index 8e9159d002ec0b048fd8304cfa462518b36bc75b..0000000000000000000000000000000000000000
--- a/dev/tests/integration/testsuite/Magento/Log/Model/ShellTest.php
+++ /dev/null
@@ -1,65 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Log\Model;
-
-class ShellTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * Returns prepared model
-     *
-     * @param string $entryPoint
-     * @return \Magento\Log\Model\Shell
-     */
-    protected function _getModel($entryPoint = 'fake.php')
-    {
-        return \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-            'Magento\Log\Model\Shell',
-            ['entryPoint' => $entryPoint]
-        );
-    }
-
-    /**
-     * Returns result of running model - can be real model or mocked one
-     *
-     * @param \Magento\Log\Model\Shell $model Can be mock
-     * @return string
-     */
-    protected function _run($model)
-    {
-        ob_start();
-        $model->run();
-        $result = ob_get_contents();
-        ob_end_clean();
-        return $result;
-    }
-
-    public function testGetUsageHelp()
-    {
-        $model = $this->_getModel('testme.php');
-        $this->assertContains('testme.php', $model->getUsageHelp());
-    }
-
-    public function testRunWithoutParams()
-    {
-        $model = $this->_getModel('testme.php');
-        $result = $this->_run($model);
-        $this->assertContains('testme.php', $result);
-        $this->assertContains('log', $result); // Something about logs
-    }
-
-    public function testRunLogStatus()
-    {
-        $model = $this->_getModel('testme.php');
-        $model->setRawArgs(['testme.php', 'status']);
-        $result = $this->_run($model);
-
-        $this->assertNotContains('testme.php', $result);
-        $this->assertNotContains('Usage:', $result);
-        $this->assertContains('Table', $result);
-        $this->assertContains('Total', $result);
-        $this->assertContains('Rows', $result);
-    }
-}
diff --git a/dev/tests/integration/testsuite/Magento/Payment/Block/Transparent/IframeTest.php b/dev/tests/integration/testsuite/Magento/Payment/Block/Transparent/IframeTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c91ead38e49e959564d03b2f90785d4f5e710bdb
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Payment/Block/Transparent/IframeTest.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Payment\Block\Transparent;
+
+class IframeTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @magentoAppIsolation enabled
+     * @magentoAppArea frontend
+     */
+    public function testToHtml()
+    {
+        $xssString = '</script><script>alert("XSS")</script>';
+
+        /** @var $block Iframe */
+        $block = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
+            'Magento\Framework\View\LayoutInterface'
+        )->createBlock(
+            'Magento\Payment\Block\Transparent\Iframe'
+        );
+
+        $block->setTemplate('transparent/iframe.phtml');
+        $block->setData(
+            'params',
+            [
+                'redirect' => $xssString,
+                'redirect_parent' => $xssString,
+                'error_msg' => $xssString
+            ]
+        );
+
+        $content = $block->toHtml();
+
+        $this->assertNotContains($xssString, $content, 'Params mast be escaped');
+        $this->assertContains(htmlspecialchars($xssString), $content, 'Content must present');
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Payment/Model/ObserverTest.php b/dev/tests/integration/testsuite/Magento/Payment/Model/ObserverTest.php
index 14f306766a10720ac021fc9ce9b94ecff8ee08cd..f83337a307eb201a8d5fd2fc8ef9dc8d6005880a 100644
--- a/dev/tests/integration/testsuite/Magento/Payment/Model/ObserverTest.php
+++ b/dev/tests/integration/testsuite/Magento/Payment/Model/ObserverTest.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Payment\Model;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 /**
  * @magentoAppArea adminhtml
  */
@@ -68,7 +70,7 @@ class ObserverTest extends \PHPUnit_Framework_TestCase
         $config->saveConfig(
             'payment/checkmo/order_status',
             $statusCode,
-            \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT,
+            ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
             0
         );
 
diff --git a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php
index 1313db5e278a098d9687b95ed80501862295b0ec..0a35f0488948b5d142693ee2a423f600eab01e7b 100644
--- a/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php
+++ b/dev/tests/integration/testsuite/Magento/Sales/Controller/Adminhtml/Order/CreateTest.php
@@ -7,6 +7,7 @@ namespace Magento\Sales\Controller\Adminhtml\Order;
 
 /**
  * @magentoAppArea adminhtml
+ * @magentoDbIsolation enabled
  */
 class CreateTest extends \Magento\Backend\Utility\Controller
 {
diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/I18nCollectPhrasesCommandTest.php b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/I18nCollectPhrasesCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..924853df6bc0c75cb219ec88afb42317c33d4f1d
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/I18nCollectPhrasesCommandTest.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Console\Command;
+
+use Symfony\Component\Console\Tester\CommandTester;
+
+class I18nCollectPhrasesCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var I18nCollectPhrasesCommand
+     */
+    private $command;
+
+    /**
+     * @var CommandTester
+     */
+    private $tester;
+
+    public function setUp()
+    {
+        $this->command = new I18nCollectPhrasesCommand();
+        $this->tester = new CommandTester($this->command);
+    }
+
+    public function tearDown()
+    {
+        $property = new \ReflectionProperty('\Magento\Setup\Module\I18n\ServiceLocator', '_dictionaryGenerator');
+        $property->setAccessible(true);
+        $property->setValue(null);
+        $property->setAccessible(false);
+    }
+
+    public function testExecuteConsoleOutput()
+    {
+        $this->tester->execute(
+            [
+                'directory' => BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/',
+            ]
+        );
+
+        $this->assertEquals('Dictionary successfully processed.' . PHP_EOL, $this->tester->getDisplay());
+    }
+
+    public function testExecuteCsvOutput()
+    {
+        $outputPath = BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/output/output.csv';
+        $this->tester->execute(
+            [
+                'directory' => BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/',
+                '--output' => $outputPath,
+            ]
+        );
+
+        $handle = fopen($outputPath, 'r');
+        $output = fread($handle, filesize($outputPath));
+        $expected = '"Hello world","Hello world"' . PHP_EOL . '"Foo bar","Foo bar"' . PHP_EOL;
+        $this->assertEquals($expected, $output);
+        unlink($outputPath);
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage Specified path doesn't exist
+     */
+    public function testExecuteNonExistingPath()
+    {
+        $this->tester->execute(
+            [
+                'directory' => BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/non_exist',
+            ]
+        );
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/I18nPackCommandTest.php b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/I18nPackCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0185b06a5376b5b20884e28a241ca9d5a76854f4
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/I18nPackCommandTest.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Console\Command;
+
+use Symfony\Component\Console\Tester\CommandTester;
+
+class I18nPackCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var I18nCollectPhrasesCommand
+     */
+    private $command;
+
+    /**
+     * @var CommandTester
+     */
+    private $tester;
+
+    public function setUp()
+    {
+        $this->command = new I18nPackCommand();
+        $this->tester = new CommandTester($this->command);
+    }
+
+    public function testExecute()
+    {
+        $this->tester->execute(
+            [
+                'source' => BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/i18n.csv',
+                'pack' => BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/output/pack',
+                'locale' => 'de_DE',
+                '--allow-duplicates' => true,
+            ]
+        );
+
+        $this->assertEquals('Successfully saved de_DE language package.' . PHP_EOL, $this->tester->getDisplay());
+        $basePath = BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/output/pack/app/code';
+        $this->assertFileExists($basePath . '/Magento/A/i18n/de_DE.csv');
+        $this->assertFileExists($basePath . '/Magento/B/i18n/de_DE.csv');
+        $this->assertFileExists($basePath . '/Magento/C/i18n/de_DE.csv');
+        $this->assertFileExists($basePath . '/Magento/D/i18n/de_DE.csv');
+        unlink($basePath . '/Magento/A/i18n/de_DE.csv');
+        unlink($basePath . '/Magento/B/i18n/de_DE.csv');
+        unlink($basePath . '/Magento/C/i18n/de_DE.csv');
+        unlink($basePath . '/Magento/D/i18n/de_DE.csv');
+        $this->recursiveRmdir(BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/output/pack');
+
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage Cannot open dictionary file:
+     */
+    public function testExecuteNonExistingPath()
+    {
+        $nonExistPath = BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/non_exist.csv';
+        $this->tester->execute(
+            [
+                'source' => $nonExistPath,
+                'pack' => BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/output/pack',
+                'locale' => 'de_DE',
+                '--allow-duplicates' => true,
+            ]
+        );
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage Possible values for 'mode' option are 'replace' and 'merge'
+     */
+    public function testExecuteInvalidMode()
+    {
+        $this->tester->execute(
+            [
+                'source' => BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/i18n.csv',
+                'pack' => BP . '/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/output/pack',
+                'locale' => 'de_DE',
+                '--allow-duplicates' => true,
+                '--mode' => 'invalid'
+            ]
+        );
+    }
+
+    /**
+     * Removes directories recursively
+     *
+     * @param string $dir
+     * @return void
+     */
+    private function recursiveRmdir($dir)
+    {
+        if (is_dir($dir)) {
+            $subdirs = scandir($dir);
+            foreach ($subdirs as $subdir) {
+                if ($subdir !== '.' && $subdir !== '..' && filetype($dir . '/' . $subdir) === 'dir') {
+                    $this->recursiveRmdir($dir . '/' . $subdir);
+                }
+            }
+            rmdir($dir);
+        }
+    }
+}
diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/Magento/TestModule/Phrases.php b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/Magento/TestModule/Phrases.php
new file mode 100644
index 0000000000000000000000000000000000000000..d55885ff96f2b8da7acce4f97c505fa2a6b8aa76
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/Magento/TestModule/Phrases.php
@@ -0,0 +1,7 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+$a = __("Hello world");
+$b = __("Foo bar");
diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/i18n.csv b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/i18n.csv
new file mode 100644
index 0000000000000000000000000000000000000000..534d54c7c26bb98887ec60d9fbd122864b821c75
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/i18n.csv
@@ -0,0 +1,9 @@
+"Read Details","Read Details",module,Magento_A
+"Mark as Read","Mark as Read",module,Magento_A
+"Are you sure?","Are you sure?",module,"Magento_A,Magento_B,Magento_C"
+"Messages Inbox","Messages Inbox",module,Magento_D
+"You have %1 new system messages","You have %1 new system messages",module,Magento_A
+"You have %1 new system message","You have %1 new system message",module,Magento_B
+"Incoming Message","Incoming Message",module,Magento_C
+close,close,module,"Magento_B,Magento_C"
+"Read details","Read details",module,Magento_D
diff --git a/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/output/.gitignore b/dev/tests/integration/testsuite/Magento/Setup/Console/Command/_files/output/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/GeneratorTest.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/GeneratorTest.php
similarity index 78%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/GeneratorTest.php
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/GeneratorTest.php
index 04048be30c063d6d06759d5133c2fdf5492158a9..7f879a81daeffc30fad8346e7ad980789d1bb5bb 100644
--- a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/GeneratorTest.php
+++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/GeneratorTest.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Test\Tools\I18n\Dictionary;
+namespace Magento\Setup\Module\I18n\Dictionary;
 
-use Magento\Tools\I18n\ServiceLocator;
+use Magento\Setup\Module\I18n\ServiceLocator;
 
 class GeneratorTest extends \PHPUnit_Framework_TestCase
 {
@@ -30,7 +30,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
     protected $outputFileName;
 
     /**
-     * @var \Magento\Tools\I18n\Dictionary\Generator
+     * @var \Magento\Setup\Module\I18n\Dictionary\Generator
      */
     protected $generator;
 
@@ -41,6 +41,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
         $this->source = $this->testDir . '/source';
         $this->outputFileName = $this->testDir . '/translate.csv';
         $this->generator = ServiceLocator::getDictionaryGenerator();
+
     }
 
     protected function tearDown()
@@ -48,6 +49,10 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
         if (file_exists($this->outputFileName)) {
             unlink($this->outputFileName);
         }
+        $property = new \ReflectionProperty('Magento\Setup\Module\I18n\ServiceLocator', '_dictionaryGenerator');
+        $property->setAccessible(true);
+        $property->setValue(null);
+        $property->setAccessible(false);
     }
 
     public function testGenerationWithoutContext()
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/expected/with_context.csv b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/expected/with_context.csv
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/expected/with_context.csv
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/expected/with_context.csv
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/expected/without_context.csv b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/expected/without_context.csv
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/expected/without_context.csv
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/expected/without_context.csv
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Helper/Helper.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Helper/Helper.php
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Helper/Helper.php
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Helper/Helper.php
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Model/Model.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Model/Model.php
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Model/Model.php
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Model/Model.php
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/default.xml b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/default.xml
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/default.xml
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/default.xml
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/file.js b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/file.js
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/file.js
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/file.js
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/template.phtml b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/template.phtml
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/template.phtml
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/view/frontend/template.phtml
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/SecondModule/Model/Model.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/SecondModule/Model/Model.php
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/SecondModule/Model/Model.php
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/SecondModule/Model/Model.php
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/default.xml b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/default.xml
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/default.xml
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/default.xml
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/template.phtml b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/template.phtml
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/template.phtml
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/design/adminhtml/default/backend/template.phtml
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/lib/web/mage/file.js b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/mage/file.js
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/lib/web/mage/file.js
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/mage/file.js
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/lib/web/varien/file.js b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/varien/file.js
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/lib/web/varien/file.js
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/lib/web/varien/file.js
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/not_magento_dir/Model.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/Model.php
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/not_magento_dir/Model.php
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/Model.php
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/not_magento_dir/file.js b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/file.js
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/not_magento_dir/file.js
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/file.js
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/not_magento_dir/template.phtml b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/template.phtml
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/not_magento_dir/template.phtml
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/template.phtml
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/GeneratorTest.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/GeneratorTest.php
similarity index 92%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/GeneratorTest.php
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/GeneratorTest.php
index c38ce4760b52d31646ff7d8aa762ba0f5b1ee7ec..ff28ebe4eda12bc1a7555365424326188eefff0e 100644
--- a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/GeneratorTest.php
+++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/GeneratorTest.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Test\Tools\I18n\Pack;
+namespace Magento\Setup\Module\I18n\Pack;
 
-use Magento\Tools\I18n\ServiceLocator;
+use Magento\Setup\Module\I18n\ServiceLocator;
 
 class GeneratorTest extends \PHPUnit_Framework_TestCase
 {
@@ -40,7 +40,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
     protected $_expectedFiles;
 
     /**
-     * @var \Magento\Tools\I18n\Pack\Generator
+     * @var \Magento\Setup\Module\I18n\Pack\Generator
      */
     protected $_generator;
 
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/_files/expected/app/code/Magento/FirstModule/i18n/de_DE.csv b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/_files/expected/app/code/Magento/FirstModule/i18n/de_DE.csv
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/_files/expected/app/code/Magento/FirstModule/i18n/de_DE.csv
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/_files/expected/app/code/Magento/FirstModule/i18n/de_DE.csv
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/_files/expected/app/code/Magento/SecondModule/i18n/de_DE.csv b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/_files/expected/app/code/Magento/SecondModule/i18n/de_DE.csv
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/_files/expected/app/code/Magento/SecondModule/i18n/de_DE.csv
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/_files/expected/app/code/Magento/SecondModule/i18n/de_DE.csv
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/_files/expected/app/design/adminhtml/default/i18n/de_DE.csv b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/_files/expected/app/design/adminhtml/default/i18n/de_DE.csv
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/_files/expected/app/design/adminhtml/default/i18n/de_DE.csv
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/_files/expected/app/design/adminhtml/default/i18n/de_DE.csv
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/_files/expected/lib/web/i18n/de_DE.csv b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/_files/expected/lib/web/i18n/de_DE.csv
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/_files/expected/lib/web/i18n/de_DE.csv
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/_files/expected/lib/web/i18n/de_DE.csv
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/_files/source.csv b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/_files/source.csv
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Pack/_files/source.csv
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Pack/_files/source.csv
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php
similarity index 76%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php
index 7e0f91b9e91b53e38d5f4db838bd1ade388a43a5..eda3f0f515808a7c45245bf53d2d6fabce0dd596 100644
--- a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php
+++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php
@@ -3,14 +3,13 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Test\Tools\I18n\Parser\Adapter\Php\Tokenizer;
+namespace Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer;
 
 use Magento\Framework\ObjectManager;
 use Magento\TestFramework\Helper\Bootstrap;
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector;
 
 /**
- * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
+ * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
  */
 class PhraseCollectorTest extends \PHPUnit_Framework_TestCase
 {
@@ -28,12 +27,12 @@ class PhraseCollectorTest extends \PHPUnit_Framework_TestCase
     {
         $this->objectManager = Bootstrap::getObjectManager();
         $this->phraseCollector = $this->objectManager->create(
-            'Magento\\Tools\\I18n\\Parser\\Adapter\\Php\\Tokenizer\\PhraseCollector'
+            'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector'
         );
     }
 
     /**
-     * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector::parse
+     * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector::parse
      */
     public function testParse()
     {
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollectorTest.php b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollectorTest.php
similarity index 73%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollectorTest.php
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollectorTest.php
index 6d401f7ce7ee767f8875d0014d13c29f330a56c6..b2d0bd34d90250af7300e12a54325c985c886819 100644
--- a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollectorTest.php
+++ b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollectorTest.php
@@ -3,14 +3,13 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Test\Tools\I18n\Parser\Adapter\Php\Tokenizer\Translate;
+namespace Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Translate;
 
 use Magento\Framework\ObjectManager;
 use Magento\TestFramework\Helper\Bootstrap;
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector;
 
 /**
- * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector
+ * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector
  */
 class MethodCollectorTest extends \PHPUnit_Framework_TestCase
 {
@@ -28,12 +27,12 @@ class MethodCollectorTest extends \PHPUnit_Framework_TestCase
     {
         $this->objectManager = Bootstrap::getObjectManager();
         $this->methodCollector = $this->objectManager->create(
-            'Magento\\Tools\\I18n\\Parser\\Adapter\\Php\\Tokenizer\\Translate\\MethodCollector'
+            'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector'
         );
     }
 
     /**
-     * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector::parse
+     * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector::parse
      */
     public function testParse()
     {
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Parser/Adapter/Php/Tokenizer/_files/methodsCode.php.txt b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/_files/methodsCode.php.txt
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Parser/Adapter/Php/Tokenizer/_files/methodsCode.php.txt
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/_files/methodsCode.php.txt
diff --git a/dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Parser/Adapter/Php/Tokenizer/_files/objectsCode.php.txt b/dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/_files/objectsCode.php.txt
similarity index 100%
rename from dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Parser/Adapter/Php/Tokenizer/_files/objectsCode.php.txt
rename to dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/_files/objectsCode.php.txt
diff --git a/dev/tests/integration/testsuite/Magento/Tax/Block/Adminhtml/Rate/FormTest.php b/dev/tests/integration/testsuite/Magento/Tax/Block/Adminhtml/Rate/FormTest.php
deleted file mode 100644
index 0bc80a86389f29b09fc9d4b80b001347662d97f8..0000000000000000000000000000000000000000
--- a/dev/tests/integration/testsuite/Magento/Tax/Block/Adminhtml/Rate/FormTest.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Tax\Block\Adminhtml\Rate;
-
-use Magento\TestFramework\Helper\Bootstrap;
-
-class FormTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \Magento\Framework\ObjectManagerInterface
-     */
-    protected $_objectManager;
-
-    /** @var \Magento\Tax\Block\Adminhtml\Rate\Form */
-    protected $_block;
-
-    protected function setUp()
-    {
-        $this->_objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
-        $this->_block = $this->_objectManager->create(
-            'Magento\Tax\Block\Adminhtml\Rate\Form'
-        );
-    }
-
-    public function testGetRateCollection()
-    {
-        /** @var \Magento\Tax\Model\Resource\Calculation\Rate\Collection $collection */
-        $collection = Bootstrap::getObjectManager()->get('Magento\Tax\Model\Resource\Calculation\Rate\Collection');
-        $dbTaxRatesQty = $collection->count();
-        if (($dbTaxRatesQty == 0) || ($collection->getFirstItem()->getId() != 1)) {
-            $this->fail("Preconditions failed.");
-        }
-
-        $ratesCollection = $this->_block->getRateCollection();
-
-        $collectionTaxRatesQty = count($ratesCollection);
-        $this->assertEquals($dbTaxRatesQty, $collectionTaxRatesQty, 'Tax rates quantity is invalid.');
-        $taxRate = $ratesCollection[0];
-        $expectedTaxRateData = [
-            'tax_calculation_rate_id' => '1',
-            'code' => 'US-CA-*-Rate 1',
-            'tax_country_id' => 'US',
-            'tax_region_id' => '12',
-            'region_name' => 'CA',
-            'tax_postcode' => '*',
-            'rate' => '8.25',
-            'zip_is_range' => null,
-            'zip_from' => null,
-            'zip_to' => null,
-            'rate' => '8.25',
-        ];
-        $this->assertEquals($taxRate, $expectedTaxRateData, 'Tax rate data is invalid.');
-    }
-}
diff --git a/dev/tests/integration/testsuite/Magento/Tax/Controller/Adminhtml/RateTest.php b/dev/tests/integration/testsuite/Magento/Tax/Controller/Adminhtml/RateTest.php
index b6e6a11859231e98d4f303fcec041ff6f690ad38..ab5c6cd2ba0d57b05bd90e250dd4550a254010e1 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/Controller/Adminhtml/RateTest.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/Controller/Adminhtml/RateTest.php
@@ -44,6 +44,11 @@ class RateTest extends \Magento\Backend\Utility\Controller
         $this->assertEquals($expectedData['tax_postcode'], $rate->getTaxPostcode());
     }
 
+    /**
+     * Data provider for testAjaxSaveAction
+     *
+     * @return array
+     */
     public function ajaxSaveActionDataProvider()
     {
         $postData = ['rate' => '10', 'tax_country_id' => 'US', 'tax_region_id' => '1'];
@@ -193,4 +198,102 @@ class RateTest extends \Magento\Backend\Utility\Controller
             ]
         ];
     }
+
+    /**
+     * @dataProvider ajaxSaveActionDataProvider
+     * @magentoDbIsolation enabled
+     *
+     * @param array $rateClassData
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     */
+    public function testAjaxLoadAction($rateClassData)
+    {
+        /** @var \Magento\Tax\Api\Data\TaxRateInterfaceFactory $rateClassFactory */
+        $rateClassFactory = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
+            'Magento\Tax\Api\Data\TaxRateInterfaceFactory'
+        );
+
+        $rateClass = $rateClassFactory->create();
+        $rateClass->setRate($rateClassData['rate'])
+                  ->setTaxCountryId($rateClassData['tax_country_id'])
+                  ->setTaxRegionId($rateClassData['tax_region_id'])
+                  ->setCode($rateClassData['code'])
+                  ->setZipFrom($rateClassData['zip_from'])
+                  ->setZipIsRange($rateClassData['zip_is_range'])
+                  ->setZipFrom($rateClassData['zip_from'])
+                  ->setZipTo($rateClassData['zip_to'])
+                  ->setTaxPostcode($rateClassData['tax_postcode']);
+
+        $rateClass->save($rateClass);
+
+        $rateClassId=$rateClass->getTaxCalculationRateId();
+        /** @var $class \Magento\Tax\Model\Calculation\Rate */
+        $class = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+            ->create('Magento\Tax\Model\Calculation\Rate')
+            ->load($rateClassId, 'tax_calculation_rate_id');
+
+        $this->assertEquals($rateClassData['tax_country_id'], $class->getTaxCountryId());
+        $this->assertEquals($rateClassData['tax_region_id'], $class->getTaxRegionId());
+        $this->assertEquals($rateClassData['code'], $class->getCode());
+        $this->assertEquals($rateClassData['rate'], $class->getRate());
+        $this->assertEquals($rateClassData['zip_is_range']==1 ? 1 : 0, $class->getZipIsRange() ? 1 : 0);
+        if ($rateClassData['zip_is_range']=='1') {
+            $this->assertEquals($rateClassData['zip_from'], $class->getZipFrom());
+            $this->assertEquals($rateClassData['zip_to'], $class->getZipTo());
+        }
+
+        $postData = [ 'id' => $rateClassId ];
+        $this->getRequest()->setPostValue($postData);
+        $this->dispatch('backend/tax/rate/ajaxLoad');
+        $jsonBody = $this->getResponse()->getBody();
+
+        $result = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
+            'Magento\Framework\Json\Helper\Data'
+        )->jsonDecode(
+            $jsonBody
+        );
+
+        $this->assertTrue(is_array($result));
+        $this->assertArrayHasKey('success', $result);
+        $this->assertTrue($result['success'] == true);
+        $this->assertArrayHasKey('result', $result);
+        $this->assertTrue(is_array($result['result']));
+        $this->assertEquals($result['result']['tax_country_id'], $class->getTaxCountryId());
+        $this->assertEquals($result['result']['tax_region_id'], $class->getTaxRegionId());
+        $this->assertEquals($result['result']['tax_postcode'], $class->getTaxPostcode());
+        $this->assertEquals($result['result']['code'], $class->getCode());
+        $this->assertEquals($result['result']['rate'], $class->getRate());
+
+        $expectedZipIsRange=$result['result']['zip_is_range'] == 1  ? 1 : 0;
+        $this->assertEquals($expectedZipIsRange, $class->getZipIsRange() ? 1 : 0);
+        if ($expectedZipIsRange) {
+            $this->assertEquals($result['result']['zip_from'], $class->getZipFrom());
+            $this->assertEquals($result['result']['zip_to'], $class->getZipTo());
+        }
+    }
+
+    /**
+     * @magentoDbIsolation enabled
+     *
+     */
+    public function testAjaxNonLoadAction()
+    {
+        $postData = [ 'id' => 99999999 ];
+        $this->getRequest()->setPostValue($postData);
+        $this->dispatch('backend/tax/rate/ajaxLoad');
+        $jsonBody = $this->getResponse()->getBody();
+
+        $result = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
+            'Magento\Framework\Json\Helper\Data'
+        )->jsonDecode(
+            $jsonBody
+        );
+
+        $this->assertTrue(is_array($result));
+        $this->assertArrayHasKey('success', $result);
+        $this->assertTrue($result['success'] == false);
+        $this->assertTrue(!array_key_exists('result', $result));
+        $this->assertArrayHasKey('error_message', $result);
+        $this->assertTrue(strlen($result['error_message'])>0);
+    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/Calculation/RateRepositoryTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/Calculation/RateRepositoryTest.php
index 1e9c43ca7fd49621116be74791c4a180c2c4763d..2b0d311757846900c2a9b1f9ccffb29cd221d4c1 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/Model/Calculation/RateRepositoryTest.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/Model/Calculation/RateRepositoryTest.php
@@ -9,6 +9,7 @@ namespace Magento\Tax\Model\Calculation;
 use Magento\Framework\Exception\InputException;
 use Magento\Framework\Exception\NoSuchEntityException;
 use Magento\Tax\Api\Data\TaxRateInterface;
+use Magento\Tax\Model\Calculation\Rate;
 use Magento\Tax\Model\TaxRuleFixtureFactory;
 use Magento\TestFramework\Helper\Bootstrap;
 
@@ -566,14 +567,14 @@ class RateRepositoryTest extends \PHPUnit_Framework_TestCase
 
         return [
             'eq' => [
-                [$filterBuilder->setField(TaxRateInterface::KEY_REGION_ID)->setValue(42)->create()],
+                [$filterBuilder->setField(Rate::KEY_REGION_ID)->setValue(42)->create()],
                 null,
                 ['US - 42 - 7.5', 'US - 42 - 22'],
             ],
             'and' => [
                 [
-                    $filterBuilder->setField(TaxRateInterface::KEY_REGION_ID)->setValue(42)->create(),
-                    $filterBuilder->setField(TaxRateInterface::KEY_PERCENTAGE_RATE)->setValue(22.0)->create(),
+                    $filterBuilder->setField(Rate::KEY_REGION_ID)->setValue(42)->create(),
+                    $filterBuilder->setField(Rate::KEY_PERCENTAGE_RATE)->setValue(22.0)->create(),
                 ],
                 [],
                 ['US - 42 - 22'],
@@ -581,15 +582,14 @@ class RateRepositoryTest extends \PHPUnit_Framework_TestCase
             'or' => [
                 [],
                 [
-                    $filterBuilder->setField(TaxRateInterface::KEY_PERCENTAGE_RATE)->setValue(22.0)->create(),
-                    $filterBuilder->setField(TaxRateInterface::KEY_PERCENTAGE_RATE)->setValue(10.0)->create(),
+                    $filterBuilder->setField(Rate::KEY_PERCENTAGE_RATE)->setValue(22.0)->create(),
+                    $filterBuilder->setField(Rate::KEY_PERCENTAGE_RATE)->setValue(10.0)->create(),
                 ],
                 ['US - 42 - 22', 'US - 12 - 10'],
             ],
             'like' => [
                 [
-                    $filterBuilder->setField(TaxRateInterface::KEY_CODE)->setValue('%7.5')->setConditionType('like')
-                        ->create(),
+                    $filterBuilder->setField(Rate::KEY_CODE)->setValue('%7.5')->setConditionType('like')->create(),
                 ],
                 [],
                 ['US - 42 - 7.5', 'US - 12 - 7.5'],
diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SetupUtil.php b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SetupUtil.php
index 861079efbac7df145af34557037fa6b79bb886e0..331bfebab31ad4078259e912e982010cb44302e6 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SetupUtil.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/SetupUtil.php
@@ -8,6 +8,7 @@
 
 namespace Magento\Tax\Model\Sales\Total\Quote;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Tax\Model\Config;
 use Magento\Tax\Model\Calculation;
 
@@ -221,7 +222,7 @@ class SetupUtil
             $config->saveConfig(
                 $path,
                 $value,
-                \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT,
+                ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
                 0
             );
         }
diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php
index 0c3af306bdeaa8f70d4a0b9e3e0d4bda252693e1..4f8e5da64ba2d3f77397905e9a470127626a84a6 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/Model/TaxCalculationTest.php
@@ -5,8 +5,8 @@
  */
 namespace Magento\Tax\Model;
 
-use Magento\Framework\Model\AbstractExtensibleModel;
 use Magento\Tax\Api\Data\TaxClassKeyInterface;
+use Magento\Tax\Model\TaxClass\Key;
 use Magento\TestFramework\Helper\Bootstrap;
 
 /**
@@ -121,8 +121,8 @@ class TaxCalculationTest extends \PHPUnit_Framework_TestCase
             'quantity' => 2,
             'unit_price' => 10,
             'tax_class_key' => [
-                TaxClassKeyInterface::KEY_TYPE => TaxClassKeyInterface::TYPE_NAME,
-                TaxClassKeyInterface::KEY_VALUE => 'DefaultProductClass',
+                Key::KEY_TYPE => TaxClassKeyInterface::TYPE_NAME,
+                Key::KEY_VALUE => 'DefaultProductClass',
             ],
         ];
         $oneProductResults = [
@@ -649,8 +649,8 @@ class TaxCalculationTest extends \PHPUnit_Framework_TestCase
                     ],
                 ],
                 'customer_tax_class_key' => [
-                    TaxClassKeyInterface::KEY_TYPE => TaxClassKeyInterface::TYPE_NAME,
-                    TaxClassKeyInterface::KEY_VALUE => 'DefaultCustomerClass',
+                    Key::KEY_TYPE => TaxClassKeyInterface::TYPE_NAME,
+                    Key::KEY_VALUE => 'DefaultCustomerClass',
                 ],
             ],
             'expected_tax_details' => [
@@ -1064,8 +1064,8 @@ class TaxCalculationTest extends \PHPUnit_Framework_TestCase
             'quantity' => 9,
             'unit_price' => 0.33, // this is including the store tax of 10%. Pre tax is 0.3
             'tax_class_key' => [
-                TaxClassKeyInterface::KEY_TYPE => TaxClassKeyInterface::TYPE_NAME,
-                TaxClassKeyInterface::KEY_VALUE => 'HigherProductClass',
+                Key::KEY_TYPE => TaxClassKeyInterface::TYPE_NAME,
+                Key::KEY_VALUE => 'HigherProductClass',
             ],
             'tax_included' => true,
         ];
@@ -1817,8 +1817,8 @@ class TaxCalculationTest extends \PHPUnit_Framework_TestCase
                     && is_string($value)
                 ) {
                     $value = [
-                        TaxClassKeyInterface::KEY_TYPE => TaxClassKeyInterface::TYPE_ID,
-                        TaxClassKeyInterface::KEY_VALUE => $this->taxClassIds[$value],
+                        Key::KEY_TYPE => TaxClassKeyInterface::TYPE_ID,
+                        Key::KEY_VALUE => $this->taxClassIds[$value],
                     ];
                 }
             }
diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/TaxClass/ManagementTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/TaxClass/ManagementTest.php
index 606540aa09c90b91c3b41a2c6345447a247bfd38..853a42f225c85c999748b0763388cc58d48a83e9 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/Model/TaxClass/ManagementTest.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/Model/TaxClass/ManagementTest.php
@@ -8,6 +8,7 @@ namespace Magento\Tax\Model\TaxClass;
 use Magento\Tax\Api\Data\TaxClassInterfaceFactory;
 use Magento\Tax\Api\Data\TaxClassKeyInterface;
 use Magento\Tax\Api\TaxClassManagementInterface;
+use Magento\Tax\Model\TaxClass\Key;
 use Magento\TestFramework\Helper\Bootstrap;
 
 class ManagementTest extends \PHPUnit_Framework_TestCase
@@ -63,8 +64,8 @@ class ManagementTest extends \PHPUnit_Framework_TestCase
         $this->dataObjectHelper->populateWithArray(
             $taxClassKeyTypeId,
             [
-                TaxClassKeyInterface::KEY_TYPE => TaxClassKeyInterface::TYPE_ID,
-                TaxClassKeyInterface::KEY_VALUE => $taxClassId,
+                Key::KEY_TYPE => TaxClassKeyInterface::TYPE_ID,
+                Key::KEY_VALUE => $taxClassId,
             ],
             '\Magento\Tax\Api\Data\TaxClassKeyInterface'
         );
@@ -76,8 +77,8 @@ class ManagementTest extends \PHPUnit_Framework_TestCase
         $this->dataObjectHelper->populateWithArray(
             $taxClassKeyTypeName,
             [
-                TaxClassKeyInterface::KEY_TYPE => TaxClassKeyInterface::TYPE_NAME,
-                TaxClassKeyInterface::KEY_VALUE => $taxClassName,
+                Key::KEY_TYPE => TaxClassKeyInterface::TYPE_NAME,
+                Key::KEY_VALUE => $taxClassName,
             ],
             '\Magento\Tax\Api\Data\TaxClassKeyInterface'
         );
diff --git a/dev/tests/integration/testsuite/Magento/Test/Integrity/Magento/Payment/MethodsTest.php b/dev/tests/integration/testsuite/Magento/Test/Integrity/Magento/Payment/MethodsTest.php
index 56dfca42c97498e1a5a08510b766b7b925cfeb71..a0073fdd17b0ff1c859e85ec12dc0bc992c6f74c 100644
--- a/dev/tests/integration/testsuite/Magento/Test/Integrity/Magento/Payment/MethodsTest.php
+++ b/dev/tests/integration/testsuite/Magento/Test/Integrity/Magento/Payment/MethodsTest.php
@@ -60,7 +60,7 @@ class MethodsTest extends \PHPUnit_Framework_TestCase
             /** @var $block \Magento\Framework\View\Element\Template */
             $block = $blockFactory->createBlock($blockClass);
             $block->setArea('frontend');
-            $this->assertFileExists($block->getTemplateFile(), $message);
+            $this->assertFileExists((string)$block->getTemplateFile(), $message);
             if ($model->canUseInternal()) {
                 try {
                     \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
@@ -69,7 +69,7 @@ class MethodsTest extends \PHPUnit_Framework_TestCase
                         \Magento\Store\Model\Store::DEFAULT_STORE_ID
                     );
                     $block->setArea('adminhtml');
-                    $this->assertFileExists($block->getTemplateFile(), $message);
+                    $this->assertFileExists((string)$block->getTemplateFile(), $message);
                     \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get(
                         'Magento\Store\Model\StoreManagerInterface'
                     )->getStore()->setId(
diff --git a/dev/tests/performance/framework/Magento/TestFramework/Application.php b/dev/tests/performance/framework/Magento/TestFramework/Application.php
index d236858ef259a39473edec5fc8df71fdae81d41a..bd192386c9d747fbb5b154c615a70014c1e7ead6 100644
--- a/dev/tests/performance/framework/Magento/TestFramework/Application.php
+++ b/dev/tests/performance/framework/Magento/TestFramework/Application.php
@@ -118,7 +118,7 @@ class Application
     public function reindex()
     {
         $this->_shell->execute(
-            'php -f ' . $this->_config->getApplicationBaseDir() . '/dev/shell/indexer.php -- reindexall'
+            'php -f ' . $this->_config->getApplicationBaseDir() . '/bin/magento indexer:reindex --all'
         );
         return $this;
     }
diff --git a/dev/tests/performance/testsuite/fixtures/catalog_category_flat_enabled.php b/dev/tests/performance/testsuite/fixtures/catalog_category_flat_enabled.php
index 00cd8ce5cb1d148ff81ebcad4ad463fd1933df2f..056fe99b815516c7bb1b20181297a78013312268 100644
--- a/dev/tests/performance/testsuite/fixtures/catalog_category_flat_enabled.php
+++ b/dev/tests/performance/testsuite/fixtures/catalog_category_flat_enabled.php
@@ -3,6 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+use Magento\Framework\App\Config\ScopeConfigInterface;
 
 /** @var \Magento\TestFramework\Application $this */
 
@@ -13,7 +14,7 @@ $configData = $this->getObjectManager()->create('Magento\Framework\App\Config\Va
 $configData->setPath(
     'catalog/frontend/flat_catalog_category'
 )->setScope(
-    \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+    ScopeConfigInterface::SCOPE_TYPE_DEFAULT
 )->setScopeId(
     0
 )->setValue(
diff --git a/dev/tests/performance/testsuite/fixtures/catalog_product_flat_enabled.php b/dev/tests/performance/testsuite/fixtures/catalog_product_flat_enabled.php
index 2258e72023d4ad642e1e799134e8b32cbb94d1ab..e06ed0e26c053f2742d6a132f17b4a0f4b8558ce 100644
--- a/dev/tests/performance/testsuite/fixtures/catalog_product_flat_enabled.php
+++ b/dev/tests/performance/testsuite/fixtures/catalog_product_flat_enabled.php
@@ -3,6 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+use Magento\Framework\App\Config\ScopeConfigInterface;
 
 /** @var \Magento\TestFramework\Application $this */
 
@@ -13,7 +14,7 @@ $configData = $this->getObjectManager()->create('Magento\Framework\App\Config\Va
 $configData->setPath(
     'catalog/frontend/flat_catalog_product'
 )->setScope(
-    \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+    ScopeConfigInterface::SCOPE_TYPE_DEFAULT
 )->setScopeId(
     0
 )->setValue(
diff --git a/dev/tests/performance/testsuite/fixtures/shipping_flatrate_enabled.php b/dev/tests/performance/testsuite/fixtures/shipping_flatrate_enabled.php
index e0f50505c4adcf397a358a5d8d31e336bd00a3e6..15b445ce1f8b5ca75cf4b6eb1ae20a179bcfa356 100644
--- a/dev/tests/performance/testsuite/fixtures/shipping_flatrate_enabled.php
+++ b/dev/tests/performance/testsuite/fixtures/shipping_flatrate_enabled.php
@@ -3,6 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+use Magento\Framework\App\Config\ScopeConfigInterface;
 
 /** @var \Magento\TestFramework\Application $this */
 
@@ -13,7 +14,7 @@ $configData = $this->getObjectManager()->create('Magento\Framework\App\Config\Va
 $configData->setPath(
     'carriers/flatrate/active'
 )->setScope(
-    \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+    ScopeConfigInterface::SCOPE_TYPE_DEFAULT
 )->setScopeId(
     0
 )->setValue(
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/TranslationFilesTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/TranslationFilesTest.php
index c0d1f61f6b0ff1c2da92142b3345fea1b1af586c..e4e8b509da43cedb2925339ec0d57e16d40d3475 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/TranslationFilesTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/App/Language/TranslationFilesTest.php
@@ -13,7 +13,7 @@ class TranslationFilesTest extends TranslationFiles
     /**
      * Context
      *
-     * @var \Magento\Tools\I18n\Context
+     * @var \Magento\Setup\Module\I18n\Context
      */
     protected $context;
 
@@ -45,7 +45,7 @@ class TranslationFilesTest extends TranslationFiles
     {
         $parser = $this->prepareParser();
 
-        $optionResolverFactory = new \Magento\Tools\I18n\Dictionary\Options\ResolverFactory();
+        $optionResolverFactory = new \Magento\Setup\Module\I18n\Dictionary\Options\ResolverFactory();
         $optionResolver = $optionResolverFactory->create(
             \Magento\Framework\App\Utility\Files::init()->getPathToSource(),
             true
@@ -70,7 +70,7 @@ class TranslationFilesTest extends TranslationFiles
     }
 
     /**
-     * @param \Magento\Tools\I18n\Dictionary\Phrase $phrase
+     * @param \Magento\Setup\Module\I18n\Dictionary\Phrase $phrase
      * @param array $context
      * @return string
      */
@@ -78,41 +78,41 @@ class TranslationFilesTest extends TranslationFiles
     {
         $path = $this->getContext()->buildPathToLocaleDirectoryByContext($phrase->getContextType(), $context);
         return \Magento\Framework\App\Utility\Files::init()->getPathToSource() . '/'
-        . $path . \Magento\Tools\I18n\Locale::DEFAULT_SYSTEM_LOCALE
-        . '.' . \Magento\Tools\I18n\Pack\Writer\File\Csv::FILE_EXTENSION;
+        . $path . \Magento\Setup\Module\I18n\Locale::DEFAULT_SYSTEM_LOCALE
+        . '.' . \Magento\Setup\Module\I18n\Pack\Writer\File\Csv::FILE_EXTENSION;
     }
 
     /**
-     * @return \Magento\Tools\I18n\Context
+     * @return \Magento\Setup\Module\I18n\Context
      */
     protected function getContext()
     {
         if ($this->context === null) {
-            $this->context = new \Magento\Tools\I18n\Context();
+            $this->context = new \Magento\Setup\Module\I18n\Context();
         }
         return $this->context;
     }
 
     /**
-     * @return \Magento\Tools\I18n\Parser\Contextual
+     * @return \Magento\Setup\Module\I18n\Parser\Contextual
      */
     protected function prepareParser()
     {
-        $filesCollector = new \Magento\Tools\I18n\FilesCollector();
+        $filesCollector = new \Magento\Setup\Module\I18n\FilesCollector();
 
-        $phraseCollector = new \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector(
-            new \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer()
+        $phraseCollector = new \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector(
+            new \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer()
         );
         $adapters = [
-            'php' => new \Magento\Tools\I18n\Parser\Adapter\Php($phraseCollector),
-            'js' =>  new \Magento\Tools\I18n\Parser\Adapter\Js(),
-            'xml' => new \Magento\Tools\I18n\Parser\Adapter\Xml(),
+            'php' => new \Magento\Setup\Module\I18n\Parser\Adapter\Php($phraseCollector),
+            'js' =>  new \Magento\Setup\Module\I18n\Parser\Adapter\Js(),
+            'xml' => new \Magento\Setup\Module\I18n\Parser\Adapter\Xml(),
         ];
 
-        $parserContextual = new \Magento\Tools\I18n\Parser\Contextual(
+        $parserContextual = new \Magento\Setup\Module\I18n\Parser\Contextual(
             $filesCollector,
-            new \Magento\Tools\I18n\Factory(),
-            new \Magento\Tools\I18n\Context()
+            new \Magento\Setup\Module\I18n\Factory(),
+            new \Magento\Setup\Module\I18n\Context()
         );
         foreach ($adapters as $type => $adapter) {
             $parserContextual->addAdapter($type, $adapter);
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php
index 780e83022c4aa53c7d9bd05fcec9514cd5966448..23fcd366b3325a1789c9c05f5645ffdc91603ad1 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Di/CompilerTest.php
@@ -68,10 +68,18 @@ class CompilerTest extends \PHPUnit_Framework_TestCase
         $basePath = \Magento\Framework\App\Utility\Files::init()->getPathToSource();
         $basePath = str_replace('\\', '/', $basePath);
 
+
         $this->_tmpDir = realpath(__DIR__) . '/tmp';
         $this->_generationDir = $this->_tmpDir . '/generation';
+        if (!file_exists($this->_generationDir)) {
+            mkdir($this->_generationDir, 0777, true);
+        }
         $this->_compilationDir = $this->_tmpDir . '/di';
-        $this->_command = 'php ' . $basePath . '/dev/tools/Magento/Tools/Di/compiler.php --generation=%s --di=%s';
+        if (!file_exists($this->_compilationDir)) {
+            mkdir($this->_compilationDir, 0777, true);
+        }
+
+        $this->_command = 'php ' . $basePath . '/bin/magento setup:di:compile-multi-tenant --generation=%s --di=%s';
 
         $booleanUtils = new \Magento\Framework\Stdlib\BooleanUtils();
         $constInterpreter = new \Magento\Framework\Data\Argument\Interpreter\Constant();
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/AbstractTestCase.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/AbstractTestCase.php
index ec48f6e8a1a25e95939ed472fb4f27700cdd2a87..fdd1a38c2753d971e4bfa460f7943d413eb10cb0 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/AbstractTestCase.php
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/AbstractTestCase.php
@@ -9,7 +9,7 @@
  */
 namespace Magento\Test\Integrity\Phrase;
 
-use Magento\Tools\I18n\FilesCollector;
+use Magento\Setup\Module\I18n\FilesCollector;
 
 class AbstractTestCase extends \PHPUnit_Framework_TestCase
 {
@@ -27,7 +27,7 @@ class AbstractTestCase extends \PHPUnit_Framework_TestCase
      */
     protected function _getFiles()
     {
-        $filesCollector = new \Magento\Tools\I18n\FilesCollector();
+        $filesCollector = new \Magento\Setup\Module\I18n\FilesCollector();
 
         return $filesCollector->getFiles(
             [\Magento\Framework\App\Utility\Files::init()->getPathToSource()],
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/ArgumentsTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/ArgumentsTest.php
index 77b1c099f1cc4a7eef7f91c7d2081a1cd54766b0..514f39e7180c4dcec384f6cf3cc15bce62e1f466 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/ArgumentsTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/ArgumentsTest.php
@@ -10,12 +10,12 @@
  */
 namespace Magento\Test\Integrity\Phrase;
 
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer;
+use Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer;
 
 class ArgumentsTest extends \Magento\Test\Integrity\Phrase\AbstractTestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
+     * @var \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
      */
     protected $_phraseCollector;
 
@@ -29,8 +29,8 @@ class ArgumentsTest extends \Magento\Test\Integrity\Phrase\AbstractTestCase
 
     protected function setUp()
     {
-        $this->_phraseCollector = new \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector(
-            new \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer()
+        $this->_phraseCollector = new \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector(
+            new \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer()
         );
 
         $rootDir = \Magento\Framework\App\Utility\Files::init()->getPathToSource();
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/Legacy/SignatureTest.php b/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/Legacy/SignatureTest.php
index 0cec004de647fc17f31e8d8c402fc110069a271d..ba905c42fe0cdf739e1d402165dff0c137228ae1 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/Legacy/SignatureTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Phrase/Legacy/SignatureTest.php
@@ -9,20 +9,20 @@
  */
 namespace Magento\Test\Integrity\Phrase\Legacy;
 
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer;
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector;
+use Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer;
+use Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector;
 
 class SignatureTest extends \Magento\Test\Integrity\Phrase\AbstractTestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector
+     * @var \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector
      */
     protected $_phraseCollector;
 
     protected function setUp()
     {
-        $this->_phraseCollector = new \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector(
-            new \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer()
+        $this->_phraseCollector = new MethodCollector(
+            new Tokenizer()
         );
     }
 
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/Readme/_files/blacklist/ce.txt b/dev/tests/static/testsuite/Magento/Test/Integrity/Readme/_files/blacklist/ce.txt
index 2fd6ad123621cb9b830d5d02b3840463d4520fbc..564d756255d7e6b7be5db625ccf8ebb0e634a026 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/Readme/_files/blacklist/ce.txt
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/Readme/_files/blacklist/ce.txt
@@ -35,5 +35,6 @@ lib/internal/Magento/Framework/System
 lib/internal/Magento/Framework/Test
 lib/internal/Magento/Framework/App/Utility
 lib/internal/Magento/Framework/Url
+lib/internal/Magento/Framework/UrlInterface
 lib/internal/Magento/Framework/Xml
 lib/internal/Magento/Framework
diff --git a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/namespace.txt b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/namespace.txt
index 1c00c272708bd0ec91a8cdd3b6f4ff1df4637715..f15f6f424a7c8311ffc4ca22503c61e32ee7efb5 100644
--- a/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/namespace.txt
+++ b/dev/tests/static/testsuite/Magento/Test/Integrity/_files/blacklist/namespace.txt
@@ -1,7 +1,3 @@
-dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/Model/Test.php
-dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/Helper/Test.php
-dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/Element.php
-dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/ElementFactory.php
 lib/internal/Magento/Framework/Code/Test/Unit/_files/app/code/Magento/SomeModule/Model/Proxy.php
 lib/internal/Magento/Framework/Code/Test/Unit/_files/app/code/Magento/SomeModule/Model/ElementFactory.php
 lib/internal/Magento/Framework/Code/Test/Unit/_files/app/code/Magento/SomeModule/Model/One/Test.php
@@ -21,13 +17,13 @@ lib/internal/Magento/Framework/ObjectManager/Test/Unit/_files/Aggregate/Aggregat
 lib/internal/Magento/Framework/ObjectManager/Test/Unit/_files/Aggregate/Child.php
 lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/Sample.php
 lib/internal/Magento/Framework/Api/Test/Unit/Code/Generator/_files/ExtensibleSample.php
-dev/tools/Magento/Tools/I18n/Zend/Exception.php
-dev/tools/Magento/Tools/I18n/Zend/Console/Getopt/Exception.php
-dev/tools/Magento/Tools/I18n/Zend/Console/Getopt.php
-dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Model/Model.php
-dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/SecondModule/Model/Model.php
-dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/not_magento_dir/Model.php
-dev/tests/integration/testsuite/Magento/Test/Tools/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Helper/Helper.php
+setup/src/Magento/Setup/Module/I18n/Zend/Exception.php
+setup/src/Magento/Setup/Module/I18n/Zend/Console/Getopt/Exception.php
+setup/src/Magento/Setup/Module/I18n/Zend/Console/Getopt.php
+dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Model/Model.php
+dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/SecondModule/Model/Model.php
+dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/not_magento_dir/Model.php
+dev/tests/integration/testsuite/Magento/Setup/Module/I18n/Dictionary/_files/source/app/code/Magento/FirstModule/Helper/Helper.php
 dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeAddressInterface.php
 dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeExtensibleOneInterface.php
 dev/tests/integration/testsuite/Magento/Framework/Api/_files/Magento/Wonderland/Api/Data/FakeExtensibleTwoInterface.php
@@ -96,3 +92,7 @@ dev/tests/integration/testsuite/Magento/Test/Tools/Dependency/_files/code/Magent
 dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceFactory.php
 dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceInterceptor.php
 dev/tests/integration/testsuite/Magento/Framework/Code/_expected/SourceClassWithNamespaceProxy.php
+setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/Model/Test.php
+setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/Helper/Test.php
+setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/Element.php
+setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/ElementFactory.php
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/LayoutTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/LayoutTest.php
index ae89d5ddb32941c6dace4b041fe459153a34a6cb..28353e7f953138cfa0dd3d91b04c17f70062e07a 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/LayoutTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/LayoutTest.php
@@ -316,7 +316,6 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
             'setListOrders',
             'setMAPTemplate',
             'setMethodFormTemplate',
-            'setMethodInfo',
             'setMyClass',
             'setPageLayout',
             'setPageTitle',
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
index 57cd1b6a4c81734430ee2dca24c68aa4ff61b623..59cf16d245655b3613dbf2bcedbf296ef0ed4330 100755
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_classes.php
@@ -2875,7 +2875,7 @@ return [
     ['Magento\Tax\Service\V1\Data\TaxDetails\AppliedTaxRate', 'Magento\Tax\Api\Data\AppliedTaxRateInterface'],
     ['Magento\Tax\Service\V1\Data\TaxDetails\Item', 'Magento\Tax\Api\Data\TaxDetailsItemInterface'],
     ['Magento\Tax\Service\V1\OrderTaxServiceInterface', 'Magento\Tax\Api\OrderTaxManagementInterface'],
-    ['Magento\Tools\I18n\Code', 'Magento\Tools\I18n'],
+    ['Magento\Tools\I18n\Code', 'Magento\Setup\Module\I18n'],
     ['Magento\TestFramework\Utility\AggregateInvoker', 'Magento\Framework\App\Utility\AggregateInvoker'],
     ['Magento\TestFramework\Utility\Classes', 'Magento\Framework\App\Utility\Classes'],
     ['Magento\TestFramework\Utility\Files', 'Magento\Framework\App\Utility\Files'],
@@ -3161,4 +3161,177 @@ return [
     ['Magento\Framework\Exception\File\ValidatorException'],
     ['Magento\Framework\Filesystem\FilesystemException', 'Magento\Framework\Exception\FileSystemException'],
     ['Magento\Shipping\Exception'],
+    ['Magento\Log\Model\Shell'],
+    ['Magento\Log\App\Shell'],
+    ['Magento\Framework\App\Cache\ManagerApp'],
+    ['Magento\Log\Model\Shell\Command\Factory'],
+    ['Magento\Tools\Di\App\Compiler'],
+    ['Magento\Indexer\App\Shell'],
+    ['Magento\Indexer\Model\Shell'],
+    ['Magento\Tools\I18n\Context', 'Magento\Setup\Module\I18n\Context'],
+    ['Magento\Tools\I18n\Dictionary\Generator', 'Magento\Setup\Module\I18n\Dictionary\Generator'],
+    [
+        'Magento\Tools\I18n\Dictionary\Loader\File\AbstractFile',
+        'Magento\Setup\Module\I18n\Dictionary\Loader\File\AbstractFile'
+    ],
+    ['Magento\Tools\I18n\Dictionary\Loader\File\Csv', 'Magento\Setup\Module\I18n\Dictionary\Loader\File\Csv'],
+    ['Magento\Tools\I18n\Dictionary\Loader\FileInterface', 'Magento\Setup\Module\I18n\Dictionary\Loader\FileInterface'],
+    ['Magento\Tools\I18n\Dictionary\Options\Resolver', 'Magento\Setup\Module\I18n\Dictionary\Options\Resolver'],
+    [
+        'Magento\Tools\I18n\Dictionary\Options\ResolverFactory',
+        'Magento\Setup\Module\I18n\Dictionary\Options\ResolverFactory'
+    ],
+    [
+        'Magento\Tools\I18n\Dictionary\Options\ResolverInterface',
+        'Magento\Setup\Module\I18n\Dictionary\Options\ResolverInterface'
+    ],
+    ['Magento\Tools\I18n\Dictionary\Phrase', 'Magento\Setup\Module\I18n\Dictionary\Phrase'],
+    ['Magento\Tools\I18n\Dictionary\Writer\Csv\Stdo', 'Magento\Setup\Module\I18n\Dictionary\Writer\Csv\Stdo'],
+    ['Magento\Tools\I18n\Dictionary\Writer\Csv', 'Magento\Setup\Module\I18n\Dictionary\Writer\Csv'],
+    ['Magento\Tools\I18n\Dictionary\WriterInterface', 'Magento\Setup\Module\I18n\Dictionary\WriterInterface'],
+    ['Magento\Tools\I18n\Dictionary', 'Magento\Setup\Module\I18n\Dictionary'],
+    ['Magento\Tools\I18n\Factory', 'Magento\Setup\Module\I18n\Factory'],
+    ['Magento\Tools\I18n\FilesCollector', 'Magento\Setup\Module\I18n\FilesCollector'],
+    ['Magento\Tools\I18n\Locale', 'Magento\Setup\Module\I18n\Locale'],
+    ['Magento\Tools\I18n\Pack\Generator', 'Magento\Setup\Module\I18n\Pack\Generator'],
+    ['Magento\Tools\I18n\Pack\Writer\File\AbstractFile', 'Magento\Setup\Module\I18n\Pack\Writer\File\AbstractFile'],
+    ['Magento\Tools\I18n\Pack\Writer\File\Csv', 'Magento\Setup\Module\I18n\Pack\Writer\File\Csv'],
+    ['Magento\Tools\I18n\Pack\WriterInterface', 'Magento\Setup\Module\I18n\Pack\WriterInterface'],
+    ['Magento\Tools\I18n\Parser\AbstractParser', 'Magento\Setup\Module\I18n\Parser\AbstractParser'],
+    ['Magento\Tools\I18n\Parser\Adapter\AbstractAdapter', 'Magento\Setup\Module\I18n\Parser\Adapter\AbstractAdapter'],
+    ['Magento\Tools\I18n\Parser\Adapter\Js', 'Magento\Setup\Module\I18n\Parser\Adapter\Js'],
+    [
+        'Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector',
+        'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector'
+    ],
+    [
+        'Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token',
+        'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token'
+    ],
+    [
+        'Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Translate',
+        'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Translate'
+    ],
+    [
+        'Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector',
+        'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Translate\MethodCollector'
+    ],
+    ['Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer', 'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer'],
+    ['Magento\Tools\I18n\Parser\Adapter\Php', 'Magento\Setup\Module\I18n\Parser\Adapter\Php'],
+    ['Magento\Tools\I18n\Parser\Adapter\Xml', 'Magento\Setup\Module\I18n\Parser\Adapter\Xml'],
+    ['Magento\Tools\I18n\Parser\AdapterInterface', 'Magento\Setup\Module\I18n\Parser\AdapterInterface'],
+    ['Magento\Tools\I18n\Parser\Contextual', 'Magento\Setup\Module\I18n\Parser\Contextual'],
+    ['Magento\Tools\I18n\Parser\Parser', 'Magento\Setup\Module\I18n\Parser\Parser'],
+    ['Magento\Tools\I18n\ParserInterface', 'Magento\Setup\Module\I18n\ParserInterface'],
+    ['Magento\Tools\I18n\ServiceLocator', 'Magento\Setup\Module\I18n\ServiceLocator'],
+    ['Magento\Tools\Di\App\Task\Manager', 'Magento\Setup\Module\Di\App\Task\Manager'],
+    [
+        'Magento\Tools\Di\App\Task\Operation\ApplicationCodeGenerator',
+        'Magento\Setup\Module\Di\App\Task\Operation\ApplicationCodeGenerator'
+    ],
+    ['Magento\Tools\Di\App\Task\Operation\Area', 'Magento\Setup\Module\Di\App\Task\Operation\Area'],
+    ['Magento\Tools\Di\App\Task\Operation\Interception', 'Magento\Setup\Module\Di\App\Task\Operation\Interception'],
+    [
+        'Magento\Tools\Di\App\Task\Operation\InterceptionCache',
+        'Magento\Setup\Module\Di\App\Task\Operation\InterceptionCache'
+    ],
+    [
+        'Magento\Tools\Di\App\Task\Operation\RepositoryGenerator',
+        'Magento\Setup\Module\Di\App\Task\Operation\RepositoryGenerator'
+    ],
+    ['Magento\Tools\Di\App\Task\OperationException', 'Magento\Setup\Module\Di\App\Task\OperationException'],
+    ['Magento\Tools\Di\App\Task\OperationFactory', 'Magento\Setup\Module\Di\App\Task\OperationFactory'],
+    ['Magento\Tools\Di\App\Task\OperationInterface', 'Magento\Setup\Module\Di\App\Task\OperationInterface'],
+    [
+        'Magento\Tools\Di\Code\Generator\InterceptionConfigurationBuilder',
+        'Magento\Setup\Module\Di\Code\Generator\InterceptionConfigurationBuilder'
+    ],
+    ['Magento\Tools\Di\Code\Generator\Interceptor', 'Magento\Setup\Module\Di\Code\Generator\Interceptor'],
+    ['Magento\Tools\Di\Code\Generator\PluginList', 'Magento\Setup\Module\Di\Code\Generator\PluginList'],
+    ['Magento\Tools\Di\Code\Generator', 'Magento\Setup\Module\Di\Code\Generator'],
+    ['Magento\Tools\Di\Code\GeneratorFactory', 'Magento\Setup\Module\Di\Code\GeneratorFactory'],
+    ['Magento\Tools\Di\Code\Reader\ClassesScanner', 'Magento\Setup\Module\Di\Code\Reader\ClassesScanner'],
+    [
+        'Magento\Tools\Di\Code\Reader\ClassesScannerInterface',
+        'Magento\Setup\Module\Di\Code\Reader\ClassesScannerInterface'
+    ],
+    ['Magento\Tools\Di\Code\Reader\ClassReaderDecorator', 'Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator'],
+    ['Magento\Tools\Di\Code\Reader\Decorator\Area', 'Magento\Setup\Module\Di\Code\Reader\Decorator\Area'],
+    ['Magento\Tools\Di\Code\Reader\Decorator\Directory', 'Magento\Setup\Module\Di\Code\Reader\Decorator\Directory'],
+    [
+        'Magento\Tools\Di\Code\Reader\Decorator\Interceptions',
+        'Magento\Setup\Module\Di\Code\Reader\Decorator\Interceptions'
+    ],
+    ['Magento\Tools\Di\Code\Reader\Type', 'Magento\Setup\Module\Di\Code\Reader\Type'],
+    ['Magento\Tools\Di\Code\Scanner\ArrayScanner', 'Magento\Setup\Module\Di\Code\Scanner\ArrayScanner'],
+    ['Magento\Tools\Di\Code\Scanner\CompositeScanner', 'Magento\Setup\Module\Di\Code\Scanner\CompositeScanner'],
+    ['Magento\Tools\Di\Code\Scanner\DirectoryScanner', 'Magento\Setup\Module\Di\Code\Scanner\DirectoryScanner'],
+    [
+        'Magento\Tools\Di\Code\Scanner\InheritanceInterceptorScanner',
+        'Magento\Setup\Module\Di\Code\Scanner\InheritanceInterceptorScanner'
+    ],
+    [
+        'Magento\Tools\Di\Code\Scanner\InterceptedInstancesScanner',
+        'Magento\Setup\Module\Di\Code\Scanner\InterceptedInstancesScanner'
+    ],
+    ['Magento\Tools\Di\Code\Scanner\PhpScanner', 'Magento\Setup\Module\Di\Code\Scanner\PhpScanner'],
+    ['Magento\Tools\Di\Code\Scanner\PluginScanner', 'Magento\Setup\Module\Di\Code\Scanner\PluginScanner'],
+    ['Magento\Tools\Di\Code\Scanner\RepositoryScanner', 'Magento\Setup\Module\Di\Code\Scanner\RepositoryScanner'],
+    ['Magento\Tools\Di\Code\Scanner\ScannerInterface', 'Magento\Setup\Module\Di\Code\Scanner\ScannerInterface'],
+    [
+        'Magento\Tools\Di\Code\Scanner\XmlInterceptorScanner',
+        'Magento\Setup\Module\Di\Code\Scanner\XmlInterceptorScanner'
+    ],
+    ['Magento\Tools\Di\Code\Scanner\XmlScanner', 'Magento\Setup\Module\Di\Code\Scanner\XmlScanner'],
+    ['Magento\Tools\Di\Compiler\ArgumentsResolver', 'Magento\Setup\Module\Di\Compiler\ArgumentsResolver'],
+    ['Magento\Tools\Di\Compiler\ArgumentsResolverFactory', 'Magento\Setup\Module\Di\Compiler\ArgumentsResolverFactory'],
+    [
+        'Magento\Tools\Di\Compiler\Config\Chain\ArgumentsSerialization',
+        'Magento\Setup\Module\Di\Compiler\Config\Chain\ArgumentsSerialization'
+    ],
+    [
+        'Magento\Tools\Di\Compiler\Config\Chain\BackslashTrim',
+        'Magento\Setup\Module\Di\Compiler\Config\Chain\BackslashTrim'
+    ],
+    [
+        'Magento\Tools\Di\Compiler\Config\Chain\InterceptorSubstitution',
+        'Magento\Setup\Module\Di\Compiler\Config\Chain\InterceptorSubstitution'
+    ],
+    [
+        'Magento\Tools\Di\Compiler\Config\Chain\PreferencesResolving',
+        'Magento\Setup\Module\Di\Compiler\Config\Chain\PreferencesResolving'
+    ],
+    [
+        'Magento\Tools\Di\Compiler\Config\ModificationChain',
+        'Magento\Setup\Module\Di\Compiler\Config\ModificationChain'
+    ],
+    [
+        'Magento\Tools\Di\Compiler\Config\ModificationInterface',
+        'Magento\Setup\Module\Di\Compiler\Config\ModificationInterface'
+    ],
+    ['Magento\Tools\Di\Compiler\Config\Reader', 'Magento\Setup\Module\Di\Compiler\Config\Reader'],
+    ['Magento\Tools\Di\Compiler\Config\Writer\Filesystem', 'Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem'],
+    ['Magento\Tools\Di\Compiler\Config\WriterInterface', 'Magento\Setup\Module\Di\Compiler\Config\WriterInterface'],
+    ['Magento\Tools\Di\Compiler\ConstructorArgument', 'Magento\Setup\Module\Di\Compiler\ConstructorArgument'],
+    ['Magento\Tools\Di\Compiler\Log\Log', 'Magento\Setup\Module\Di\Compiler\Log\Log'],
+    ['Magento\Tools\Di\Compiler\Log\Writer\Console', 'Magento\Setup\Module\Di\Compiler\Log\Writer\Console'],
+    ['Magento\Tools\Di\Definition\Collection', 'Magento\Setup\Module\Di\Definition\Collection'],
+    ['Magento\Tools\Di\Definition\Compressor\UniqueList', 'Magento\Setup\Module\Di\Definition\Compressor\UniqueList'],
+    ['Magento\Tools\Di\Definition\Compressor', 'Magento\Setup\Module\Di\Definition\Compressor'],
+    ['Magento\Tools\Di\Definition\Serializer\Igbinary', 'Magento\Setup\Module\Di\Definition\Serializer\Igbinary'],
+    [
+        'Magento\Tools\Di\Definition\Serializer\SerializerInterface',
+        'Magento\Setup\Module\Di\Definition\Serializer\SerializerInterface'
+    ],
+    ['Magento\Tools\Di\Definition\Serializer\Standard', 'Magento\Setup\Module\Di\Definition\Serializer\Standard'],
+    ['Magento\Tools\Di\Compiler\Log\Writer\Quiet'],
+    ['Magento\Tools\Di\Compiler\Log\Writer\WriterInterface'],
+    ['Magento\Tools\View\Deployer', 'Magento\Setup\Model\Deployer'],
+    ['Magento\Tools\Webdev\CliParams'],
+    ['Magento\Tools\Webdev\App\FileAssembler'],
+    ['Magento\Tools\View\Deployer\Log'],
+    ['Magento\Log\Model\Shell\Command\Status'],
+    ['Magento\Log\Model\LogFactory\Clean'],
+    ['Magento\Log\Model\Shell\CommandInterface'],
+    ['Magento\Framework\App\Filesystem\DirectoryList\AbstractShell'],
 ];
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php
index a3fa40a7f43a6718bc2949067c23dd314b874c11..b0e6f2627029a8da911b3e6a4358c3aff4f133af 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/_files/obsolete_constants.php
@@ -702,4 +702,26 @@ return [
         'Use \Magento\Eav\Model\Entity\Type::getDefaultAttributeSetId() method instead',
     ],
     ['CONFIG_PATH_WSDL_CACHE_ENABLED', 'Magento\Webapi\Model\Soap\Server'],
+    ['ENTITY', 'Magento\Framework\App\Config\ValueInterface'],
+    ['XML_PATH_ALLOW_CURRENCIES_INSTALLED', 'Magento\Framework\Locale\CurrencyInterface'],
+    [
+        'DEFAULT_CURRENCY',
+        'Magento\Framework\Locale\CurrencyInterface',
+        'Magento\Framework\Locale\Currency::DEFAULT_CURRENCY'
+    ],
+    [
+        'DEFAULT_LOCALE',
+        'Magento\Framework\Locale\ResolverInterface',
+        'Magento\Framework\Locale\Resolver::DEFAULT_LOCALE'
+    ],
+    [
+        'DEFAULT_GROUP',
+        'Magento\Framework\Message\ManagerInterface',
+        'Magento\Framework\Message\Manager::DEFAULT_GROUP'
+    ],
+    [
+        'SCOPE_DEFAULT',
+        'Magento\Framework\App\ScopeInterface',
+        'Magento\Framework\App\Config\ScopeConfigInterface::SCOPE_TYPE_DEFAULT'
+    ]
 ];
diff --git a/dev/tools/Magento/Tools/Di/App/Compiler.php b/dev/tools/Magento/Tools/Di/App/Compiler.php
deleted file mode 100644
index 751eca2ac1c178fc5db662be4d3f5d26de48b35f..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Di/App/Compiler.php
+++ /dev/null
@@ -1,195 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Tools\Di\App;
-
-use Magento\Framework\App;
-use Magento\Framework\App\Console\Response;
-use Magento\Framework\ObjectManagerInterface;
-
-/**
- * Class Compiler
- * @package Magento\Tools\Di\App
- *
- */
-class Compiler implements \Magento\Framework\AppInterface
-{
-    /**
-     * @var ObjectManagerInterface
-     */
-    private $objectManager;
-
-    /**
-     * @var Task\Manager
-     */
-    private $taskManager;
-
-    /**
-     * @var Response
-     */
-    private $response;
-
-    /**
-     * @var array
-     */
-    private $compiledPathsList = [];
-
-    /**
-     * @var array
-     */
-    private $excludedPathsList = [];
-
-    /**
-     * @param Task\Manager $taskManager
-     * @param ObjectManagerInterface $objectManager
-     * @param Response $response
-     * @param array $compiledPathsList
-     * @param array $excludedPathsList
-     */
-    public function __construct(
-        Task\Manager $taskManager,
-        ObjectManagerInterface $objectManager,
-        Response $response,
-        $compiledPathsList = [],
-        $excludedPathsList = []
-    ) {
-        $this->taskManager = $taskManager;
-        $this->objectManager = $objectManager;
-        $this->response = $response;
-
-        if (empty($compiledPathsList)) {
-            $compiledPathsList = [
-                'application' => BP . '/'  . 'app/code',
-                'library' => BP . '/'  . 'lib/internal/Magento/Framework',
-                'generated_helpers' => BP . '/'  . 'var/generation'
-            ];
-        }
-        $this->compiledPathsList = $compiledPathsList;
-
-        if (empty($excludedPathsList)) {
-            $excludedPathsList = [
-                'application' => '#^' . BP . '/app/code/[\\w]+/[\\w]+/Test#',
-                'framework' => '#^' . BP . '/lib/internal/[\\w]+/[\\w]+/([\\w]+/)?Test#'
-            ];
-        }
-        $this->excludedPathsList = $excludedPathsList;
-    }
-
-    /**
-     * Launch application
-     *
-     * @return \Magento\Framework\App\ResponseInterface
-     */
-    public function launch()
-    {
-        $this->objectManager->configure(
-            [
-                'preferences' =>
-                [
-                    'Magento\Tools\Di\Compiler\Config\WriterInterface' =>
-                        'Magento\Tools\Di\Compiler\Config\Writer\Filesystem',
-                    'Magento\Tools\Di\Compiler\Log\Writer\WriterInterface' =>
-                        'Magento\Tools\Di\Compiler\Log\Writer\Console'
-                ],
-                'Magento\Tools\Di\Compiler\Config\ModificationChain' => [
-                    'arguments' => [
-                        'modificationsList' => [
-                            'BackslashTrim' =>
-                                ['instance' => 'Magento\Tools\Di\Compiler\Config\Chain\BackslashTrim'],
-                            'PreferencesResolving' =>
-                                ['instance' => 'Magento\Tools\Di\Compiler\Config\Chain\PreferencesResolving'],
-                            'InterceptorSubstitution' =>
-                                ['instance' => 'Magento\Tools\Di\Compiler\Config\Chain\InterceptorSubstitution'],
-                            'InterceptionPreferencesResolving' =>
-                                ['instance' => 'Magento\Tools\Di\Compiler\Config\Chain\PreferencesResolving'],
-                            'ArgumentsSerialization' =>
-                                ['instance' => 'Magento\Tools\Di\Compiler\Config\Chain\ArgumentsSerialization'],
-                        ]
-                    ]
-                ],
-                'Magento\Tools\Di\Code\Generator\PluginList' => [
-                    'arguments' => [
-                        'cache' => [
-                            'instance' => 'Magento\Framework\App\Interception\Cache\CompiledConfig'
-                        ]
-                    ]
-                ],
-                'Magento\Tools\Di\Code\Reader\ClassesScanner' => [
-                    'arguments' => [
-                        'excludePatterns' => $this->excludedPathsList
-                    ]
-                ]
-            ]
-        );
-
-        $operations = [
-            Task\OperationFactory::REPOSITORY_GENERATOR => [
-                'path' => $this->compiledPathsList['application'],
-                'filePatterns' => ['di' => '/\/etc\/([a-zA-Z_]*\/di|di)\.xml$/']
-            ],
-            Task\OperationFactory::APPLICATION_CODE_GENERATOR => [
-                $this->compiledPathsList['application'],
-                $this->compiledPathsList['library'],
-                $this->compiledPathsList['generated_helpers'],
-            ],
-            Task\OperationFactory::INTERCEPTION =>
-                [
-                    'intercepted_paths' => [
-                        $this->compiledPathsList['application'],
-                        $this->compiledPathsList['library'],
-                        $this->compiledPathsList['generated_helpers'],
-                    ],
-                    'path_to_store' => $this->compiledPathsList['generated_helpers'],
-                ],
-            Task\OperationFactory::AREA_CONFIG_GENERATOR => [
-                $this->compiledPathsList['application'],
-                $this->compiledPathsList['library'],
-                $this->compiledPathsList['generated_helpers'],
-            ],
-            Task\OperationFactory::INTERCEPTION_CACHE => [
-                $this->compiledPathsList['application'],
-                $this->compiledPathsList['library'],
-                $this->compiledPathsList['generated_helpers'],
-            ]
-        ];
-
-        $responseCode = Response::SUCCESS;
-        try {
-            foreach ($operations as $operationCode => $arguments) {
-                $this->taskManager->addOperation(
-                    $operationCode,
-                    $arguments
-                );
-            }
-            $this->taskManager->process();
-
-        } catch (Task\OperationException $e) {
-            $responseCode = Response::ERROR;
-            $this->response->setBody($e->getMessage());
-        }
-
-        $this->response->setCode($responseCode);
-        return $this->response;
-    }
-
-    /**
-     * Ability to handle exceptions that may have occurred during bootstrap and launch
-     *
-     * Return values:
-     * - true: exception has been handled, no additional action is needed
-     * - false: exception has not been handled - pass the control to Bootstrap
-     *
-     * @param App\Bootstrap $bootstrap
-     * @param \Exception $exception
-     * @return bool
-     *
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
-     */
-    public function catchException(App\Bootstrap $bootstrap, \Exception $exception)
-    {
-        return false;
-    }
-}
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Config/Writer/Filesystem.php b/dev/tools/Magento/Tools/Di/Compiler/Config/Writer/Filesystem.php
deleted file mode 100644
index b50d6a996c8b3913e8f834b6718f6b1e5d8ef9da..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Di/Compiler/Config/Writer/Filesystem.php
+++ /dev/null
@@ -1,40 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Tools\Di\Compiler\Config\Writer;
-
-use Magento\Tools\Di\Compiler\Config\WriterInterface;
-
-class Filesystem implements WriterInterface
-{
-    /**
-     * Writes config in storage
-     *
-     * @param string $key
-     * @param array $config
-     * @return void
-     */
-    public function write($key, array $config)
-    {
-        $this->initialize();
-
-        $serialized = serialize($config);
-        file_put_contents(BP . '/var/di/' . $key . '.ser', $serialized);
-    }
-
-    /**
-     * Initializes writer
-     *
-     * @return void
-     */
-    private function initialize()
-    {
-        if (!file_exists(BP . '/var/di')) {
-            mkdir(BP . '/var/di');
-        }
-    }
-}
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Log/Writer/Console.php b/dev/tools/Magento/Tools/Di/Compiler/Log/Writer/Console.php
deleted file mode 100644
index e38644559cd1921e3d24e794cd1167b7271a5c4d..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Di/Compiler/Log/Writer/Console.php
+++ /dev/null
@@ -1,57 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Tools\Di\Compiler\Log\Writer;
-
-use Magento\Tools\Di\Compiler\Log\Log;
-
-class Console implements WriterInterface
-{
-    /**
-     * Report messages by type
-     *
-     * @var array
-     */
-    protected $_messages = [
-        Log::GENERATION_SUCCESS => 'Generated classes:',
-        Log::GENERATION_ERROR => 'Errors during class generation:',
-        Log::COMPILATION_ERROR => 'Errors during compilation:',
-        Log::CONFIGURATION_ERROR => 'Errors during configuration scanning:',
-    ];
-
-    /**
-     * Output log data
-     *
-     * @param array $data
-     * @return void
-     */
-    public function write(array $data)
-    {
-        $errorsCount = 0;
-        foreach ($data as $type => $classes) {
-            if (!count($classes)) {
-                continue;
-            }
-            echo $this->_messages[$type] . "\n";
-            foreach ($classes as $className => $messages) {
-                if (count($messages)) {
-                    echo "\t" . $className . "\n";
-                    foreach ($messages as $message) {
-                        if ($message) {
-                            echo "\t\t - " . $message . "\n";
-                            if ($type != Log::GENERATION_SUCCESS) {
-                                $errorsCount++;
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        if ($errorsCount) {
-            echo 'Total Errors Count: ' . $errorsCount . "\n";
-        }
-    }
-}
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Log/Writer/Quiet.php b/dev/tools/Magento/Tools/Di/Compiler/Log/Writer/Quiet.php
deleted file mode 100644
index 3696fb51f34305a50afb368451a60d47e5c51c4a..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Di/Compiler/Log/Writer/Quiet.php
+++ /dev/null
@@ -1,20 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Tools\Di\Compiler\Log\Writer;
-
-class Quiet implements WriterInterface
-{
-    /**
-     * Output log data
-     *
-     * @param array $data
-     * @return void
-     */
-    public function write(array $data)
-    {
-        // Do nothing
-    }
-}
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Log/Writer/WriterInterface.php b/dev/tools/Magento/Tools/Di/Compiler/Log/Writer/WriterInterface.php
deleted file mode 100644
index b36f3172b6c549c41217e1cce55214f16d008b0f..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Di/Compiler/Log/Writer/WriterInterface.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Tools\Di\Compiler\Log\Writer;
-
-interface WriterInterface
-{
-    /**
-     * Output log data
-     *
-     * @param array $data
-     * @return void
-     */
-    public function write(array $data);
-}
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/App/CompilerTest.php b/dev/tools/Magento/Tools/Di/Test/Unit/App/CompilerTest.php
deleted file mode 100644
index 665e5c237a0cf58a4075b3daadcbfdd4e6118035..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Di/Test/Unit/App/CompilerTest.php
+++ /dev/null
@@ -1,180 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Tools\Di\Test\Unit\App;
-
-use Magento\Framework\App\Console\Response;
-use Magento\Tools\Di\App\Compiler;
-use Magento\Tools\Di\App\Task;
-
-class CompilerTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var Compiler
-     */
-    private $application;
-
-    /**
-     * @var \Magento\Framework\ObjectManagerInterface | \PHPUnit_Framework_MockObject_MockObject
-     */
-    private $objectManagerMock;
-
-    /**
-     * @var \Magento\Tools\Di\App\Task\Manager | \PHPUnit_Framework_MockObject_MockObject
-     */
-    private $taskManagerMock;
-
-    /**
-     * @var Response | \PHPUnit_Framework_MockObject_MockObject
-     */
-    private $responseMock;
-
-    protected function setUp()
-    {
-        $this->objectManagerMock = $this->getMockBuilder('Magento\Framework\ObjectManagerInterface')
-            ->setMethods([])
-            ->getMock();
-        $this->taskManagerMock = $this->getMockBuilder('Magento\Tools\Di\App\Task\Manager')
-            ->disableOriginalConstructor()
-            ->setMethods([])
-            ->getMock();
-        $this->responseMock = $this->getMockBuilder('Magento\Framework\App\Console\Response')
-            ->disableOriginalConstructor()
-            ->setMethods([])
-            ->getMock();
-
-        $this->application = new Compiler(
-            $this->taskManagerMock,
-            $this->objectManagerMock,
-            $this->responseMock
-        );
-    }
-
-    public function testLaunchSuccess()
-    {
-        $this->objectManagerMock->expects($this->once())
-            ->method('configure')
-            ->with($this->getPreferences());
-        $index = 0;
-        foreach ($this->getOptions() as $code => $arguments) {
-            $this->taskManagerMock->expects($this->at($index))
-                ->method('addOperation')
-                ->with($code, $arguments);
-            $index++;
-        }
-        $this->taskManagerMock->expects($this->at($index))->method('process');
-        $this->responseMock->expects($this->once())
-            ->method('setCode')
-            ->with(Response::SUCCESS);
-
-        $this->assertInstanceOf('\Magento\Framework\App\Console\Response', $this->application->launch());
-    }
-
-    public function testLaunchException()
-    {
-        $this->objectManagerMock->expects($this->once())
-            ->method('configure')
-            ->with($this->getPreferences());
-        $code = key($this->getOptions());
-        $arguments = current($this->getOptions());
-        $exception = new Task\OperationException(
-            'Unrecognized operation',
-            Task\OperationException::UNAVAILABLE_OPERATION
-        );
-
-        $this->taskManagerMock->expects($this->once())
-            ->method('addOperation')
-            ->with($code, $arguments)
-            ->willThrowException($exception);
-
-        $this->taskManagerMock->expects($this->never())->method('process');
-        $this->responseMock->expects($this->once())
-            ->method('setCode')
-            ->with(Response::ERROR);
-
-        $this->assertInstanceOf('\Magento\Framework\App\Console\Response', $this->application->launch());
-    }
-
-    /**
-     * Returns configured preferences
-     *
-     * @return array
-     */
-    private function getPreferences()
-    {
-        return [
-            'preferences' =>
-                [
-                    'Magento\Tools\Di\Compiler\Config\WriterInterface' =>
-                        'Magento\Tools\Di\Compiler\Config\Writer\Filesystem',
-                    'Magento\Tools\Di\Compiler\Log\Writer\WriterInterface' =>
-                        'Magento\Tools\Di\Compiler\Log\Writer\Console'
-                ],
-            'Magento\Tools\Di\Compiler\Config\ModificationChain' => [
-                'arguments' => [
-                    'modificationsList' => [
-                        'BackslashTrim' =>
-                            ['instance' => 'Magento\Tools\Di\Compiler\Config\Chain\BackslashTrim'],
-                        'PreferencesResolving' =>
-                            ['instance' => 'Magento\Tools\Di\Compiler\Config\Chain\PreferencesResolving'],
-                        'InterceptorSubstitution' =>
-                            ['instance' => 'Magento\Tools\Di\Compiler\Config\Chain\InterceptorSubstitution'],
-                        'InterceptionPreferencesResolving' =>
-                            ['instance' => 'Magento\Tools\Di\Compiler\Config\Chain\PreferencesResolving'],
-                        'ArgumentsSerialization' =>
-                            ['instance' => 'Magento\Tools\Di\Compiler\Config\Chain\ArgumentsSerialization'],
-                    ]
-                ]
-            ],
-            'Magento\Tools\Di\Code\Generator\PluginList' => [
-                'arguments' => [
-                    'cache' => [
-                        'instance' => 'Magento\Framework\App\Interception\Cache\CompiledConfig'
-                    ]
-                ]
-            ],
-            'Magento\Tools\Di\Code\Reader\ClassesScanner' => [
-                'arguments' => [
-                    'excludePatterns' => [
-                        'application' => '#^' . BP . '/app/code/[\\w]+/[\\w]+/Test#',
-                        'framework' => '#^' . BP . '/lib/internal/[\\w]+/[\\w]+/([\\w]+/)?Test#'
-                    ]
-                ]
-            ]
-        ];
-    }
-
-    /**
-     * Returns options
-     *
-     * @return array
-     */
-    private function getOptions()
-    {
-        return  [
-            Task\OperationFactory::REPOSITORY_GENERATOR => [
-                'path' => BP . '/' . 'app/code',
-                'filePatterns' => ['di' => '/\/etc\/([a-zA-Z_]*\/di|di)\.xml$/']
-            ],
-            Task\OperationFactory::APPLICATION_CODE_GENERATOR => [
-                BP . '/' . 'app/code', BP . '/' . 'lib/internal/Magento/Framework', BP . '/' . 'var/generation'
-            ],
-            Task\OperationFactory::INTERCEPTION => [
-                'intercepted_paths' => [
-                    BP . '/' . 'app/code',
-                    BP . '/' . 'lib/internal/Magento/Framework',
-                    BP . '/' . 'var/generation'
-                ],
-                'path_to_store' => BP . '/var/generation',
-            ],
-            Task\OperationFactory::AREA_CONFIG_GENERATOR => [
-                BP . '/' . 'app/code', BP . '/' . 'lib/internal/Magento/Framework', BP . '/' . 'var/generation'
-            ],
-            Task\OperationFactory::INTERCEPTION_CACHE => [
-                BP . '/' . 'app/code', BP . '/' . 'lib/internal/Magento/Framework', BP . '/' . 'var/generation'
-            ]
-        ];
-    }
-}
diff --git a/dev/tools/Magento/Tools/Di/compiler.php b/dev/tools/Magento/Tools/Di/compiler.php
deleted file mode 100644
index ced28772e7c6108f8f1a033617cf4af379687195..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Di/compiler.php
+++ /dev/null
@@ -1,258 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-require __DIR__ . '/../../../bootstrap.php';
-
-$rootDir = realpath(__DIR__ . '/../../../../../');
-use Magento\Framework\Api\Code\Generator\Mapper;
-use Magento\Framework\Api\Code\Generator\SearchResults;
-use Magento\Framework\Autoload\AutoloaderRegistry;
-use Magento\Framework\Interception\Code\Generator\Interceptor;
-use Magento\Framework\ObjectManager\Code\Generator\Converter;
-use Magento\Framework\ObjectManager\Code\Generator\Factory;
-use Magento\Framework\ObjectManager\Code\Generator\Proxy;
-use Magento\Framework\ObjectManager\Code\Generator\Repository;
-use Magento\Framework\ObjectManager\Code\Generator\Persistor;
-use Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator;
-use Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator;
-use Magento\Tools\Di\Code\Scanner;
-use Magento\Tools\Di\Compiler\Log\Log;
-use Magento\Tools\Di\Compiler\Log\Writer;
-use Magento\Tools\Di\Definition\Compressor;
-use Magento\Tools\Di\Definition\Serializer\Igbinary;
-use Magento\Tools\Di\Definition\Serializer\Standard;
-
-try {
-    $opt = new Zend_Console_Getopt(
-        [
-            'serializer=w'         => 'serializer function that should be used (serialize|igbinary) default: serialize',
-            'verbose|v'            => 'output report after tool run',
-            'extra-classes-file=s' => 'path to file with extra proxies and factories to generate',
-            'generation=s'         => 'absolute path to generated classes, <magento_root>/var/generation by default',
-            'di=s'                 => 'absolute path to DI definitions directory, <magento_root>/var/di by default',
-            'exclude-pattern=s'    => 'allows to exclude Paths from compilation (default is #[\\\\/]m1[\\\\/]#i)',
-        ]
-    );
-    $opt->parse();
-
-    $generationDir = $opt->getOption('generation') ? $opt->getOption('generation') : $rootDir . '/var/generation';
-    $diDir = $opt->getOption('di') ? $opt->getOption('di') : $rootDir . '/var/di';
-
-    $testExcludePatterns = [
-        "#^$rootDir/app/code/[\\w]+/[\\w]+/Test#",
-        "#^$rootDir/lib/internal/[\\w]+/[\\w]+/([\\w]+/)?Test#",
-        "#^$rootDir/setup/src/Magento/Setup/Test#",
-        "#^$rootDir/dev/tools/Magento/Tools/[\\w]+/Test#"
-    ];
-    $fileExcludePatterns = $opt->getOption('exclude-pattern') ?
-        [$opt->getOption('exclude-pattern')] : ['#[\\\\/]M1[\\\\/]#i'];
-    $fileExcludePatterns = array_merge($fileExcludePatterns, $testExcludePatterns);
-
-    $relationsFile = $diDir . '/relations.ser';
-    $pluginDefFile = $diDir . '/plugins.ser';
-
-    $compilationDirs = [
-        $rootDir . '/app/code',
-        $rootDir . '/lib/internal/Magento',
-        $rootDir . '/dev/tools/Magento/Tools'
-    ];
-
-    /** @var Writer\WriterInterface $logWriter Writer model for success messages */
-    $logWriter = $opt->getOption('v') ? new Writer\Console() : new Writer\Quiet();
-    $log = new Log($logWriter, new Writer\Console());
-
-    $serializer = $opt->getOption('serializer') == Igbinary::NAME ? new Igbinary() : new Standard();
-
-    AutoloaderRegistry::getAutoloader()->addPsr4('Magento\\', $generationDir . '/Magento/');
-
-    // 1 Code generation
-    // 1.1 Code scan
-    $filePatterns = ['php' => '/.*\.php$/', 'di' => '/\/etc\/([a-zA-Z_]*\/di|di)\.xml$/'];
-    $codeScanDir = realpath($rootDir . '/app');
-    $directoryScanner = new Scanner\DirectoryScanner();
-    $files = $directoryScanner->scan($codeScanDir, $filePatterns, $fileExcludePatterns);
-    $files['additional'] = [$opt->getOption('extra-classes-file')];
-    $entities = [];
-
-    $repositoryScanner = new Scanner\RepositoryScanner();
-    $repositories = $repositoryScanner->collectEntities($files['di']);
-
-    $scanner = new Scanner\CompositeScanner();
-    $scanner->addChild(new Scanner\PhpScanner($log), 'php');
-    $scanner->addChild(new Scanner\XmlScanner($log), 'di');
-    $scanner->addChild(new Scanner\ArrayScanner(), 'additional');
-    $entities = $scanner->collectEntities($files);
-
-    $interceptorScanner = new Scanner\XmlInterceptorScanner();
-    $entities['interceptors'] = $interceptorScanner->collectEntities($files['di']);
-
-    // 1.2 Generation of Factory and Additional Classes
-    $generatorIo = new \Magento\Framework\Code\Generator\Io(
-        new \Magento\Framework\Filesystem\Driver\File(),
-        $generationDir
-    );
-    $generator = new \Magento\Framework\Code\Generator(
-        $generatorIo,
-        [
-            Interceptor::ENTITY_TYPE => 'Magento\Framework\Interception\Code\Generator\Interceptor',
-            Proxy::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Proxy',
-            Factory::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Factory',
-            Mapper::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\Mapper',
-            Persistor::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Persistor',
-            Repository::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Repository',
-            Converter::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Converter',
-            SearchResults::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\SearchResults',
-            ExtensionAttributesInterfaceGenerator::ENTITY_TYPE =>
-                'Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator',
-            ExtensionAttributesGenerator::ENTITY_TYPE =>
-                'Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator'
-        ]
-    );
-    /** Initialize object manager for code generation based on configs */
-    $magentoObjectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER);
-    $objectManager = $magentoObjectManagerFactory->create($_SERVER);
-    $generator->setObjectManager($objectManager);
-
-    $generatorAutoloader = new \Magento\Framework\Code\Generator\Autoloader($generator);
-    spl_autoload_register([$generatorAutoloader, 'load']);
-
-    foreach ($repositories as $entityName) {
-        switch ($generator->generateClass($entityName)) {
-            case \Magento\Framework\Code\Generator::GENERATION_SUCCESS:
-                $log->add(Log::GENERATION_SUCCESS, $entityName);
-                break;
-
-            case \Magento\Framework\Code\Generator::GENERATION_ERROR:
-                $log->add(Log::GENERATION_ERROR, $entityName);
-                break;
-
-            case \Magento\Framework\Code\Generator::GENERATION_SKIP:
-            default:
-                //no log
-                break;
-        }
-    }
-
-    foreach (['php', 'additional'] as $type) {
-        sort($entities[$type]);
-        foreach ($entities[$type] as $entityName) {
-            switch ($generator->generateClass($entityName)) {
-                case \Magento\Framework\Code\Generator::GENERATION_SUCCESS:
-                    $log->add(Log::GENERATION_SUCCESS, $entityName);
-                    break;
-
-                case \Magento\Framework\Code\Generator::GENERATION_ERROR:
-                    $log->add(Log::GENERATION_ERROR, $entityName);
-                    break;
-
-                case \Magento\Framework\Code\Generator::GENERATION_SKIP:
-                default:
-                    //no log
-                    break;
-            }
-        }
-    }
-
-    // 2. Compilation
-    // 2.1 Code scan
-
-    $validator = new \Magento\Framework\Code\Validator();
-    $validator->add(new \Magento\Framework\Code\Validator\ConstructorIntegrity());
-    $validator->add(new \Magento\Framework\Code\Validator\ContextAggregation());
-    $classesScanner = new \Magento\Tools\Di\Code\Reader\ClassesScanner();
-    $classesScanner->addExcludePatterns($fileExcludePatterns);
-
-    $directoryInstancesNamesList = new \Magento\Tools\Di\Code\Reader\Decorator\Directory(
-        $log,
-        new \Magento\Framework\Code\Reader\ClassReader(),
-        $classesScanner,
-        $validator,
-        $generationDir
-    );
-
-    foreach ($compilationDirs as $path) {
-        if (is_readable($path)) {
-            $directoryInstancesNamesList->getList($path);
-        }
-    }
-
-    $inheritanceScanner = new Scanner\InheritanceInterceptorScanner();
-    $entities['interceptors'] = $inheritanceScanner->collectEntities(
-        get_declared_classes(),
-        $entities['interceptors']
-    );
-
-    // 2.1.1 Generation of Proxy and Interceptor Classes
-    foreach (['interceptors', 'di'] as $type) {
-        foreach ($entities[$type] as $entityName) {
-            switch ($generator->generateClass($entityName)) {
-                case \Magento\Framework\Code\Generator::GENERATION_SUCCESS:
-                    $log->add(Log::GENERATION_SUCCESS, $entityName);
-                    break;
-
-                case \Magento\Framework\Code\Generator::GENERATION_ERROR:
-                    $log->add(Log::GENERATION_ERROR, $entityName);
-                    break;
-
-                case \Magento\Framework\Code\Generator::GENERATION_SKIP:
-                default:
-                    //no log
-                    break;
-            }
-        }
-    }
-
-    //2.1.2 Compile relations for Proxy/Interceptor classes
-    $directoryInstancesNamesList->getList($generationDir);
-
-    $relations = $directoryInstancesNamesList->getRelations();
-
-    // 2.2 Compression
-    if (!file_exists(dirname($relationsFile))) {
-        mkdir(dirname($relationsFile), 0777, true);
-    }
-    $relations = array_filter($relations);
-    file_put_contents($relationsFile, $serializer->serialize($relations));
-
-    // 3. Plugin Definition Compilation
-    $pluginScanner = new Scanner\CompositeScanner();
-    $pluginScanner->addChild(new Scanner\PluginScanner(), 'di');
-    $pluginDefinitions = [];
-    $pluginList = $pluginScanner->collectEntities($files);
-    $pluginDefinitionList = new \Magento\Framework\Interception\Definition\Runtime();
-    foreach ($pluginList as $type => $entityList) {
-        foreach ($entityList as $entity) {
-            $pluginDefinitions[ltrim($entity, '\\')] = $pluginDefinitionList->getMethodList($entity);
-        }
-    }
-
-    $output = $serializer->serialize($pluginDefinitions);
-
-    if (!file_exists(dirname($pluginDefFile))) {
-        mkdir(dirname($pluginDefFile), 0777, true);
-    }
-
-    file_put_contents($pluginDefFile, $output);
-
-    //Reporter
-    $log->report();
-
-    if ($log->hasError()) {
-        exit(1);
-    }
-
-    echo 'On *nix systems, verify the Magento application has permissions to modify files created by the compiler'
-        . ' in the "var" directory. For instance, if you run the Magento application using Apache,'
-        . ' the owner of the files in the "var" directory should be the Apache user (example command:'
-        . ' "chown -R www-data:www-data <MAGENTO_ROOT>/var" where MAGENTO_ROOT is the Magento root directory).' . "\n";
-
-} catch (Zend_Console_Getopt_Exception $e) {
-    echo $e->getUsageMessage();
-    echo 'Please, use quotes(") for wrapping strings.' . "\n";
-    exit(1);
-} catch (Exception $e) {
-    fwrite(STDERR, "Compiler failed with exception: " . $e->getMessage());
-    throw($e);
-}
diff --git a/dev/tools/Magento/Tools/Di/entity_generator.php b/dev/tools/Magento/Tools/Di/entity_generator.php
deleted file mode 100644
index 17592837a0b0c2cd7274975c478a7cd879a94ab4..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Di/entity_generator.php
+++ /dev/null
@@ -1,101 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-use Magento\Framework\Api\Code\Generator\Mapper;
-use Magento\Framework\Api\Code\Generator\SearchResults;
-use Magento\Framework\Autoload\AutoloaderRegistry;
-use Magento\Framework\Code\Generator;
-use Magento\Framework\Code\Generator\Io;
-use Magento\Framework\Exception\LocalizedException;
-use Magento\Framework\Filesystem\Driver\File;
-use Magento\Framework\Interception\Code\Generator\Interceptor;
-use Magento\Framework\ObjectManager\Code\Generator\Converter;
-use Magento\Framework\ObjectManager\Code\Generator\Factory;
-use Magento\Framework\ObjectManager\Code\Generator\Proxy;
-use Magento\Framework\ObjectManager\Code\Generator\Repository;
-use Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator;
-use Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator;
-
-require __DIR__ . '/../../../../../app/bootstrap.php';
-
-// default generation dir
-$generationDir = BP . '/' . Io::DEFAULT_DIRECTORY;
-try {
-    $opt = new \Zend_Console_Getopt(
-        [
-            'type|t=w' => 'entity type(required)',
-            'class|c=s' => 'entity class name(required)',
-            'generation|g=s' => 'generation dir. Default value ' . $generationDir,
-        ]
-    );
-    $opt->parse();
-
-    $entityType = $opt->getOption('t');
-    if (empty($entityType)) {
-        throw new \Zend_Console_Getopt_Exception('type is a required parameter');
-    }
-
-    $className = $opt->getOption('c');
-    if (empty($className)) {
-        throw new \Zend_Console_Getopt_Exception('class is a required parameter');
-    }
-    $substitutions = ['proxy' => '_Proxy', 'factory' => 'Factory', 'interceptor' => '_Interceptor'];
-    if (!in_array($entityType, array_keys($substitutions))) {
-        throw new \Zend_Console_Getopt_Exception('unrecognized type: ' . $entityType);
-    }
-    $className .= $substitutions[$entityType];
-
-    if ($opt->getOption('g')) {
-        $generationDir = $opt->getOption('g');
-    }
-    AutoloaderRegistry::getAutoloader()->addPsr4('Magento\\', $generationDir . '/Magento/');
-} catch (\Zend_Console_Getopt_Exception $e) {
-    $generator = new Generator();
-    $entities = $generator->getGeneratedEntities();
-
-    $allowedTypes = 'Allowed entity types are: ' . implode(', ', $entities) . '.';
-    $example = 'Example: php -f entity_generator.php -- -t factory -c \Magento\Framework\Event\Observer ' .
-        '-g /var/mage/m2ee/generation' .
-        ' - will generate file /var/mage/m2ee/generation/Magento/Framework/Event/ObserverFactory.php';
-
-    echo $e->getMessage() . "\n";
-    echo $e->getUsageMessage() . "\n";
-    echo $allowedTypes . "\n";
-    echo 'Default generation dir is ' . $generationDir . "\n";
-    exit($example);
-}
-
-//reinit generator with correct generation path
-$io = new Io(new File(), $generationDir);
-$generator = new Generator(
-    $io,
-    [
-        Proxy::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Proxy',
-        Factory::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Factory',
-        Interceptor::ENTITY_TYPE => 'Magento\Framework\Interception\Code\Generator\Interceptor',
-        Mapper::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\Mapper',
-        Repository::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Repository',
-        Converter::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Converter',
-        SearchResults::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\SearchResults',
-        ExtensionAttributesInterfaceGenerator::ENTITY_TYPE =>
-            'Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator',
-        ExtensionAttributesGenerator::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator'
-    ]
-);
-/** Initialize object manager for code generation based on configs */
-$magentoObjectManagerFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, $_SERVER);
-$objectManager = $magentoObjectManagerFactory->create($_SERVER);
-$generator->setObjectManager($objectManager);
-
-try {
-    if (Generator::GENERATION_SUCCESS == $generator->generateClass($className)) {
-        print "Class {$className} was successfully generated.\n";
-    } else {
-        print "Can't generate class {$className}. This class either not generated entity, or it already exists.\n";
-    }
-} catch (LocalizedException $e) {
-    print "Error! {$e->getMessage()}\n";
-}
diff --git a/dev/tools/Magento/Tools/Di/singletenant_compiler.php b/dev/tools/Magento/Tools/Di/singletenant_compiler.php
deleted file mode 100644
index 39646da196ccde7e1692df39b398fdf3fa048eca..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Di/singletenant_compiler.php
+++ /dev/null
@@ -1,12 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-require __DIR__ . '/../../../../../app/bootstrap.php';
-
-$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
-/** @var \Magento\Framework\App\Http $app */
-$app = $bootstrap->createApplication('Magento\Tools\Di\App\Compiler');
-$bootstrap->run($app);
diff --git a/dev/tools/Magento/Tools/I18n/generator.php b/dev/tools/Magento/Tools/I18n/generator.php
deleted file mode 100644
index d0cef23ad8649405740b8a7297768915fb3c8e46..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/I18n/generator.php
+++ /dev/null
@@ -1,44 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-require_once __DIR__ . '/bootstrap.php';
-use Magento\Tools\I18n\ServiceLocator;
-
-try {
-    $console = new \Zend_Console_Getopt(
-        [
-            'directory|d=s' => 'Path to a directory to parse',
-            'output-file|o=s' => 'Path (with filename) to output file, '
-                . 'by default output the results into standard output stream',
-            'magento|m-s' => 'Indicates whether the specified "directory" path is a Magento root directory,'
-                . ' "no" by default',
-        ]
-    );
-    $console->parse();
-
-    if (!count($console->getOptions())) {
-        throw new \Zend_Console_Getopt_Exception(
-            'Required parameters are missed, please see usage description',
-            $console->getUsageMessage()
-        );
-    }
-    $directory = $console->getOption('directory');
-    if (empty($directory)) {
-        throw new \Zend_Console_Getopt_Exception('Directory is a required parameter.', $console->getUsageMessage());
-    }
-    $outputFilename = $console->getOption('output-file') ?: null;
-    $isMagento = in_array($console->getOption('magento'), ['y', 'yes', 'Y', 'Yes', 'YES', '1']);
-
-    $generator = ServiceLocator::getDictionaryGenerator();
-    $generator->generate($directory, $outputFilename, $isMagento);
-
-    fwrite(STDOUT, "\nDictionary successfully processed.\n");
-} catch (\Zend_Console_Getopt_Exception $e) {
-    fwrite(STDERR, $e->getMessage() . "\n\n" . $e->getUsageMessage() . "\n");
-    exit(1);
-} catch (\Exception $e) {
-    fwrite(STDERR, $e->getMessage() . "\n");
-    exit(1);
-}
diff --git a/dev/tools/Magento/Tools/I18n/pack.php b/dev/tools/Magento/Tools/I18n/pack.php
deleted file mode 100644
index 443a844d82d25a2884390b680362ffe1c959c81b..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/I18n/pack.php
+++ /dev/null
@@ -1,53 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-require __DIR__ . '/bootstrap.php';
-use Magento\Tools\I18n\ServiceLocator;
-
-try {
-    $console = new \Zend_Console_Getopt(
-        [
-            'source|s=s' => 'Path to source dictionary file with translations',
-            'pack|p=s' => 'Path to language package',
-            'locale|l=s' => 'Target locale for dictionary, for example "de_DE"',
-            'mode|m-s' => 'Save mode for dictionary
-        - "replace" - replace language pack by new one
-        - "merge" -  merge language packages, by default "replace"',
-            'allow_duplicates|d=s' => 'Is allowed to save duplicates of translate, by default "no"',
-        ]
-    );
-    $console->parse();
-    if (!count($console->getOptions())) {
-        throw new \UnexpectedValueException(
-            'Required parameters are missed, please see usage description' . "\n\n" . $console->getUsageMessage()
-        );
-    }
-    $dictionaryPath = $console->getOption('source');
-    $packPath = $console->getOption('pack');
-    $locale = $console->getOption('locale');
-    $allowDuplicates = in_array($console->getOption('allow_duplicates'), ['y', 'Y', 'yes', 'Yes', '1']);
-    $saveMode = $console->getOption('mode');
-
-    if (!$dictionaryPath) {
-        throw new \Zend_Console_Getopt_Exception('Dictionary source path parameter is required.');
-    }
-    if (!$packPath) {
-        throw new \Zend_Console_Getopt_Exception('Pack path parameter is required.');
-    }
-    if (!$locale) {
-        throw new \Zend_Console_Getopt_Exception('Locale parameter is required.');
-    }
-
-    $generator = ServiceLocator::getPackGenerator();
-    $generator->generate($dictionaryPath, $packPath, $locale, $saveMode, $allowDuplicates);
-
-    fwrite(STDOUT, sprintf("\nSuccessfully saved %s language package.\n", $locale));
-} catch (\Zend_Console_Getopt_Exception $e) {
-    fwrite(STDERR, $e->getMessage() . "\n\n" . $e->getUsageMessage() . "\n");
-    exit(1);
-} catch (\Exception $e) {
-    fwrite(STDERR, $e->getMessage() . "\n");
-    exit(1);
-}
diff --git a/dev/tools/Magento/Tools/View/Deployer/Log.php b/dev/tools/Magento/Tools/View/Deployer/Log.php
deleted file mode 100644
index 871b8944138f26c11844b17a063e978f8d0b9ca5..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/View/Deployer/Log.php
+++ /dev/null
@@ -1,100 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Tools\View\Deployer;
-
-/**
- * An echo-logger with separating types of messages
- */
-class Log
-{
-    /**#@+
-     * Bitmasks for verbosity level
-     */
-    const SILENT = 0;
-    const ERROR = 1;
-    const DEBUG = 2;
-    /**#@-*/
-
-    /**
-     * @var int
-     */
-    private $verbosity;
-
-    /**
-     * If last output printed inline
-     *
-     * @var bool
-     */
-    private $isInline = false;
-
-    /**
-     * @param int $verbosity
-     */
-    public function __construct($verbosity)
-    {
-        $this->verbosity = (int)$verbosity;
-    }
-
-    /**
-     * Log anything
-     *
-     * @param string $msg
-     * @return void
-     */
-    public function logMessage($msg)
-    {
-        if ($this->verbosity !== self::SILENT) {
-            $this->terminateLine();
-            echo "{$msg}\n";
-        }
-    }
-
-    /**
-     * Log an error
-     *
-     * @param string $msg
-     * @return void
-     */
-    public function logError($msg)
-    {
-        if ($this->verbosity & self::ERROR) {
-            $this->terminateLine();
-            echo "ERROR: {$msg}\n";
-        }
-    }
-
-    /**
-     * Log a debug message
-     *
-     * @param string $msg
-     * @param string $altInline Alternative message for normal mode (printed inline)
-     * @return void
-     */
-    public function logDebug($msg, $altInline = '')
-    {
-        if ($this->verbosity & self::DEBUG) {
-            $this->terminateLine();
-            echo "{$msg}\n";
-        } elseif ($altInline && $this->verbosity !== self::SILENT) {
-            echo $altInline;
-            $this->isInline = true;
-        }
-    }
-
-    /**
-     * Ensures the next log message will be printed on new line
-     *
-     * @return void
-     */
-    private function terminateLine()
-    {
-        if ($this->isInline) {
-            $this->isInline = false;
-            echo "\n";
-        }
-    }
-}
diff --git a/dev/tools/Magento/Tools/View/Test/Unit/Deployer/LogTest.php b/dev/tools/Magento/Tools/View/Test/Unit/Deployer/LogTest.php
deleted file mode 100644
index 163d6d34bb122ff6c23c37f8aac5e0a9f3c33325..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/View/Test/Unit/Deployer/LogTest.php
+++ /dev/null
@@ -1,73 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Tools\View\Test\Unit\Deployer;
-
-use \Magento\Tools\View\Deployer\Log;
-
-class LogTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @param string $method
-     * @param int $verbosity
-     * @param string $expectedMsg
-     * @dataProvider logDataProvider
-     */
-    public function testLog($method, $verbosity, $expectedMsg)
-    {
-        $object = new Log($verbosity);
-        $object->$method('foo');
-        $this->expectOutputString($expectedMsg);
-    }
-
-    /**
-     * @return array
-     */
-    public function logDataProvider()
-    {
-        $foo = "foo\n";
-        $err = "ERROR: {$foo}";
-        return [
-            ['logMessage', Log::SILENT, ''],
-            ['logError',   Log::SILENT, ''],
-            ['logDebug',   Log::SILENT, ''],
-            ['logMessage', Log::ERROR, $foo],
-            ['logError',   Log::ERROR, $err],
-            ['logDebug',   Log::ERROR, ''],
-            ['logMessage', Log::DEBUG, $foo],
-            ['logError',   Log::DEBUG, ''],
-            ['logDebug',   Log::DEBUG, $foo],
-            ['logMessage', Log::ERROR | Log::DEBUG, $foo],
-            ['logError',   Log::ERROR | Log::DEBUG, $err],
-            ['logDebug',   Log::ERROR | Log::DEBUG, $foo],
-        ];
-    }
-
-    /**
-     * @param int $verbosity
-     * @param string $expectedMsg
-     *
-     * @dataProvider logDebugAltDataProvider
-     */
-    public function testLogDebugAlt($verbosity, $expectedMsg)
-    {
-        $object = new Log($verbosity);
-        $object->logDebug('foo', '[alt]');
-        $this->expectOutputString($expectedMsg);
-    }
-
-    /**
-     * @return array
-     */
-    public function logDebugAltDataProvider()
-    {
-        return[
-            'debug mode' => [Log::DEBUG, "foo\n"],
-            'default mode' => [Log::ERROR, '[alt]'],
-            'silent mode' => [Log::SILENT, '']
-        ];
-    }
-}
diff --git a/dev/tools/Magento/Tools/View/deploy.php b/dev/tools/Magento/Tools/View/deploy.php
deleted file mode 100644
index f380efd3f360d68738842b900cc4372a0af2ddc4..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/View/deploy.php
+++ /dev/null
@@ -1,69 +0,0 @@
-<?php
-/**
- * A script for deploying static view files for Magento system "production mode"
- *
- * The resulting files will be recorded into pub/static directory.
- * They can be used not only by the server where Magento instance is,
- * but also can be copied to a CDN, and the Magento instance may be configured to generate base URL to the CDN.
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-use Magento\Framework\Autoload\AutoloaderRegistry;
-
-$baseName = basename(__FILE__);
-$options = getopt('', ['langs::', 'dry-run', 'verbose::', 'help']);
-define('USAGE', "USAGE:\n\tphp -f {$baseName} -- [--langs=en_US,de_DE,...] [--verbose=0|1] [--dry-run] [--help]\n");
-require __DIR__ . '/../../../../../app/bootstrap.php';
-
-AutoloaderRegistry::getAutoloader()->addPsr4('Magento\\', [BP . '/tools/Magento/']);
-
-// parse all options
-if (isset($options['help'])) {
-    echo USAGE;
-    exit(0);
-}
-$langs = ['en_US'];
-if (isset($options['langs'])) {
-    $langs = explode(',', $options['langs']);
-    foreach ($langs as $lang) {
-        if (!preg_match('/^[a-z]{2}_[A-Z]{2}$/', $lang)) {
-            echo USAGE;
-            exit(1);
-        }
-    }
-}
-$isDryRun = isset($options['dry-run']);
-$verbosity = \Magento\Tools\View\Deployer\Log::ERROR;
-if (isset($options['verbose'])) {
-    $verbosity = 0 === (int)$options['verbose'] ? \Magento\Tools\View\Deployer\Log::SILENT
-        : \Magento\Tools\View\Deployer\Log::ERROR | \Magento\Tools\View\Deployer\Log::DEBUG;
-}
-$logger = new \Magento\Tools\View\Deployer\Log($verbosity);
-
-try {
-    // run the deployment logic
-    $filesUtil = new \Magento\Framework\App\Utility\Files(BP);
-    $omFactory = \Magento\Framework\App\Bootstrap::createObjectManagerFactory(BP, []);
-    $objectManager = $omFactory->create(
-        [\Magento\Framework\App\State::PARAM_MODE => \Magento\Framework\App\State::MODE_DEFAULT]
-    );
-
-    /** @var \Magento\Framework\App\DeploymentConfig $deploymentConfig */
-    $deploymentConfig = $objectManager->get('Magento\Framework\App\DeploymentConfig');
-    $isAppInstalled = $deploymentConfig->isAvailable();
-    if (!$isAppInstalled) {
-        throw new \Exception('You need to install the Magento application before running this utility.');
-    }
-
-    /** @var \Magento\Tools\View\Deployer $deployer */
-    $deployer = $objectManager->create(
-        'Magento\Tools\View\Deployer',
-        ['filesUtil' => $filesUtil, 'logger' => $logger, 'isDryRun' => $isDryRun]
-    );
-    $deployer->deploy($omFactory, $langs);
-} catch (\Exception $e) {
-    $logger->logError($e->getMessage());
-    $logger->logDebug($e->getTraceAsString());
-    exit(1);
-}
diff --git a/dev/tools/Magento/Tools/Webdev/App/FileAssembler.php b/dev/tools/Magento/Tools/Webdev/App/FileAssembler.php
deleted file mode 100644
index 0a07540a19c94695f0a9454f0f5f4b3b86c12182..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Webdev/App/FileAssembler.php
+++ /dev/null
@@ -1,198 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Tools\Webdev\App;
-
-use Magento\Framework\App;
-use Magento\Framework\App\State;
-use Magento\Framework\AppInterface;
-use Magento\Framework\Filesystem;
-use Magento\Tools\Webdev\CliParams;
-use Magento\Tools\View\Deployer\Log;
-use Magento\Framework\View\Asset\Source;
-use Magento\Framework\App\Console\Response;
-use Magento\Framework\View\Asset\Repository;
-use Magento\Framework\ObjectManagerInterface;
-use Magento\Framework\App\ObjectManager\ConfigLoader;
-use Magento\Framework\View\Asset\SourceFileGeneratorPool;
-use Magento\Framework\View\Asset\PreProcessor\ChainFactoryInterface;
-use Magento\Framework\App\Filesystem\DirectoryList;
-
-/**
- * Class FileAssembler
- *
- * @package Magento\Tools\Di\App
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
- */
-class FileAssembler implements AppInterface
-{
-    /**
-     * @var ObjectManagerInterface
-     */
-    private $objectManager;
-
-    /**
-     * @var Response
-     */
-    private $response;
-
-    /**
-     * @var CliParams
-     */
-    private $params;
-
-    /**
-     * @var Repository
-     */
-    private $assetRepo;
-
-    /**
-     * @var ConfigLoader
-     */
-    private $configLoader;
-
-    /**
-     * @var State
-     */
-    private $state;
-
-    /**
-     * @var \Magento\Framework\Less\FileGenerator
-     */
-    private $sourceFileGeneratorPool;
-
-    /**
-     * @var \Magento\Framework\View\Asset\Source
-     */
-    private $assetSource;
-
-    /**
-     * @var \Magento\Tools\View\Deployer\Log
-     */
-    private $logger;
-
-    /**
-     * @var ChainFactoryInterface
-     */
-    private $chainFactory;
-
-    /**
-     * @var Filesystem
-     */
-    private $filesystem;
-
-    /**
-     * @param ObjectManagerInterface $objectManager
-     * @param Response $response
-     * @param CliParams $params
-     * @param Repository $assetRepo
-     * @param ConfigLoader $configLoader
-     * @param State $state
-     * @param Source $assetSource
-     * @param \Magento\Framework\View\Asset\SourceFileGeneratorPool $sourceFileGeneratorPoll
-     * @param \Magento\Tools\View\Deployer\Log $logger
-     * @param ChainFactoryInterface $chainFactory
-     * @param Filesystem $filesystem
-     *
-     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
-     */
-    public function __construct(
-        ObjectManagerInterface $objectManager,
-        Response $response,
-        CliParams $params,
-        Repository $assetRepo,
-        ConfigLoader $configLoader,
-        State $state,
-        Source $assetSource,
-        SourceFileGeneratorPool $sourceFileGeneratorPoll,
-        Log $logger,
-        ChainFactoryInterface $chainFactory,
-        Filesystem $filesystem
-    ) {
-        $this->response = $response;
-        $this->params = $params;
-        $this->state = $state;
-        $this->objectManager = $objectManager;
-        $this->configLoader = $configLoader;
-        $this->assetRepo = $assetRepo;
-        $this->sourceFileGeneratorPool = $sourceFileGeneratorPoll;
-        $this->assetSource = $assetSource;
-        $this->logger = $logger;
-        $this->chainFactory = $chainFactory;
-        $this->filesystem = $filesystem;
-    }
-
-    /**
-     * Launch application
-     *
-     * @return \Magento\Framework\App\ResponseInterface
-     */
-    public function launch()
-    {
-        $this->state->setAreaCode($this->params->getArea());
-        $this->objectManager->configure($this->configLoader->load($this->params->getArea()));
-
-        $sourceFileGenerator = $this->sourceFileGeneratorPool->create($this->params->getExt());
-
-        foreach ($this->params->getFiles() as $file) {
-            $file .= '.' . $this->params->getExt();
-
-            $this->logger->logMessage("Gathering {$file} sources.");
-
-            $asset = $this->assetRepo->createAsset(
-                $file,
-                [
-                    'area' => $this->params->getArea(),
-                    'theme' => $this->params->getTheme(),
-                    'locale' => $this->params->getLocale(),
-                ]
-            );
-
-            $sourceFile = $this->assetSource->findSource($asset);
-            $content = \file_get_contents($sourceFile);
-
-            $chain = $this->chainFactory->create(
-                [
-                    'asset'           => $asset,
-                    'origContent'     => $content,
-                    'origContentType' => $asset->getContentType()
-                ]
-            );
-
-            $processedCoreFile = $sourceFileGenerator->generateFileTree($chain);
-
-            $targetDir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW);
-            $rootDir = $this->filesystem->getDirectoryWrite(DirectoryList::ROOT);
-            $source = $rootDir->getRelativePath($processedCoreFile);
-            $destination = $asset->getPath();
-            $rootDir->copyFile($source, $destination, $targetDir);
-
-            $this->logger->logMessage("Done");
-        }
-
-        $this->response->setCode(Response::SUCCESS);
-
-        return $this->response;
-    }
-
-    /**
-     * Ability to handle exceptions that may have occurred during bootstrap and launch
-     *
-     * Return values:
-     * - true: exception has been handled, no additional action is needed
-     * - false: exception has not been handled - pass the control to Bootstrap
-     *
-     * @param App\Bootstrap $bootstrap
-     * @param \Exception $exception
-     * @return bool
-     *
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
-     */
-    public function catchException(App\Bootstrap $bootstrap, \Exception $exception)
-    {
-        return false;
-    }
-}
diff --git a/dev/tools/Magento/Tools/Webdev/CliParams.php b/dev/tools/Magento/Tools/Webdev/CliParams.php
deleted file mode 100644
index b06560868d8a84796ef9cb4bdddcaba518cf33f7..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Webdev/CliParams.php
+++ /dev/null
@@ -1,192 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Tools\Webdev;
-
-use Magento\Tools\View\Deployer\Log;
-
-/**
- * Class CliParams
- *
- * @package Magento\Tools\Webdev
- */
-class CliParams
-{
-    /**
-     * AREA_DOC
-     */
-    const AREA_DOC = 'doc';
-
-    /**
-     * AREA_FRONTEND
-     */
-    const AREA_FRONTEND = 'frontend';
-
-    /**
-     * AREA_ADMIN
-     */
-    const AREA_ADMIN = 'adminhtml';
-
-    /**
-     * @var string
-     */
-    private $locale = 'en_US';
-
-    /**
-     * @var string
-     */
-    private $area = self::AREA_FRONTEND;
-
-    /**
-     * @var string
-     */
-    private $theme = 'Magento/blank';
-
-    /**
-     * @var array
-     */
-    private $files = ['css/styles-m'];
-
-    /**
-     * @var string
-     */
-    private $ext;
-
-    /**
-     * @var int
-     */
-    private $verbose = Log::ERROR;
-
-    /**
-     * @param \Zend_Console_Getopt $opt
-     * @SuppressWarnings(PHPMD.NPathComplexity)
-     * @throws \Zend_Console_Getopt_Exception
-     */
-    public function __construct(\Zend_Console_Getopt $opt)
-    {
-        $this->locale = $opt->getOption('locale')? :$this->locale;
-
-        if (!$opt->getOption('ext')) {
-            throw new \Zend_Console_Getopt_Exception('Provide "ext" parameter!');
-        }
-
-        $this->ext = $opt->getOption('ext');
-
-        if (!preg_match('/^[a-z]{2}_[A-Z]{2}$/', $this->locale)) {
-            throw new \Zend_Console_Getopt_Exception('Invalid locale format');
-        }
-
-        $this->area = $opt->getOption('area')? :$this->area;
-        $this->theme = $opt->getOption('theme')? :$this->theme;
-
-        if ($opt->getOption('files')) {
-            $this->files = explode(',', $opt->getOption('files'));
-        }
-
-        if ($opt->getOption('verbose')) {
-            $this->verbose = Log::ERROR | Log::DEBUG;
-        }
-    }
-
-    /**
-     * @return string
-     */
-    public function getLocale()
-    {
-        return $this->locale;
-    }
-
-    /**
-     * @param string $locale
-     *
-     * @throws \Zend_Console_Getopt_Exception
-     *
-     * @return void
-     */
-    public function setLocale($locale)
-    {
-        $this->locale = $locale;
-    }
-
-    /**
-     * @return string
-     */
-    public function getArea()
-    {
-        return $this->area;
-    }
-
-    /**
-     * @param string $area
-     *
-     * @return void
-     */
-    public function setArea($area)
-    {
-        $this->area = $area;
-    }
-
-    /**
-     * @return string
-     */
-    public function getTheme()
-    {
-        return $this->theme;
-    }
-
-    /**
-     * @param string $theme
-     *
-     * @return void
-     */
-    public function setTheme($theme)
-    {
-        $this->theme = $theme;
-    }
-
-    /**
-     * @return array
-     */
-    public function getFiles()
-    {
-        return $this->files;
-    }
-
-    /**
-     * @param array $files
-     *
-     * @return void
-     */
-    public function setFiles($files)
-    {
-        $this->files = $files;
-    }
-
-    /**
-     * @return int
-     */
-    public function getVerbose()
-    {
-        return $this->verbose;
-    }
-
-    /**
-     * @param int $verbose
-     *
-     * @return void
-     */
-    public function setVerbose($verbose)
-    {
-        $this->verbose = $verbose;
-    }
-
-    /**
-     * @return string
-     */
-    public function getExt()
-    {
-        return $this->ext;
-    }
-}
diff --git a/dev/tools/Magento/Tools/Webdev/file_assembler.php b/dev/tools/Magento/Tools/Webdev/file_assembler.php
deleted file mode 100644
index 669ffa8d535856606b1a86ebbf5d0882aa99f353..0000000000000000000000000000000000000000
--- a/dev/tools/Magento/Tools/Webdev/file_assembler.php
+++ /dev/null
@@ -1,49 +0,0 @@
-<?php
-/**
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-use Magento\Tools\Webdev\CliParams;
-use Magento\Tools\View\Deployer\Log;
-
-require __DIR__ . '/../../../bootstrap.php';
-
-try {
-    $opt = new \Zend_Console_Getopt(
-        [
-            'locale=s'  => 'locale, default: en_US',
-            'area=s'    => 'area, one of (frontend|adminhtml|doc), default: frontend',
-            'theme=s'   => 'theme in format Vendor/theme, default: Magento/blank',
-            'files=s'   => 'files to pre-process (accept more than one file type as comma-separate values),'
-                . ' default: css/styles-m',
-            'ext=s'     => 'dynamic stylesheet language: less|sass',
-            'verbose|v' => 'provide extra output',
-            'help|h'    => 'show help',
-        ]
-    );
-
-    $opt->parse();
-
-    if ($opt->getOption('help')) {
-        echo $opt->getUsageMessage();
-        exit(0);
-    }
-
-    $params = new CliParams($opt);
-    $logger = new Log($params->getVerbose());
-
-} catch (\Zend_Console_Getopt_Exception $e) {
-    echo $e->getMessage() . PHP_EOL;
-    echo 'Please, use quotes(") for wrapping strings.' . PHP_EOL;
-    exit(1);
-}
-
-$bootstrap = \Magento\Framework\App\Bootstrap::create(BP, $_SERVER);
-/** @var \Magento\Framework\App\Http $app */
-$app = $bootstrap->createApplication(
-    'Magento\Tools\Webdev\App\FileAssembler',
-    ['params' => $params, 'logger' => $logger]
-);
-$bootstrap->run($app);
diff --git a/dev/tools/grunt/configs/combo.js b/dev/tools/grunt/configs/combo.js
index 1ead93cb6265474399e612d02bad98cfbdaaee5b..cd3484eee7836c516e6cacd766fecc4410c71707 100644
--- a/dev/tools/grunt/configs/combo.js
+++ b/dev/tools/grunt/configs/combo.js
@@ -16,12 +16,10 @@ module.exports = {
         var cmdPlus = /^win/.test(process.platform) ? ' & ' : ' && ',
             command = 'grunt --force clean:' + themeName + cmdPlus;
 
-        command = command + 'php -f dev/tools/Magento/Tools/Webdev/file_assembler.php --' +
+        command = command + 'php bin/magento dev:css:deploy ' + theme[themeName].dsl + ' ' + theme[themeName].files.join(' ') +
         ' --locale=' + theme[themeName].locale +
         ' --area=' + theme[themeName].area +
-        ' --theme=' + theme[themeName].name +
-        ' --files=' + theme[themeName].files.join(',') +
-        ' --ext=' + theme[themeName].dsl;
+        ' --theme=' + theme[themeName].name;
 
         return command;
     },
diff --git a/dev/tools/grunt/tasks/deploy.js b/dev/tools/grunt/tasks/deploy.js
index bff8b1fabecaf8d9774a79aa3134c7163847ca30..13bedbc8a23e7fa929d6d659c27cc5b8c1d16fb6 100644
--- a/dev/tools/grunt/tasks/deploy.js
+++ b/dev/tools/grunt/tasks/deploy.js
@@ -20,7 +20,7 @@ module.exports = function (grunt) {
         ok('"pub/static" is empty.');
 
         log('Deploying Magento application...');
-        deploy = spawn('php', ['dev/tools/Magento/Tools/View/deploy.php']);
+        deploy = spawn('php', ['bin/magento', 'setup:static-content:deploy']);
 
         deploy.stdout.on('data', function (data) {
             log(data);
diff --git a/dev/tools/performance-toolkit/framework/Magento/ToolkitFramework/Application.php b/dev/tools/performance-toolkit/framework/Magento/ToolkitFramework/Application.php
index d1df2a830d5d1b7a1df8785c278e3147ffe8d28a..9e6706a7713448e76b711becb20f25a415667f52 100644
--- a/dev/tools/performance-toolkit/framework/Magento/ToolkitFramework/Application.php
+++ b/dev/tools/performance-toolkit/framework/Magento/ToolkitFramework/Application.php
@@ -132,7 +132,7 @@ class Application
     public function reindex()
     {
         $this->_shell->execute(
-            'php -f ' . $this->_applicationBaseDir . '/dev/shell/indexer.php -- reindexall'
+            'php -f ' . $this->_applicationBaseDir . '/bin/magento indexer:reindex --all'
         );
         return $this;
     }
diff --git a/dev/tools/tests.php b/dev/tools/tests.php
deleted file mode 100644
index fc04fa8a7311f2f4f8cfcb6b5d72e800a1021150..0000000000000000000000000000000000000000
--- a/dev/tools/tests.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-/**
- * Batch tool for running all or some of tests
- *
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-$vendorDir = require '../../app/etc/vendor_path.php';
-
-$commands = [
-    'unit'                   => ['../tests/unit', ''],
-    'unit-performance'       => ['../tests/performance/framework/tests/unit', ''],
-    'unit-static'            => ['../tests/static/framework/tests/unit', ''],
-    'unit-integration'       => ['../tests/integration/framework/tests/unit', ''],
-    'integration'            => ['../tests/integration', ''],
-    'integration-integrity'  => ['../tests/integration', ' testsuite/Magento/Test/Integrity'],
-    'static-default'         => ['../tests/static', ''],
-    'static-legacy'          => ['../tests/static', ' testsuite/Magento/Test/Legacy'],
-    'static-integration-php' => ['../tests/static', ' testsuite/Magento/Test/Php/Exemplar'],
-    'static-integration-js'  => ['../tests/static', ' testsuite/Magento/Test/Js/Exemplar'],
-];
-$types = [
-    'all'             => array_keys($commands),
-    'unit'            => ['unit', 'unit-performance', 'unit-static', 'unit-integration'],
-    'integration'     => ['integration'],
-    'integration-all' => ['integration', 'integration-integrity'],
-    'static'          => ['static-default'],
-    'static-all'      => ['static-default', 'static-legacy', 'static-integration-php', 'static-integration-js'],
-    'integrity'       => ['static-default', 'static-legacy', 'integration-integrity'],
-    'legacy'          => ['static-legacy'],
-    'default'         => [
-        'unit', 'unit-performance', 'unit-static', 'unit-integration', 'integration', 'static-default',
-    ],
-];
-
-$arguments = getopt('', ['type::']);
-if (!isset($arguments['type'])) {
-    $arguments['type'] = 'default';
-} elseif (!isset($types[$arguments['type']])) {
-    echo "Invalid type: '{$arguments['type']}'. Available types: " . implode(', ', array_keys($types)) . "\n\n";
-    exit(1);
-}
-
-$failures = [];
-$runCommands = $types[$arguments['type']];
-foreach ($runCommands as $key) {
-    list($dir, $options) = $commands[$key];
-    $dirName = realpath(__DIR__ . '/' . $dir);
-    chdir($dirName);
-    $command = realpath(__DIR__ . '/../../') . '/' . $vendorDir . '/phpunit/phpunit/phpunit' . $options;
-    $message = $dirName . '> ' . $command;
-    echo "\n\n";
-    echo str_pad("---- {$message} ", 70, '-');
-    echo "\n\n";
-    passthru($command, $returnVal);
-    if ($returnVal) {
-        $failures[] = $message;
-    }
-}
-
-echo "\n" , str_repeat('-', 70), "\n";
-if ($failures) {
-    echo "\nFAILED - " . count($failures) . ' of ' . count($runCommands) . ":\n";
-    foreach ($failures as $message) {
-        echo ' - ' . $message . "\n";
-    }
-} else {
-    echo "\nPASSED (" . count($runCommands) . ")\n";
-}
diff --git a/lib/internal/Magento/Framework/App/AbstractShell.php b/lib/internal/Magento/Framework/App/AbstractShell.php
deleted file mode 100644
index ce24586bb7cec5a589bb1f3530df07f6fdc6eb8d..0000000000000000000000000000000000000000
--- a/lib/internal/Magento/Framework/App/AbstractShell.php
+++ /dev/null
@@ -1,190 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Framework\App;
-
-use Magento\Framework\App\Filesystem\DirectoryList;
-
-/**
- * Shell scripts abstract class
- */
-abstract class AbstractShell
-{
-    /**
-     * Raw arguments, that should be parsed
-     *
-     * @var string[]
-     */
-    protected $_rawArgs = [];
-
-    /**
-     * Parsed input arguments
-     *
-     * @var array
-     */
-    protected $_args = [];
-
-    /**
-     * Entry point - script filename that is executed
-     *
-     * @var string
-     */
-    protected $_entryPoint = null;
-
-    /**
-     * @var \Magento\Framework\Filesystem\Directory\ReadInterface
-     */
-    protected $rootDirectory;
-
-    /**
-     * Initializes application and parses input parameters
-     *
-     * @param \Magento\Framework\Filesystem $filesystem
-     * @param string $entryPoint
-     * @throws \Exception
-     */
-    public function __construct(\Magento\Framework\Filesystem $filesystem, $entryPoint)
-    {
-        if (isset($_SERVER['REQUEST_METHOD'])) {
-            throw new \Exception('This script cannot be run from Browser. This is the shell script.');
-        }
-
-        $this->rootDirectory = $filesystem->getDirectoryRead(DirectoryList::ROOT);
-        $this->_entryPoint = $entryPoint;
-        $this->_rawArgs = $_SERVER['argv'];
-        $this->_applyPhpVariables();
-        $this->_parseArgs();
-    }
-
-    /**
-     * Sets raw arguments to be parsed
-     *
-     * @param string[] $args
-     * @return $this
-     */
-    public function setRawArgs($args)
-    {
-        $this->_rawArgs = $args;
-        $this->_parseArgs();
-        return $this;
-    }
-
-    /**
-     * Parses .htaccess file and apply php settings to shell script
-     *
-     * @return $this
-     */
-    protected function _applyPhpVariables()
-    {
-        $htaccess = '.htaccess';
-        if ($this->rootDirectory->isFile($htaccess)) {
-            // parse htaccess file
-            $data = $this->rootDirectory->readFile($htaccess);
-            $matches = [];
-            preg_match_all('#^\s+?php_value\s+([a-z_]+)\s+(.+)$#siUm', $data, $matches, PREG_SET_ORDER);
-            if ($matches) {
-                foreach ($matches as $match) {
-                    @ini_set($match[1], str_replace("\r", '', $match[2]));
-                }
-            }
-            preg_match_all('#^\s+?php_flag\s+([a-z_]+)\s+(.+)$#siUm', $data, $matches, PREG_SET_ORDER);
-            if ($matches) {
-                foreach ($matches as $match) {
-                    @ini_set($match[1], str_replace("\r", '', $match[2]));
-                }
-            }
-        }
-        return $this;
-    }
-
-    /**
-     * Parses input arguments
-     *
-     * @return $this
-     */
-    protected function _parseArgs()
-    {
-        $current = null;
-        foreach ($this->_rawArgs as $arg) {
-            $match = [];
-            if (preg_match(
-                '#^--([\w\d_-]{1,})(=(.*))?$#',
-                $arg,
-                $match
-            ) || preg_match(
-                '#^-([\w\d_]{1,})$#',
-                $arg,
-                $match
-            )
-            ) {
-                if (isset($match[3])) {
-                    $this->_args[$match[1]] = $match[3];
-                    $current = null;
-                } else {
-                    $current = $match[1];
-                    $this->_args[$current] = true;
-                }
-            } else {
-                if ($current) {
-                    $this->_args[$current] = $arg;
-                    $current = null;
-                } elseif (preg_match('#^([\w\d_]{1,})$#', $arg, $match)) {
-                    $this->_args[$match[1]] = true;
-                }
-            }
-        }
-        return $this;
-    }
-
-    /**
-     * Runs script
-     *
-     * @return $this
-     */
-    abstract public function run();
-
-    /**
-     * Shows usage help, if requested
-     *
-     * @return bool
-     */
-    protected function _showHelp()
-    {
-        if (isset($this->_args['h']) || isset($this->_args['help'])) {
-            echo $this->getUsageHelp();
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Retrieves usage help message
-     *
-     * @return string
-     */
-    public function getUsageHelp()
-    {
-        return <<<USAGE
-Usage:  php -f {$this->_entryPoint} -- [options]
-
-  -h            Short alias for help
-  help          This help
-USAGE;
-    }
-
-    /**
-     * Retrieves argument value by name. If argument is not found - returns FALSE.
-     *
-     * @param string $name the argument name
-     * @return mixed
-     */
-    public function getArg($name)
-    {
-        if (isset($this->_args[$name])) {
-            return $this->_args[$name];
-        }
-        return false;
-    }
-}
diff --git a/lib/internal/Magento/Framework/App/Area/FrontNameResolverInterface.php b/lib/internal/Magento/Framework/App/Area/FrontNameResolverInterface.php
index bbdd3787b1825ffa9c35882776a9173c03b9607a..e8a3e92263e7d9b50226911e4d445b1a663171f7 100644
--- a/lib/internal/Magento/Framework/App/Area/FrontNameResolverInterface.php
+++ b/lib/internal/Magento/Framework/App/Area/FrontNameResolverInterface.php
@@ -7,6 +7,10 @@
  */
 namespace Magento\Framework\App\Area;
 
+/**
+ * Interface FrontNameResolverInterface
+ * @api
+ */
 interface FrontNameResolverInterface
 {
     /**
diff --git a/lib/internal/Magento/Framework/App/AreaInterface.php b/lib/internal/Magento/Framework/App/AreaInterface.php
index 806a7983424599690e3b7f02443fb7e9b4b328a5..544ac56e19e6f10dd13c5a284d56dba2d6e4b010 100644
--- a/lib/internal/Magento/Framework/App/AreaInterface.php
+++ b/lib/internal/Magento/Framework/App/AreaInterface.php
@@ -6,6 +6,9 @@
  */
 namespace Magento\Framework\App;
 
+/**
+ * Interface AreaInterface
+ */
 interface AreaInterface
 {
     const PART_CONFIG = 'config';
diff --git a/lib/internal/Magento/Framework/App/AreaList.php b/lib/internal/Magento/Framework/App/AreaList.php
index 270fb22e36675b08576b06500e7cd6da38f39466..c010388797d870fa25e7aec9a192edef8ed0a73b 100644
--- a/lib/internal/Magento/Framework/App/AreaList.php
+++ b/lib/internal/Magento/Framework/App/AreaList.php
@@ -63,6 +63,7 @@ class AreaList
      *
      * @param string $frontName
      * @return null|string
+     * @api
      */
     public function getCodeByFrontName($frontName)
     {
@@ -84,6 +85,7 @@ class AreaList
      *
      * @param string $areaCode
      * @return string
+     * @api
      */
     public function getFrontName($areaCode)
     {
@@ -94,6 +96,7 @@ class AreaList
      * Retrieve area codes
      *
      * @return string[]
+     * @api
      */
     public function getCodes()
     {
@@ -105,6 +108,7 @@ class AreaList
      *
      * @param string $areaCode
      * @return string
+     * @api
      */
     public function getDefaultRouter($areaCode)
     {
diff --git a/lib/internal/Magento/Framework/App/Cache/Manager.php b/lib/internal/Magento/Framework/App/Cache/Manager.php
index fc49b8af25f568876eb2336c2aa690a296285a7b..3936853833b98fe671c4a748052d944184f6e6a9 100644
--- a/lib/internal/Magento/Framework/App/Cache/Manager.php
+++ b/lib/internal/Magento/Framework/App/Cache/Manager.php
@@ -85,8 +85,7 @@ class Manager
     public function clean(array $types)
     {
         foreach ($types as $type) {
-            $frontend = $this->pool->get($type);
-            $frontend->clean();
+            $this->cacheTypeList->cleanType($type);
         }
     }
 
diff --git a/lib/internal/Magento/Framework/App/Cache/ManagerApp.php b/lib/internal/Magento/Framework/App/Cache/ManagerApp.php
deleted file mode 100644
index 15f2f92ddf81fd1b66aebd41c93b1c211b405306..0000000000000000000000000000000000000000
--- a/lib/internal/Magento/Framework/App/Cache/ManagerApp.php
+++ /dev/null
@@ -1,154 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Framework\App\Cache;
-
-use Magento\Framework\App;
-use Magento\Framework\App\Console\Response;
-use Magento\Framework\AppInterface;
-
-/**
- * An application for managing cache status
- */
-class ManagerApp implements AppInterface
-{
-    /**#@+
-     * Request keys for managing caches
-     */
-    const KEY_TYPES = 'types';
-    const KEY_SET = 'set';
-    const KEY_CLEAN = 'clean';
-    const KEY_FLUSH = 'flush';
-    const KEY_STATUS = 'status';
-    /**#@- */
-
-    /**
-     * Console response
-     *
-     * @var Response
-     */
-    private $response;
-
-    /**
-     * Requested changes
-     *
-     * @var array
-     */
-    private $requestArgs;
-
-    /**
-     * Cache manager
-     *
-     * @var Manager
-     */
-    private $cacheManager;
-
-    /**
-     * Constructor
-     *
-     * @param Manager $cacheManager
-     * @param Response $response
-     * @param array $requestArgs
-     */
-    public function __construct(
-        Manager $cacheManager,
-        Response $response,
-        array $requestArgs
-    ) {
-        $this->cacheManager = $cacheManager;
-        $this->response = $response;
-        $this->requestArgs = $requestArgs;
-    }
-
-    /**
-     * {@inheritdoc}
-     * @return Response
-     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
-     */
-    public function launch()
-    {
-        $output = [];
-        $types = $this->getRequestedTypes();
-
-        $enabledTypes = [];
-        if (isset($this->requestArgs[self::KEY_SET])) {
-            $isEnabled = (bool)(int)$this->requestArgs[self::KEY_SET];
-            $changedTypes = $this->cacheManager->setEnabled($types, $isEnabled);
-            if ($isEnabled) {
-                $enabledTypes = $changedTypes;
-            }
-            if ($changedTypes) {
-                $output[] = 'Changed cache status:';
-                foreach ($changedTypes as $type) {
-                    $output[] = sprintf('%30s: %d -> %d', $type, !$isEnabled, $isEnabled);
-                }
-            } else {
-                $output[] = 'There is nothing to change in cache status';
-            }
-        }
-        if (isset($this->requestArgs[self::KEY_FLUSH])) {
-            $this->cacheManager->flush($types);
-            $output[] = 'Flushed cache types:';
-            $output[] = join("\n", $types);
-        } elseif (isset($this->requestArgs[self::KEY_CLEAN])) {
-            $this->cacheManager->clean($types);
-            $output[] = 'Cleaned cache types:';
-            $output[] = join("\n", $types);
-        } elseif (isset($this->requestArgs[self::KEY_STATUS])) {
-            $output[] = 'Current status:';
-            foreach ($this->cacheManager->getStatus() as $cache => $status) {
-                $output[] = sprintf('%30s: %d', $cache, $status);
-            }
-        } elseif (!empty($enabledTypes)) {
-            $this->cacheManager->clean($enabledTypes);
-            $output[] = 'Cleaned cache types:';
-            $output[] = join("\n", $enabledTypes);
-        }
-
-        $output[] = '';
-        $this->response->setBody(join("\n", $output));
-        return $this->response;
-    }
-
-    /**
-     * Maps requested type from request into the current registry of types
-     *
-     * @return string[]
-     * @throws \InvalidArgumentException
-     */
-    private function getRequestedTypes()
-    {
-        $requestedTypes = [];
-        if (isset($this->requestArgs[self::KEY_TYPES])) {
-            $requestedTypes = explode(',', $this->requestArgs[self::KEY_TYPES]);
-            $requestedTypes = array_filter(array_map('trim', $requestedTypes), 'strlen');
-        }
-        $availableTypes = $this->cacheManager->getAvailableTypes();
-        if (empty($requestedTypes)) {
-            return $availableTypes;
-        } else {
-            $unsupportedTypes = array_diff($requestedTypes, $availableTypes);
-            if ($unsupportedTypes) {
-                throw new \InvalidArgumentException(
-                    "The following requested cache types are not supported: '" . join("', '", $unsupportedTypes)
-                    . "'.\nSupported types: " . join(", ", $availableTypes) . ""
-                );
-            }
-            return array_values(array_intersect($availableTypes, $requestedTypes));
-        }
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function catchException(App\Bootstrap $bootstrap, \Exception $exception)
-    {
-        $this->response->setBody($exception->getMessage());
-        $this->response->terminateOnSend(false);
-        $this->response->sendResponse();
-        return false;
-    }
-}
diff --git a/lib/internal/Magento/Framework/App/Cache/Type/Config.php b/lib/internal/Magento/Framework/App/Cache/Type/Config.php
index ded73329969b9f7faec6409ed73715cab06390eb..506eff32a8e099edc9a4a9193b7e42bafdc2ac58 100644
--- a/lib/internal/Magento/Framework/App/Cache/Type/Config.php
+++ b/lib/internal/Magento/Framework/App/Cache/Type/Config.php
@@ -25,10 +25,40 @@ class Config extends TagScope implements CacheInterface
     const CACHE_TAG = 'CONFIG';
 
     /**
-     * @param FrontendPool $cacheFrontendPool
+     * @var \Magento\Framework\App\Cache\Type\FrontendPool
      */
-    public function __construct(FrontendPool $cacheFrontendPool)
+    private $cacheFrontendPool;
+
+    /**
+     * @param \Magento\Framework\App\Cache\Type\FrontendPool $cacheFrontendPool
+     */
+    public function __construct(\Magento\Framework\App\Cache\Type\FrontendPool $cacheFrontendPool)
+    {
+        $this->cacheFrontendPool = $cacheFrontendPool;
+    }
+
+    /**
+     * Retrieve cache frontend instance being decorated
+     *
+     * @return \Magento\Framework\Cache\FrontendInterface
+     */
+    protected function _getFrontend()
+    {
+        $frontend = parent::_getFrontend();
+        if (!$frontend) {
+            $frontend = $this->cacheFrontendPool->get(self::TYPE_IDENTIFIER);
+            $this->setFrontend($frontend);
+        }
+        return $frontend;
+    }
+
+    /**
+     * Retrieve cache tag name
+     *
+     * @return string
+     */
+    public function getTag()
     {
-        parent::__construct($cacheFrontendPool->get(self::TYPE_IDENTIFIER), self::CACHE_TAG);
+        return self::CACHE_TAG;
     }
 }
diff --git a/lib/internal/Magento/Framework/App/Config.php b/lib/internal/Magento/Framework/App/Config.php
index 047849f0034bde6164c2a054c81817e2daccdd2a..898a19a00ea5f20ff98bce5a7cb5eaa322972869 100644
--- a/lib/internal/Magento/Framework/App/Config.php
+++ b/lib/internal/Magento/Framework/App/Config.php
@@ -7,6 +7,8 @@
  */
 namespace Magento\Framework\App;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 class Config implements \Magento\Framework\App\Config\ScopeConfigInterface
 {
     /**
@@ -37,7 +39,7 @@ class Config implements \Magento\Framework\App\Config\ScopeConfigInterface
      */
     public function getValue(
         $path = null,
-        $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT,
+        $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
         $scopeCode = null
     ) {
         return $this->_scopePool->getScope($scope, $scopeCode)->getValue($path);
@@ -51,7 +53,7 @@ class Config implements \Magento\Framework\App\Config\ScopeConfigInterface
      * @param null|string $scopeCode
      * @return bool
      */
-    public function isSetFlag($path, $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, $scopeCode = null)
+    public function isSetFlag($path, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null)
     {
         return (bool) $this->getValue($path, $scope, $scopeCode);
     }
diff --git a/lib/internal/Magento/Framework/App/Config/Data.php b/lib/internal/Magento/Framework/App/Config/Data.php
index 3b5f17fe71639559575a77bc431fccc7071388f0..38389e71e40aaf297d4983bdde8377db615d5493 100644
--- a/lib/internal/Magento/Framework/App/Config/Data.php
+++ b/lib/internal/Magento/Framework/App/Config/Data.php
@@ -42,10 +42,7 @@ class Data implements DataInterface
     }
 
     /**
-     * Retrieve configuration value by path
-     *
-     * @param null|string $path
-     * @return array|string
+     * @inheritdoc
      */
     public function getValue($path = null)
     {
@@ -65,11 +62,7 @@ class Data implements DataInterface
     }
 
     /**
-     * Set configuration value
-     *
-     * @param string $path
-     * @param mixed $value
-     * @return void
+     * @inheritdoc
      */
     public function setValue($path, $value)
     {
diff --git a/lib/internal/Magento/Framework/App/Config/Data/ProcessorFactory.php b/lib/internal/Magento/Framework/App/Config/Data/ProcessorFactory.php
index 8f473e2a37b2ba3c9cf3a0e707dd43f9bbe70902..8084dcd5d08f45c755a9c5b0490bf1fea78f8894 100644
--- a/lib/internal/Magento/Framework/App/Config/Data/ProcessorFactory.php
+++ b/lib/internal/Magento/Framework/App/Config/Data/ProcessorFactory.php
@@ -30,21 +30,22 @@ class ProcessorFactory
     /**
      * Get concrete Processor Interface instance
      *
-     * @param string $model
+     * @param string $processorModel Classname of the instance to get
      * @return ProcessorInterface
-     * @throws \InvalidArgumentException
+     * @throws \InvalidArgumentException In case the given classname is not an instance of ProcessorInterface
+     * @api
      */
-    public function get($model)
+    public function get($processorModel)
     {
-        if (!isset($this->_pool[$model])) {
-            $instance = $this->_objectManager->create($model);
+        if (!isset($this->_pool[$processorModel])) {
+            $instance = $this->_objectManager->create($processorModel);
             if (!$instance instanceof ProcessorInterface) {
                 throw new \InvalidArgumentException(
-                    $model . ' is not instance of \Magento\Framework\App\Config\Data\ProcessorInterface'
+                    $processorModel . ' is not instance of \Magento\Framework\App\Config\Data\ProcessorInterface'
                 );
             }
-            $this->_pool[$model] = $instance;
+            $this->_pool[$processorModel] = $instance;
         }
-        return $this->_pool[$model];
+        return $this->_pool[$processorModel];
     }
 }
diff --git a/lib/internal/Magento/Framework/App/Config/Data/ProcessorInterface.php b/lib/internal/Magento/Framework/App/Config/Data/ProcessorInterface.php
index 71102131f42cf4071b6d213d225ac8178956945a..d4467339676739d2e92250b986d992458772cc68 100644
--- a/lib/internal/Magento/Framework/App/Config/Data/ProcessorInterface.php
+++ b/lib/internal/Magento/Framework/App/Config/Data/ProcessorInterface.php
@@ -1,19 +1,22 @@
 <?php
 /**
- * Processor interface
- *
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 namespace Magento\Framework\App\Config\Data;
 
+/**
+ * Processes data from admin store configuration fields
+ *
+ * @api
+ */
 interface ProcessorInterface
 {
     /**
      * Process config value
      *
-     * @param string $value
-     * @return string
+     * @param string $value Raw value of the configuration field
+     * @return string Processed value
      */
     public function processValue($value);
 }
diff --git a/lib/internal/Magento/Framework/App/Config/DataInterface.php b/lib/internal/Magento/Framework/App/Config/DataInterface.php
index bbdaf54d1c342a11803527f92160ebacef27a0a6..b07ca0e0df1fc3ce8085227057148619c371f0f9 100644
--- a/lib/internal/Magento/Framework/App/Config/DataInterface.php
+++ b/lib/internal/Magento/Framework/App/Config/DataInterface.php
@@ -5,11 +5,27 @@
  */
 namespace Magento\Framework\App\Config;
 
+/**
+ * Configuration data storage
+ *
+ * @api
+ */
 interface DataInterface
 {
     /**
+     * Retrieve configuration value by path
+     *
      * @param string|null $path
-     * @return string|array
+     * @return mixed
      */
     public function getValue($path);
+
+    /**
+     * Set configuration value by path
+     *
+     * @param string $path
+     * @param mixed $value
+     * @return void
+     */
+    public function setValue($path, $value);
 }
diff --git a/lib/internal/Magento/Framework/App/Config/Initial.php b/lib/internal/Magento/Framework/App/Config/Initial.php
index 68db7b1eb84d42c669f3874b180038292a087983..3b2beb5ca37423ee054d94d2d3289bdacd21bca5 100644
--- a/lib/internal/Magento/Framework/App/Config/Initial.php
+++ b/lib/internal/Magento/Framework/App/Config/Initial.php
@@ -7,6 +7,8 @@
  */
 namespace Magento\Framework\App\Config;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 class Initial
 {
     /**
@@ -50,14 +52,14 @@ class Initial
     /**
      * Get initial data by given scope
      *
-     * @param string $scope
+     * @param string $scope Format is scope type and scope code separated by pipe: e.g. "type|code"
      * @return array
      */
     public function getData($scope)
     {
         list($scopeType, $scopeCode) = array_pad(explode('|', $scope), 2, null);
 
-        if (\Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT == $scopeType) {
+        if (ScopeConfigInterface::SCOPE_TYPE_DEFAULT == $scopeType) {
             return isset($this->_data[$scopeType]) ? $this->_data[$scopeType] : [];
         } elseif ($scopeCode) {
             return isset($this->_data[$scopeType][$scopeCode]) ? $this->_data[$scopeType][$scopeCode] : [];
diff --git a/lib/internal/Magento/Framework/App/Config/MutableScopeConfigInterface.php b/lib/internal/Magento/Framework/App/Config/MutableScopeConfigInterface.php
index 37a371b547f40439addcfad205d29dd9c178fb07..f68048ddc94611267e17df9c85eb203bf28097a2 100644
--- a/lib/internal/Magento/Framework/App/Config/MutableScopeConfigInterface.php
+++ b/lib/internal/Magento/Framework/App/Config/MutableScopeConfigInterface.php
@@ -8,6 +8,9 @@
 
 namespace Magento\Framework\App\Config;
 
+/**
+ * @api
+ */
 interface MutableScopeConfigInterface extends \Magento\Framework\App\Config\ScopeConfigInterface
 {
     /**
@@ -15,14 +18,14 @@ interface MutableScopeConfigInterface extends \Magento\Framework\App\Config\Scop
      *
      * @param string $path
      * @param mixed $value
-     * @param string $scope
+     * @param string $scopeType
      * @param null|string $scopeCode
      * @return void
      */
     public function setValue(
         $path,
         $value,
-        $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT,
+        $scopeType = \Magento\Framework\App\Config\ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
         $scopeCode = null
     );
 }
diff --git a/lib/internal/Magento/Framework/App/Config/ReinitableConfigInterface.php b/lib/internal/Magento/Framework/App/Config/ReinitableConfigInterface.php
index 5b9d9d78eb3b4789a2ac6477e5e686ff3e4f0c6f..f9fc887a878e0ec0b73e2ad956ae0ff3b1ae166a 100644
--- a/lib/internal/Magento/Framework/App/Config/ReinitableConfigInterface.php
+++ b/lib/internal/Magento/Framework/App/Config/ReinitableConfigInterface.php
@@ -8,6 +8,9 @@
 
 namespace Magento\Framework\App\Config;
 
+/**
+ * @api
+ */
 interface ReinitableConfigInterface extends \Magento\Framework\App\Config\MutableScopeConfigInterface
 {
     /**
diff --git a/lib/internal/Magento/Framework/App/Config/Resource/ConfigInterface.php b/lib/internal/Magento/Framework/App/Config/Resource/ConfigInterface.php
index aa0e06048980767a44d1f0688ebe6956bbb13355..8084c21ab0d9cd26be2319dd9cfad4e00992dae7 100644
--- a/lib/internal/Magento/Framework/App/Config/Resource/ConfigInterface.php
+++ b/lib/internal/Magento/Framework/App/Config/Resource/ConfigInterface.php
@@ -6,12 +6,12 @@
 namespace Magento\Framework\App\Config\Resource;
 
 /**
- * Resource Config Interface
+ * Resource for storing store configuration values
  */
 interface ConfigInterface
 {
     /**
-     * Save config value
+     * Save config value to the storage resource
      *
      * @param string $path
      * @param string $value
@@ -22,7 +22,7 @@ interface ConfigInterface
     public function saveConfig($path, $value, $scope, $scopeId);
 
     /**
-     * Delete config value
+     * Delete config value from the storage resource
      *
      * @param string $path
      * @param string $scope
diff --git a/lib/internal/Magento/Framework/App/Config/Scope/ReaderInterface.php b/lib/internal/Magento/Framework/App/Config/Scope/ReaderInterface.php
index bf20ecd1d530881e76749275afcff6dbd87939d1..cdcbb42828e51d4ff2f3e13c9449037c64ac9ad5 100644
--- a/lib/internal/Magento/Framework/App/Config/Scope/ReaderInterface.php
+++ b/lib/internal/Magento/Framework/App/Config/Scope/ReaderInterface.php
@@ -12,7 +12,9 @@ interface ReaderInterface
     /**
      * Read configuration scope
      *
+     * @param string|null $scopeType
+     * @throws \Exception May throw an exception if the given scope is invalid
      * @return array
      */
-    public function read();
+    public function read($scopeType = null);
 }
diff --git a/lib/internal/Magento/Framework/App/Config/ScopeConfigInterface.php b/lib/internal/Magento/Framework/App/Config/ScopeConfigInterface.php
index ac84e7358b5d2599a531ea45047d92626370bd44..e98fe284024f1780d731500d810516011b7528ba 100644
--- a/lib/internal/Magento/Framework/App/Config/ScopeConfigInterface.php
+++ b/lib/internal/Magento/Framework/App/Config/ScopeConfigInterface.php
@@ -8,25 +8,33 @@
 
 namespace Magento\Framework\App\Config;
 
+/**
+ * @api
+ */
 interface ScopeConfigInterface
 {
     /**
-     * Retrieve config value by path and scope
+     * Default scope type
+     */
+    const SCOPE_TYPE_DEFAULT = 'default';
+
+    /**
+     * Retrieve config value by path and scope.
      *
-     * @param string $path
-     * @param string $scope
+     * @param string $path The path through the tree of configuration values, e.g., 'general/store_information/name'
+     * @param string $scopeType The scope to use to determine config value, e.g., 'store' or 'default'
      * @param null|string $scopeCode
      * @return mixed
      */
-    public function getValue($path, $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, $scopeCode = null);
+    public function getValue($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null);
 
     /**
      * Retrieve config flag by path and scope
      *
-     * @param string $path
-     * @param string $scope
+     * @param string $path The path through the tree of configuration values, e.g., 'general/store_information/name'
+     * @param string $scopeType The scope to use to determine config value, e.g., 'store' or 'default'
      * @param null|string $scopeCode
      * @return bool
      */
-    public function isSetFlag($path, $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, $scopeCode = null);
+    public function isSetFlag($path, $scopeType = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeCode = null);
 }
diff --git a/lib/internal/Magento/Framework/App/Config/ScopePool.php b/lib/internal/Magento/Framework/App/Config/ScopePool.php
index 34b24deb0028b63402dc2d169f2dbb47566dae9d..1a15575b1a514a0a0a04b728e454c2c18ef0645e 100644
--- a/lib/internal/Magento/Framework/App/Config/ScopePool.php
+++ b/lib/internal/Magento/Framework/App/Config/ScopePool.php
@@ -5,6 +5,8 @@
  */
 namespace Magento\Framework\App\Config;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 class ScopePool
 {
     const CACHE_TAG = 'config_scopes';
@@ -78,7 +80,7 @@ class ScopePool
                 $data = unserialize($data);
             } else {
                 $reader = $this->_readerPool->getReader($scopeType);
-                if ($scopeType === \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT) {
+                if ($scopeType === ScopeConfigInterface::SCOPE_TYPE_DEFAULT) {
                     $data = $reader->read();
                 } else {
                     $data = $reader->read($scopeCode);
@@ -111,7 +113,7 @@ class ScopePool
     protected function _getScopeCode($scopeType, $scopeCode)
     {
         if (($scopeCode === null || is_numeric($scopeCode))
-            && $scopeType !== \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+            && $scopeType !== ScopeConfigInterface::SCOPE_TYPE_DEFAULT
         ) {
             $scopeResolver = $this->_scopeResolverPool->get($scopeType);
             $scopeCode = $scopeResolver->getScope($scopeCode);
diff --git a/lib/internal/Magento/Framework/App/Config/Storage/Writer.php b/lib/internal/Magento/Framework/App/Config/Storage/Writer.php
index b98e4074efa1b953fac38e02be2bbe435568d8c5..63b5ae83dfec68c85f61ebf17ae11396b485373e 100644
--- a/lib/internal/Magento/Framework/App/Config/Storage/Writer.php
+++ b/lib/internal/Magento/Framework/App/Config/Storage/Writer.php
@@ -7,6 +7,8 @@
  */
 namespace Magento\Framework\App\Config\Storage;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 class Writer implements \Magento\Framework\App\Config\Storage\WriterInterface
 {
     /**
@@ -32,7 +34,7 @@ class Writer implements \Magento\Framework\App\Config\Storage\WriterInterface
      * @param   int $scopeId
      * @return  void
      */
-    public function delete($path, $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, $scopeId = 0)
+    public function delete($path, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeId = 0)
     {
         $this->_resource->deleteConfig(rtrim($path, '/'), $scope, $scopeId);
     }
@@ -46,7 +48,7 @@ class Writer implements \Magento\Framework\App\Config\Storage\WriterInterface
      * @param int $scopeId
      * @return void
      */
-    public function save($path, $value, $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, $scopeId = 0)
+    public function save($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeId = 0)
     {
         $this->_resource->saveConfig(rtrim($path, '/'), $value, $scope, $scopeId);
     }
diff --git a/lib/internal/Magento/Framework/App/Config/Storage/WriterInterface.php b/lib/internal/Magento/Framework/App/Config/Storage/WriterInterface.php
index 3a3a3af6241361ca757699bf1d1e37ecfab6ad45..67b2aebd5d4a6da8d19eaad74175ca26726a57e0 100644
--- a/lib/internal/Magento/Framework/App/Config/Storage/WriterInterface.php
+++ b/lib/internal/Magento/Framework/App/Config/Storage/WriterInterface.php
@@ -7,6 +7,8 @@
  */
 namespace Magento\Framework\App\Config\Storage;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
+
 interface WriterInterface
 {
     /**
@@ -17,7 +19,7 @@ interface WriterInterface
      * @param   int $scopeId
      * @return void
      */
-    public function delete($path, $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, $scopeId = 0);
+    public function delete($path, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeId = 0);
 
     /**
      * Save config value to storage
@@ -28,5 +30,5 @@ interface WriterInterface
      * @param int $scopeId
      * @return void
      */
-    public function save($path, $value, $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, $scopeId = 0);
+    public function save($path, $value, $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, $scopeId = 0);
 }
diff --git a/lib/internal/Magento/Framework/App/Config/Value.php b/lib/internal/Magento/Framework/App/Config/Value.php
index 17c50d20b8b3a854cb7f61a319ba5d21b21e1dac..92ee527a9c48eb77a35f527c2c471c2507d1b546 100644
--- a/lib/internal/Magento/Framework/App/Config/Value.php
+++ b/lib/internal/Magento/Framework/App/Config/Value.php
@@ -91,7 +91,7 @@ class Value extends \Magento\Framework\Model\AbstractModel implements \Magento\F
     {
         return (string)$this->_config->getValue(
             $this->getPath(),
-            $this->getScope() ?: \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT,
+            $this->getScope() ?: ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
             $this->getScopeCode()
         );
     }
diff --git a/lib/internal/Magento/Framework/App/Filesystem/DirectoryList.php b/lib/internal/Magento/Framework/App/Filesystem/DirectoryList.php
index b73959ca803be367c533b64e33041669d51712f3..cb3767cc11fce65c015b2e6bcedcee9e253fca17 100644
--- a/lib/internal/Magento/Framework/App/Filesystem/DirectoryList.php
+++ b/lib/internal/Magento/Framework/App/Filesystem/DirectoryList.php
@@ -90,6 +90,11 @@ class DirectoryList extends \Magento\Framework\Filesystem\DirectoryList
      */
     const SESSION = 'session';
 
+    /**
+     * Directory for Setup application
+     */
+    const SETUP = 'setup';
+
     /**
      * Dependency injection related file directory
      */
@@ -139,6 +144,7 @@ class DirectoryList extends \Magento\Framework\Filesystem\DirectoryList
             self::UPLOAD => [parent::PATH => 'pub/media/upload', parent::URL_PATH => 'pub/media/upload'],
             self::TMP_MATERIALIZATION_DIR => [parent::PATH => 'var/view_preprocessed'],
             self::TEMPLATE_MINIFICATION_DIR => [parent::PATH => 'var/view_preprocessed/html'],
+            self::SETUP => [parent::PATH => 'setup/src'],
         ];
         return parent::getDefaultConfig() + $result;
     }
diff --git a/lib/internal/Magento/Framework/App/MutableScopeConfig.php b/lib/internal/Magento/Framework/App/MutableScopeConfig.php
index c94fb73f9d5e4cb35ddf246710bf464a932a25ad..418817465bd6f11af59b2ae5f4eaf53eea7559cd 100644
--- a/lib/internal/Magento/Framework/App/MutableScopeConfig.php
+++ b/lib/internal/Magento/Framework/App/MutableScopeConfig.php
@@ -9,6 +9,7 @@
 namespace Magento\Framework\App;
 
 use Magento\Framework\App\Config\MutableScopeConfigInterface;
+use Magento\Framework\App\Config\ScopeConfigInterface;
 
 class MutableScopeConfig extends Config implements MutableScopeConfigInterface
 {
@@ -24,7 +25,7 @@ class MutableScopeConfig extends Config implements MutableScopeConfigInterface
     public function setValue(
         $path,
         $value,
-        $scope = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT,
+        $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
         $scopeCode = null
     ) {
         if (empty($scopeCode)) {
diff --git a/lib/internal/Magento/Framework/App/Request/Http.php b/lib/internal/Magento/Framework/App/Request/Http.php
index c09ead13054e791d5e6bff403623545b4e24f9e6..e6e502cf38171387aef13cdf606845d082f8664d 100644
--- a/lib/internal/Magento/Framework/App/Request/Http.php
+++ b/lib/internal/Magento/Framework/App/Request/Http.php
@@ -7,6 +7,7 @@
  */
 namespace Magento\Framework\App\Request;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\App\RequestInterface;
 use Magento\Framework\App\Route\ConfigInterface\Proxy as ConfigInterface;
 use Magento\Framework\HTTP\PhpEnvironment\Request;
@@ -384,7 +385,7 @@ class Http extends Request implements RequestInterface
         $offLoaderHeader = trim(
             (string)$config->getValue(
                 self::XML_PATH_OFFLOADER_HEADER,
-                \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT
+                ScopeConfigInterface::SCOPE_TYPE_DEFAULT
             )
         );
 
diff --git a/lib/internal/Magento/Framework/App/Resource.php b/lib/internal/Magento/Framework/App/Resource.php
index b38629a460a4fa8a7ed78c1a9e77450ec23c1c8a..b498ec9d349fea88b942b42d2ff6277c23a2449a 100644
--- a/lib/internal/Magento/Framework/App/Resource.php
+++ b/lib/internal/Magento/Framework/App/Resource.php
@@ -126,6 +126,7 @@ class Resource
      * @param   string|string[] $modelEntity
      * @param   string $connectionName
      * @return  string
+     * @api
      */
     public function getTableName($modelEntity, $connectionName = self::DEFAULT_READ_RESOURCE)
     {
diff --git a/lib/internal/Magento/Framework/App/Route/ConfigInterface.php b/lib/internal/Magento/Framework/App/Route/ConfigInterface.php
index c6798f7ce4ab659e813488a155d0aa467ac41449..d96a4af89eac0d2a4c3932995643c1cbccec25e5 100644
--- a/lib/internal/Magento/Framework/App/Route/ConfigInterface.php
+++ b/lib/internal/Magento/Framework/App/Route/ConfigInterface.php
@@ -1,12 +1,15 @@
 <?php
 /**
- * Routes configuration interface
- *
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
 namespace Magento\Framework\App\Route;
 
+/**
+ * Routes configuration interface
+ *
+ * @api
+ */
 interface ConfigInterface
 {
     /**
@@ -32,7 +35,7 @@ interface ConfigInterface
      *
      * @param string $frontName
      * @param string $scope
-     * @return array
+     * @return string[]
      */
     public function getModulesByFrontName($frontName, $scope = null);
 }
diff --git a/lib/internal/Magento/Framework/App/ScopeInterface.php b/lib/internal/Magento/Framework/App/ScopeInterface.php
index d244ec5bf3a1f612722795b72e938fef77f1102f..77c8a8b890ac209400fdf8005636ee869d8ecfd0 100644
--- a/lib/internal/Magento/Framework/App/ScopeInterface.php
+++ b/lib/internal/Magento/Framework/App/ScopeInterface.php
@@ -7,11 +7,6 @@ namespace Magento\Framework\App;
 
 interface ScopeInterface
 {
-    /**
-     * Default scope type
-     */
-    const SCOPE_DEFAULT = 'default';
-
     /**
      * Retrieve scope code
      *
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/AbstractShellTest.php b/lib/internal/Magento/Framework/App/Test/Unit/AbstractShellTest.php
deleted file mode 100644
index 07c320180d3e1c62ee2a3de19bf511f301a85f91..0000000000000000000000000000000000000000
--- a/lib/internal/Magento/Framework/App/Test/Unit/AbstractShellTest.php
+++ /dev/null
@@ -1,75 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Framework\App\Test\Unit;
-
-class AbstractShellTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \Magento\Framework\App\AbstractShell | \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $_model;
-
-    protected function setUp()
-    {
-        $this->_model = $this->getMockBuilder(
-            '\Magento\Framework\App\AbstractShell'
-        )->disableOriginalConstructor()->setMethods(
-            ['_applyPhpVariables']
-        )->getMockForAbstractClass();
-    }
-
-    protected function tearDown()
-    {
-        unset($this->_model);
-    }
-
-    /**
-     * @param array $arguments
-     * @param string $argName
-     * @param string $expectedValue
-     *
-     * @dataProvider setGetArgDataProvider
-     */
-    public function testSetGetArg($arguments, $argName, $expectedValue)
-    {
-        $this->_model->setRawArgs($arguments);
-        $this->assertEquals($this->_model->getArg($argName), $expectedValue);
-    }
-
-    /**
-     * @return array
-     */
-    public function setGetArgDataProvider()
-    {
-        return [
-            'argument with no value' => [
-                'arguments' => ['argument', 'argument2'],
-                'argName' => 'argument',
-                'expectedValue' => true,
-            ],
-            'dashed argument with value' => [
-                'arguments' => ['-argument', 'value'],
-                'argName' => 'argument',
-                'expectedValue' => 'value',
-            ],
-            'double-dashed argument with separate value' => [
-                'arguments' => ['--argument-name', 'value'],
-                'argName' => 'argument-name',
-                'expectedValue' => 'value',
-            ],
-            'double-dashed argument with included value' => [
-                'arguments' => ['--argument-name=value'],
-                'argName' => 'argument-name',
-                'expectedValue' => 'value',
-            ],
-            'argument with value, then single argument with no value' => [
-                'arguments' => ['-argument', 'value', 'argument2'],
-                'argName' => 'argument',
-                'expectedValue' => 'value',
-            ]
-        ];
-    }
-}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Cache/ManagerAppTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Cache/ManagerAppTest.php
deleted file mode 100644
index b3d7c803071dd9a231db4224c85c8c4c3f6a74bb..0000000000000000000000000000000000000000
--- a/lib/internal/Magento/Framework/App/Test/Unit/Cache/ManagerAppTest.php
+++ /dev/null
@@ -1,228 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Framework\App\Test\Unit\Cache;
-
-use \Magento\Framework\App\Cache\ManagerApp;
-
-class ManagerAppTest extends \PHPUnit_Framework_TestCase
-{
-    /**
-     * @var \Magento\Framework\App\Cache\Manager|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $cacheManager;
-
-    /**
-     * @var \Magento\Framework\App\Console\Response|\PHPUnit_Framework_MockObject_MockObject
-     */
-    private $response;
-
-    protected function setUp()
-    {
-        $this->cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false);
-        $this->cacheManager->expects($this->any())
-            ->method('getAvailableTypes')
-            ->will($this->returnValue(['foo', 'bar', 'baz']));
-        $this->cacheManager->expects($this->any())
-            ->method('getStatus')
-            ->will($this->returnValue(['foo' => true, 'bar' => true, 'baz' => false]));
-        $this->response = $this->getMock('Magento\Framework\App\Console\Response', [], [], '', false);
-    }
-
-    public function testLaunchStatus()
-    {
-        $requestArgs = [
-            ManagerApp::KEY_STATUS => true
-        ];
-
-        $this->response->expects($this->once())
-            ->method('setBody')
-            ->with(
-                $this->matches("Current status:%afoo: 1%abar: 1%abaz: 0")
-            );
-
-        $model = new ManagerApp($this->cacheManager, $this->response, $requestArgs);
-        $model->launch();
-    }
-
-    public function testLaunchEnable()
-    {
-        $requestArgs = [
-            ManagerApp::KEY_SET => true,
-            ManagerApp::KEY_TYPES => 'foo,,bar, baz,',
-        ];
-        $this->cacheManager->expects($this->once())
-            ->method('setEnabled')
-            ->with(['foo', 'bar', 'baz'], true)
-            ->will($this->returnValue(['baz']));
-        $this->cacheManager->expects($this->once())
-            ->method('clean')
-            ->with(['baz']);
-        $this->response->expects($this->once())
-            ->method('setBody')
-            ->with(
-                $this->matches("Changed cache status:\n%abaz: 0 -> 1\nCleaned cache types:\nbaz")
-            );
-
-        $model = new ManagerApp($this->cacheManager, $this->response, $requestArgs);
-        $model->launch();
-    }
-
-    public function testLaunchDisable()
-    {
-        $requestArgs = [
-            ManagerApp::KEY_SET => false,
-            ManagerApp::KEY_TYPES => 'foo,,bar, baz,',
-        ];
-        $this->cacheManager->expects($this->once())
-            ->method('setEnabled')
-            ->with(['foo', 'bar', 'baz'], false)
-            ->will($this->returnValue(['baz']));
-        $this->cacheManager->expects($this->never())
-            ->method('clean');
-        $this->response->expects($this->once())
-            ->method('setBody')
-            ->with(
-                $this->matches("Changed cache status:\n%abaz: 1 -> 0\n")
-            );
-
-        $model = new ManagerApp($this->cacheManager, $this->response, $requestArgs);
-        $model->launch();
-    }
-
-    public function testLaunchFlush()
-    {
-        $requestArgs = [
-            ManagerApp::KEY_FLUSH => true,
-            ManagerApp::KEY_TYPES => 'foo,bar',
-        ];
-        $this->cacheManager->expects($this->never())
-            ->method('setEnabled');
-        $this->cacheManager->expects($this->once())
-            ->method('flush')
-            ->with(['foo', 'bar']);
-        $this->cacheManager->expects($this->never())
-            ->method('clean');
-        $this->response->expects($this->once())
-            ->method('setBody')
-            ->with(
-                $this->matches("Flushed cache types:\nfoo\nbar")
-            );
-
-        $model = new ManagerApp($this->cacheManager, $this->response, $requestArgs);
-        $model->launch();
-    }
-
-    public function testLaunchClean()
-    {
-        $requestArgs = [
-            ManagerApp::KEY_CLEAN => true,
-            ManagerApp::KEY_TYPES => 'foo,bar',
-        ];
-        $this->cacheManager->expects($this->never())
-            ->method('setEnabled');
-        $this->cacheManager->expects($this->never())
-            ->method('flush');
-        $this->cacheManager->expects($this->once())
-            ->method('clean')
-            ->with(['foo', 'bar']);
-        $this->response->expects($this->once())
-            ->method('setBody')
-            ->with(
-                $this->matches("Cleaned cache types:\nfoo\nbar")
-            );
-
-        $model = new ManagerApp($this->cacheManager, $this->response, $requestArgs);
-        $model->launch();
-    }
-
-    public function testLaunchSetAndClean()
-    {
-        $requestArgs = [
-            ManagerApp::KEY_SET => true,
-            ManagerApp::KEY_CLEAN => true,
-            ManagerApp::KEY_TYPES => 'foo,bar',
-        ];
-        $this->cacheManager->expects($this->once())
-            ->method('setEnabled')
-            ->with(['foo', 'bar'], true)
-            ->will($this->returnValue(['foo']));
-        $this->cacheManager->expects($this->never())
-            ->method('flush');
-        $this->cacheManager->expects($this->once())
-            ->method('clean')
-            ->with(['foo', 'bar']);
-        $this->response->expects($this->once())
-            ->method('setBody')
-            ->with(
-                $this->matches("Changed cache status:\n%afoo: 0 -> 1\nCleaned cache types:\nfoo\nbar")
-            );
-
-        $model = new ManagerApp($this->cacheManager, $this->response, $requestArgs);
-        $model->launch();
-    }
-
-    public function testLaunchAll()
-    {
-        $requestArgs = [
-            ManagerApp::KEY_SET => true,
-            ManagerApp::KEY_FLUSH => true,
-            ManagerApp::KEY_CLEAN => true,
-            ManagerApp::KEY_TYPES => 'foo,baz',
-        ];
-        $this->cacheManager->expects($this->once())
-            ->method('setEnabled')
-            ->with(['foo', 'baz'], true)
-            ->will($this->returnValue(['baz']));
-        $this->cacheManager->expects($this->once())
-            ->method('flush')
-            ->with(['foo', 'baz']);
-        $this->cacheManager->expects($this->never())
-            ->method('clean');
-        $this->response->expects($this->once())
-            ->method('setBody')
-            ->with(
-                $this->matches("Changed cache status:\n%abaz: 0 -> 1%aFlushed cache types:\nfoo\nbaz")
-            );
-
-        $model = new ManagerApp($this->cacheManager, $this->response, $requestArgs);
-        $model->launch();
-    }
-
-    /**
-     * @expectedException \InvalidArgumentException
-     * @expectedExceptionMessage The following requested cache types are not supported: 'unsupported', 'wrong'
-     */
-    public function testLaunchWithUnsupportedCacheTypes()
-    {
-        $requestArgs = [
-            ManagerApp::KEY_SET => true,
-            ManagerApp::KEY_TYPES => 'foo,unsupported,wrong,bar',
-        ];
-        $cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false);
-        $cacheManager->expects($this->any())
-            ->method('getAvailableTypes')
-            ->will($this->returnValue(['foo', 'bar', 'baz']));
-        $cacheManager->expects($this->never())
-            ->method('setEnabled');
-
-        $model = new ManagerApp($cacheManager, $this->response, $requestArgs);
-        $model->launch();
-    }
-
-    public function testCatchException()
-    {
-        $exceptionMessage = 'Exception message';
-        $model = new ManagerApp($this->cacheManager, $this->response, []);
-        $this->response->expects($this->once())
-            ->method('setBody')
-            ->with($exceptionMessage);
-        $this->assertFalse($model->catchException(
-            $this->getMock('Magento\Framework\App\Bootstrap', [], [], '', false),
-            new \Exception($exceptionMessage)
-        ));
-    }
-}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Cache/Type/ConfigTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Type/ConfigTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..c6887709da50fbd2bf4fdb303f3e256749a4e197
--- /dev/null
+++ b/lib/internal/Magento/Framework/App/Test/Unit/Cache/Type/ConfigTest.php
@@ -0,0 +1,169 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\App\Test\Unit\Cache\Type;
+
+use Magento\Framework\App\Cache\Type\FrontendPool;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class ConfigTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\Cache\Type\Config
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\Cache\FrontendInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $frontendMock;
+
+    protected function setUp()
+    {
+        $cacheFrontendPoolMock = $this->getMockBuilder('Magento\Framework\App\Cache\Type\FrontendPool')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $this->model = (new ObjectManager($this))->getObject(
+            'Magento\Framework\App\Cache\Type\Config',
+            ['cacheFrontendPool' => $cacheFrontendPoolMock]
+        );
+        $this->frontendMock = $this->getMock('Magento\Framework\Cache\FrontendInterface');
+        $cacheFrontendPoolMock->expects($this->once())
+            ->method('get')
+            ->with(\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER)
+            ->willReturn($this->frontendMock);
+    }
+
+    /**
+     * @param string $method
+     * @param array $params
+     * @param mixed $expectedResult
+     * @dataProvider proxyMethodDataProvider
+     */
+    public function testProxyMethod($method, $params, $expectedResult)
+    {
+        $helper = new \Magento\Framework\TestFramework\Unit\Helper\ProxyTesting();
+        $result = $helper->invokeWithExpectations($this->model, $this->frontendMock, $method, $params, $expectedResult);
+        $this->assertSame($expectedResult, $result);
+    }
+
+    /**
+     * @return array
+     */
+    public function proxyMethodDataProvider()
+    {
+        return [
+            ['test', ['record_id'], 111],
+            ['load', ['record_id'], '111'],
+            ['remove', ['record_id'], true],
+            ['getBackend', [], $this->getMock('Zend_Cache_Backend')],
+            ['getLowLevelFrontend', [], $this->getMock('Zend_Cache_Core')],
+        ];
+    }
+
+    public function testSave()
+    {
+        $expectedResult = new \stdClass();
+        $this->frontendMock->expects(
+            $this->once()
+        )->method(
+            'save'
+        )->with(
+            'test_value',
+            'test_id',
+            ['test_tag_one', 'test_tag_two', \Magento\Framework\App\Cache\Type\Config::CACHE_TAG],
+            111
+        )->will(
+            $this->returnValue($expectedResult)
+        );
+        $actualResult = $this->model->save('test_value', 'test_id', ['test_tag_one', 'test_tag_two'], 111);
+        $this->assertSame($expectedResult, $actualResult);
+    }
+
+    public function testCleanModeAll()
+    {
+        $expectedResult = new \stdClass();
+        $this->frontendMock->expects(
+            $this->once()
+        )->method(
+            'clean'
+        )->with(
+            \Zend_Cache::CLEANING_MODE_MATCHING_TAG,
+            [\Magento\Framework\App\Cache\Type\Config::CACHE_TAG]
+        )->will(
+            $this->returnValue($expectedResult)
+        );
+        $actualResult = $this->model->clean(
+            \Zend_Cache::CLEANING_MODE_ALL,
+            ['ignored_tag_one', 'ignored_tag_two']
+        );
+        $this->assertSame($expectedResult, $actualResult);
+    }
+
+    public function testCleanModeMatchingTag()
+    {
+        $expectedResult = new \stdClass();
+        $this->frontendMock->expects(
+            $this->once()
+        )->method(
+            'clean'
+        )->with(
+            \Zend_Cache::CLEANING_MODE_MATCHING_TAG,
+            ['test_tag_one', 'test_tag_two', \Magento\Framework\App\Cache\Type\Config::CACHE_TAG]
+        )->will(
+            $this->returnValue($expectedResult)
+        );
+        $actualResult = $this->model->clean(
+            \Zend_Cache::CLEANING_MODE_MATCHING_TAG,
+            ['test_tag_one', 'test_tag_two']
+        );
+        $this->assertSame($expectedResult, $actualResult);
+    }
+
+    /**
+     * @param bool $fixtureResultOne
+     * @param bool $fixtureResultTwo
+     * @param bool $expectedResult
+     * @dataProvider cleanModeMatchingAnyTagDataProvider
+     */
+    public function testCleanModeMatchingAnyTag($fixtureResultOne, $fixtureResultTwo, $expectedResult)
+    {
+        $this->frontendMock->expects(
+            $this->at(0)
+        )->method(
+            'clean'
+        )->with(
+            \Zend_Cache::CLEANING_MODE_MATCHING_TAG,
+            ['test_tag_one', \Magento\Framework\App\Cache\Type\Config::CACHE_TAG]
+        )->will(
+            $this->returnValue($fixtureResultOne)
+        );
+        $this->frontendMock->expects(
+            $this->at(1)
+        )->method(
+            'clean'
+        )->with(
+            \Zend_Cache::CLEANING_MODE_MATCHING_TAG,
+            ['test_tag_two', \Magento\Framework\App\Cache\Type\Config::CACHE_TAG]
+        )->will(
+            $this->returnValue($fixtureResultTwo)
+        );
+        $actualResult = $this->model->clean(
+            \Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG,
+            ['test_tag_one', 'test_tag_two']
+        );
+        $this->assertEquals($expectedResult, $actualResult);
+    }
+
+    public function cleanModeMatchingAnyTagDataProvider()
+    {
+        return [
+            'failure, failure' => [false, false, false],
+            'failure, success' => [false, true, true],
+            'success, failure' => [true, false, true],
+            'success, success' => [true, true, true]
+        ];
+    }
+}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Config/Storage/WriterTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Config/Storage/WriterTest.php
index 57040f09ee4dd82eb4ec80df99f0b827cc859573..887a1cf477663f00253816aed0bfdd273cd6fe5f 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/Config/Storage/WriterTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/Config/Storage/WriterTest.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Framework\App\Test\Unit\Config\Storage;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\App\ScopeInterface;
 
 class WriterTest extends \PHPUnit_Framework_TestCase
@@ -40,7 +41,7 @@ class WriterTest extends \PHPUnit_Framework_TestCase
     {
         $this->resource->expects($this->once())
             ->method('deleteConfig')
-            ->with('path', ScopeInterface::SCOPE_DEFAULT, 0);
+            ->with('path', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 0);
         $this->model->delete('path');
     }
 
@@ -58,7 +59,7 @@ class WriterTest extends \PHPUnit_Framework_TestCase
     {
         $this->resource->expects($this->once())
             ->method('saveConfig')
-            ->with('path', 'value', ScopeInterface::SCOPE_DEFAULT, 0);
+            ->with('path', 'value', ScopeConfigInterface::SCOPE_TYPE_DEFAULT, 0);
         $this->model->save('path', 'value');
     }
 }
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/Request/HttpTest.php b/lib/internal/Magento/Framework/App/Test/Unit/Request/HttpTest.php
index 090580da2726653983a7ed76ec9f16405393092f..8bfb9be2f3bb253932ba96c59d11d9819b704b50 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/Request/HttpTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/Request/HttpTest.php
@@ -9,6 +9,7 @@
 
 namespace Magento\Framework\App\Test\Unit\Request;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use \Magento\Framework\App\Request\Http;
 use Magento\Framework\App\ScopeInterface;
 use Zend\Stdlib\Parameters;
@@ -325,7 +326,7 @@ class HttpTest extends \PHPUnit_Framework_TestCase
             ->getMock();
         $configMock->expects($this->exactly($configCall))
             ->method('getValue')
-            ->with(\Magento\Framework\App\Request\Http::XML_PATH_OFFLOADER_HEADER, ScopeInterface::SCOPE_DEFAULT)
+            ->with(\Magento\Framework\App\Request\Http::XML_PATH_OFFLOADER_HEADER, ScopeConfigInterface::SCOPE_TYPE_DEFAULT)
             ->willReturn($configOffloadHeader);
         $this->objectManager->expects($this->exactly($configCall))
             ->method('get')
diff --git a/lib/internal/Magento/Framework/Cache/Frontend/Decorator/Bare.php b/lib/internal/Magento/Framework/Cache/Frontend/Decorator/Bare.php
index b856e8608aa726ebf0f32e07ecb01ad7ac8d7d6f..cae35e66ff83d2b40b562b77aaaeaed4d030221e 100644
--- a/lib/internal/Magento/Framework/Cache/Frontend/Decorator/Bare.php
+++ b/lib/internal/Magento/Framework/Cache/Frontend/Decorator/Bare.php
@@ -27,6 +27,18 @@ class Bare implements \Magento\Framework\Cache\FrontendInterface
         $this->_frontend = $frontend;
     }
 
+    /**
+     * Set frontend
+     *
+     * @param \Magento\Framework\Cache\FrontendInterface $frontend
+     * @return $this
+     */
+    protected function setFrontend(\Magento\Framework\Cache\FrontendInterface $frontend)
+    {
+        $this->_frontend = $frontend;
+        return $this;
+    }
+
     /**
      * Retrieve cache frontend instance being decorated
      *
@@ -42,7 +54,7 @@ class Bare implements \Magento\Framework\Cache\FrontendInterface
      */
     public function test($identifier)
     {
-        return $this->_frontend->test($identifier);
+        return $this->_getFrontend()->test($identifier);
     }
 
     /**
@@ -50,7 +62,7 @@ class Bare implements \Magento\Framework\Cache\FrontendInterface
      */
     public function load($identifier)
     {
-        return $this->_frontend->load($identifier);
+        return $this->_getFrontend()->load($identifier);
     }
 
     /**
@@ -60,7 +72,7 @@ class Bare implements \Magento\Framework\Cache\FrontendInterface
      */
     public function save($data, $identifier, array $tags = [], $lifeTime = null)
     {
-        return $this->_frontend->save($data, $identifier, $tags, $lifeTime);
+        return $this->_getFrontend()->save($data, $identifier, $tags, $lifeTime);
     }
 
     /**
@@ -68,7 +80,7 @@ class Bare implements \Magento\Framework\Cache\FrontendInterface
      */
     public function remove($identifier)
     {
-        return $this->_frontend->remove($identifier);
+        return $this->_getFrontend()->remove($identifier);
     }
 
     /**
@@ -76,7 +88,7 @@ class Bare implements \Magento\Framework\Cache\FrontendInterface
      */
     public function clean($mode = \Zend_Cache::CLEANING_MODE_ALL, array $tags = [])
     {
-        return $this->_frontend->clean($mode, $tags);
+        return $this->_getFrontend()->clean($mode, $tags);
     }
 
     /**
@@ -84,7 +96,7 @@ class Bare implements \Magento\Framework\Cache\FrontendInterface
      */
     public function getBackend()
     {
-        return $this->_frontend->getBackend();
+        return $this->_getFrontend()->getBackend();
     }
 
     /**
@@ -92,6 +104,6 @@ class Bare implements \Magento\Framework\Cache\FrontendInterface
      */
     public function getLowLevelFrontend()
     {
-        return $this->_frontend->getLowLevelFrontend();
+        return $this->_getFrontend()->getLowLevelFrontend();
     }
 }
diff --git a/lib/internal/Magento/Framework/Cache/Frontend/Decorator/TagScope.php b/lib/internal/Magento/Framework/Cache/Frontend/Decorator/TagScope.php
index 32c9e4422417cf220a28db98137ef954a26ba705..0f74b1894865754521bd9b595f0b14a5572e1e8c 100644
--- a/lib/internal/Magento/Framework/Cache/Frontend/Decorator/TagScope.php
+++ b/lib/internal/Magento/Framework/Cache/Frontend/Decorator/TagScope.php
@@ -45,7 +45,7 @@ class TagScope extends \Magento\Framework\Cache\Frontend\Decorator\Bare
      */
     public function save($data, $identifier, array $tags = [], $lifeTime = null)
     {
-        $tags[] = $this->_tag;
+        $tags[] = $this->getTag();
         return parent::save($data, $identifier, $tags, $lifeTime);
     }
 
@@ -59,16 +59,16 @@ class TagScope extends \Magento\Framework\Cache\Frontend\Decorator\Bare
         if ($mode == \Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG) {
             $result = false;
             foreach ($tags as $tag) {
-                if (parent::clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [$tag, $this->_tag])) {
+                if (parent::clean(\Zend_Cache::CLEANING_MODE_MATCHING_TAG, [$tag, $this->getTag()])) {
                     $result = true;
                 }
             }
         } else {
             if ($mode == \Zend_Cache::CLEANING_MODE_ALL) {
                 $mode = \Zend_Cache::CLEANING_MODE_MATCHING_TAG;
-                $tags = [$this->_tag];
+                $tags = [$this->getTag()];
             } else {
-                $tags[] = $this->_tag;
+                $tags[] = $this->getTag();
             }
             $result = parent::clean($mode, $tags);
         }
diff --git a/lib/internal/Magento/Framework/Code/Generator.php b/lib/internal/Magento/Framework/Code/Generator.php
index 03ac500f47daccb01521a26559f1b6b3669f8494..da6d60b14ed9bff46b34410eba6c2c0bb4136926 100644
--- a/lib/internal/Magento/Framework/Code/Generator.php
+++ b/lib/internal/Magento/Framework/Code/Generator.php
@@ -68,7 +68,7 @@ class Generator
      * Generate Class
      *
      * @param string $className
-     * @return string
+     * @return string | void
      * @throws \Magento\Framework\Exception\LocalizedException
      * @throws \InvalidArgumentException
      */
@@ -99,15 +99,17 @@ class Generator
         $generatorClass = $this->_generatedEntities[$entity];
         /** @var EntityAbstract $generator */
         $generator = $this->createGeneratorInstance($generatorClass, $entityName, $className);
-        $this->tryToLoadSourceClass($className, $generator);
-        if (!($file = $generator->generate())) {
-            $errors = $generator->getErrors();
-            throw new \Magento\Framework\Exception\LocalizedException(
-                new \Magento\Framework\Phrase(implode(' ', $errors))
-            );
+        if ($generator !== null) {
+            $this->tryToLoadSourceClass($className, $generator);
+            if (!($file = $generator->generate())) {
+                $errors = $generator->getErrors();
+                throw new \Magento\Framework\Exception\LocalizedException(
+                    new \Magento\Framework\Phrase(implode(' ', $errors))
+                );
+            }
+            $this->includeFile($file);
+            return self::GENERATION_SUCCESS;
         }
-        $this->includeFile($file);
-        return self::GENERATION_SUCCESS;
     }
 
     /**
diff --git a/lib/internal/Magento/Framework/Console/README.md b/lib/internal/Magento/Framework/Console/README.md
index 8d77e82bdff7213f81673b8d7d9c32bf0f017573..b9057127c88914c576e5385aeee9839b87ea3c90 100644
--- a/lib/internal/Magento/Framework/Console/README.md
+++ b/lib/internal/Magento/Framework/Console/README.md
@@ -8,7 +8,7 @@ For example we can introduce new command in module using di.xml:
 <type name="Magento\Framework\Console\CommandList">
     <arguments>
         <argument name="commands" xsi:type="array">
-            <item name="test_me" xsi:type="string">Magento\MyModule\Console\TestMeCommand</item>
+            <item name="test_me" xsi:type="object">Magento\MyModule\Console\TestMeCommand</item>
         </argument>
     </arguments>
 </type>
diff --git a/lib/internal/Magento/Framework/Data/Collection/Filesystem.php b/lib/internal/Magento/Framework/Data/Collection/Filesystem.php
index 817c4b420519697de1ad27984ca0d286e151a125..cec62bc94a82b655866f71fe5118c13336868bef 100644
--- a/lib/internal/Magento/Framework/Data/Collection/Filesystem.php
+++ b/lib/internal/Magento/Framework/Data/Collection/Filesystem.php
@@ -284,6 +284,7 @@ class Filesystem extends \Magento\Framework\Data\Collection
      * @param bool $printQuery
      * @param bool $logQuery
      * @return $this
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      * @throws \Exception
      */
     public function loadData($printQuery = false, $logQuery = false)
@@ -668,6 +669,7 @@ class Filesystem extends \Magento\Framework\Data\Collection
      * @param string $value
      * @param string $type
      * @return $this
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
      */
     public function addFilter($field, $value, $type = 'and')
     {
@@ -696,7 +698,7 @@ class Filesystem extends \Magento\Framework\Data\Collection
      */
     public function filterCallbackLike($field, $filterValue, $row)
     {
-        $filterValueRegex = str_replace('%', '(.*?)', preg_quote($filterValue, '/'));
+        $filterValueRegex = str_replace('%', '(.*?)', str_replace('\'', '', preg_quote($filterValue, '/')));
         return (bool)preg_match("/^{$filterValueRegex}\$/i", $row[$field]);
     }
 
diff --git a/lib/internal/Magento/Framework/Data/Test/Unit/Collection/FilesystemTest.php b/lib/internal/Magento/Framework/Data/Test/Unit/Collection/FilesystemTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b764079a841b7f07f35dc9a692b9ffeb6968fe5f
--- /dev/null
+++ b/lib/internal/Magento/Framework/Data/Test/Unit/Collection/FilesystemTest.php
@@ -0,0 +1,30 @@
+<?php
+/***
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Framework\Data\Test\Unit\Collection;
+
+class FilesystemTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var \Magento\Framework\Data\Collection\Filesystem */
+    private $model;
+
+    public function setUp()
+    {
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->model = $objectManager->getObject('Magento\Framework\Data\Collection\Filesystem');
+    }
+
+    public function testFilterCallbackLike()
+    {
+        $field = 'field';
+        $row = [$field => 'beginning_filter_target_end',];
+        $filterValueSuccess = new \Zend_Db_Expr('%filter_target%');
+        $filterValueFailure = new \Zend_Db_Expr('%not_found_in_the_row%');
+
+        $this->assertTrue($this->model->filterCallbackLike($field, $filterValueSuccess, $row));
+        $this->assertFalse($this->model->filterCallbackLike($field, $filterValueFailure, $row));
+    }
+}
diff --git a/lib/internal/Magento/Framework/Locale/ConfigInterface.php b/lib/internal/Magento/Framework/Locale/ConfigInterface.php
index 3539f09409a800e83665f16d58871797f96161d0..e0f28fd015c33675eaed0445956c7a728a5e0d84 100644
--- a/lib/internal/Magento/Framework/Locale/ConfigInterface.php
+++ b/lib/internal/Magento/Framework/Locale/ConfigInterface.php
@@ -5,19 +5,24 @@
  */
 namespace Magento\Framework\Locale;
 
+/**
+ * Provides access to locale-related config information
+ *
+ * @api
+ */
 interface ConfigInterface
 {
     /**
      * Get list pre-configured allowed locales
      *
-     * @return array
+     * @return string[]
      */
     public function getAllowedLocales();
 
     /**
      * Get list pre-configured allowed currencies
      *
-     * @return array
+     * @return string[]
      */
     public function getAllowedCurrencies();
 }
diff --git a/lib/internal/Magento/Framework/Locale/Currency.php b/lib/internal/Magento/Framework/Locale/Currency.php
index 5d3c5a9ec9b7e961d870e4a458bc4b3fa69b5b89..f0be6c12172278b8e3a32b86848f296cd606d96a 100644
--- a/lib/internal/Magento/Framework/Locale/Currency.php
+++ b/lib/internal/Magento/Framework/Locale/Currency.php
@@ -7,6 +7,10 @@ namespace Magento\Framework\Locale;
 
 class Currency implements \Magento\Framework\Locale\CurrencyInterface
 {
+    /**
+     * Default currency
+     */
+    const DEFAULT_CURRENCY = 'USD';
     /**
      * @var array
      */
@@ -45,20 +49,15 @@ class Currency implements \Magento\Framework\Locale\CurrencyInterface
     }
 
     /**
-     * Retrieve currency code
-     *
-     * @return string
+     * @inheritdoc
      */
     public function getDefaultCurrency()
     {
-        return \Magento\Framework\Locale\CurrencyInterface::DEFAULT_CURRENCY;
+        return self::DEFAULT_CURRENCY;
     }
 
     /**
-     * Create \Zend_Currency object for current locale
-     *
-     * @param   string $currency
-     * @return  \Magento\Framework\Currency
+     * @inheritdoc
      */
     public function getCurrency($currency)
     {
diff --git a/lib/internal/Magento/Framework/Locale/CurrencyInterface.php b/lib/internal/Magento/Framework/Locale/CurrencyInterface.php
index 774f7d5120f3cead8f11e9d7545928e62634faa2..00bbc4452eedd604d19cb9144d1f38e9417e9568 100644
--- a/lib/internal/Magento/Framework/Locale/CurrencyInterface.php
+++ b/lib/internal/Magento/Framework/Locale/CurrencyInterface.php
@@ -5,27 +5,22 @@
  */
 namespace Magento\Framework\Locale;
 
+/**
+ * Provides access to currency config information
+ *
+ * @api
+ */
 interface CurrencyInterface
 {
     /**
-     * Default currency
-     */
-    const DEFAULT_CURRENCY = 'USD';
-
-    /**
-     * XML path to installed currencies
-     */
-    const XML_PATH_ALLOW_CURRENCIES_INSTALLED = 'system/currency/installed';
-
-    /**
-     * Retrieve currency code
+     * Retrieve default currency code
      *
      * @return string
      */
     public function getDefaultCurrency();
 
     /**
-     * Create \Magento\Framework\Currency object for current locale
+     * Create Currency object for current locale
      *
      * @param   string $currency
      * @return  \Magento\Framework\Currency
diff --git a/lib/internal/Magento/Framework/Locale/Resolver.php b/lib/internal/Magento/Framework/Locale/Resolver.php
index b78be470920ec0638dd4a8a786d13b97470277f3..6a81f60cc5a0cda5d7d55a31f7f9b599e905c94a 100644
--- a/lib/internal/Magento/Framework/Locale/Resolver.php
+++ b/lib/internal/Magento/Framework/Locale/Resolver.php
@@ -9,6 +9,10 @@ use Magento\Framework\App\Config\ScopeConfigInterface;
 
 class Resolver implements ResolverInterface
 {
+    /**
+     * Default locale
+     */
+    const DEFAULT_LOCALE = 'en_US';
     /**
      * Default locale code
      *
@@ -85,7 +89,7 @@ class Resolver implements ResolverInterface
         if (!$this->defaultLocale) {
             $locale = $this->scopeConfig->getValue($this->getDefaultLocalePath(), $this->scopeType);
             if (!$locale) {
-                $locale = ResolverInterface::DEFAULT_LOCALE;
+                $locale = self::DEFAULT_LOCALE;
             }
             $this->defaultLocale = $locale;
         }
diff --git a/lib/internal/Magento/Framework/Locale/ResolverInterface.php b/lib/internal/Magento/Framework/Locale/ResolverInterface.php
index 08add444266f073aaa354935b6857be2c7edd34f..a17932ed8628870f7ce9f086946807498c836807 100644
--- a/lib/internal/Magento/Framework/Locale/ResolverInterface.php
+++ b/lib/internal/Magento/Framework/Locale/ResolverInterface.php
@@ -5,13 +5,13 @@
  */
 namespace Magento\Framework\Locale;
 
+/**
+ * Manages locale config information
+ *
+ * @api
+ */
 interface ResolverInterface
 {
-    /**
-     * Default locale
-     */
-    const DEFAULT_LOCALE = 'en_US';
-
     /**
      * Return path to default locale
      *
diff --git a/lib/internal/Magento/Framework/Locale/Test/Unit/CurrencyTest.php b/lib/internal/Magento/Framework/Locale/Test/Unit/CurrencyTest.php
index 01552d3a972294bd649141074cc91f985829743b..226e8d4d8508be64e2a9a9454aeaa94cbb3de243 100644
--- a/lib/internal/Magento/Framework/Locale/Test/Unit/CurrencyTest.php
+++ b/lib/internal/Magento/Framework/Locale/Test/Unit/CurrencyTest.php
@@ -8,6 +8,7 @@
 
 namespace Magento\Framework\Locale\Test\Unit;
 
+use Magento\Framework\Locale\Currency;
 use Magento\Framework\Locale\CurrencyInterface;
 
 class CurrencyTest extends \PHPUnit_Framework_TestCase
@@ -68,7 +69,7 @@ class CurrencyTest extends \PHPUnit_Framework_TestCase
 
     public function testGetDefaultCurrency()
     {
-        $expectedDefaultCurrency = CurrencyInterface::DEFAULT_CURRENCY;
+        $expectedDefaultCurrency = Currency::DEFAULT_CURRENCY;
         $retrievedDefaultCurrency = $this->testCurrencyObject->getDefaultCurrency();
         $this->assertEquals($expectedDefaultCurrency, $retrievedDefaultCurrency);
     }
diff --git a/lib/internal/Magento/Framework/Locale/Validator.php b/lib/internal/Magento/Framework/Locale/Validator.php
index b30727562c45755db8b67dfb00be40c18bae09fc..0cdf265af01b329f3a87eca97ac8de8c723902b6 100644
--- a/lib/internal/Magento/Framework/Locale/Validator.php
+++ b/lib/internal/Magento/Framework/Locale/Validator.php
@@ -29,10 +29,12 @@ class Validator
     }
 
     /**
-     * Validate locale code
+     * Validate locale code. Code must be in the list of allowed locales.
      *
      * @param string $localeCode
      * @return bool
+     *
+     * @api
      */
     public function isValid($localeCode)
     {
diff --git a/lib/internal/Magento/Framework/Message/Factory.php b/lib/internal/Magento/Framework/Message/Factory.php
index 4c16064b5b6599dbb98f48307601dfff7eda1ee3..be7e3c9bb566a041c026a5916f4e51364e06b07d 100644
--- a/lib/internal/Magento/Framework/Message/Factory.php
+++ b/lib/internal/Magento/Framework/Message/Factory.php
@@ -45,11 +45,12 @@ class Factory
     }
 
     /**
-     * Create message instance with specified parameters
+     * Create a message instance of a given type with given text.
      *
-     * @param string $type
-     * @param string $text
-     * @throws \InvalidArgumentException
+     * @param string $type The message type to create, must correspond to a message type under the
+     * namespace Magento\Framework\Message\
+     * @param string $text The text to inject into the message
+     * @throws \InvalidArgumentException Exception gets thrown if type does not correspond to a valid Magento message
      * @return MessageInterface
      */
     public function create($type, $text)
diff --git a/lib/internal/Magento/Framework/Message/Manager.php b/lib/internal/Magento/Framework/Message/Manager.php
index 73b212a58e3ee88769bd653a815c15ecafde2578..815296c80bad2d8453564f10797ade913a2e5c7f 100644
--- a/lib/internal/Magento/Framework/Message/Manager.php
+++ b/lib/internal/Magento/Framework/Message/Manager.php
@@ -14,6 +14,10 @@ use Psr\Log\LoggerInterface as Logger;
  */
 class Manager implements ManagerInterface
 {
+    /**
+     * Default message group
+     */
+    const DEFAULT_GROUP = 'default';
     /**
      * @var Session
      */
@@ -74,9 +78,7 @@ class Manager implements ManagerInterface
     }
 
     /**
-     * Retrieve default message group
-     *
-     * @return string
+     * {@inheritdoc}
      */
     public function getDefaultGroup()
     {
@@ -95,7 +97,7 @@ class Manager implements ManagerInterface
     }
 
     /**
-     * Retrieve messages
+     * @inheritdoc
      *
      * @param string|null $group
      * @param bool $clear
@@ -118,7 +120,7 @@ class Manager implements ManagerInterface
     }
 
     /**
-     * Adding new message to message collection
+     * @inheritdoc
      *
      * @param MessageInterface $message
      * @param string|null $group
@@ -133,7 +135,7 @@ class Manager implements ManagerInterface
     }
 
     /**
-     * Adding messages array to message collection
+     * @inheritdoc
      *
      * @param MessageInterface[] $messages
      * @param string|null $group
@@ -148,7 +150,7 @@ class Manager implements ManagerInterface
     }
 
     /**
-     * Adding new error message
+     * @inheritdoc
      *
      * @param string $message
      * @param string|null $group
@@ -161,7 +163,7 @@ class Manager implements ManagerInterface
     }
 
     /**
-     * Adding new warning message
+     * @inheritdoc
      *
      * @param string $message
      * @param string|null $group
@@ -174,7 +176,7 @@ class Manager implements ManagerInterface
     }
 
     /**
-     * Adding new notice message
+     * @inheritdoc
      *
      * @param string $message
      * @param string|null $group
@@ -187,7 +189,7 @@ class Manager implements ManagerInterface
     }
 
     /**
-     * Adding new success message
+     * @inheritdoc
      *
      * @param string $message
      * @param string|null $group
@@ -200,7 +202,7 @@ class Manager implements ManagerInterface
     }
 
     /**
-     * Adds messages array to message collection, but doesn't add duplicates to it
+     * @inheritdoc
      *
      * @param MessageInterface[]|MessageInterface $messages
      * @param string|null $group
@@ -244,7 +246,7 @@ class Manager implements ManagerInterface
     }
 
     /**
-     * Not Magento exception handling
+     * @inheritdoc
      *
      * @param \Exception $exception
      * @param string $alternativeText
diff --git a/lib/internal/Magento/Framework/Message/ManagerInterface.php b/lib/internal/Magento/Framework/Message/ManagerInterface.php
index 36851dc866c49be7c9e0f0ea15490c79b776db4a..dd73d2a2fcfbc8acbd9aabdef42a3f5d59616f4d 100644
--- a/lib/internal/Magento/Framework/Message/ManagerInterface.php
+++ b/lib/internal/Magento/Framework/Message/ManagerInterface.php
@@ -6,15 +6,12 @@
 namespace Magento\Framework\Message;
 
 /**
- * Message manager interface
+ * Adds different types of messages to the session, and allows access to existing messages.
+ *
+ * @api
  */
 interface ManagerInterface
 {
-    /**
-     * Default message group
-     */
-    const DEFAULT_GROUP = 'default';
-
     /**
      * Retrieve messages
      *
@@ -32,7 +29,7 @@ interface ManagerInterface
     public function getDefaultGroup();
 
     /**
-     * Adding new message to message collection
+     * Adds new message to message collection
      *
      * @param MessageInterface $message
      * @param string|null $group
@@ -41,7 +38,7 @@ interface ManagerInterface
     public function addMessage(MessageInterface $message, $group = null);
 
     /**
-     * Adding messages array to message collection
+     * Adds messages array to message collection
      *
      * @param array $messages
      * @param string|null $group
@@ -50,7 +47,7 @@ interface ManagerInterface
     public function addMessages(array $messages, $group = null);
 
     /**
-     * Adding new error message
+     * Adds new error message
      *
      * @param string $message
      * @param string|null $group
@@ -59,7 +56,7 @@ interface ManagerInterface
     public function addError($message, $group = null);
 
     /**
-     * Adding new warning message
+     * Adds new warning message
      *
      * @param string $message
      * @param string|null $group
@@ -68,7 +65,7 @@ interface ManagerInterface
     public function addWarning($message, $group = null);
 
     /**
-     * Adding new notice message
+     * Adds new notice message
      *
      * @param string $message
      * @param string|null $group
@@ -77,7 +74,7 @@ interface ManagerInterface
     public function addNotice($message, $group = null);
 
     /**
-     * Adding new success message
+     * Adds new success message
      *
      * @param string $message
      * @param string|null $group
@@ -86,7 +83,7 @@ interface ManagerInterface
     public function addSuccess($message, $group = null);
 
     /**
-     * Adds messages array to message collection, but doesn't add duplicates to it
+     * Adds messages array to message collection, without adding duplicate messages
      *
      * @param array|MessageInterface $messages
      * @param string|null $group
@@ -95,7 +92,7 @@ interface ManagerInterface
     public function addUniqueMessages($messages, $group = null);
 
     /**
-     * Not Magento exception handling
+     * Adds a message describing an exception. Does not contain Exception handling logic.
      *
      * @param \Exception $exception
      * @param string $alternativeText
diff --git a/lib/internal/Magento/Framework/Message/MessageInterface.php b/lib/internal/Magento/Framework/Message/MessageInterface.php
index e5342f49ac042e79fb0b572fca328a1285ab8b22..d9d60e047b1713fd6a6288a86b2a7b74b8ddae0a 100644
--- a/lib/internal/Magento/Framework/Message/MessageInterface.php
+++ b/lib/internal/Magento/Framework/Message/MessageInterface.php
@@ -6,7 +6,9 @@
 namespace Magento\Framework\Message;
 
 /**
- * Interface for message
+ * Represent a message with a type, content text, and an isSticky attribute to prevent message from being cleared.
+ *
+ * @api
  */
 interface MessageInterface
 {
diff --git a/lib/internal/Magento/Framework/Message/Session.php b/lib/internal/Magento/Framework/Message/Session.php
index da86d172577a4f0ae18dce396deaf6688cd42d2e..8ceb66543e370ccf34321cef02be325bedb2cf85 100644
--- a/lib/internal/Magento/Framework/Message/Session.php
+++ b/lib/internal/Magento/Framework/Message/Session.php
@@ -8,6 +8,6 @@ namespace Magento\Framework\Message;
 /**
  * Message session model
  */
-class Session extends \Magento\Framework\Session\Generic
+class Session extends \Magento\Framework\Session\SessionManager
 {
 }
diff --git a/lib/internal/Magento/Framework/Message/Test/Unit/ManagerTest.php b/lib/internal/Magento/Framework/Message/Test/Unit/ManagerTest.php
index c4980974bc289f00167474eb50040197e020cb66..d65a5459a4ee92dae76a266743cb03d39c3220b6 100644
--- a/lib/internal/Magento/Framework/Message/Test/Unit/ManagerTest.php
+++ b/lib/internal/Magento/Framework/Message/Test/Unit/ManagerTest.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Framework\Message\Test\Unit;
 
+use Magento\Framework\Message\Manager;
 use Magento\Framework\Message\MessageInterface;
 use Magento\Framework\Message\ManagerInterface;
 
@@ -86,7 +87,7 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
 
     public function testGetDefaultGroup()
     {
-        $this->assertEquals(ManagerInterface::DEFAULT_GROUP, $this->model->getDefaultGroup());
+        $this->assertEquals(Manager::DEFAULT_GROUP, $this->model->getDefaultGroup());
 
         $customDefaultGroup = 'some_group';
         $customManager = $this->objectManager->getObject(
@@ -117,7 +118,7 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
         )->method(
             'getData'
         )->with(
-            ManagerInterface::DEFAULT_GROUP
+            Manager::DEFAULT_GROUP
         )->will(
             $this->returnValue(null)
         );
@@ -126,7 +127,7 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
         )->method(
             'setData'
         )->with(
-            ManagerInterface::DEFAULT_GROUP,
+            Manager::DEFAULT_GROUP,
             $messageCollection
         )->will(
             $this->returnValue($this->session)
@@ -136,7 +137,7 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
         )->method(
             'getData'
         )->with(
-            ManagerInterface::DEFAULT_GROUP
+            Manager::DEFAULT_GROUP
         )->will(
             $this->returnValue($messageCollection)
         );
@@ -161,7 +162,7 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
         )->method(
             'getData'
         )->with(
-            ManagerInterface::DEFAULT_GROUP
+            Manager::DEFAULT_GROUP
         )->will(
             $this->returnValue($messageCollection)
         );
@@ -209,7 +210,7 @@ class ManagerTest extends \PHPUnit_Framework_TestCase
         )->method(
             'getData'
         )->with(
-            ManagerInterface::DEFAULT_GROUP
+            Manager::DEFAULT_GROUP
         )->will(
             $this->returnValue($messageCollection)
         );
diff --git a/lib/internal/Magento/Framework/Model/Resource/AbstractResource.php b/lib/internal/Magento/Framework/Model/Resource/AbstractResource.php
index 831dcf5ae71fb2f832a7372efd8abdfe49a0ac40..c2a9bd81aad960e498303fae9f00a0f333a26272 100644
--- a/lib/internal/Magento/Framework/Model/Resource/AbstractResource.php
+++ b/lib/internal/Magento/Framework/Model/Resource/AbstractResource.php
@@ -61,6 +61,7 @@ abstract class AbstractResource
      * Start resource transaction
      *
      * @return $this
+     * @api
      */
     public function beginTransaction()
     {
@@ -73,6 +74,7 @@ abstract class AbstractResource
      *
      * @param array $callback
      * @return $this
+     * @api
      */
     public function addCommitCallback($callback)
     {
@@ -85,6 +87,7 @@ abstract class AbstractResource
      * Commit resource transaction
      *
      * @return $this
+     * @api
      */
     public function commit()
     {
@@ -109,6 +112,7 @@ abstract class AbstractResource
      * Roll back resource transaction
      *
      * @return $this
+     * @api
      */
     public function rollBack()
     {
diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php b/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php
index 351365b08d9eb57d45b6b65a50c53edbb93d482c..ba80e64a256222d7d02ac7eaae6cd95f7ec3717a 100644
--- a/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php
+++ b/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php
@@ -233,6 +233,7 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso
      *
      * @throws LocalizedException
      * @return string
+     * @api
      */
     public function getIdFieldName()
     {
@@ -248,6 +249,7 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso
      *
      * @throws LocalizedException
      * @return string
+     * @api
      */
     public function getMainTable()
     {
@@ -262,6 +264,7 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso
      *
      * @param string $tableName
      * @return string
+     * @api
      */
     public function getTable($tableName)
     {
@@ -391,6 +394,7 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso
      * @param \Magento\Framework\Model\AbstractModel $object
      * @return $this
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @api
      */
     public function save(\Magento\Framework\Model\AbstractModel $object)
     {
diff --git a/lib/internal/Magento/Framework/Object/Copy.php b/lib/internal/Magento/Framework/Object/Copy.php
index 9145e0aba3bc9b9a106863967d2b7c5a3bd8b124..c0d87722872490ec10c4b15efb33fc3f2385fd33 100644
--- a/lib/internal/Magento/Framework/Object/Copy.php
+++ b/lib/internal/Magento/Framework/Object/Copy.php
@@ -47,6 +47,8 @@ class Copy
      * @param array|\Magento\Framework\Object $target
      * @param string $root
      * @return array|\Magento\Framework\Object|null the value of $target
+     *
+     * @api
      */
     public function copyFieldsetToTarget($fieldset, $aspect, $source, $target, $root = 'global')
     {
@@ -91,6 +93,8 @@ class Copy
      * @param array|\Magento\Framework\Object $source
      * @param string $root
      * @return array $data
+     *
+     * @api
      */
     public function getDataFromFieldset($fieldset, $aspect, $source, $root = 'global')
     {
diff --git a/lib/internal/Magento/Framework/Object/Copy/Config/Data/Proxy.php b/lib/internal/Magento/Framework/Object/Copy/Config/Data/Proxy.php
new file mode 100644
index 0000000000000000000000000000000000000000..ea974307333d3da54ea344c57d8b72331f30a44f
--- /dev/null
+++ b/lib/internal/Magento/Framework/Object/Copy/Config/Data/Proxy.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Object\Copy\Config\Data;
+
+/**
+ * Proxy class for @see \Magento\Framework\Object\Copy\Config\Data
+ */
+class Proxy extends \Magento\Framework\Object\Copy\Config\Data
+{
+    /**
+     * Object Manager instance
+     *
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $_objectManager = null;
+
+    /**
+     * Proxied instance name
+     *
+     * @var string
+     */
+    protected $_instanceName = null;
+
+    /**
+     * Proxied instance
+     *
+     * @var \Magento\Framework\Object\Copy\Config\Data
+     */
+    protected $_subject = null;
+
+    /**
+     * Instance shareability flag
+     *
+     * @var bool
+     */
+    protected $_isShared = null;
+
+    /**
+     * Proxy constructor
+     *
+     * @param \Magento\Framework\ObjectManagerInterface $objectManager
+     * @param string $instanceName
+     * @param bool $shared
+     */
+    public function __construct(
+        \Magento\Framework\ObjectManagerInterface $objectManager,
+        $instanceName = '\\Magento\\Framework\\Object\\Copy\\Config\\Data',
+        $shared = true
+    ) {
+        $this->_objectManager = $objectManager;
+        $this->_instanceName = $instanceName;
+        $this->_isShared = $shared;
+    }
+
+    /**
+     * @return array
+     */
+    public function __sleep()
+    {
+        return ['_subject', '_isShared'];
+    }
+
+    /**
+     * Retrieve ObjectManager from global scope
+     *
+     * @return void
+     */
+    public function __wakeup()
+    {
+        $this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+    }
+
+    /**
+     * Clone proxied instance
+     *
+     * @return void
+     */
+    public function __clone()
+    {
+        $this->_subject = clone $this->_getSubject();
+    }
+
+    /**
+     * Get proxied instance
+     *
+     * @return \Magento\Framework\Object\Copy\Config\Data
+     */
+    protected function _getSubject()
+    {
+        if (!$this->_subject) {
+            $this->_subject = true === $this->_isShared
+                ? $this->_objectManager->get($this->_instanceName)
+                : $this->_objectManager->create($this->_instanceName);
+        }
+        return $this->_subject;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function merge(array $config)
+    {
+        return $this->_getSubject()->merge($config);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function get($path = null, $default = null)
+    {
+        return $this->_getSubject()->get($path, $default);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function reset()
+    {
+        return $this->_getSubject()->reset();
+    }
+}
diff --git a/lib/internal/Magento/Framework/ObjectManager/Profiler/FactoryDecorator.php b/lib/internal/Magento/Framework/ObjectManager/Profiler/FactoryDecorator.php
index ad3864500bbc9502a1d8d6ecbaa296c76ac82d19..895377327281b908c2a8d0944a9415bbdb400275 100644
--- a/lib/internal/Magento/Framework/ObjectManager/Profiler/FactoryDecorator.php
+++ b/lib/internal/Magento/Framework/ObjectManager/Profiler/FactoryDecorator.php
@@ -8,6 +8,11 @@ namespace Magento\Framework\ObjectManager\Profiler;
 
 class FactoryDecorator implements \Magento\Framework\ObjectManager\FactoryInterface
 {
+    /**
+     * Name of the class that generates logging wrappers
+     */
+    const GENERATOR_NAME = 'Magento\Framework\ObjectManager\Profiler\Code\Generator\Logger';
+
     /**
      * @var \Magento\Framework\ObjectManager\FactoryInterface
      */
@@ -45,9 +50,12 @@ class FactoryDecorator implements \Magento\Framework\ObjectManager\FactoryInterf
     {
         $this->log->startCreating($requestedType);
         $result = $this->subject->create($requestedType, $arguments);
-        $loggerClassName = get_class($result) . "\\Logger";
-        $wrappedResult = new $loggerClassName($result, $this->log);
-        $this->log->stopCreating($result);
-        return $wrappedResult;
+        if ($requestedType !== self::GENERATOR_NAME) {
+            $loggerClassName = get_class($result) . "\\Logger";
+            $wrappedResult = new $loggerClassName($result, $this->log);
+            $this->log->stopCreating($result);
+            $result = $wrappedResult;
+        }
+        return $result;
     }
 }
diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Profiler/FactoryDecoratorTest.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Profiler/FactoryDecoratorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..1d0fa91e42286c72588946788f40491de72e925e
--- /dev/null
+++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/Profiler/FactoryDecoratorTest.php
@@ -0,0 +1,75 @@
+<?php
+/***
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Framework\ObjectManager\Test\Unit\Profiler;
+
+class FactoryDecoratorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Name of the base class to wrap in logger
+     */
+    const CLASS_NAME = 'Magento\Test\Di\WrappedClass';
+
+    /**
+     * Name of the wrapper class that does logging
+     */
+    const LOGGER_NAME = 'Magento\Test\Di\WrappedClass\Logger';
+
+    /**
+     * Name of the class that generates wrappers - should not be wrapped by logger
+     */
+    const GENERATOR_NAME = 'Magento\Framework\ObjectManager\Profiler\Code\Generator\Logger';
+
+    /** @var  \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\ObjectManager\FactoryInterface*/
+    private $objectManagerMock;
+
+    /** @var  \Magento\Framework\ObjectManager\Profiler\FactoryDecorator */
+    private $model;
+
+    public function setUp()
+    {
+        require_once __DIR__ . '/../_files/logger_classes.php';
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+
+        $this->objectManagerMock = $this->getMockBuilder('Magento\Framework\ObjectManager\FactoryInterface')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        // Instantiate SUT
+        $this->model = $objectManager->getObject(
+            'Magento\Framework\ObjectManager\Profiler\FactoryDecorator',
+            ['subject' => $this->objectManagerMock]
+        );
+    }
+
+    public function testCreate()
+    {
+        $baseObjectName = self::CLASS_NAME;
+        $baseObject = new $baseObjectName();
+
+        $arguments = [1, 2, 3];
+
+        $this->objectManagerMock->expects($this->once())
+            ->method('create')
+            ->with(self::CLASS_NAME, $arguments)
+            ->willReturn($baseObject);
+
+        $this->assertInstanceOf(self::LOGGER_NAME, $this->model->create(self::CLASS_NAME, $arguments));
+    }
+
+    public function testCreateNeglectGenerator()
+    {
+        $arguments = [1, 2, 3];
+        $loggerMock = $this->getMockBuilder(self::GENERATOR_NAME)->disableOriginalConstructor()->getMock();
+
+        $this->objectManagerMock->expects($this->once())
+            ->method('create')
+            ->with(self::GENERATOR_NAME, $arguments)
+            ->willReturn($loggerMock);
+
+        $this->assertSame($loggerMock, $this->model->create(self::GENERATOR_NAME, $arguments));
+    }
+}
diff --git a/lib/internal/Magento/Framework/ObjectManager/Test/Unit/_files/logger_classes.php b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/_files/logger_classes.php
new file mode 100644
index 0000000000000000000000000000000000000000..da593225f2079af53a730190a56afc0cb7715400
--- /dev/null
+++ b/lib/internal/Magento/Framework/ObjectManager/Test/Unit/_files/logger_classes.php
@@ -0,0 +1,26 @@
+<?php
+/***
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+//@codingStandardsIgnoreStart
+namespace Magento\Test\Di {
+
+    /**
+     * Test classes used for \Magento\Framework\ObjectManager\Test\Unit\Profiler\FactoryDecoratorTest
+     */
+    class WrappedClass
+    {
+
+    }
+}
+
+namespace Magento\Test\Di\WrappedClass {
+
+    class Logger
+    {
+
+    }
+}
+//@codingStandardsIgnoreEnd
diff --git a/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php b/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php
index 9a0c8b2925b027ea2f72dfe536820fe2d3888181..980a8ff079c9b6f7c369099d801144ada04fdcee 100644
--- a/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php
+++ b/lib/internal/Magento/Framework/Pricing/PriceCurrencyInterface.php
@@ -89,4 +89,11 @@ interface PriceCurrencyInterface
      * @return \Magento\Framework\Model\AbstractModel
      */
     public function getCurrency($scope = null, $currency = null);
+
+    /**
+     * @param null|string|bool|int|\Magento\Framework\App\ScopeInterface $scope
+     * @param \Magento\Framework\Model\AbstractModel|string|null $currency
+     * @return string
+     */
+    public function getCurrencySymbol($scope = null, $currency = null);
 }
diff --git a/lib/internal/Magento/Framework/Pricing/Render/Amount.php b/lib/internal/Magento/Framework/Pricing/Render/Amount.php
index f58510aaf55fcbe87f23b80bcd733fcd614117de..a17c6d08af4c5bf66afd4e9832f5b237c9858ba7 100644
--- a/lib/internal/Magento/Framework/Pricing/Render/Amount.php
+++ b/lib/internal/Magento/Framework/Pricing/Render/Amount.php
@@ -142,6 +142,14 @@ class Amount extends Template implements AmountRenderInterface
         return $this->priceCurrency->getCurrency()->getCurrencyCode();
     }
 
+    /**
+     * @return string
+     */
+    public function getDisplayCurrencySymbol()
+    {
+        return $this->priceCurrency->getCurrencySymbol();
+    }
+
     /**
      * @return bool
      */
diff --git a/lib/internal/Magento/Framework/Pricing/Render/AmountRenderInterface.php b/lib/internal/Magento/Framework/Pricing/Render/AmountRenderInterface.php
index 66d0dc84a169876c2a7b025697b75fd93194eb4d..3779c69dd31ca6781a6a75b44f78c907518640df 100644
--- a/lib/internal/Magento/Framework/Pricing/Render/AmountRenderInterface.php
+++ b/lib/internal/Magento/Framework/Pricing/Render/AmountRenderInterface.php
@@ -50,6 +50,11 @@ interface AmountRenderInterface
      */
     public function getDisplayCurrencyCode();
 
+    /**
+     * @return string
+     */
+    public function getDisplayCurrencySymbol();
+
     /**
      * @return string
      */
diff --git a/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/AmountTest.php b/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/AmountTest.php
index 552cee4846656bd5fcdc6ce7d996bcadc0cb9535..fbf8d4f834f2fb7b1cc54af8ac75c6aad527c174 100644
--- a/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/AmountTest.php
+++ b/lib/internal/Magento/Framework/Pricing/Test/Unit/Render/AmountTest.php
@@ -127,6 +127,15 @@ class AmountTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($result, $this->model->formatCurrency($amount, $includeContainer, $precision));
     }
 
+    public function testGetDisplayCurrencySymbol()
+    {
+        $currencySymbol = '$';
+        $this->priceCurrency->expects($this->once())
+            ->method('getCurrencySymbol')
+            ->willReturn($currencySymbol);
+        $this->assertEquals($currencySymbol, $this->model->getDisplayCurrencySymbol());
+    }
+
     /**
      * Test case for getAdjustmentRenders method through toHtml()
      */
diff --git a/lib/internal/Magento/Framework/Reflection/AttributeTypeResolver.php b/lib/internal/Magento/Framework/Reflection/AttributeTypeResolver.php
index 8552cba5a5d2458014a60e259857fc5c01becf90..6824dca09e58c813d114dba3f3c720dad27a710d 100644
--- a/lib/internal/Magento/Framework/Reflection/AttributeTypeResolver.php
+++ b/lib/internal/Magento/Framework/Reflection/AttributeTypeResolver.php
@@ -44,7 +44,7 @@ class AttributeTypeResolver implements AttributeTypeResolverInterface
         $config = isset($data[$context]) ? $data[$context] : [];
         $output = get_class($value);
         if (isset($config[$attributeCode])) {
-            $type = $config[$attributeCode];
+            $type = $config[$attributeCode]['type'];
             $output = $this->typeProcessor->getArrayItemType($type);
             if (!(class_exists($output) || interface_exists($output))) {
                 throw new \LogicException(
diff --git a/lib/internal/Magento/Framework/Reflection/Test/Unit/AttributeTypeResolverTest.php b/lib/internal/Magento/Framework/Reflection/Test/Unit/AttributeTypeResolverTest.php
index 8391d4643482d17da3c717dbbc732b7c43002b19..68902f3851380d368c88ca8e2357bada00a2de7d 100644
--- a/lib/internal/Magento/Framework/Reflection/Test/Unit/AttributeTypeResolverTest.php
+++ b/lib/internal/Magento/Framework/Reflection/Test/Unit/AttributeTypeResolverTest.php
@@ -62,7 +62,13 @@ class AttributeTypeResolverTest extends \PHPUnit_Framework_TestCase
         $code = 'some_code';
         $value = new \stdClass();
         $context = '\Some\Class';
-        $config = ['Some\Class' => ['some_code' => '\Magento\Framework\Object']];
+        $config = [
+            'Some\Class' => [
+                'some_code' => [
+                    'type' => '\Magento\Framework\Object',
+                ],
+            ]
+        ];
 
         $this->typeProcessor->expects($this->once())
             ->method('getArrayItemType')
@@ -82,7 +88,13 @@ class AttributeTypeResolverTest extends \PHPUnit_Framework_TestCase
         $code = 'some_code';
         $value = new \stdClass();
         $context = '\Some\Class';
-        $config = ['Some\Class' => ['some_code' => '\Some\Class']];
+        $config = [
+            'Some\Class' => [
+                'some_code' => [
+                    'type' => '\Some\Class',
+                ]
+            ]
+        ];
 
         $this->typeProcessor->expects($this->once())
             ->method('getArrayItemType')
diff --git a/lib/internal/Magento/Framework/Search/Dynamic/DataProviderFactory.php b/lib/internal/Magento/Framework/Search/Dynamic/DataProviderFactory.php
index 1cfc1477a7957b46fe1f58f752749b3d8a4193a2..1b534b4dbf4991c3c5f71f2b8009bd6efd9f20df 100644
--- a/lib/internal/Magento/Framework/Search/Dynamic/DataProviderFactory.php
+++ b/lib/internal/Magento/Framework/Search/Dynamic/DataProviderFactory.php
@@ -33,7 +33,7 @@ class DataProviderFactory
         ScopeConfigInterface $scopeConfig,
         $configPath,
         $dataProviders,
-        $scope = ScopeInterface::SCOPE_DEFAULT
+        $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT
     ) {
         $this->objectManager = $objectManager;
         $configValue = $scopeConfig->getValue($configPath, $scope);
diff --git a/lib/internal/Magento/Framework/Search/Dynamic/IntervalFactory.php b/lib/internal/Magento/Framework/Search/Dynamic/IntervalFactory.php
index bba9824e19083f82aa5c249338bf16d2d4da5575..80ac66bb04e62950ae6a7d4dedc4e0fd8dd148d4 100644
--- a/lib/internal/Magento/Framework/Search/Dynamic/IntervalFactory.php
+++ b/lib/internal/Magento/Framework/Search/Dynamic/IntervalFactory.php
@@ -33,7 +33,7 @@ class IntervalFactory
         ScopeConfigInterface $scopeConfig,
         $configPath,
         $intervals,
-        $scope = ScopeInterface::SCOPE_DEFAULT
+        $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT
     ) {
         $this->objectManager = $objectManager;
         $configValue = $scopeConfig->getValue($configPath, $scope);
diff --git a/lib/internal/Magento/Framework/Search/Request/Mapper.php b/lib/internal/Magento/Framework/Search/Request/Mapper.php
index e2dcbef74cda6ab201ed6bdd7dc6b3dcda916cd7..d69d5e4e6d6689170096767166c1cc44fba09d6d 100644
--- a/lib/internal/Magento/Framework/Search/Request/Mapper.php
+++ b/lib/internal/Magento/Framework/Search/Request/Mapper.php
@@ -14,6 +14,11 @@ use Magento\Framework\Phrase;
  */
 class Mapper
 {
+    /**
+     * @var QueryInterface
+     */
+    private $rootQuery;
+
     /**
      * @var array
      */
@@ -45,9 +50,9 @@ class Mapper
     private $objectManager;
 
     /**
-     * @var QueryInterface
+     * @var string
      */
-    private $rootQuery = null;
+    private $rootQueryName;
 
     /**
      * @param \Magento\Framework\ObjectManagerInterface $objectManager
@@ -70,26 +75,26 @@ class Mapper
         $this->queries = $queries;
         $this->aggregations = $aggregations;
         $this->filters = $filters;
-
-        $this->rootQuery = $this->get($rootQueryName);
+        $this->rootQueryName = $rootQueryName;
     }
 
     /**
      * Get Query Interface by name
      *
-     * @param string $queryName
      * @return QueryInterface
      * @throws \Exception
      * @throws \InvalidArgumentException
      * @throws StateException
      */
-    private function get($queryName)
+    public function getRootQuery()
     {
-        $this->mappedQueries = [];
-        $this->mappedFilters = [];
-        $query = $this->mapQuery($queryName);
-        $this->validate();
-        return $query;
+        if (!$this->rootQuery) {
+            $this->mappedQueries = [];
+            $this->mappedFilters = [];
+            $this->rootQuery = $this->mapQuery($this->rootQueryName);
+            $this->validate();
+        }
+        return $this->rootQuery;
     }
 
     /**
@@ -304,14 +309,6 @@ class Mapper
         $this->validateNotUsed($this->filters, $this->mappedFilters, 'Filter %1 is not used in request hierarchy');
     }
 
-    /**
-     * @return QueryInterface
-     */
-    public function getRootQuery()
-    {
-        return $this->rootQuery;
-    }
-
     /**
      * Build BucketInterface[] from array
      *
diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/DimensionsTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/DimensionsTest.php
index 3b37a0bf3d574e10044e2bdea2f8c4b2c2eccebb..5b0736c5fa2ef890b1362bae14c6d9b70f38bf97 100644
--- a/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/DimensionsTest.php
+++ b/lib/internal/Magento/Framework/Search/Test/Unit/Adapter/Mysql/DimensionsTest.php
@@ -6,6 +6,7 @@
 
 namespace Magento\Framework\Search\Test\Unit\Adapter\Mysql;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use \Magento\Framework\Search\Adapter\Mysql\Dimensions;
 
 use Magento\Framework\Search\Adapter\Mysql\Dimensions as DimensionsBuilder;
@@ -103,7 +104,7 @@ class DimensionsTest extends \PHPUnit_Framework_TestCase
     {
         $tableAlias = 'search_index';
         $name = 'scope';
-        $value = \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT;
+        $value = ScopeConfigInterface::SCOPE_TYPE_DEFAULT;
         $scopeId = -123456;
 
         $this->dimension->expects($this->once())
diff --git a/lib/internal/Magento/Framework/Search/Test/Unit/Dynamic/IntervalFactoryTest.php b/lib/internal/Magento/Framework/Search/Test/Unit/Dynamic/IntervalFactoryTest.php
index 0d7b52e00630adde68df4600dd353d1d7e314207..232f789de3ae77014a26ee1e251dbcce6235d0e5 100644
--- a/lib/internal/Magento/Framework/Search/Test/Unit/Dynamic/IntervalFactoryTest.php
+++ b/lib/internal/Magento/Framework/Search/Test/Unit/Dynamic/IntervalFactoryTest.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Framework\Search\Test\Unit\Dynamic;
 
+use Magento\Framework\App\Config\ScopeConfigInterface;
 use Magento\Framework\Search\Dynamic\IntervalInterface;
 use Magento\Framework\App\ScopeInterface;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
@@ -63,7 +64,7 @@ class IntervalFactoryTest extends \PHPUnit_Framework_TestCase
     {
         $this->scopeConfig->expects($this->once())
             ->method('getValue')
-            ->with(self::CONFIG_PATH, ScopeInterface::SCOPE_DEFAULT)
+            ->with(self::CONFIG_PATH, ScopeConfigInterface::SCOPE_TYPE_DEFAULT)
             ->willReturn(self::CONFIG_PATH . 't');
         $this->objectManager->expects($this->once())
             ->method('create')
@@ -83,7 +84,7 @@ class IntervalFactoryTest extends \PHPUnit_Framework_TestCase
     {
         $this->scopeConfig->expects($this->once())
             ->method('getValue')
-            ->with(self::CONFIG_PATH, ScopeInterface::SCOPE_DEFAULT)
+            ->with(self::CONFIG_PATH, ScopeConfigInterface::SCOPE_TYPE_DEFAULT)
             ->willReturn('t');
 
         $this->factoryCreate();
@@ -97,7 +98,7 @@ class IntervalFactoryTest extends \PHPUnit_Framework_TestCase
     {
         $this->scopeConfig->expects($this->once())
             ->method('getValue')
-            ->with(self::CONFIG_PATH, ScopeInterface::SCOPE_DEFAULT)
+            ->with(self::CONFIG_PATH, ScopeConfigInterface::SCOPE_TYPE_DEFAULT)
             ->willReturn(self::CONFIG_PATH . 't');
         $this->objectManager->expects($this->once())
             ->method('create')
diff --git a/lib/internal/Magento/Framework/Session/Generic.php b/lib/internal/Magento/Framework/Session/Generic.php
index dd7da87c933a3fff8be209f77e93b77c5eebea1a..bfaf48d74ee9d7f4851e181e8e69f06437da8993 100644
--- a/lib/internal/Magento/Framework/Session/Generic.php
+++ b/lib/internal/Magento/Framework/Session/Generic.php
@@ -7,38 +7,4 @@ namespace Magento\Framework\Session;
 
 class Generic extends SessionManager
 {
-    /**
-     * Constructor
-     *
-     * @param \Magento\Framework\App\Request\Http $request
-     * @param SidResolverInterface $sidResolver
-     * @param \Magento\Framework\Session\Config\ConfigInterface $sessionConfig
-     * @param SaveHandlerInterface $saveHandler
-     * @param ValidatorInterface $validator
-     * @param StorageInterface $storage
-     * @param \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager
-     * @param \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory
-     */
-    public function __construct(
-        \Magento\Framework\App\Request\Http $request,
-        SidResolverInterface $sidResolver,
-        \Magento\Framework\Session\Config\ConfigInterface $sessionConfig,
-        SaveHandlerInterface $saveHandler,
-        ValidatorInterface $validator,
-        StorageInterface $storage,
-        \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager,
-        \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory
-    ) {
-        parent::__construct(
-            $request,
-            $sidResolver,
-            $sessionConfig,
-            $saveHandler,
-            $validator,
-            $storage,
-            $cookieManager,
-            $cookieMetadataFactory
-        );
-        $this->start();
-    }
 }
diff --git a/lib/internal/Magento/Framework/Session/SessionManager.php b/lib/internal/Magento/Framework/Session/SessionManager.php
index 17636fa0776804b433129011dd25b2edaec33275..c66672e87ca8f6b7098a3ecf17a0df582dad6072 100644
--- a/lib/internal/Magento/Framework/Session/SessionManager.php
+++ b/lib/internal/Magento/Framework/Session/SessionManager.php
@@ -11,6 +11,7 @@ use Magento\Framework\Session\Config\ConfigInterface;
 
 /**
  * Session Manager
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class SessionManager implements SessionManagerInterface
 {
@@ -87,8 +88,11 @@ class SessionManager implements SessionManagerInterface
     protected $cookieMetadataFactory;
 
     /**
-     * Constructor
-     *
+     * @var \Magento\Framework\App\State
+     */
+    private $appState;
+
+    /**
      * @param \Magento\Framework\App\Request\Http $request
      * @param SidResolverInterface $sidResolver
      * @param ConfigInterface $sessionConfig
@@ -97,6 +101,8 @@ class SessionManager implements SessionManagerInterface
      * @param StorageInterface $storage
      * @param \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager
      * @param \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory
+     * @param \Magento\Framework\App\State $appState
+     * @throws \Magento\Framework\Exception\SessionException
      */
     public function __construct(
         \Magento\Framework\App\Request\Http $request,
@@ -106,7 +112,8 @@ class SessionManager implements SessionManagerInterface
         ValidatorInterface $validator,
         StorageInterface $storage,
         \Magento\Framework\Stdlib\CookieManagerInterface $cookieManager,
-        \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory
+        \Magento\Framework\Stdlib\Cookie\CookieMetadataFactory $cookieMetadataFactory,
+        \Magento\Framework\App\State $appState
     ) {
         $this->request = $request;
         $this->sidResolver = $sidResolver;
@@ -116,9 +123,11 @@ class SessionManager implements SessionManagerInterface
         $this->storage = $storage;
         $this->cookieManager = $cookieManager;
         $this->cookieMetadataFactory = $cookieMetadataFactory;
+        $this->appState = $appState;
 
         // Enable session.use_only_cookies
         ini_set('session.use_only_cookies', '1');
+        $this->start();
     }
 
     /**
@@ -152,12 +161,25 @@ class SessionManager implements SessionManagerInterface
     /**
      * Configure session handler and start session
      *
+     * @throws \Magento\Framework\Exception\SessionException
      * @return $this
      */
     public function start()
     {
         if (!$this->isSessionExists()) {
             \Magento\Framework\Profiler::start('session_start');
+
+            try {
+                $this->appState->getAreaCode();
+            } catch (\Magento\Framework\Exception\LocalizedException $e) {
+                throw new \Magento\Framework\Exception\SessionException(
+                    new \Magento\Framework\Phrase(
+                        'Area code not set: Area code must be set before starting a session.'
+                    ),
+                    $e
+                );
+            }
+
             // Need to apply the config options so they can be ready by session_start
             $this->initIniOptions();
             $this->registerSaveHandler();
diff --git a/lib/internal/Magento/Framework/Shell.php b/lib/internal/Magento/Framework/Shell.php
index 0652d49d039e0c43d21375d3d87153db78b1e243..2372ba4088571c89d7865d4a9d2b7523fdd6e1eb 100644
--- a/lib/internal/Magento/Framework/Shell.php
+++ b/lib/internal/Magento/Framework/Shell.php
@@ -49,7 +49,7 @@ class Shell implements ShellInterface
         $command = $this->commandRenderer->render($command, $arguments);
         $this->log($command);
 
-        $disabled = explode(',', ini_get('disable_functions'));
+        $disabled = explode(',', str_replace(' ', ',', ini_get('disable_functions')));
         if (in_array('exec', $disabled)) {
             throw new Exception\LocalizedException(new \Magento\Framework\Phrase("exec function is disabled."));
         }
diff --git a/lib/internal/Magento/Framework/Simplexml/Config.php b/lib/internal/Magento/Framework/Simplexml/Config.php
index 4e1265ebd4a4c180d7bbc4a8b84b0334b5b1676a..2f45cd6550b87a9417f2e50355866765c26d2a2b 100644
--- a/lib/internal/Magento/Framework/Simplexml/Config.php
+++ b/lib/internal/Magento/Framework/Simplexml/Config.php
@@ -118,12 +118,12 @@ class Config
      */
     public function getNode($path = null)
     {
-        if (!$this->_xml instanceof Element) {
+        if (!$this->getXml() instanceof Element) {
             return false;
         } elseif ($path === null) {
-            return $this->_xml;
+            return $this->getXml();
         } else {
-            return $this->_xml->descend($path);
+            return $this->getXml()->descend($path);
         }
     }
 
@@ -135,11 +135,12 @@ class Config
      */
     public function getXpath($xpath)
     {
-        if (empty($this->_xml)) {
+        $xml = $this->getXml();
+        if (empty($xml)) {
             return false;
         }
 
-        if (!($result = @$this->_xml->xpath($xpath))) {
+        if (!($result = @$xml->xpath($xpath))) {
             return false;
         }
 
@@ -476,7 +477,7 @@ class Config
         if (!empty($string)) {
             $xml = simplexml_load_string($string, $this->_elementClass);
             if ($xml) {
-                $this->_xml = $xml;
+                $this->setXml($xml);
                 return true;
             }
         }
@@ -493,7 +494,7 @@ class Config
     {
         $xml = simplexml_import_dom($dom, $this->_elementClass);
         if ($xml) {
-            $this->_xml = $xml;
+            $this->setXml($xml);
             return true;
         }
 
@@ -510,7 +511,7 @@ class Config
      */
     public function setNode($path, $value, $overwrite = true)
     {
-        $this->_xml->setNode($path, $value, $overwrite);
+        $this->getXml()->setNode($path, $value, $overwrite);
         return $this;
     }
 
@@ -575,4 +576,14 @@ class Config
     {
         $this->_xml = null;
     }
+
+    /**
+     * Getter for xml element
+     *
+     * @return Element
+     */
+    protected function getXml()
+    {
+        return $this->_xml;
+    }
 }
diff --git a/lib/internal/Magento/Framework/Test/Unit/UrlTest.php b/lib/internal/Magento/Framework/Test/Unit/UrlTest.php
index 46d9a13f0bf0a5290fd6086d78aab72a9bf502ca..69e2260002ce05ff621e5b63baf613c7e30a879b 100644
--- a/lib/internal/Magento/Framework/Test/Unit/UrlTest.php
+++ b/lib/internal/Magento/Framework/Test/Unit/UrlTest.php
@@ -73,9 +73,10 @@ class UrlTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
+     * @param bool $resolve
      * @return \Magento\Framework\Url\RouteParamsResolverFactory|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected function getRouteParamsResolver()
+    protected function getRouteParamsResolverFactory($resolve = true)
     {
         $routeParamsResolverFactoryMock = $this->getMock(
             'Magento\Framework\Url\RouteParamsResolverFactory',
@@ -84,8 +85,10 @@ class UrlTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $routeParamsResolverFactoryMock->expects($this->once())->method('create')
-            ->will($this->returnValue($this->routeParamsResolverMock));
+        if ($resolve) {
+            $routeParamsResolverFactoryMock->expects($this->once())->method('create')
+                    ->will($this->returnValue($this->routeParamsResolverMock));
+        }
         return $routeParamsResolverFactoryMock;
     }
 
@@ -152,7 +155,10 @@ class UrlTest extends \PHPUnit_Framework_TestCase
     public function testGetBaseUrlNotLinkType()
     {
         $model = $this->getUrlModel(
-            ['scopeResolver' => $this->scopeResolverMock, 'routeParamsResolver' => $this->getRouteParamsResolver()]
+            [
+                'scopeResolver' => $this->scopeResolverMock,
+                'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory()
+            ]
         );
 
         $baseUrl = 'base-url';
@@ -184,9 +190,12 @@ class UrlTest extends \PHPUnit_Framework_TestCase
         $requestMock = $this->getRequestMock();
         $routeConfigMock = $this->getMock('Magento\Framework\App\Route\ConfigInterface');
         $model = $this->getUrlModel(
-            ['scopeResolver' => $this->scopeResolverMock, 'routeParamsResolver' => $this->getRouteParamsResolver(),
+            [
+                'scopeResolver' => $this->scopeResolverMock,
+                'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
                 'queryParamsResolver' => $this->queryParamsResolverMock,
-                'request' => $requestMock, 'routeConfig' => $routeConfigMock, ]
+                'request' => $requestMock, 'routeConfig' => $routeConfigMock,
+            ]
         );
 
         $baseUrl = 'http://localhost/index.php/';
@@ -218,7 +227,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
     {
         $model = $this->getUrlModel([
             'scopeResolver' => $this->scopeResolverMock,
-            'routeParamsResolver' => $this->getRouteParamsResolver(),
+            'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
         ]);
         $model->setData('route_path', 'catalog/product/view');
 
@@ -233,7 +242,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
     {
         $model = $this->getUrlModel([
             'scopeResolver' => $this->scopeResolverMock,
-            'routeParamsResolver' => $this->getRouteParamsResolver(),
+            'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
             'request' => $this->getRequestMock()
         ]);
         $model->setData('route_name', 'catalog');
@@ -251,7 +260,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue(['foo' => 'bar', 'true' => false]));
         $model = $this->getUrlModel([
             'scopeResolver' => $this->scopeResolverMock,
-            'routeParamsResolver' => $this->getRouteParamsResolver(),
+            'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
             'request' => $this->getRequestMock()
         ]);
 
@@ -270,7 +279,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
         $request->expects($this->once())->method('getAlias')->will($this->returnValue('/catalog/product/view/'));
         $model = $this->getUrlModel([
             'scopeResolver' => $this->scopeResolverMock,
-            'routeParamsResolver' => $this->getRouteParamsResolver(),
+            'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
             'request' => $request,
         ]);
 
@@ -299,9 +308,12 @@ class UrlTest extends \PHPUnit_Framework_TestCase
         $requestMock = $this->getRequestMock();
         $routeConfigMock = $this->getMock('Magento\Framework\App\Route\ConfigInterface');
         $model = $this->getUrlModel(
-            ['scopeResolver' => $this->scopeResolverMock, 'routeParamsResolver' => $this->getRouteParamsResolver(),
+            [
+                'scopeResolver' => $this->scopeResolverMock,
+                'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
                 'queryParamsResolver' => $this->queryParamsResolverMock,
-                'request' => $requestMock, 'routeConfig' => $routeConfigMock, ]
+                'request' => $requestMock, 'routeConfig' => $routeConfigMock,
+            ]
         );
 
         $baseUrl = 'http://localhost/index.php/';
@@ -332,9 +344,12 @@ class UrlTest extends \PHPUnit_Framework_TestCase
         $requestMock = $this->getRequestMock();
         $routeConfigMock = $this->getMock('Magento\Framework\App\Route\ConfigInterface');
         $model = $this->getUrlModel(
-            ['scopeResolver' => $this->scopeResolverMock, 'routeParamsResolver' => $this->getRouteParamsResolver(),
+            [
+                'scopeResolver' => $this->scopeResolverMock,
+                'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
                 'queryParamsResolver' => $this->queryParamsResolverMock,
-                'request' => $requestMock, 'routeConfig' => $routeConfigMock, ]
+                'request' => $requestMock, 'routeConfig' => $routeConfigMock,
+            ]
         );
 
         $baseUrl = 'http://localhost/index.php/';
@@ -363,7 +378,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
             'request' => $requestMock,
             'sidResolver' => $this->sidResolverMock,
             'scopeResolver' => $this->scopeResolverMock,
-            'routeParamsResolver' => $this->getRouteParamsResolver(),
+            'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(false),
             'queryParamsResolver' => $this->queryParamsResolverMock,
         ]);
 
@@ -376,8 +391,12 @@ class UrlTest extends \PHPUnit_Framework_TestCase
     public function testGetRedirectUrl()
     {
         $model = $this->getUrlModel(
-            ['routeParamsResolver' => $this->getRouteParamsResolver(), 'session' => $this->sessionMock,
-                'sidResolver' => $this->sidResolverMock, 'queryParamsResolver' => $this->queryParamsResolverMock, ]
+            [
+                'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
+                'session' => $this->sessionMock,
+                'sidResolver' => $this->sidResolverMock,
+                'queryParamsResolver' => $this->queryParamsResolverMock,
+            ]
         );
 
         $this->sidResolverMock->expects($this->once())->method('getUseSessionInUrl')->will($this->returnValue(true));
@@ -396,8 +415,12 @@ class UrlTest extends \PHPUnit_Framework_TestCase
     public function testGetRedirectUrlWithSessionId()
     {
         $model = $this->getUrlModel(
-            ['routeParamsResolver' => $this->getRouteParamsResolver(), 'session' => $this->sessionMock,
-                'sidResolver' => $this->sidResolverMock, 'queryParamsResolver' => $this->queryParamsResolverMock, ]
+            [
+                'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(false),
+                'session' => $this->sessionMock,
+                'sidResolver' => $this->sidResolverMock,
+                'queryParamsResolver' => $this->queryParamsResolverMock,
+            ]
         );
 
         $this->sidResolverMock->expects($this->once())->method('getUseSessionInUrl')->will($this->returnValue(true));
@@ -422,7 +445,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
 
     public function testGetRouteUrlWithValidUrl()
     {
-        $model = $this->getUrlModel(['routeParamsResolver' => $this->getRouteParamsResolver()]);
+        $model = $this->getUrlModel(['routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(false)]);
 
         $this->routeParamsResolverMock->expects($this->never())->method('unsetData');
         $this->assertEquals('http://example.com', $model->getRouteUrl('http://example.com'));
@@ -485,7 +508,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
         $urlSecurityInfoMock = $this->getMock('Magento\Framework\Url\SecurityInfoInterface');
         $model = $this->getUrlModel([
             'urlSecurityInfo' => $urlSecurityInfoMock,
-            'routeParamsResolver' => $this->getRouteParamsResolver(),
+            'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
             'scopeResolver' => $this->scopeResolverMock,
             'scopeConfig' => $this->scopeConfig,
         ]);
@@ -530,7 +553,7 @@ class UrlTest extends \PHPUnit_Framework_TestCase
     public function testGetConfigDataWithSecureIsForcedParam()
     {
         $model = $this->getUrlModel([
-            'routeParamsResolver' => $this->getRouteParamsResolver(),
+            'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
             'scopeResolver' => $this->scopeResolverMock,
             'scopeConfig' => $this->scopeConfig,
         ]);
@@ -562,8 +585,13 @@ class UrlTest extends \PHPUnit_Framework_TestCase
     {
         $requestMock = $this->getRequestMock();
         $model = $this->getUrlModel(
-            ['session' => $this->sessionMock, 'request' => $requestMock, 'sidResolver' => $this->sidResolverMock,
-                'scopeResolver' => $this->scopeResolverMock, 'routeParamsResolver' => $this->getRouteParamsResolver(), ]
+            [
+                'session' => $this->sessionMock,
+                'request' => $requestMock,
+                'sidResolver' => $this->sidResolverMock,
+                'scopeResolver' => $this->scopeResolverMock,
+                'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
+            ]
         );
 
         $requestMock->expects($this->once())
@@ -585,8 +613,13 @@ class UrlTest extends \PHPUnit_Framework_TestCase
     {
         $requestMock = $this->getRequestMock();
         $model = $this->getUrlModel(
-            ['session' => $this->sessionMock, 'request' => $requestMock, 'sidResolver' => $this->sidResolverMock,
-                'scopeResolver' => $this->scopeResolverMock, 'routeParamsResolver' => $this->getRouteParamsResolver(), ]
+            [
+                'session' => $this->sessionMock,
+                'request' => $requestMock,
+                'sidResolver' => $this->sidResolverMock,
+                'scopeResolver' => $this->scopeResolverMock,
+                'routeParamsResolverFactory' => $this->getRouteParamsResolverFactory(),
+            ]
         );
 
         $requestMock->expects($this->once())->method('getHttpHost')->will($this->returnValue('localhost'));
diff --git a/lib/internal/Magento/Framework/Url.php b/lib/internal/Magento/Framework/Url.php
index efffc744e3fe46da126f655f16a95c9f1c5bd4a7..697e461df050f1f623075655acd3ea4fc13ccaa9 100644
--- a/lib/internal/Magento/Framework/Url.php
+++ b/lib/internal/Magento/Framework/Url.php
@@ -56,6 +56,7 @@ namespace Magento\Framework;
  * - G: route_path
  * - H: route_url
  * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInterface
 {
@@ -133,8 +134,12 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
     /**
      * @var \Magento\Framework\Url\RouteParamsResolverInterface
      */
-    protected $_routeParamsResolver;
+    private $_routeParamsResolver;
 
+    /**
+     * @var \Magento\Framework\Url\RouteParamsResolverFactory
+     */
+    private $_routeParamsResolverFactory;
     /**
      * @var \Magento\Framework\Url\ScopeResolverInterface
      */
@@ -157,7 +162,7 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
      * @param \Magento\Framework\Url\ScopeResolverInterface $scopeResolver
      * @param \Magento\Framework\Session\Generic $session
      * @param \Magento\Framework\Session\SidResolverInterface $sidResolver
-     * @param \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolver
+     * @param \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory
      * @param \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param string $scopeType
@@ -171,7 +176,7 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
         \Magento\Framework\Url\ScopeResolverInterface $scopeResolver,
         \Magento\Framework\Session\Generic $session,
         \Magento\Framework\Session\SidResolverInterface $sidResolver,
-        \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolver,
+        \Magento\Framework\Url\RouteParamsResolverFactory $routeParamsResolverFactory,
         \Magento\Framework\Url\QueryParamsResolverInterface $queryParamsResolver,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         $scopeType,
@@ -183,7 +188,7 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
         $this->_scopeResolver = $scopeResolver;
         $this->_session = $session;
         $this->_sidResolver = $sidResolver;
-        $this->_routeParamsResolver = $routeParamsResolver->create();
+        $this->_routeParamsResolverFactory = $routeParamsResolverFactory;
         $this->_queryParamsResolver = $queryParamsResolver;
         $this->_scopeConfig = $scopeConfig;
         $this->_scopeType = $scopeType;
@@ -322,10 +327,10 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
      */
     protected function _getType()
     {
-        if (!$this->_routeParamsResolver->hasData('type')) {
-            $this->_routeParamsResolver->setData('type', self::DEFAULT_URL_TYPE);
+        if (!$this->getRouteParamsResolver()->hasData('type')) {
+            $this->getRouteParamsResolver()->setData('type', self::DEFAULT_URL_TYPE);
         }
-        return $this->_routeParamsResolver->getType();
+        return $this->getRouteParamsResolver()->getType();
     }
 
     /**
@@ -335,27 +340,27 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
      */
     protected function _isSecure()
     {
-        if ($this->_routeParamsResolver->hasData('secure_is_forced')) {
-            return (bool) $this->_routeParamsResolver->getData('secure');
+        if ($this->getRouteParamsResolver()->hasData('secure_is_forced')) {
+            return (bool) $this->getRouteParamsResolver()->getData('secure');
         }
 
         if (!$this->_getScope()->isUrlSecure()) {
             return false;
         }
 
-        if (!$this->_routeParamsResolver->hasData('secure')) {
+        if (!$this->getRouteParamsResolver()->hasData('secure')) {
             if ($this->_getType() == UrlInterface::URL_TYPE_LINK) {
                 $pathSecure = $this->_urlSecurityInfo->isSecure('/' . $this->_getActionPath());
-                $this->_routeParamsResolver->setData('secure', $pathSecure);
+                $this->getRouteParamsResolver()->setData('secure', $pathSecure);
             } elseif ($this->_getType() == UrlInterface::URL_TYPE_STATIC) {
                 $isRequestSecure = $this->_getRequest()->isSecure();
-                $this->_routeParamsResolver->setData('secure', $isRequestSecure);
+                $this->getRouteParamsResolver()->setData('secure', $isRequestSecure);
             } else {
-                $this->_routeParamsResolver->setData('secure', true);
+                $this->getRouteParamsResolver()->setData('secure', true);
             }
         }
 
-        return $this->_routeParamsResolver->getData('secure');
+        return $this->getRouteParamsResolver()->getData('secure');
     }
 
     /**
@@ -367,7 +372,7 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
     public function setScope($params)
     {
         $this->setData('scope', $this->_scopeResolver->getScope($params));
-        $this->_routeParamsResolver->setScope($this->_scopeResolver->getScope($params));
+        $this->getRouteParamsResolver()->setScope($this->_scopeResolver->getScope($params));
         return $this;
     }
 
@@ -401,11 +406,11 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
             $this->setScope($params['_scope']);
         }
         if (isset($params['_type'])) {
-            $this->_routeParamsResolver->setType($params['_type']);
+            $this->getRouteParamsResolver()->setType($params['_type']);
         }
 
         if (isset($params['_secure'])) {
-            $this->_routeParamsResolver->setSecure($params['_secure']);
+            $this->getRouteParamsResolver()->setSecure($params['_secure']);
         }
 
         /**
@@ -416,13 +421,13 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
                 $this->_getRouteFrontName()
             )
         ) {
-            $this->_routeParamsResolver->setType(UrlInterface::URL_TYPE_DIRECT_LINK);
+            $this->getRouteParamsResolver()->setType(UrlInterface::URL_TYPE_DIRECT_LINK);
         }
 
         $result = $this->_getScope()->getBaseUrl($this->_getType(), $this->_isSecure());
         // setting back the original scope
         $this->setScope($origScope);
-        $this->_routeParamsResolver->setType(self::DEFAULT_URL_TYPE);
+        $this->getRouteParamsResolver()->setType(self::DEFAULT_URL_TYPE);
         return $result;
     }
 
@@ -471,7 +476,7 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
                 $key = array_shift($routePieces);
                 if (!empty($routePieces)) {
                     $value = array_shift($routePieces);
-                    $this->_routeParamsResolver->setRouteParam($key, $value);
+                    $this->getRouteParamsResolver()->setRouteParam($key, $value);
                 }
             }
         }
@@ -650,7 +655,7 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
      */
     protected function _setRouteParams(array $data, $unsetOldParams = true)
     {
-        $this->_routeParamsResolver->setRouteParams($data, $unsetOldParams);
+        $this->getRouteParamsResolver()->setRouteParams($data, $unsetOldParams);
         return $this;
     }
 
@@ -661,7 +666,7 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
      */
     protected function _getRouteParams()
     {
-        return $this->_routeParamsResolver->getRouteParams();
+        return $this->getRouteParamsResolver()->getRouteParams();
     }
 
     /**
@@ -677,7 +682,7 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
             return $routePath;
         }
 
-        $this->_routeParamsResolver->unsetData('route_params');
+        $this->getRouteParamsResolver()->unsetData('route_params');
 
         if (isset($routeParams['_direct'])) {
             if (is_array($routeParams)) {
@@ -786,7 +791,7 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
          * this method has condition for adding default controller and action names
          * in case when we have params
          */
-        $this->_routeParamsResolver->unsetData('secure');
+        $this->getRouteParamsResolver()->unsetData('secure');
         $fragment = null;
         if (isset($routeParams['_fragment'])) {
             $fragment = $routeParams['_fragment'];
@@ -840,7 +845,7 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
         if (!is_null($fragment)) {
             $url .= '#' . $fragment;
         }
-        $this->_routeParamsResolver->unsetData('secure');
+        $this->getRouteParamsResolver()->unsetData('secure');
         return $this->escape($url);
     }
 
@@ -1038,4 +1043,17 @@ class Url extends \Magento\Framework\Object implements \Magento\Framework\UrlInt
         $url = $this->_request->getScheme() . '://' . $this->_request->getHttpHost() . $port . $requestUri;
         return $url;
     }
+
+    /**
+     * Get Route Params Resolver
+     *
+     * @return Url\RouteParamsResolverInterface
+     */
+    protected function getRouteParamsResolver()
+    {
+        if (!$this->_routeParamsResolver) {
+            $this->_routeParamsResolver = $this->_routeParamsResolverFactory->create();
+        }
+        return $this->_routeParamsResolver;
+    }
 }
diff --git a/lib/internal/Magento/Framework/Url/ScopeResolverInterface.php b/lib/internal/Magento/Framework/Url/ScopeResolverInterface.php
index 893443659220d4b68e5ec3514f25beb0ea3c7725..a31ae25c76ea41a6efea88d85ccfb5c424092143 100644
--- a/lib/internal/Magento/Framework/Url/ScopeResolverInterface.php
+++ b/lib/internal/Magento/Framework/Url/ScopeResolverInterface.php
@@ -10,7 +10,7 @@ interface ScopeResolverInterface extends \Magento\Framework\App\ScopeResolverInt
     /**
      * Retrieve area code
      *
-     * @return \Magento\Framework\Url\ScopeInterface[]
+     * @return string|null
      */
     public function getAreaCode();
 }
diff --git a/lib/internal/Magento/Framework/UrlInterface/Proxy.php b/lib/internal/Magento/Framework/UrlInterface/Proxy.php
new file mode 100644
index 0000000000000000000000000000000000000000..7ed1a1bbc7bff3df6959ec70ed2aa2c779b21636
--- /dev/null
+++ b/lib/internal/Magento/Framework/UrlInterface/Proxy.php
@@ -0,0 +1,212 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\UrlInterface;
+
+/**
+ * Proxy class for @see \Magento\Framework\UrlInterface
+ */
+class Proxy implements \Magento\Framework\UrlInterface
+{
+    /**
+     * Object Manager instance
+     *
+     * @var \Magento\Framework\ObjectManagerInterface
+     */
+    protected $_objectManager = null;
+
+    /**
+     * Proxied instance name
+     *
+     * @var string
+     */
+    protected $_instanceName = null;
+
+    /**
+     * Proxied instance
+     *
+     * @var \Magento\Framework\UrlInterface
+     */
+    protected $_subject = null;
+
+    /**
+     * Instance shareability flag
+     *
+     * @var bool
+     */
+    protected $_isShared = null;
+
+    /**
+     * Proxy constructor
+     *
+     * @param \Magento\Framework\ObjectManagerInterface $objectManager
+     * @param string $instanceName
+     * @param bool $shared
+     */
+    public function __construct(
+        \Magento\Framework\ObjectManagerInterface $objectManager,
+        $instanceName = '\\Magento\\Framework\\UrlInterface',
+        $shared = true
+    ) {
+        $this->_objectManager = $objectManager;
+        $this->_instanceName = $instanceName;
+        $this->_isShared = $shared;
+    }
+
+    /**
+     * @return array
+     */
+    public function __sleep()
+    {
+        return ['_subject', '_isShared'];
+    }
+
+    /**
+     * Retrieve ObjectManager from global scope
+     *
+     * @return void
+     */
+    public function __wakeup()
+    {
+        $this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+    }
+
+    /**
+     * Clone proxied instance
+     *
+     * @return void
+     */
+    public function __clone()
+    {
+        $this->_subject = clone $this->_getSubject();
+    }
+
+    /**
+     * Get proxied instance
+     *
+     * @return \Magento\Framework\UrlInterface
+     */
+    protected function _getSubject()
+    {
+        if (!$this->_subject) {
+            $this->_subject = true === $this->_isShared
+                ? $this->_objectManager->get($this->_instanceName)
+                : $this->_objectManager->create($this->_instanceName);
+        }
+        return $this->_subject;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getUseSession()
+    {
+        return $this->_getSubject()->getUseSession();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getBaseUrl($params = [])
+    {
+        return $this->_getSubject()->getBaseUrl($params);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getCurrentUrl()
+    {
+        return $this->_getSubject()->getCurrentUrl();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRouteUrl($routePath = null, $routeParams = null)
+    {
+        return $this->_getSubject()->getRouteUrl($routePath, $routeParams);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function addSessionParam()
+    {
+        return $this->_getSubject()->addSessionParam();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function addQueryParams(array $data)
+    {
+        return $this->_getSubject()->addQueryParams($data);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setQueryParam($key, $data)
+    {
+        return $this->_getSubject()->setQueryParam($key, $data);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getUrl($routePath = null, $routeParams = null)
+    {
+        return $this->_getSubject()->getUrl($routePath, $routeParams);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function escape($value)
+    {
+        return $this->_getSubject()->escape($value);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getDirectUrl($url, $params = [])
+    {
+        return $this->_getSubject()->getDirectUrl($url, $params);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function sessionUrlVar($html)
+    {
+        return $this->_getSubject()->sessionUrlVar($html);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isOwnOriginUrl()
+    {
+        return $this->_getSubject()->isOwnOriginUrl();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRedirectUrl($url)
+    {
+        return $this->_getSubject()->getRedirectUrl($url);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setScope($params)
+    {
+        return $this->_getSubject()->setScope($params);
+    }
+}
diff --git a/lib/internal/Magento/Framework/Validator/Factory.php b/lib/internal/Magento/Framework/Validator/Factory.php
index a663b91cc745f01f164e1d30a1f6e9f04682087b..ef5679b220c2460dbc1e94d7d09760af0436fa31 100644
--- a/lib/internal/Magento/Framework/Validator/Factory.php
+++ b/lib/internal/Magento/Framework/Validator/Factory.php
@@ -24,6 +24,11 @@ class Factory
      */
     protected $_configFiles = null;
 
+    /**
+     * @var bool
+     */
+    private $isDefaultTranslatorInitialized = false;
+
     /**
      * Initialize dependencies
      *
@@ -36,7 +41,6 @@ class Factory
     ) {
         $this->_objectManager = $objectManager;
         $this->_configFiles = $moduleReader->getConfigurationFiles('validation.xml');
-        $this->_initializeDefaultTranslator();
     }
 
     /**
@@ -46,15 +50,18 @@ class Factory
      */
     protected function _initializeDefaultTranslator()
     {
-        // Pass translations to \Magento\Framework\TranslateInterface from validators
-        $translatorCallback = function () {
-            $argc = func_get_args();
-            return (string)new \Magento\Framework\Phrase(array_shift($argc), $argc);
-        };
-        /** @var \Magento\Framework\Translate\Adapter $translator */
-        $translator = $this->_objectManager->create('Magento\Framework\Translate\Adapter');
-        $translator->setOptions(['translator' => $translatorCallback]);
-        \Magento\Framework\Validator\AbstractValidator::setDefaultTranslator($translator);
+        if (!$this->isDefaultTranslatorInitialized) {
+            // Pass translations to \Magento\Framework\TranslateInterface from validators
+            $translatorCallback = function () {
+                $argc = func_get_args();
+                return (string)new \Magento\Framework\Phrase(array_shift($argc), $argc);
+            };
+            /** @var \Magento\Framework\Translate\Adapter $translator */
+            $translator = $this->_objectManager->create('Magento\Framework\Translate\Adapter');
+            $translator->setOptions(['translator' => $translatorCallback]);
+            \Magento\Framework\Validator\AbstractValidator::setDefaultTranslator($translator);
+            $this->isDefaultTranslatorInitialized = true;
+        }
     }
 
     /**
@@ -66,6 +73,7 @@ class Factory
      */
     public function getValidatorConfig()
     {
+        $this->_initializeDefaultTranslator();
         return $this->_objectManager->create('Magento\Framework\Validator\Config', ['configFiles' => $this->_configFiles]);
     }
 
@@ -79,6 +87,7 @@ class Factory
      */
     public function createValidatorBuilder($entityName, $groupName, array $builderConfig = null)
     {
+        $this->_initializeDefaultTranslator();
         return $this->getValidatorConfig()->createValidatorBuilder($entityName, $groupName, $builderConfig);
     }
 
@@ -92,6 +101,7 @@ class Factory
      */
     public function createValidator($entityName, $groupName, array $builderConfig = null)
     {
+        $this->_initializeDefaultTranslator();
         return $this->getValidatorConfig()->createValidator($entityName, $groupName, $builderConfig);
     }
 }
diff --git a/lib/internal/Magento/Framework/View/Element/Template.php b/lib/internal/Magento/Framework/View/Element/Template.php
index d03112f72ec82d223b72c2603948d29f5b4032a2..a7f4b683343f87bdda4c73305a248ea92b6d81c6 100644
--- a/lib/internal/Magento/Framework/View/Element/Template.php
+++ b/lib/internal/Magento/Framework/View/Element/Template.php
@@ -190,7 +190,7 @@ class Template extends AbstractBlock
     /**
      * Get absolute path to template
      *
-     * @param null $template
+     * @param string|null $template
      * @return string
      */
     public function getTemplateFile($template = null)
diff --git a/lib/internal/Magento/Framework/View/Layout.php b/lib/internal/Magento/Framework/View/Layout.php
index 6c857548d18ed329d6767bbc6f35684f8205e059..da8130891b3b05e624f358c2f0fe5b1b52d7444d 100644
--- a/lib/internal/Magento/Framework/View/Layout.php
+++ b/lib/internal/Magento/Framework/View/Layout.php
@@ -23,6 +23,12 @@ use Magento\Framework\View\Layout\ScheduledStructure;
  */
 class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Framework\View\LayoutInterface
 {
+
+    /**
+     * Empty layout xml
+     */
+    const LAYOUT_NODE = '<layout/>';
+
     /**
      * Layout Update module
      *
@@ -173,7 +179,6 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
         $cacheable = true
     ) {
         $this->_elementClass = 'Magento\Framework\View\Layout\Element';
-        $this->setXml(simplexml_load_string('<layout/>', $this->_elementClass));
         $this->_renderingOutput = new \Magento\Framework\Object();
 
         $this->_processorFactory = $processorFactory;
@@ -188,8 +193,6 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
 
         $this->readerContextFactory = $readerContextFactory;
         $this->generatorContextFactory = $generatorContextFactory;
-
-        $this->readerContext = $this->readerContextFactory->create();
     }
 
     /**
@@ -248,7 +251,7 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
             $this->_update = null;
         }
         $this->_blocks = [];
-        $this->_xml = null;
+        parent::__destruct();
     }
 
     /**
@@ -278,14 +281,6 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
         return $this;
     }
 
-    /**
-     * @return Layout\Reader\Context
-     */
-    public function getReaderContext()
-    {
-        return $this->readerContext;
-    }
-
     /**
      * Create structure of elements from the loaded XML configuration
      *
@@ -297,13 +292,12 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
         $cacheId = 'structure_' . $this->getUpdate()->getCacheId();
         $result = $this->cache->load($cacheId);
         if ($result) {
-            /** @var Layout\Reader\Context $readerContext */
             $this->readerContext = unserialize($result);
         } else {
             \Magento\Framework\Profiler::start('build_structure');
-            $this->readerPool->interpret($this->readerContext, $this->getNode());
+            $this->readerPool->interpret($this->getReaderContext(), $this->getNode());
             \Magento\Framework\Profiler::stop('build_structure');
-            $this->cache->save(serialize($this->readerContext), $cacheId, $this->getUpdate()->getHandles());
+            $this->cache->save(serialize($this->getReaderContext()), $cacheId, $this->getUpdate()->getHandles());
         }
 
         $generatorContext = $this->generatorContextFactory->create(
@@ -314,7 +308,7 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
         );
 
         \Magento\Framework\Profiler::start('generate_elements');
-        $this->generatorPool->process($this->readerContext, $generatorContext);
+        $this->generatorPool->process($this->getReaderContext(), $generatorContext);
         \Magento\Framework\Profiler::stop('generate_elements');
 
         $this->addToOutputRootContainers();
@@ -1035,7 +1029,7 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
     public function isCacheable()
     {
         $this->build();
-        $cacheableXml = !(bool)count($this->_xml->xpath('//' . Element::TYPE_BLOCK . '[@cacheable="false"]'));
+        $cacheableXml = !(bool)count($this->getXml()->xpath('//' . Element::TYPE_BLOCK . '[@cacheable="false"]'));
         return $this->cacheable && $cacheableXml;
     }
 
@@ -1060,4 +1054,30 @@ class Layout extends \Magento\Framework\Simplexml\Config implements \Magento\Fra
         $this->isPrivate = (bool)$isPrivate;
         return $this;
     }
+
+    /**
+     * Getter and lazy loader for xml element
+     *
+     * @return \Magento\Framework\Simplexml\Element
+     */
+    protected function getXml()
+    {
+        if (!$this->_xml) {
+            $this->setXml(simplexml_load_string(self::LAYOUT_NODE, $this->_elementClass));
+        }
+        return $this->_xml;
+    }
+
+    /**
+     * Getter and lazy loader for reader context
+     *
+     * @return Layout\Reader\Context
+     */
+    public function getReaderContext()
+    {
+        if (!$this->readerContext) {
+            $this->readerContext = $this->readerContextFactory->create();
+        }
+        return $this->readerContext;
+    }
 }
diff --git a/lib/internal/Magento/Framework/View/Layout/Proxy.php b/lib/internal/Magento/Framework/View/Layout/Proxy.php
index 8c399f4e4161a7f847b4f22db49e7e97e8528ef2..95220e34913df356a84e427d9d72e04f5c73b6ac 100644
--- a/lib/internal/Magento/Framework/View/Layout/Proxy.php
+++ b/lib/internal/Magento/Framework/View/Layout/Proxy.php
@@ -6,8 +6,7 @@
 namespace Magento\Framework\View\Layout;
 
 /**
- * Proxy class for \Magento\Framework\View\Layout
- *
+ * Proxy class for @see \Magento\Framework\View\Layout
  * @SuppressWarnings(PHPMD.ExcessivePublicCount)
  */
 class Proxy extends \Magento\Framework\View\Layout
@@ -17,42 +16,44 @@ class Proxy extends \Magento\Framework\View\Layout
      *
      * @var \Magento\Framework\ObjectManagerInterface
      */
-    protected $objectManager;
+    protected $_objectManager = null;
 
     /**
      * Proxied instance name
      *
      * @var string
      */
-    protected $instanceName;
+    protected $_instanceName = null;
 
     /**
      * Proxied instance
      *
      * @var \Magento\Framework\View\Layout
      */
-    protected $subject;
+    protected $_subject = null;
 
     /**
      * Instance shareability flag
      *
      * @var bool
      */
-    protected $isShared;
+    protected $_isShared = null;
 
     /**
+     * Proxy constructor
+     *
      * @param \Magento\Framework\ObjectManagerInterface $objectManager
      * @param string $instanceName
      * @param bool $shared
      */
     public function __construct(
         \Magento\Framework\ObjectManagerInterface $objectManager,
-        $instanceName = 'Magento\Framework\View\Layout',
+        $instanceName = '\\Magento\\Framework\\View\\Layout',
         $shared = true
     ) {
-        $this->objectManager = $objectManager;
-        $this->instanceName = $instanceName;
-        $this->isShared = $shared;
+        $this->_objectManager = $objectManager;
+        $this->_instanceName = $instanceName;
+        $this->_isShared = $shared;
     }
 
     /**
@@ -70,7 +71,7 @@ class Proxy extends \Magento\Framework\View\Layout
      */
     public function __wakeup()
     {
-        $this->objectManager = \Magento\Framework\App\ObjectManager::getInstance();
+        $this->_objectManager = \Magento\Framework\App\ObjectManager::getInstance();
     }
 
     /**
@@ -80,7 +81,7 @@ class Proxy extends \Magento\Framework\View\Layout
      */
     public function __clone()
     {
-        $this->subject = clone $this->getSubject();
+        $this->_subject = clone $this->_getSubject();
     }
 
     /**
@@ -88,415 +89,334 @@ class Proxy extends \Magento\Framework\View\Layout
      *
      * @return \Magento\Framework\View\Layout
      */
-    protected function getSubject()
+    protected function _getSubject()
     {
-        if (!$this->subject) {
-            $this->subject = true === $this->isShared
-                ? $this->objectManager->get($this->instanceName)
-                : $this->objectManager->create($this->instanceName);
+        if (!$this->_subject) {
+            $this->_subject = true === $this->_isShared
+                ? $this->_objectManager->get($this->_instanceName)
+                : $this->_objectManager->create($this->_instanceName);
         }
-        return $this->subject;
+        return $this->_subject;
     }
 
     /**
-     * Retrieve the layout update instance
-     *
-     * @return \Magento\Framework\View\Layout\ProcessorInterface
+     * {@inheritdoc}
+     */
+    public function setGeneratorPool(\Magento\Framework\View\Layout\GeneratorPool $generatorPool)
+    {
+        return $this->_getSubject()->setGeneratorPool($generatorPool);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setBuilder(\Magento\Framework\View\Layout\BuilderInterface $builder)
+    {
+        return $this->_getSubject()->setBuilder($builder);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function publicBuild()
+    {
+        $this->_getSubject()->publicBuild();
+    }
+
+    /**
+     * {@inheritdoc}
      */
     public function getUpdate()
     {
-        return $this->getSubject()->getUpdate();
+        return $this->_getSubject()->getUpdate();
     }
 
     /**
-     * Layout xml generation
-     *
-     * @return $this
+     * {@inheritdoc}
      */
     public function generateXml()
     {
-        return $this->getSubject()->generateXml();
+        return $this->_getSubject()->generateXml();
     }
 
     /**
-     * Create structure of elements from the loaded XML configuration
-     *
-     * @return void
+     * {@inheritdoc}
      */
     public function generateElements()
     {
-        $this->getSubject()->generateElements();
+        $this->_getSubject()->generateElements();
     }
 
     /**
-     * Get child block if exists
-     *
-     * @param string $parentName
-     * @param string $alias
-     * @return bool|\Magento\Framework\View\Element\AbstractBlock
+     * {@inheritdoc}
      */
     public function getChildBlock($parentName, $alias)
     {
-        return $this->getSubject()->getChildBlock($parentName, $alias);
+        return $this->_getSubject()->getChildBlock($parentName, $alias);
     }
 
     /**
-     * Set child element into layout structure
-     *
-     * @param string $parentName
-     * @param string $elementName
-     * @param string $alias
-     * @return $this
+     * {@inheritdoc}
      */
     public function setChild($parentName, $elementName, $alias)
     {
-        return $this->getSubject()->setChild($parentName, $elementName, $alias);
+        return $this->_getSubject()->setChild($parentName, $elementName, $alias);
     }
 
     /**
-     * Reorder a child of a specified element
-     *
-     * If $offsetOrSibling is null, it will put the element to the end
-     * If $offsetOrSibling is numeric (integer) value, it will put the element after/before specified position
-     * Otherwise -- after/before specified sibling
-     *
-     * @param string $parentName
-     * @param string $childName
-     * @param string|int|null $offsetOrSibling
-     * @param bool $after
-     * @return void
+     * {@inheritdoc}
      */
     public function reorderChild($parentName, $childName, $offsetOrSibling, $after = true)
     {
-        $this->getSubject()->reorderChild($parentName, $childName, $offsetOrSibling, $after);
+        $this->_getSubject()->reorderChild($parentName, $childName, $offsetOrSibling, $after);
     }
 
     /**
-     * Remove child element from parent
-     *
-     * @param string $parentName
-     * @param string $alias
-     * @return $this
+     * {@inheritdoc}
      */
     public function unsetChild($parentName, $alias)
     {
-        return $this->getSubject()->unsetChild($parentName, $alias);
+        return $this->_getSubject()->unsetChild($parentName, $alias);
     }
 
     /**
-     * Get list of child names
-     *
-     * @param string $parentName
-     * @return array
+     * {@inheritdoc}
      */
     public function getChildNames($parentName)
     {
-        return $this->getSubject()->getChildNames($parentName);
+        return $this->_getSubject()->getChildNames($parentName);
     }
 
     /**
-     * Get list of child blocks
-     *
-     * Returns associative array of <alias> => <block instance>
-     *
-     * @param string $parentName
-     * @return array
+     * {@inheritdoc}
      */
     public function getChildBlocks($parentName)
     {
-        return $this->getSubject()->getChildBlocks($parentName);
+        return $this->_getSubject()->getChildBlocks($parentName);
     }
 
     /**
-     * Get child name by alias
-     *
-     * @param string $parentName
-     * @param string $alias
-     * @return bool|string
+     * {@inheritdoc}
      */
     public function getChildName($parentName, $alias)
     {
-        return $this->getSubject()->getChildName($parentName, $alias);
+        return $this->_getSubject()->getChildName($parentName, $alias);
     }
 
     /**
-     * Find an element in layout, render it and return string with its output
-     *
-     * @param string $name
-     * @param bool $useCache
-     * @return string
+     * {@inheritdoc}
      */
     public function renderElement($name, $useCache = true)
     {
-        return $this->getSubject()->renderElement($name, $useCache);
+        return $this->_getSubject()->renderElement($name, $useCache);
     }
 
     /**
-     * Add element to parent group
-     *
-     * @param string $blockName
-     * @param string $parentGroupName
-     * @return bool
+     * {@inheritdoc}
+     */
+    public function renderNonCachedElement($name)
+    {
+        return $this->_getSubject()->renderNonCachedElement($name);
+    }
+
+    /**
+     * {@inheritdoc}
      */
     public function addToParentGroup($blockName, $parentGroupName)
     {
-        return $this->getSubject()->addToParentGroup($blockName, $parentGroupName);
+        return $this->_getSubject()->addToParentGroup($blockName, $parentGroupName);
     }
 
     /**
-     * Get element names for specified group
-     *
-     * @param string $blockName
-     * @param string $groupName
-     * @return array
+     * {@inheritdoc}
      */
     public function getGroupChildNames($blockName, $groupName)
     {
-        return $this->getSubject()->getGroupChildNames($blockName, $groupName);
+        return $this->_getSubject()->getGroupChildNames($blockName, $groupName);
     }
 
     /**
-     * Check if element exists in layout structure
-     *
-     * @param string $name
-     * @return bool
+     * {@inheritdoc}
      */
     public function hasElement($name)
     {
-        return $this->getSubject()->hasElement($name);
+        return $this->_getSubject()->hasElement($name);
     }
 
     /**
-     * Get property value of an element
-     *
-     * @param string $name
-     * @param string $attribute
-     * @return mixed
+     * {@inheritdoc}
      */
     public function getElementProperty($name, $attribute)
     {
-        return $this->getSubject()->getElementProperty($name, $attribute);
+        return $this->_getSubject()->getElementProperty($name, $attribute);
     }
 
     /**
-     * Whether specified element is a block
-     *
-     * @param string $name
-     * @return bool
+     * {@inheritdoc}
      */
     public function isBlock($name)
     {
-        return $this->getSubject()->isBlock($name);
+        return $this->_getSubject()->isBlock($name);
     }
 
     /**
-     * Checks if element with specified name is container
-     *
-     * @param string $name
-     * @return bool
+     * {@inheritdoc}
+     */
+    public function isUiComponent($name)
+    {
+        return $this->_getSubject()->isUiComponent($name);
+    }
+
+    /**
+     * {@inheritdoc}
      */
     public function isContainer($name)
     {
-        return $this->getSubject()->isContainer($name);
+        return $this->_getSubject()->isContainer($name);
     }
 
     /**
-     * Whether the specified element may be manipulated externally
-     *
-     * @param string $name
-     * @return bool
+     * {@inheritdoc}
      */
     public function isManipulationAllowed($name)
     {
-        return $this->getSubject()->isManipulationAllowed($name);
+        return $this->_getSubject()->isManipulationAllowed($name);
     }
 
     /**
-     * Save block in blocks registry
-     *
-     * @param string $name
-     * @param \Magento\Framework\View\Element\AbstractBlock $block
-     * @return $this
+     * {@inheritdoc}
      */
     public function setBlock($name, $block)
     {
-        return $this->getSubject()->setBlock($name, $block);
+        return $this->_getSubject()->setBlock($name, $block);
     }
 
     /**
-     * Remove block from registry
-     *
-     * @param string $name
-     * @return $this
+     * {@inheritdoc}
      */
     public function unsetElement($name)
     {
-        return $this->getSubject()->unsetElement($name);
+        return $this->_getSubject()->unsetElement($name);
     }
 
     /**
-     * Block Factory
-     *
-     * @param  string $type
-     * @param  string $name
-     * @param  array $attributes
-     * @return \Magento\Framework\View\Element\AbstractBlock
+     * {@inheritdoc}
      */
-    public function createBlock($type, $name = '', array $attributes = [])
+    public function createBlock($type, $name = '', array $arguments = [])
     {
-        return $this->getSubject()->createBlock($type, $name, $attributes);
+        return $this->_getSubject()->createBlock($type, $name, $arguments);
     }
 
     /**
-     * Add a block to registry, create new object if needed
-     *
-     * @param string|\Magento\Framework\View\Element\AbstractBlock $block
-     * @param string $name
-     * @param string $parent
-     * @param string $alias
-     * @return \Magento\Framework\View\Element\AbstractBlock
+     * {@inheritdoc}
      */
     public function addBlock($block, $name = '', $parent = '', $alias = '')
     {
-        return $this->getSubject()->addBlock($block, $name, $parent, $alias);
+        return $this->_getSubject()->addBlock($block, $name, $parent, $alias);
     }
 
     /**
-     * Insert container into layout structure
-     *
-     * @param string $name
-     * @param string $label
-     * @param array $options
-     * @param string $parent
-     * @param string $alias
-     * @return void
+     * {@inheritdoc}
      */
     public function addContainer($name, $label, array $options = [], $parent = '', $alias = '')
     {
-        $this->getSubject()->addContainer($name, $label, $options, $parent, $alias);
+        $this->_getSubject()->addContainer($name, $label, $options, $parent, $alias);
     }
 
     /**
-     * Rename element in layout and layout structure
-     *
-     * @param string $oldName
-     * @param string $newName
-     * @return bool
+     * {@inheritdoc}
      */
     public function renameElement($oldName, $newName)
     {
-        return $this->getSubject()->renameElement($oldName, $newName);
+        return $this->_getSubject()->renameElement($oldName, $newName);
     }
 
     /**
-     * Retrieve all blocks from registry as array
-     *
-     * @return array
+     * {@inheritdoc}
      */
     public function getAllBlocks()
     {
-        return $this->getSubject()->getAllBlocks();
+        return $this->_getSubject()->getAllBlocks();
     }
 
     /**
-     * Get block object by name
-     *
-     * @param string $name
-     * @return \Magento\Framework\View\Element\AbstractBlock|bool
+     * {@inheritdoc}
      */
     public function getBlock($name)
     {
-        return $this->getSubject()->getBlock($name);
+        return $this->_getSubject()->getBlock($name);
     }
 
     /**
-     * Gets parent name of an element with specified name
-     *
-     * @param string $childName
-     * @return bool|string
+     * {@inheritdoc}
+     */
+    public function getUiComponent($name)
+    {
+        return $this->_getSubject()->getUiComponent($name);
+    }
+
+    /**
+     * {@inheritdoc}
      */
     public function getParentName($childName)
     {
-        return $this->getSubject()->getParentName($childName);
+        return $this->_getSubject()->getParentName($childName);
     }
 
     /**
-     * Get element alias by name
-     *
-     * @param string $name
-     * @return bool|string
+     * {@inheritdoc}
      */
     public function getElementAlias($name)
     {
-        return $this->getSubject()->getElementAlias($name);
+        return $this->_getSubject()->getElementAlias($name);
     }
 
     /**
-     * Add an element to output
-     *
-     * @param string $name
-     * @return $this
+     * {@inheritdoc}
      */
     public function addOutputElement($name)
     {
-        return $this->getSubject()->addOutputElement($name);
+        return $this->_getSubject()->addOutputElement($name);
     }
 
     /**
-     * Remove an element from output
-     *
-     * @param string $name
-     * @return $this
+     * {@inheritdoc}
      */
     public function removeOutputElement($name)
     {
-        return $this->getSubject()->removeOutputElement($name);
+        return $this->_getSubject()->removeOutputElement($name);
     }
 
     /**
-     * Get all blocks marked for output
-     *
-     * @return string
+     * {@inheritdoc}
      */
     public function getOutput()
     {
-        return $this->getSubject()->getOutput();
+        return $this->_getSubject()->getOutput();
     }
 
     /**
-     * Retrieve messages block
-     *
-     * @return \Magento\Framework\View\Element\Messages
+     * {@inheritdoc}
      */
     public function getMessagesBlock()
     {
-        return $this->getSubject()->getMessagesBlock();
+        return $this->_getSubject()->getMessagesBlock();
     }
 
     /**
-     * Get block singleton
-     *
-     * @param string $type
-     * @throws \Magento\Framework\Exception\LocalizedException
-     * @return \Magento\Framework\App\Helper\AbstractHelper
+     * {@inheritdoc}
      */
     public function getBlockSingleton($type)
     {
-        return $this->getSubject()->getBlockSingleton($type);
+        return $this->_getSubject()->getBlockSingleton($type);
     }
 
     /**
-     * @param string $namespace
-     * @param string $staticType
-     * @param string $dynamicType
-     * @param string $type
-     * @param string $template
-     * @param array $data
-     * @return $this
+     * {@inheritdoc}
      */
     public function addAdjustableRenderer($namespace, $staticType, $dynamicType, $type, $template, $data = [])
     {
-        return $this->getSubject()->addAdjustableRenderer(
+        return $this->_getSubject()->addAdjustableRenderer(
             $namespace,
             $staticType,
             $dynamicType,
@@ -507,394 +427,298 @@ class Proxy extends \Magento\Framework\View\Layout
     }
 
     /**
-     * Get renderer options
-     *
-     * @param string $namespace
-     * @param string $staticType
-     * @param string $dynamicType
-     * @return array|null
+     * {@inheritdoc}
      */
     public function getRendererOptions($namespace, $staticType, $dynamicType)
     {
-        return $this->getSubject()->getRendererOptions($namespace, $staticType, $dynamicType);
+        return $this->_getSubject()->getRendererOptions($namespace, $staticType, $dynamicType);
     }
 
     /**
-     * Execute renderer
-     *
-     * @param string $namespace
-     * @param string $staticType
-     * @param string $dynamicType
-     * @param array $data
-     * @return void
+     * {@inheritdoc}
      */
     public function executeRenderer($namespace, $staticType, $dynamicType, $data = [])
     {
-        $this->getSubject()->executeRenderer($namespace, $staticType, $dynamicType, $data);
+        $this->_getSubject()->executeRenderer($namespace, $staticType, $dynamicType, $data);
     }
 
     /**
-     * Init messages by message storage(s), loading and adding messages to layout messages block
-     *
-     * @param string|array $messageGroups
-     * @return void
+     * {@inheritdoc}
      */
     public function initMessages($messageGroups = [])
     {
-        $this->getSubject()->initMessages($messageGroups);
+        $this->_getSubject()->initMessages($messageGroups);
     }
 
     /**
-     * Check is exists non-cacheable layout elements
-     *
-     * @return bool
+     * {@inheritdoc}
      */
     public function isCacheable()
     {
-        return $this->getSubject()->isCacheable();
+        return $this->_getSubject()->isCacheable();
     }
 
     /**
-     * Check is exists non-cacheable layout elements
-     *
-     * @return bool
+     * {@inheritdoc}
      */
     public function isPrivate()
     {
-        return $this->getSubject()->isPrivate();
+        return $this->_getSubject()->isPrivate();
     }
 
     /**
-     * Mark layout as private
-     *
-     * @param bool $isPrivate
-     * @return $this
+     * {@inheritdoc}
      */
     public function setIsPrivate($isPrivate = true)
     {
-        return $this->getSubject()->setIsPrivate($isPrivate);
+        return $this->_getSubject()->setIsPrivate($isPrivate);
     }
 
     /**
-     * Sets xml for this configuration
-     *
-     * @param \Magento\Framework\Simplexml\Element $node
-     * @return $this
+     * {@inheritdoc}
+     */
+    public function getReaderContext()
+    {
+        return $this->_getSubject()->getReaderContext();
+    }
+
+    /**
+     * {@inheritdoc}
      */
     public function setXml(\Magento\Framework\Simplexml\Element $node)
     {
-        return $this->getSubject()->setXml($node);
+        return $this->_getSubject()->setXml($node);
     }
 
     /**
-     * Returns node found by the $path
-     *
-     * @param string $path
-     * @return \Magento\Framework\Simplexml\Element|bool
-     * @see \Magento\Framework\Simplexml\Element::descend
+     * {@inheritdoc}
      */
     public function getNode($path = null)
     {
-        return $this->getSubject()->getNode($path);
+        return $this->_getSubject()->getNode($path);
     }
 
     /**
-     * Returns nodes found by xpath expression
-     *
-     * @param string $xpath
-     * @return \SimpleXMLElement[]|bool
+     * {@inheritdoc}
      */
     public function getXpath($xpath)
     {
-        return $this->getSubject()->getXpath($xpath);
+        return $this->_getSubject()->getXpath($xpath);
     }
 
     /**
-     * Set cache
-     *
-     * @param \Magento\Framework\Simplexml\Config\Cache\AbstractCache $cache
-     * @return $this
+     * {@inheritdoc}
      */
     public function setCache($cache)
     {
-        return $this->getSubject()->setCache($cache);
+        return $this->_getSubject()->setCache($cache);
     }
 
     /**
-     * Return cache
-     *
-     * @return \Magento\Framework\Simplexml\Config\Cache\AbstractCache
+     * {@inheritdoc}
      */
     public function getCache()
     {
-        return $this->getSubject()->getCache();
+        return $this->_getSubject()->getCache();
     }
 
     /**
-     * Set whether cache is saved
-     *
-     * @param boolean $flag
-     * @return $this
+     * {@inheritdoc}
      */
     public function setCacheSaved($flag)
     {
-        return $this->getSubject()->setCacheSaved($flag);
+        return $this->_getSubject()->setCacheSaved($flag);
     }
 
     /**
-     * Return whether cache is saved
-     *
-     * @return bool
-     *
-     * @SuppressWarnings(PHPMD.BooleanGetMethodName)
+     * {@inheritdoc}
      */
     public function getCacheSaved()
     {
-        return $this->getSubject()->getCacheSaved();
+        return $this->_getSubject()->getCacheSaved();
     }
 
     /**
-     * Set cache ID
-     *
-     * @param string $id
-     * @return $this
+     * {@inheritdoc}
      */
     public function setCacheId($id)
     {
-        return $this->getSubject()->setCacheId($id);
+        return $this->_getSubject()->setCacheId($id);
     }
 
     /**
-     * Return cache ID
-     *
-     * @return string
+     * {@inheritdoc}
      */
     public function getCacheId()
     {
-        return $this->getSubject()->getCacheId();
+        return $this->_getSubject()->getCacheId();
     }
 
     /**
-     * Set cache tags
-     *
-     * @param array $tags
-     * @return $this
+     * {@inheritdoc}
      */
     public function setCacheTags($tags)
     {
-        return $this->getSubject()->setCacheTags($tags);
+        return $this->_getSubject()->setCacheTags($tags);
     }
 
     /**
-     * Return cache tags
-     *
-     * @return array
+     * {@inheritdoc}
      */
     public function getCacheTags()
     {
-        return $this->getSubject()->getCacheTags();
+        return $this->_getSubject()->getCacheTags();
     }
 
     /**
-     * Set cache lifetime
-     *
-     * @param int $lifetime
-     * @return $this
+     * {@inheritdoc}
      */
     public function setCacheLifetime($lifetime)
     {
-        return $this->getSubject()->setCacheLifetime($lifetime);
+        return $this->_getSubject()->setCacheLifetime($lifetime);
     }
 
     /**
-     * Return cache lifetime
-     *
-     * @return int
+     * {@inheritdoc}
      */
     public function getCacheLifetime()
     {
-        return $this->getSubject()->getCacheLifetime();
+        return $this->_getSubject()->getCacheLifetime();
     }
 
     /**
-     * Set cache checksum
-     *
-     * @param string $data
-     * @return $this
+     * {@inheritdoc}
      */
     public function setCacheChecksum($data)
     {
-        return $this->getSubject()->setCacheChecksum($data);
+        return $this->_getSubject()->setCacheChecksum($data);
     }
 
     /**
-     * Update cache checksum
-     *
-     * @param string $data
-     * @return $this
+     * {@inheritdoc}
      */
     public function updateCacheChecksum($data)
     {
-        return $this->getSubject()->updateCacheChecksum($data);
+        return $this->_getSubject()->updateCacheChecksum($data);
     }
 
     /**
-     * Return cache checksum
-     *
-     * @return string
+     * {@inheritdoc}
      */
     public function getCacheChecksum()
     {
-        return $this->getSubject()->getCacheChecksum();
+        return $this->_getSubject()->getCacheChecksum();
     }
 
     /**
-     * Get cache checksum ID
-     *
-     * @return string
+     * {@inheritdoc}
      */
     public function getCacheChecksumId()
     {
-        return $this->getSubject()->getCacheChecksumId();
+        return $this->_getSubject()->getCacheChecksumId();
     }
 
     /**
-     * Fetch cache checksum
-     *
-     * @return boolean
+     * {@inheritdoc}
      */
     public function fetchCacheChecksum()
     {
-        return $this->getSubject()->fetchCacheChecksum();
+        return $this->_getSubject()->fetchCacheChecksum();
     }
 
     /**
-     * Validate cache checksum
-     *
-     * @return boolean
+     * {@inheritdoc}
      */
     public function validateCacheChecksum()
     {
-        return $this->getSubject()->validateCacheChecksum();
+        return $this->_getSubject()->validateCacheChecksum();
     }
 
     /**
-     * Load cache
-     *
-     * @return boolean
+     * {@inheritdoc}
      */
     public function loadCache()
     {
-        return $this->getSubject()->loadCache();
+        return $this->_getSubject()->loadCache();
     }
 
     /**
-     * Save cache
-     *
-     * @param array $tags
-     * @return $this
+     * {@inheritdoc}
      */
     public function saveCache($tags = null)
     {
-        return $this->getSubject()->saveCache($tags);
+        return $this->_getSubject()->saveCache($tags);
     }
 
     /**
-     * Return Xml of node as string
-     *
-     * @return string
+     * {@inheritdoc}
      */
     public function getXmlString()
     {
-        return $this->getSubject()->getXmlString();
+        return $this->_getSubject()->getXmlString();
     }
 
     /**
-     * Remove cache
-     *
-     * @return $this
+     * {@inheritdoc}
      */
     public function removeCache()
     {
-        return $this->getSubject()->removeCache();
+        return $this->_getSubject()->removeCache();
     }
 
     /**
-     * Imports XML file
-     *
-     * @param string $filePath
-     * @return boolean
+     * {@inheritdoc}
      */
     public function loadFile($filePath)
     {
-        return $this->getSubject()->loadFile($filePath);
+        return $this->_getSubject()->loadFile($filePath);
     }
 
     /**
-     * Imports XML string
-     *
-     * @param string $string
-     * @return boolean
+     * {@inheritdoc}
      */
     public function loadString($string)
     {
-        return $this->getSubject()->loadString($string);
+        return $this->_getSubject()->loadString($string);
     }
 
     /**
-     * Imports DOM node
-     *
-     * @param \DOMNode $dom
-     * @return bool
+     * {@inheritdoc}
      */
     public function loadDom(\DOMNode $dom)
     {
-        return $this->getSubject()->loadDom($dom);
+        return $this->_getSubject()->loadDom($dom);
     }
 
     /**
-     * Create node by $path and set its value.
-     *
-     * @param string $path separated by slashes
-     * @param string $value
-     * @param boolean $overwrite
-     * @return $this
+     * {@inheritdoc}
      */
     public function setNode($path, $value, $overwrite = true)
     {
-        return $this->getSubject()->setNode($path, $value, $overwrite);
+        return $this->_getSubject()->setNode($path, $value, $overwrite);
     }
 
     /**
-     * Process configuration xml
-     *
-     * @return $this
+     * {@inheritdoc}
      */
     public function applyExtends()
     {
-        return $this->getSubject()->applyExtends();
+        return $this->_getSubject()->applyExtends();
     }
 
     /**
-     * Stub method for processing file data right after loading the file text
-     *
-     * @param string $text
-     * @return string
+     * {@inheritdoc}
      */
     public function processFileData($text)
     {
-        return $this->getSubject()->processFileData($text);
+        return $this->_getSubject()->processFileData($text);
     }
 
     /**
-     * Extend configuration
-     *
-     * @param \Magento\Framework\Simplexml\Config $config
-     * @param boolean $overwrite
-     * @return $this
+     * {@inheritdoc}
      */
     public function extend(\Magento\Framework\Simplexml\Config $config, $overwrite = true)
     {
-        return $this->getSubject()->extend($config, $overwrite);
+        return $this->_getSubject()->extend($config, $overwrite);
     }
 }
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Element/MessagesTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Element/MessagesTest.php
index bd18ebe344f884734c1b78233ed278c6c8b6b440..6f552656be534c3322b7f778a769fb55c83a366c 100644
--- a/lib/internal/Magento/Framework/View/Test/Unit/Element/MessagesTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/Element/MessagesTest.php
@@ -9,6 +9,7 @@
  */
 namespace Magento\Framework\View\Test\Unit\Element;
 
+use Magento\Framework\Message\Manager;
 use \Magento\Framework\View\Element\Messages;
 
 use Magento\Framework\Message\ManagerInterface;
@@ -229,7 +230,7 @@ class MessagesTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($emptyMessagesCacheKey, $this->messages->getCacheKeyInfo());
 
         $messagesCacheKey = ['storage_types' => 'a:1:{i:0;s:7:"default";}'];
-        $this->messages->addStorageType(ManagerInterface::DEFAULT_GROUP);
+        $this->messages->addStorageType(Manager::DEFAULT_GROUP);
         $this->assertEquals($messagesCacheKey, $this->messages->getCacheKeyInfo());
     }
 
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php b/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php
index 45effcf449e43c4e7a05dcc77d37003195069eea..3d60c5e411300fd1ba642d03ed96720959434828 100644
--- a/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/LayoutTest.php
@@ -134,9 +134,6 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
         $this->readerContextMock = $this->getMockBuilder('Magento\Framework\View\Layout\Reader\Context')
             ->disableOriginalConstructor()
             ->getMock();
-        $this->readerContextFactoryMock->expects($this->once())
-            ->method('create')
-            ->willReturn($this->readerContextMock);
         $this->generatorContextFactoryMock = $this->getMockBuilder(
             'Magento\Framework\View\Layout\Generator\ContextFactory'
         )->disableOriginalConstructor()
@@ -683,6 +680,9 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
 
     public function testGenerateElementsWithoutCache()
     {
+        $this->readerContextFactoryMock->expects($this->once())
+            ->method('create')
+            ->willReturn($this->readerContextMock);
         $layoutCacheId = 'layout_cache_id';
         $handles = ['default', 'another'];
         /** @var \Magento\Framework\View\Layout\Element $xml */
@@ -807,4 +807,10 @@ class LayoutTest extends \PHPUnit_Framework_TestCase
 
         $this->model->generateElements();
     }
+
+    public function testGetXml()
+    {
+        $xml = '<layout/>';
+        $this->assertSame($xml, \Magento\Framework\View\Layout::LAYOUT_NODE);
+    }
 }
diff --git a/setup/pub/magento/setup/readiness-check.js b/setup/pub/magento/setup/readiness-check.js
index d7c0eb243e2fccce768b7eec41e4b5b414ca7584..fa6da9344a549ffe0fe5a228630c8b27507ef26e 100644
--- a/setup/pub/magento/setup/readiness-check.js
+++ b/setup/pub/magento/setup/readiness-check.js
@@ -32,7 +32,7 @@ angular.module('readiness-check', [])
             processed: false,
             expanded: false
         };
-        $scope.rawpost = {
+        $scope.settings = {
             visible: false,
             processed: false,
             expanded: false
@@ -62,16 +62,16 @@ angular.module('readiness-check', [])
                     $scope.stopProgress();
                 }
             },
-            'php-rawpost': {
-                url:'index.php/environment/php-rawpost',
+            'php-settings': {
+                url:'index.php/environment/php-settings',
                 show: function() {
                     $scope.startProgress();
-                    $scope.rawpost.visible = true;
+                    $scope.settings.visible = true;
                 },
                 process: function(data) {
-                    $scope.rawpost.processed = true;
-                    angular.extend($scope.rawpost, data);
-                    $scope.updateOnProcessed($scope.rawpost.responseType);
+                    $scope.settings.processed = true;
+                    angular.extend($scope.settings, data);
+                    $scope.updateOnProcessed($scope.settings.responseType);
                     $scope.stopProgress();
                 }
             },
diff --git a/setup/src/Magento/Setup/Console/Command/DeployStaticContentCommand.php b/setup/src/Magento/Setup/Console/Command/DeployStaticContentCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..5cde08cd967e98ed71d3fbf719f3adb104fb54a8
--- /dev/null
+++ b/setup/src/Magento/Setup/Console/Command/DeployStaticContentCommand.php
@@ -0,0 +1,130 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Setup\Console\Command;
+
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Magento\Framework\App\DeploymentConfig;
+use Symfony\Component\Console\Input\InputArgument;
+use Magento\Setup\Model\ObjectManagerProvider;
+
+/**
+ * Command for deploy static content
+ */
+class DeployStaticContentCommand extends Command
+{
+    /**
+     * Key for dry-run option
+     */
+    const DRY_RUN_OPTION = 'dry-run';
+
+    /**
+     * Key for languages parameter
+     */
+    const LANGUAGE_OPTION = 'languages';
+
+    /**
+     * Object manager provider
+     *
+     * @var ObjectManagerProvider
+     */
+    private $objectManagerProvider;
+
+    /**
+     * Deployment configuration
+     *
+     * @var DeploymentConfig
+     */
+    private $deploymentConfig;
+
+    /**
+     * Inject dependencies
+     *
+     * @param ObjectManagerProvider $objectManagerProvider
+     * @param DeploymentConfig $deploymentConfig
+     */
+    public function __construct(ObjectManagerProvider $objectManagerProvider, DeploymentConfig $deploymentConfig)
+    {
+        $this->objectManagerProvider = $objectManagerProvider;
+        $this->deploymentConfig = $deploymentConfig;
+        parent::__construct();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('setup:static-content:deploy')
+            ->setDescription('Deploys static view files')
+            ->setDefinition([
+                new InputOption(
+                    self::DRY_RUN_OPTION,
+                    '-d',
+                    InputOption::VALUE_NONE,
+                    'If specified, then no files will be actually deployed.'
+                ),
+                new InputArgument(
+                    self::LANGUAGE_OPTION,
+                    InputArgument::IS_ARRAY,
+                    'List of languages you want the tool populate files for.',
+                    ['en_US']
+                ),
+            ]);
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        if (!$this->deploymentConfig->isAvailable()) {
+            $output->writeln("<info>You need to install the Magento application before running this utility.</info>");
+            return;
+        }
+
+        $options = $input->getOptions();
+
+        $languages = $input->getArgument(self::LANGUAGE_OPTION);
+        foreach ($languages as $lang) {
+            if (!preg_match('/^[a-z]{2}_[A-Z]{2}$/', $lang)) {
+                throw new \InvalidArgumentException(
+                    $lang . ' argument has invalid value format'
+                );
+            }
+        }
+
+        try {
+            $objectManager = $this->objectManagerProvider->get();
+
+            // run the deployment logic
+            $filesUtil = $objectManager->create(
+                '\Magento\Framework\App\Utility\Files',
+                ['pathToSource' => BP]
+            );
+
+            $objectManagerFactory = $this->objectManagerProvider->getObjectManagerFactory();
+
+            /** @var \Magento\Setup\Model\Deployer $deployer */
+            $deployer = $objectManager->create(
+                'Magento\Setup\Model\Deployer',
+                ['filesUtil' => $filesUtil, 'output' => $output, 'isDryRun' => $options[self::DRY_RUN_OPTION]]
+            );
+            $deployer->deploy($objectManagerFactory, $languages);
+
+        } catch (\Exception $e) {
+            $output->writeln('<error>' . $e->getMessage() . '</error>>');
+            if ($output->isVerbose()) {
+                $output->writeln($e->getTraceAsString());
+            }
+            return;
+        }
+    }
+}
diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..8236627a40caf9180839f9d4d4b259bd381a1656
--- /dev/null
+++ b/setup/src/Magento/Setup/Console/Command/DiCompileCommand.php
@@ -0,0 +1,200 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Setup\Console\Command;
+
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\ObjectManagerInterface;
+use Magento\Framework\App\DeploymentConfig;
+use Magento\Setup\Model\ObjectManagerProvider;
+use Magento\Setup\Module\Di\App\Task\Manager;
+use Magento\Setup\Module\Di\App\Task\OperationFactory;
+use Magento\Setup\Module\Di\App\Task\OperationException;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Command to run compile in single-tenant mode
+ */
+class DiCompileCommand extends Command
+{
+    /**
+     * @var DeploymentConfig
+     */
+    private $deploymentConfig;
+
+    /**
+     * @var ObjectManagerInterface
+     */
+    private $objectManager;
+
+    /**
+     * @var Manager
+     */
+    private $taskManager;
+
+    /**
+     * @var DirectoryList
+     */
+    private $directoryList;
+
+    /**
+     * @var array
+     */
+    private $excludedPathsList;
+
+    /**
+     * Constructor
+     *
+     * @param DeploymentConfig $deploymentConfig
+     * @param DirectoryList $directoryList
+     * @param Manager $taskManager
+     * @param ObjectManagerProvider $objectManagerProvider
+     */
+    public function __construct(
+        DeploymentConfig $deploymentConfig,
+        DirectoryList $directoryList,
+        Manager $taskManager,
+        ObjectManagerProvider $objectManagerProvider
+    ) {
+        $this->deploymentConfig = $deploymentConfig;
+        $this->directoryList = $directoryList;
+        $this->objectManager = $objectManagerProvider->get();
+        $this->taskManager = $taskManager;
+        parent::__construct();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('setup:di:compile')
+            ->setDescription(
+                'Generates DI configuration and all non-existing interceptors and factories'
+            );
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $appCodePath = $this->directoryList->getPath(DirectoryList::MODULES);
+        $libraryPath = $this->directoryList->getPath(DirectoryList::LIB_INTERNAL);
+        $generationPath = $this->directoryList->getPath(DirectoryList::GENERATION);
+        if (!$this->deploymentConfig->isAvailable()) {
+            $output->writeln('You cannot run this command because the Magento application is not installed.');
+            return;
+        }
+        $compiledPathsList = [
+            'application' => $appCodePath,
+            'library' => $libraryPath . '/Magento/Framework',
+            'generated_helpers' => $generationPath
+        ];
+        $this->excludedPathsList = [
+            'application' => '#^' . $appCodePath . '/[\\w]+/[\\w]+/Test#',
+            'framework' => '#^' . $libraryPath . '/[\\w]+/[\\w]+/([\\w]+/)?Test#'
+        ];
+        $this->configureObjectManager($output);
+
+        $operations = [
+            OperationFactory::REPOSITORY_GENERATOR => [
+                'path' => $compiledPathsList['application'],
+                'filePatterns' => ['di' => '/\/etc\/([a-zA-Z_]*\/di|di)\.xml$/']
+            ],
+            OperationFactory::APPLICATION_CODE_GENERATOR => [
+                $compiledPathsList['application'],
+                $compiledPathsList['library'],
+                $compiledPathsList['generated_helpers'],
+            ],
+            OperationFactory::INTERCEPTION => [
+                    'intercepted_paths' => [
+                        $compiledPathsList['application'],
+                        $compiledPathsList['library'],
+                        $compiledPathsList['generated_helpers'],
+                    ],
+                    'path_to_store' => $compiledPathsList['generated_helpers'],
+            ],
+            OperationFactory::AREA_CONFIG_GENERATOR => [
+                $compiledPathsList['application'],
+                $compiledPathsList['library'],
+                $compiledPathsList['generated_helpers'],
+            ],
+            OperationFactory::INTERCEPTION_CACHE => [
+                $compiledPathsList['application'],
+                $compiledPathsList['library'],
+                $compiledPathsList['generated_helpers'],
+            ]
+        ];
+
+        try {
+            foreach ($operations as $operationCode => $arguments) {
+                $this->taskManager->addOperation(
+                    $operationCode,
+                    $arguments
+                );
+            }
+            $this->taskManager->process();
+            $output->writeln('<info>Generated code and dependency injection configuration successfully.</info>');
+        } catch (OperationException $e) {
+            $output->writeln('<error>' . $e->getMessage() . '</error>');
+        }
+    }
+
+    /**
+     * Configure Object Manager
+     *
+     * @param OutputInterface $output
+     * @return void
+     */
+    private function configureObjectManager(OutputInterface $output)
+    {
+        $this->objectManager->configure(
+            [
+                'preferences' => [
+                    'Magento\Setup\Module\Di\Compiler\Config\WriterInterface' =>
+                        'Magento\Setup\Module\Di\Compiler\Config\Writer\Filesystem',
+                ],
+                'Magento\Setup\Module\Di\Compiler\Config\ModificationChain' => [
+                    'arguments' => [
+                        'modificationsList' => [
+                            'BackslashTrim' =>
+                                ['instance' => 'Magento\Setup\Module\Di\Compiler\Config\Chain\BackslashTrim'],
+                            'PreferencesResolving' =>
+                                ['instance' => 'Magento\Setup\Module\Di\Compiler\Config\Chain\PreferencesResolving'],
+                            'InterceptorSubstitution' =>
+                                ['instance' => 'Magento\Setup\Module\Di\Compiler\Config\Chain\InterceptorSubstitution'],
+                            'InterceptionPreferencesResolving' =>
+                                ['instance' => 'Magento\Setup\Module\Di\Compiler\Config\Chain\PreferencesResolving'],
+                            'ArgumentsSerialization' =>
+                                ['instance' => 'Magento\Setup\Module\Di\Compiler\Config\Chain\ArgumentsSerialization'],
+                        ]
+                    ]
+                ],
+                'Magento\Setup\Module\Di\Code\Generator\PluginList' => [
+                    'arguments' => [
+                        'cache' => [
+                            'instance' => 'Magento\Framework\App\Interception\Cache\CompiledConfig'
+                        ]
+                    ]
+                ],
+                'Magento\Setup\Module\Di\Code\Reader\ClassesScanner' => [
+                    'arguments' => [
+                        'excludePatterns' => $this->excludedPathsList
+                    ]
+                ],
+                'Magento\Setup\Module\Di\Compiler\Log\Writer\Console' => [
+                    'arguments' => [
+                        'output' => $output,
+                    ]
+                ],
+            ]
+        );
+    }
+}
diff --git a/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php b/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..6f37a57c9c00c20a9935ce1f5f223ebcefff582d
--- /dev/null
+++ b/setup/src/Magento/Setup/Console/Command/DiCompileMultiTenantCommand.php
@@ -0,0 +1,362 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Console\Command;
+
+use Magento\Store\Model\StoreManager;
+use Magento\Setup\Model\ObjectManagerProvider;
+use Magento\Framework\App\ObjectManager;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Magento\Framework\Api\Code\Generator\Mapper;
+use Magento\Framework\Api\Code\Generator\SearchResults;
+use Magento\Framework\Autoload\AutoloaderRegistry;
+use Magento\Framework\Interception\Code\Generator\Interceptor;
+use Magento\Framework\ObjectManager\Code\Generator\Converter;
+use Magento\Framework\ObjectManager\Code\Generator\Factory;
+use Magento\Framework\ObjectManager\Code\Generator\Proxy;
+use Magento\Framework\ObjectManager\Code\Generator\Repository;
+use Magento\Framework\ObjectManager\Code\Generator\Persistor;
+use Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator;
+use Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator;
+use Magento\Setup\Module\Di\Code\Scanner;
+use Magento\Setup\Module\Di\Compiler\Log\Log;
+use Magento\Setup\Module\Di\Compiler\Log\Writer;
+use Magento\Setup\Module\Di\Definition\Compressor;
+use Magento\Setup\Module\Di\Definition\Serializer\Igbinary;
+use Magento\Setup\Module\Di\Definition\Serializer\Standard;
+use \Magento\Framework\App\Filesystem\DirectoryList;
+
+/**
+ * Command to generate all non-existing proxies and factories, and pre-compile class definitions,
+ * inheritance information and plugin definitions
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class DiCompileMultiTenantCommand extends AbstractSetupCommand
+{
+    /**#@+
+     * Names of input options
+     */
+    const INPUT_KEY_SERIALIZER = 'serializer';
+    const INPUT_KEY_EXTRA_CLASSES_FILE = 'extra-classes-file';
+    const INPUT_KEY_GENERATION = 'generation';
+    const INPUT_KEY_DI= 'di';
+    const INPUT_KEY_EXCLUDE_PATTERN= 'exclude-pattern';
+    /**#@- */
+
+    /**
+     * Object Manager
+     *
+     * @var ObjectManager
+     */
+    private $objectManager;
+
+    /**
+     * Filesystem Directory List
+     *
+     * @var DirectoryList
+     */
+    private $directoryList;
+
+    /**
+     *
+     * @var array
+     */
+    private $entities;
+
+    /**
+     *
+     * @var array
+     */
+    private $files;
+
+    /**
+     *
+     * @var \Magento\Framework\Code\Generator
+     */
+    private $generator;
+
+    /**
+     *
+     * @var Log
+     */
+    private $log;
+
+    /**
+     * Constructor
+     *
+     * @param ObjectManagerProvider $objectManagerProvider
+     * @param DirectoryList $directoryList
+     */
+    public function __construct(ObjectManagerProvider $objectManagerProvider, DirectoryList $directoryList)
+    {
+        $this->objectManager = $objectManagerProvider->get();
+        $this->directoryList = $directoryList;
+        parent::__construct();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $options = [
+            new InputOption(
+                self::INPUT_KEY_SERIALIZER,
+                null,
+                InputOption::VALUE_REQUIRED,
+                'Serializer function that should be used (serialize|igbinary) default: serialize'
+            ),
+            new InputOption(
+                self::INPUT_KEY_EXTRA_CLASSES_FILE,
+                null,
+                InputOption::VALUE_REQUIRED,
+                'Path to file with extra proxies and factories to generate'
+            ),
+            new InputOption(
+                self::INPUT_KEY_GENERATION,
+                null,
+                InputOption::VALUE_REQUIRED,
+                'Absolute path to generated classes, <magento_root>/var/generation by default'
+            ),
+            new InputOption(
+                self::INPUT_KEY_DI,
+                null,
+                InputOption::VALUE_REQUIRED,
+                'Absolute path to DI definitions directory, <magento_root>/var/di by default'
+            ),
+            new InputOption(
+                self::INPUT_KEY_EXCLUDE_PATTERN,
+                null,
+                InputOption::VALUE_REQUIRED,
+                'Allows to exclude Paths from compilation (default is #[\\\\/]m1[\\\\/]#i)'
+            ),
+        ];
+        $this->setName('setup:di:compile-multi-tenant')
+            ->setDescription(
+                'Generates all non-existing proxies and factories, and pre-compile class definitions, '
+                . 'inheritance information and plugin definitions'
+            )
+            ->setDefinition($options);
+        parent::configure();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $generationDir = $input->getOption(self::INPUT_KEY_GENERATION) ? $input->getOption(self::INPUT_KEY_GENERATION)
+            : $this->directoryList->getPath(DirectoryList::GENERATION);
+        $testExcludePatterns = [
+            "#^" . $this->directoryList->getPath(DirectoryList::MODULES) . "/[\\w]+/[\\w]+/Test#",
+            "#^" . $this->directoryList->getPath(DirectoryList::LIB_INTERNAL)
+            . "/[\\w]+/[\\w]+/([\\w]+/)?Test#",
+            "#^" . $this->directoryList->getPath(DirectoryList::SETUP) . "/[\\w]+/[\\w]+/Test#",
+            "#^" . $this->directoryList->getRoot() . "/dev/tools/Magento/Tools/[\\w]+/Test#"
+        ];
+        $fileExcludePatterns = $input->getOption('exclude-pattern') ?
+            [$input->getOption(self::INPUT_KEY_EXCLUDE_PATTERN)] : ['#[\\\\/]M1[\\\\/]#i'];
+        $fileExcludePatterns = array_merge($fileExcludePatterns, $testExcludePatterns);
+        /** @var Writer\Console logWriter Writer model for success messages */
+        $logWriter = new Writer\Console($output);
+        $this->log = new Log($logWriter, $logWriter);
+        AutoloaderRegistry::getAutoloader()->addPsr4('Magento\\', $generationDir . '/Magento/');
+        // 1 Code generation
+        $this->generateCode($generationDir, $fileExcludePatterns, $input);
+        // 2. Compilation
+        $this->compileCode($generationDir, $fileExcludePatterns, $input);
+        //Reporter
+        $this->log->report();
+        if (!$this->log->hasError()) {
+            $output->writeln(
+                '<info>On *nix systems, verify the Magento application has permissions to modify files '
+                . 'created by the compiler in the "var" directory. For instance, if you run the Magento application '
+                . 'using Apache, the owner of the files in the "var" directory should be the Apache user (example '
+                . 'command: "chown -R www-data:www-data <MAGENTO_ROOT>/var" where MAGENTO_ROOT is the Magento '
+                . 'root directory).</info>'
+            );
+        }
+    }
+
+    /**
+     * Generate Code
+     *
+     * @param string $generationDir
+     * @param array $fileExcludePatterns
+     * @param InputInterface $input
+     * @return void
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     */
+    public function generateCode($generationDir, $fileExcludePatterns, $input)
+    {
+        // 1.1 Code scan
+        $filePatterns = ['php' => '/.*\.php$/', 'di' => '/\/etc\/([a-zA-Z_]*\/di|di)\.xml$/'];
+        $codeScanDir = $this->directoryList->getRoot() . '/app';
+        $directoryScanner = new Scanner\DirectoryScanner();
+        $this->files = $directoryScanner->scan($codeScanDir, $filePatterns, $fileExcludePatterns);
+        $this->files['additional'] = [$input->getOption(self::INPUT_KEY_EXTRA_CLASSES_FILE)];
+        $repositoryScanner = new Scanner\RepositoryScanner();
+        $repositories = $repositoryScanner->collectEntities($this->files['di']);
+        $scanner = new Scanner\CompositeScanner();
+        $scanner->addChild(new Scanner\PhpScanner($this->log), 'php');
+        $scanner->addChild(new Scanner\XmlScanner($this->log), 'di');
+        $scanner->addChild(new Scanner\ArrayScanner(), 'additional');
+        $this->entities = $scanner->collectEntities($this->files);
+        $interceptorScanner = new Scanner\XmlInterceptorScanner();
+        $this->entities['interceptors'] = $interceptorScanner->collectEntities($this->files['di']);
+        // 1.2 Generation of Factory and Additional Classes
+        $generatorIo = new \Magento\Framework\Code\Generator\Io(
+            new \Magento\Framework\Filesystem\Driver\File(),
+            $generationDir
+        );
+        $this->generator = new \Magento\Framework\Code\Generator(
+            $generatorIo,
+            [
+                Interceptor::ENTITY_TYPE => 'Magento\Framework\Interception\Code\Generator\Interceptor',
+                Proxy::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Proxy',
+                Factory::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Factory',
+                Mapper::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\Mapper',
+                Persistor::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Persistor',
+                Repository::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Repository',
+                Converter::ENTITY_TYPE => 'Magento\Framework\ObjectManager\Code\Generator\Converter',
+                SearchResults::ENTITY_TYPE => 'Magento\Framework\Api\Code\Generator\SearchResults',
+                ExtensionAttributesInterfaceGenerator::ENTITY_TYPE =>
+                    'Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator',
+                ExtensionAttributesGenerator::ENTITY_TYPE =>
+                    'Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator'
+            ]
+        );
+        /** Initialize object manager for code generation based on configs */
+        $this->generator->setObjectManager($this->objectManager);
+        $generatorAutoloader = new \Magento\Framework\Code\Generator\Autoloader($this->generator);
+        spl_autoload_register([$generatorAutoloader, 'load']);
+
+        foreach ($repositories as $entityName) {
+            switch ($this->generator->generateClass($entityName)) {
+                case \Magento\Framework\Code\Generator::GENERATION_SUCCESS:
+                    $this->log->add(Log::GENERATION_SUCCESS, $entityName);
+                    break;
+                case \Magento\Framework\Code\Generator::GENERATION_ERROR:
+                    $this->log->add(Log::GENERATION_ERROR, $entityName);
+                    break;
+                case \Magento\Framework\Code\Generator::GENERATION_SKIP:
+                default:
+                    //no log
+                    break;
+            }
+        }
+        foreach (['php', 'additional'] as $type) {
+            sort($this->entities[$type]);
+            foreach ($this->entities[$type] as $entityName) {
+                switch ($this->generator->generateClass($entityName)) {
+                    case \Magento\Framework\Code\Generator::GENERATION_SUCCESS:
+                        $this->log->add(Log::GENERATION_SUCCESS, $entityName);
+                        break;
+                    case \Magento\Framework\Code\Generator::GENERATION_ERROR:
+                        $this->log->add(Log::GENERATION_ERROR, $entityName);
+                        break;
+                    case \Magento\Framework\Code\Generator::GENERATION_SKIP:
+                    default:
+                        //no log
+                        break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Compile Code
+     *
+     * @param string $generationDir
+     * @param array $fileExcludePatterns
+     * @param InputInterface $input
+     * @return void
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     */
+    private function compileCode($generationDir, $fileExcludePatterns, $input)
+    {
+        $diDir = $input->getOption(self::INPUT_KEY_DI) ? $input->getOption(self::INPUT_KEY_DI) :
+            $this->directoryList->getPath(DirectoryList::DI);
+        $relationsFile = $diDir . '/relations.ser';
+        $pluginDefFile = $diDir . '/plugins.ser';
+        $compilationDirs = [
+            $this->directoryList->getPath(DirectoryList::MODULES),
+            $this->directoryList->getPath(DirectoryList::LIB_INTERNAL) . '/Magento',
+            $this->directoryList->getPath(DirectoryList::SETUP) . '/Magento/Setup/Module',
+            $this->directoryList->getRoot() . '/dev/tools/Magento/Tools',
+        ];
+        $serializer = $input->getOption(self::INPUT_KEY_SERIALIZER) == Igbinary::NAME ? new Igbinary() : new Standard();
+        // 2.1 Code scan
+        $validator = new \Magento\Framework\Code\Validator();
+        $validator->add(new \Magento\Framework\Code\Validator\ConstructorIntegrity());
+        $validator->add(new \Magento\Framework\Code\Validator\ContextAggregation());
+        $classesScanner = new \Magento\Setup\Module\Di\Code\Reader\ClassesScanner();
+        $classesScanner->addExcludePatterns($fileExcludePatterns);
+        $directoryInstancesNamesList = new \Magento\Setup\Module\Di\Code\Reader\Decorator\Directory(
+            $this->log,
+            new \Magento\Framework\Code\Reader\ClassReader(),
+            $classesScanner,
+            $validator,
+            $generationDir
+        );
+        foreach ($compilationDirs as $path) {
+            if (is_readable($path)) {
+                $directoryInstancesNamesList->getList($path);
+            }
+        }
+        $inheritanceScanner = new Scanner\InheritanceInterceptorScanner();
+        $this->entities['interceptors'] = $inheritanceScanner->collectEntities(
+            get_declared_classes(),
+            $this->entities['interceptors']
+        );
+        // 2.1.1 Generation of Proxy and Interceptor Classes
+        foreach (['interceptors', 'di'] as $type) {
+            foreach ($this->entities[$type] as $entityName) {
+                switch ($this->generator->generateClass($entityName)) {
+                    case \Magento\Framework\Code\Generator::GENERATION_SUCCESS:
+                        $this->log->add(Log::GENERATION_SUCCESS, $entityName);
+                        break;
+                    case \Magento\Framework\Code\Generator::GENERATION_ERROR:
+                        $this->log->add(Log::GENERATION_ERROR, $entityName);
+                        break;
+                    case \Magento\Framework\Code\Generator::GENERATION_SKIP:
+                    default:
+                        //no log
+                        break;
+                }
+            }
+        }
+        //2.1.2 Compile relations for Proxy/Interceptor classes
+        $directoryInstancesNamesList->getList($generationDir);
+        $relations = $directoryInstancesNamesList->getRelations();
+        // 2.2 Compression
+        if (!file_exists(dirname($relationsFile))) {
+            mkdir(dirname($relationsFile), 0777, true);
+        }
+        $relations = array_filter($relations);
+        file_put_contents($relationsFile, $serializer->serialize($relations));
+        // 3. Plugin Definition Compilation
+        $pluginScanner = new Scanner\CompositeScanner();
+        $pluginScanner->addChild(new Scanner\PluginScanner(), 'di');
+        $pluginDefinitions = [];
+        $pluginList = $pluginScanner->collectEntities($this->files);
+        $pluginDefinitionList = new \Magento\Framework\Interception\Definition\Runtime();
+        foreach ($pluginList as $type => $entityList) {
+            foreach ($entityList as $entity) {
+                $pluginDefinitions[ltrim($entity, '\\')] = $pluginDefinitionList->getMethodList($entity);
+            }
+        }
+        $outputContent = $serializer->serialize($pluginDefinitions);
+        if (!file_exists(dirname($pluginDefFile))) {
+            mkdir(dirname($pluginDefFile), 0777, true);
+        }
+        file_put_contents($pluginDefFile, $outputContent);
+    }
+}
diff --git a/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php b/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..afb277dab8062d09326f3f6a0f911eb91162a761
--- /dev/null
+++ b/setup/src/Magento/Setup/Console/Command/I18nCollectPhrasesCommand.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Console\Command;
+
+use Magento\Setup\Module\I18n\ServiceLocator;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Command for i18n dictionary generation
+ */
+class I18nCollectPhrasesCommand extends Command
+{
+    /**#@+
+     * Keys and shortcuts for input arguments and options
+     */
+    const INPUT_KEY_DIRECTORY = 'directory';
+    const INPUT_KEY_OUTPUT = 'output';
+    const SHORTCUT_KEY_OUTPUT = 'o';
+    const INPUT_KEY_MAGENTO = 'magento';
+    const SHORTCUT_KEY_MAGENTO = 'm';
+    /**#@- */
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('i18n:collect-phrases')
+            ->setDescription('Discovers phrases in the codebase');
+        $this->setDefinition([
+            new InputArgument(self::INPUT_KEY_DIRECTORY, InputArgument::REQUIRED, 'Directory path to parse'),
+            new InputOption(
+                self::INPUT_KEY_OUTPUT,
+                self::SHORTCUT_KEY_OUTPUT,
+                InputOption::VALUE_REQUIRED,
+                'Path (including filename) to an output file. With no file specified, defaults to stdout.'
+            ),
+            new InputOption(
+                self::INPUT_KEY_MAGENTO,
+                self::SHORTCUT_KEY_MAGENTO,
+                InputOption::VALUE_NONE,
+                'Use the --magento parameter to specify the directory is the Magento root directory.' .
+                ' Omit the parameter if the directory is not the Magento root directory.'
+            ),
+        ]);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $generator = ServiceLocator::getDictionaryGenerator();
+        $generator->generate(
+            $input->getArgument(self::INPUT_KEY_DIRECTORY),
+            $input->getOption(self::INPUT_KEY_OUTPUT),
+            $input->getOption(self::INPUT_KEY_MAGENTO)
+        );
+        $output->writeln('<info>Dictionary successfully processed.</info>');
+    }
+}
diff --git a/setup/src/Magento/Setup/Console/Command/I18nPackCommand.php b/setup/src/Magento/Setup/Console/Command/I18nPackCommand.php
new file mode 100644
index 0000000000000000000000000000000000000000..82ff951a89e0d34ec7317bd854237aaead5b7412
--- /dev/null
+++ b/setup/src/Magento/Setup/Console/Command/I18nPackCommand.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Console\Command;
+
+use Magento\Setup\Module\I18n\ServiceLocator;
+use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Input\InputArgument;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * Command for i18n language packaging
+ */
+class I18nPackCommand extends Command
+{
+    /**#@+
+     * Keys and shortcuts for input arguments and options
+     */
+    const INPUT_KEY_SOURCE = 'source';
+    const INPUT_KEY_PACK = 'pack';
+    const INPUT_KEY_LOCALE = 'locale';
+    const INPUT_KEY_MODE = 'mode';
+    const INPUT_KEY_ALLOW_DUPLICATES = 'allow-duplicates';
+    /**#@-*/
+
+    /**
+     * 'replace' mode value
+     */
+    const MODE_REPLACE = 'replace';
+
+    /**
+     * 'merge' mode value
+     */
+    const MODE_MERGE = 'merge';
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function configure()
+    {
+        $this->setName('i18n:pack')
+            ->setDescription('Saves language package');
+        $this->setDefinition([
+            new InputArgument(
+                self::INPUT_KEY_SOURCE,
+                InputArgument::REQUIRED,
+                'Path to source dictionary file with translations'
+            ),
+            new InputArgument(
+                self::INPUT_KEY_PACK,
+                InputArgument::REQUIRED,
+                'Path to language package'
+            ),
+            new InputArgument(
+                self::INPUT_KEY_LOCALE,
+                InputArgument::REQUIRED,
+                'Target locale for dictionary, for example "de_DE"'
+            ),
+            new InputOption(
+                self::INPUT_KEY_MODE,
+                'm',
+                InputOption::VALUE_REQUIRED,
+                'Save mode for dictionary' . PHP_EOL . '- "replace" - replace language pack by new one' . PHP_EOL .
+                '- "merge" - merge language packages, by default "replace"',
+                self::MODE_REPLACE
+            ),
+            new InputOption(
+                self::INPUT_KEY_ALLOW_DUPLICATES,
+                'd',
+                InputOption::VALUE_NONE,
+                'Use the --allow-duplicates parameter to allow saving duplicates of translate.' .
+                ' Otherwise omit the parameter.'
+            ),
+        ]);
+    }
+
+    /**
+     * {@inheritdoc}
+     * @throws \InvalidArgumentException
+     */
+    protected function execute(InputInterface $input, OutputInterface $output)
+    {
+        $generator = ServiceLocator::getPackGenerator();
+        $mode = $input->getOption(self::INPUT_KEY_MODE);
+        if ($mode !== self::MODE_MERGE && $mode !== self::MODE_REPLACE) {
+            throw new \InvalidArgumentException("Possible values for 'mode' option are 'replace' and 'merge'");
+        }
+        $locale = $input->getArgument(self::INPUT_KEY_LOCALE);
+        $generator->generate(
+            $input->getArgument(self::INPUT_KEY_SOURCE),
+            $input->getArgument(self::INPUT_KEY_PACK),
+            $locale,
+            $input->getOption(self::INPUT_KEY_MODE),
+            $input->getOption(self::INPUT_KEY_ALLOW_DUPLICATES)
+        );
+        $output->writeln("<info>Successfully saved $locale language package.</info>");
+    }
+}
diff --git a/setup/src/Magento/Setup/Console/CommandList.php b/setup/src/Magento/Setup/Console/CommandList.php
index a75ed3b3226553a09390a93911b076192422c820..0cb36548c556e62d72ec7bce44d1ecf130ed2a0c 100644
--- a/setup/src/Magento/Setup/Console/CommandList.php
+++ b/setup/src/Magento/Setup/Console/CommandList.php
@@ -43,6 +43,11 @@ class CommandList
             'Magento\Setup\Console\Command\DbDataUpgradeCommand',
             'Magento\Setup\Console\Command\DbSchemaUpgradeCommand',
             'Magento\Setup\Console\Command\DbStatusCommand',
+            'Magento\Setup\Console\Command\DeployStaticContentCommand',
+            'Magento\Setup\Console\Command\DiCompileCommand',
+            'Magento\Setup\Console\Command\DiCompileMultiTenantCommand',
+            'Magento\Setup\Console\Command\I18nCollectPhrasesCommand',
+            'Magento\Setup\Console\Command\I18nPackCommand',
             'Magento\Setup\Console\Command\InfoCurrencyListCommand',
             'Magento\Setup\Console\Command\InfoLanguageListCommand',
             'Magento\Setup\Console\Command\InfoTimezoneListCommand',
diff --git a/setup/src/Magento/Setup/Controller/Environment.php b/setup/src/Magento/Setup/Controller/Environment.php
index 066c58d914c86617da39fb79d720f74fb5902835..3d323043d0ca0e34a2a45337bd1d7242fafcf49e 100644
--- a/setup/src/Magento/Setup/Controller/Environment.php
+++ b/setup/src/Magento/Setup/Controller/Environment.php
@@ -88,23 +88,28 @@ class Environment extends AbstractActionController
     }
 
     /**
-     * Checks if PHP version >= 5.6.0 and always_populate_raw_post_data is set
+     * Checks PHP settings
      *
      * @return JsonModel
      */
-    public function phpRawpostAction()
+    public function phpSettingsAction()
     {
-        $iniSetting = ini_get('always_populate_raw_post_data');
         $responseType = ResponseTypeInterface::RESPONSE_TYPE_SUCCESS;
-        if (version_compare(PHP_VERSION, '5.6.0') >= 0 && (int)$iniSetting > -1) {
-            $responseType = ResponseTypeInterface::RESPONSE_TYPE_ERROR;
+
+        $settings = array_merge(
+            $this->checkRawPost(),
+            $this->checkXDebugNestedLevel()
+        );
+
+        foreach ($settings as $setting) {
+            if ($setting['error']) {
+                $responseType = ResponseTypeInterface::RESPONSE_TYPE_ERROR;
+            }
         }
+
         $data = [
             'responseType' => $responseType,
-            'data' => [
-                'version' => PHP_VERSION,
-                'ini' => $iniSetting
-            ]
+            'data' => $settings
         ];
 
         return new JsonModel($data);
@@ -170,4 +175,74 @@ class Environment extends AbstractActionController
 
         return new JsonModel($data);
     }
+
+    /**
+     * Checks if PHP version >= 5.6.0 and always_populate_raw_post_data is set
+     *
+     * @return array
+     */
+    private function checkRawPost()
+    {
+        $data = [];
+        $error = false;
+        $iniSetting = ini_get('always_populate_raw_post_data');
+
+        if (version_compare(PHP_VERSION, '5.6.0') >= 0 && (int)$iniSetting > -1) {
+            $error = true;
+        }
+
+        $message = sprintf(
+            'Your PHP Version is %s, but always_populate_raw_post_data = %d.
+            $HTTP_RAW_POST_DATA is deprecated from PHP 5.6 onwards and will stop the installer from running.
+            Please open your php.ini file and set always_populate_raw_post_data to -1.
+            If you need more help please call your hosting provider.
+            ',
+            PHP_VERSION,
+            ini_get('always_populate_raw_post_data')
+        );
+
+        $data['rawpost'] = [
+            'message' => $message,
+            'helpUrl' => 'http://php.net/manual/en/ini.core.php#ini.always-populate-settings-data',
+            'error' => $error
+        ];
+
+        return $data;
+    }
+
+    /**
+     * Checks if xdebug.max_nesting_level is set 200 or more
+     * @return array
+     */
+    private function checkXDebugNestedLevel()
+    {
+        $data = [];
+        $error = false;
+
+        $currentExtensions = $this->phpInformation->getCurrent();
+        if (in_array('xdebug', $currentExtensions)) {
+
+            $currentXDebugNestingLevel = intval(ini_get('xdebug.max_nesting_level'));
+            $minimumRequiredXDebugNestedLevel = $this->phpInformation->getRequiredMinimumXDebugNestedLevel();
+
+            if ($minimumRequiredXDebugNestedLevel > $currentXDebugNestingLevel) {
+                $error = true;
+            }
+
+            $message = sprintf(
+                'Your current setting of xdebug.max_nesting_level=%d.
+                 Magento 2 requires it to be set to %d or more.
+                 Edit your config, restart web server, and try again.',
+                $currentXDebugNestingLevel,
+                $minimumRequiredXDebugNestedLevel
+            );
+
+            $data['xdebug_max_nesting_level'] = [
+                'message' => $message,
+                'error' => $error
+            ];
+        }
+
+        return $data;
+    }
 }
diff --git a/dev/tools/Magento/Tools/View/Deployer.php b/setup/src/Magento/Setup/Model/Deployer.php
similarity index 83%
rename from dev/tools/Magento/Tools/View/Deployer.php
rename to setup/src/Magento/Setup/Model/Deployer.php
index 1549724017780a260891f4f386faf09962180a5d..96883fa8c0ee65bc5baf8703153b3073aebcf128 100644
--- a/dev/tools/Magento/Tools/View/Deployer.php
+++ b/setup/src/Magento/Setup/Model/Deployer.php
@@ -4,7 +4,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\View;
+namespace Magento\Setup\Model;
 
 use Magento\Framework\App\ObjectManagerFactory;
 use Magento\Framework\App\View\Deployment\Version;
@@ -12,6 +12,7 @@ use Magento\Framework\App\View\Asset\Publisher;
 use Magento\Framework\App\Utility\Files;
 use Magento\Framework\ObjectManagerInterface;
 use Magento\Framework\Translate\Js\Config as JsTranslationConfig;
+use Symfony\Component\Console\Output\OutputInterface;
 
 /**
  * A service for deploying Magento static view files for production mode
@@ -26,8 +27,8 @@ class Deployer
     /** @var ObjectManagerFactory */
     private $omFactory;
 
-    /** @var Deployer\Log */
-    private $logger;
+    /** @var OutputInterface */
+    private $output;
 
     /** @var Version\StorageInterface */
     private $versionStorage;
@@ -71,7 +72,7 @@ class Deployer
 
     /**
      * @param Files $filesUtil
-     * @param Deployer\Log $logger
+     * @param OutputInterface $output
      * @param Version\StorageInterface $versionStorage
      * @param \Magento\Framework\Stdlib\DateTime $dateTime
      * @param \Magento\Framework\View\Asset\MinifyService $minifyService
@@ -80,7 +81,7 @@ class Deployer
      */
     public function __construct(
         Files $filesUtil,
-        Deployer\Log $logger,
+        OutputInterface $output,
         Version\StorageInterface $versionStorage,
         \Magento\Framework\Stdlib\DateTime $dateTime,
         \Magento\Framework\View\Asset\MinifyService $minifyService,
@@ -88,7 +89,7 @@ class Deployer
         $isDryRun = false
     ) {
         $this->filesUtil = $filesUtil;
-        $this->logger = $logger;
+        $this->output = $output;
         $this->versionStorage = $versionStorage;
         $this->dateTime = $dateTime;
         $this->isDryRun = $isDryRun;
@@ -103,15 +104,16 @@ class Deployer
      * @param array $locales
      * @return void
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
      */
     public function deploy(ObjectManagerFactory $omFactory, array $locales)
     {
         $this->omFactory = $omFactory;
         if ($this->isDryRun) {
-            $this->logger->logMessage('Dry run. Nothing will be recorded to the target directory.');
+            $this->output->writeln('Dry run. Nothing will be recorded to the target directory.');
         }
         $langList = implode(', ', $locales);
-        $this->logger->logMessage("Requested languages: {$langList}");
+        $this->output->writeln("Requested languages: {$langList}");
         $libFiles = $this->filesUtil->getStaticLibraryFiles();
         list($areas, $appFiles) = $this->collectAppFiles($locales);
         foreach ($areas as $area => $themes) {
@@ -119,7 +121,7 @@ class Deployer
             foreach ($locales as $locale) {
                 $this->emulateApplicationLocale($locale, $area);
                 foreach ($themes as $themePath) {
-                    $this->logger->logMessage("=== {$area} -> {$themePath} -> {$locale} ===");
+                    $this->output->writeln("=== {$area} -> {$themePath} -> {$locale} ===");
                     $this->count = 0;
                     $this->errorCount = 0;
                     foreach ($appFiles as $info) {
@@ -139,20 +141,24 @@ class Deployer
                         );
                     }
                     $this->bundleManager->flush();
-                    $this->logger->logMessage("\nSuccessful: {$this->count} files; errors: {$this->errorCount}\n---\n");
+                    $this->output->writeln("\nSuccessful: {$this->count} files; errors: {$this->errorCount}\n---\n");
                 }
             }
         }
-        $this->logger->logMessage("=== Minify templates ===");
+        $this->output->writeln("=== Minify templates ===");
         $this->count = 0;
         foreach ($this->filesUtil->getPhtmlFiles(false, false) as $template) {
             $this->htmlMinifier->minify($template);
-            $this->logger->logDebug($template . " minified\n", '.');
+            if ($this->output->isVerbose()) {
+                $this->output->writeln($template . " minified\n");
+            } else {
+                $this->output->write('.');
+            }
             $this->count++;
         }
-        $this->logger->logMessage("\nSuccessful: {$this->count} files modified\n---\n");
+        $this->output->writeln("\nSuccessful: {$this->count} files modified\n---\n");
         $version = (new \DateTime())->getTimestamp();
-        $this->logger->logMessage("New version of deployed files: {$version}");
+        $this->output->writeln("New version of deployed files: {$version}");
         if (!$this->isDryRun) {
             $this->versionStorage->save($version);
         }
@@ -185,7 +191,7 @@ class Deployer
         }
         if (!empty($locales)) {
             $langList = implode(', ', $locales);
-            $this->logger->logMessage(
+            $this->output->writeln(
                 "WARNING: there were files for the following languages detected in the file system: {$langList}."
                 . ' These languages were not requested, so the files will not be populated.'
             );
@@ -243,6 +249,7 @@ class Deployer
      * @param string $locale
      * @param string $module
      * @return void
+     * @SuppressWarnings(PHPMD.NPathComplexity)
      */
     private function deployFile($filePath, $area, $themePath, $locale, $module)
     {
@@ -254,14 +261,20 @@ class Deployer
         if ($module) {
             $logMessage .= ", module '$module'";
         }
-        $this->logger->logDebug($logMessage);
+
+        $this->verboseLog($logMessage);
+
         try {
             $asset = $this->assetRepo->createAsset(
                 $requestedPath,
                 ['area' => $area, 'theme' => $themePath, 'locale' => $locale, 'module' => $module]
             );
             $asset = $this->minifyService->getAssets([$asset], true)[0];
-            $this->logger->logDebug("\tDeploying the file to '{$asset->getPath()}'", '.');
+            if ($this->output->isVerbose()) {
+                $this->output->writeln("\tDeploying the file to '{$asset->getPath()}'");
+            } else {
+                $this->output->write('.');
+            }
             if ($this->isDryRun) {
                 $asset->getContent();
             } else {
@@ -271,19 +284,32 @@ class Deployer
             $this->count++;
         } catch (\Magento\Framework\View\Asset\File\NotFoundException $e) {
             // File was not found by Fallback (possibly because it's wrong context for it) - there is nothing to publish
-            $this->logger->logDebug(
+            $this->verboseLog(
                 "\tNotice: Could not find file '$filePath'. This file may not be relevant for the theme or area."
             );
         } catch (\Less_Exception_Compiler $e) {
-            $this->logger->logDebug(
+            $this->verboseLog(
                 "\tNotice: Could not parse LESS file '$filePath'. "
                 . "This may indicate that the file is incomplete, but this is acceptable. "
                 . "The file '$filePath' will be combined with another LESS file."
             );
         } catch (\Exception $e) {
-            $this->logger->logError($e->getMessage() . " ($logMessage)");
-            $this->logger->logDebug((string)$e);
+            $this->output->writeln($e->getMessage() . " ($logMessage)");
+            $this->verboseLog((string)$e);
             $this->errorCount++;
         }
     }
+
+    /**
+     * Verbose log
+     *
+     * @param string $message
+     * @return void
+     */
+    private function verboseLog($message)
+    {
+        if ($this->output->isVerbose()) {
+            $this->output->writeln($message);
+        }
+    }
 }
diff --git a/setup/src/Magento/Setup/Model/Installer.php b/setup/src/Magento/Setup/Model/Installer.php
index 5db3a546a66113ea49ff556c9f346281ec8afc44..414ef89f37a612ce5dcbbe14f6438d30e11a11a5 100644
--- a/setup/src/Magento/Setup/Model/Installer.php
+++ b/setup/src/Magento/Setup/Model/Installer.php
@@ -787,6 +787,9 @@ class Installer
     public function installUserConfig($data)
     {
         $userConfig = new StoreConfigurationDataMapper();
+        /** @var \Magento\Framework\App\State $appState */
+        $appState = $this->objectManagerProvider->get()->get('Magento\Framework\App\State');
+        $appState->setAreaCode('setup');
         $configData = $userConfig->getConfigData($data);
         if (count($configData) === 0) {
             return;
diff --git a/setup/src/Magento/Setup/Model/Lists.php b/setup/src/Magento/Setup/Model/Lists.php
index e898ed40c16c383ac2fa1ccadbdab2419aae793d..e52e921594caec60421e975f3782c8abf552ac13 100644
--- a/setup/src/Magento/Setup/Model/Lists.php
+++ b/setup/src/Magento/Setup/Model/Lists.php
@@ -10,6 +10,7 @@ use Magento\Framework\Locale\Bundle\CurrencyBundle;
 use Magento\Framework\Locale\Bundle\LanguageBundle;
 use Magento\Framework\Locale\Bundle\RegionBundle;
 use Magento\Framework\Locale\ConfigInterface;
+use Magento\Framework\Locale\Resolver;
 use Magento\Framework\Locale\ResolverInterface;
 
 class Lists
@@ -42,7 +43,7 @@ class Lists
             $list[$code] = \IntlTimeZone::createTimeZone($code)->getDisplayName(
                 false,
                 \IntlTimeZone::DISPLAY_LONG,
-                ResolverInterface::DEFAULT_LOCALE
+                Resolver::DEFAULT_LOCALE
             ) . ' (' . $code . ')';
         }
         asort($list);
@@ -56,7 +57,7 @@ class Lists
      */
     public function getCurrencyList()
     {
-        $currencies = (new CurrencyBundle())->get(ResolverInterface::DEFAULT_LOCALE)['Currencies'];
+        $currencies = (new CurrencyBundle())->get(Resolver::DEFAULT_LOCALE)['Currencies'];
         $list = [];
         foreach ($currencies as $code => $data) {
             $list[$code] = $data[1] . ' (' . $code . ')';
@@ -72,8 +73,8 @@ class Lists
      */
     public function getLocaleList()
     {
-        $languages = (new LanguageBundle())->get(ResolverInterface::DEFAULT_LOCALE)['Languages'];
-        $countries = (new RegionBundle())->get(ResolverInterface::DEFAULT_LOCALE)['Countries'];
+        $languages = (new LanguageBundle())->get(Resolver::DEFAULT_LOCALE)['Languages'];
+        $countries = (new RegionBundle())->get(Resolver::DEFAULT_LOCALE)['Countries'];
         $locales = \ResourceBundle::getLocales(null);
 
         $list = [];
diff --git a/setup/src/Magento/Setup/Model/ObjectManagerProvider.php b/setup/src/Magento/Setup/Model/ObjectManagerProvider.php
index d887f0031fe67df47e8e9208a838c1ba5f8ee940..2c54f37be72ffbe69c40cc8af986abb270c5c274 100644
--- a/setup/src/Magento/Setup/Model/ObjectManagerProvider.php
+++ b/setup/src/Magento/Setup/Model/ObjectManagerProvider.php
@@ -70,4 +70,18 @@ class ObjectManagerProvider
     {
         $this->objectManager = null;
     }
+    
+    /**
+     * Returns ObjectManagerFactory
+     *
+     * @param array $initParams
+     * @return \Magento\Framework\App\ObjectManagerFactory
+     */
+    public function getObjectManagerFactory($initParams = [])
+    {
+        return Bootstrap::createObjectManagerFactory(
+            BP,
+            $initParams
+        );
+    }
 }
diff --git a/setup/src/Magento/Setup/Model/PhpInformation.php b/setup/src/Magento/Setup/Model/PhpInformation.php
index fcb89e65f60a15141168f36ee3a4ad0c39f43b17..f6786c8b2b525bb7feae54db994f633a18259141 100644
--- a/setup/src/Magento/Setup/Model/PhpInformation.php
+++ b/setup/src/Magento/Setup/Model/PhpInformation.php
@@ -11,6 +11,12 @@ use Magento\Framework\Filesystem;
 
 class PhpInformation
 {
+
+    /**
+     * Allowed XDebug nested level
+     */
+    const XDEBUG_NESTED_LEVEL = 200;
+
     /**
      * List of required extensions
      *
@@ -59,6 +65,15 @@ class PhpInformation
         }
     }
 
+    /**
+     * Returns minimum required XDebug nested level
+     * @return int
+     */
+    public function getRequiredMinimumXDebugNestedLevel()
+    {
+        return self::XDEBUG_NESTED_LEVEL;
+    }
+
     /**
      * Retrieve list of required extensions
      *
diff --git a/dev/tools/Magento/Tools/Di/App/Task/Manager.php b/setup/src/Magento/Setup/Module/Di/App/Task/Manager.php
similarity index 96%
rename from dev/tools/Magento/Tools/Di/App/Task/Manager.php
rename to setup/src/Magento/Setup/Module/Di/App/Task/Manager.php
index c9c0d0d048b7ebc336065fdfc78275fd212b99f7..7e4171c0873d2bef4bbd23ad558980c051e55622 100644
--- a/dev/tools/Magento/Tools/Di/App/Task/Manager.php
+++ b/setup/src/Magento/Setup/Module/Di/App/Task/Manager.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\App\Task;
+namespace Magento\Setup\Module\Di\App\Task;
 
 class Manager
 {
diff --git a/dev/tools/Magento/Tools/Di/App/Task/Operation/ApplicationCodeGenerator.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/ApplicationCodeGenerator.php
similarity index 83%
rename from dev/tools/Magento/Tools/Di/App/Task/Operation/ApplicationCodeGenerator.php
rename to setup/src/Magento/Setup/Module/Di/App/Task/Operation/ApplicationCodeGenerator.php
index 21b24e52c91a028629b5e2973b642836e9469e13..1228703ab08fd6e99af5e1c5e18715a4d3783e91 100644
--- a/dev/tools/Magento/Tools/Di/App/Task/Operation/ApplicationCodeGenerator.php
+++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/ApplicationCodeGenerator.php
@@ -3,10 +3,10 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\App\Task\Operation;
+namespace Magento\Setup\Module\Di\App\Task\Operation;
 
-use Magento\Tools\Di\App\Task\OperationInterface;
-use Magento\Tools\Di\Code\Reader\ClassesScanner;
+use Magento\Setup\Module\Di\App\Task\OperationInterface;
+use Magento\Setup\Module\Di\Code\Reader\ClassesScanner;
 
 class ApplicationCodeGenerator implements OperationInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/App/Task/Operation/Area.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php
similarity index 79%
rename from dev/tools/Magento/Tools/Di/App/Task/Operation/Area.php
rename to setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php
index c9a8089251b42be57f6003f8ea802ee4362612cb..f129e56dc8d8c67afa7d971393fb60d987585df5 100644
--- a/dev/tools/Magento/Tools/Di/App/Task/Operation/Area.php
+++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Area.php
@@ -3,12 +3,12 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\App\Task\Operation;
+namespace Magento\Setup\Module\Di\App\Task\Operation;
 
-use Magento\Tools\Di\App\Task\OperationInterface;
+use Magento\Setup\Module\Di\App\Task\OperationInterface;
 use Magento\Framework\App;
-use Magento\Tools\Di\Compiler\Config;
-use Magento\Tools\Di\Definition\Collection as DefinitionsCollection;
+use Magento\Setup\Module\Di\Compiler\Config;
+use Magento\Setup\Module\Di\Definition\Collection as DefinitionsCollection;
 
 class Area implements OperationInterface
 {
@@ -18,7 +18,7 @@ class Area implements OperationInterface
     private $areaList;
 
     /**
-     * @var \Magento\Tools\Di\Code\Reader\Decorator\Area
+     * @var \Magento\Setup\Module\Di\Code\Reader\Decorator\Area
      */
     private $areaInstancesNamesList;
 
@@ -38,21 +38,21 @@ class Area implements OperationInterface
     private $data = [];
 
     /**
-     * @var \Magento\Tools\Di\Compiler\Config\ModificationChain
+     * @var \Magento\Setup\Module\Di\Compiler\Config\ModificationChain
      */
     private $modificationChain;
 
     /**
      * @param App\AreaList $areaList
-     * @param \Magento\Tools\Di\Code\Reader\Decorator\Area $areaInstancesNamesList
+     * @param \Magento\Setup\Module\Di\Code\Reader\Decorator\Area $areaInstancesNamesList
      * @param Config\Reader $configReader
      * @param Config\WriterInterface $configWriter
-     * @param \Magento\Tools\Di\Compiler\Config\ModificationChain $modificationChain
+     * @param \Magento\Setup\Module\Di\Compiler\Config\ModificationChain $modificationChain
      * @param array $data
      */
     public function __construct(
         App\AreaList $areaList,
-        \Magento\Tools\Di\Code\Reader\Decorator\Area $areaInstancesNamesList,
+        \Magento\Setup\Module\Di\Code\Reader\Decorator\Area $areaInstancesNamesList,
         Config\Reader $configReader,
         Config\WriterInterface $configWriter,
         Config\ModificationChain $modificationChain,
diff --git a/dev/tools/Magento/Tools/Di/App/Task/Operation/Interception.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Interception.php
similarity index 86%
rename from dev/tools/Magento/Tools/Di/App/Task/Operation/Interception.php
rename to setup/src/Magento/Setup/Module/Di/App/Task/Operation/Interception.php
index f6cf82e11a1a09f2b31e82e42a6014b058d0bc88..6d5d9ae3502a806f22bb4c58e04ed2105b2755aa 100644
--- a/dev/tools/Magento/Tools/Di/App/Task/Operation/Interception.php
+++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/Interception.php
@@ -3,14 +3,14 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\App\Task\Operation;
+namespace Magento\Setup\Module\Di\App\Task\Operation;
 
-use Magento\Tools\Di\App\Task\OperationInterface;
-use Magento\Tools\Di\Code\Generator\InterceptionConfigurationBuilder;
+use Magento\Setup\Module\Di\App\Task\OperationInterface;
+use Magento\Setup\Module\Di\Code\Generator\InterceptionConfigurationBuilder;
 use Magento\Framework\Interception\Code\Generator\Interceptor;
 use Magento\Framework\App;
-use Magento\Tools\Di\Code\GeneratorFactory;
-use Magento\Tools\Di\Code\Reader\ClassesScanner;
+use Magento\Setup\Module\Di\Code\GeneratorFactory;
+use Magento\Setup\Module\Di\Code\Reader\ClassesScanner;
 
 class Interception implements OperationInterface
 {
@@ -87,7 +87,7 @@ class Interception implements OperationInterface
             [
                 'ioObject' => $generatorIo,
                 'generatedEntities' => [
-                    Interceptor::ENTITY_TYPE => 'Magento\Tools\Di\Code\Generator\Interceptor',
+                    Interceptor::ENTITY_TYPE => 'Magento\Setup\Module\Di\Code\Generator\Interceptor',
                 ]
             ]
         );
diff --git a/dev/tools/Magento/Tools/Di/App/Task/Operation/InterceptionCache.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/InterceptionCache.php
similarity index 76%
rename from dev/tools/Magento/Tools/Di/App/Task/Operation/InterceptionCache.php
rename to setup/src/Magento/Setup/Module/Di/App/Task/Operation/InterceptionCache.php
index 31180fc27d701d9ca0730943c414fc09878e1dbc..b37f329ebfc78a57a6ce41b0e63358a7b04c411d 100644
--- a/dev/tools/Magento/Tools/Di/App/Task/Operation/InterceptionCache.php
+++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/InterceptionCache.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\App\Task\Operation;
+namespace Magento\Setup\Module\Di\App\Task\Operation;
 
-use Magento\Tools\Di\App\Task\OperationInterface;
+use Magento\Setup\Module\Di\App\Task\OperationInterface;
 
 class InterceptionCache implements OperationInterface
 {
@@ -20,18 +20,18 @@ class InterceptionCache implements OperationInterface
     private $configInterface;
 
     /**
-     * @var \Magento\Tools\Di\Code\Reader\Decorator\Interceptions
+     * @var \Magento\Setup\Module\Di\Code\Reader\Decorator\Interceptions
      */
     private $interceptionsInstancesNamesList;
 
     /**
      * @param \Magento\Framework\Interception\Config\Config $configInterface
-     * @param \Magento\Tools\Di\Code\Reader\Decorator\Interceptions $interceptionsInstancesNamesList
+     * @param \Magento\Setup\Module\Di\Code\Reader\Decorator\Interceptions $interceptionsInstancesNamesList
      * @param array $data
      */
     public function __construct(
         \Magento\Framework\Interception\Config\Config $configInterface,
-        \Magento\Tools\Di\Code\Reader\Decorator\Interceptions $interceptionsInstancesNamesList,
+        \Magento\Setup\Module\Di\Code\Reader\Decorator\Interceptions $interceptionsInstancesNamesList,
         array $data = []
     ) {
         $this->configInterface = $configInterface;
diff --git a/dev/tools/Magento/Tools/Di/App/Task/Operation/RepositoryGenerator.php b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/RepositoryGenerator.php
similarity index 89%
rename from dev/tools/Magento/Tools/Di/App/Task/Operation/RepositoryGenerator.php
rename to setup/src/Magento/Setup/Module/Di/App/Task/Operation/RepositoryGenerator.php
index 20d25b65dfad84be98b36c6bcd245230b0eb4613..41e9e80e5fe4e04628af960d4bf2b25f1eb89936 100644
--- a/dev/tools/Magento/Tools/Di/App/Task/Operation/RepositoryGenerator.php
+++ b/setup/src/Magento/Setup/Module/Di/App/Task/Operation/RepositoryGenerator.php
@@ -4,11 +4,11 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\App\Task\Operation;
+namespace Magento\Setup\Module\Di\App\Task\Operation;
 
-use Magento\Tools\Di\App\Task\OperationInterface;
-use Magento\Tools\Di\Code\Scanner;
-use Magento\Tools\Di\Code\Reader\ClassesScanner;
+use Magento\Setup\Module\Di\App\Task\OperationInterface;
+use Magento\Setup\Module\Di\Code\Scanner;
+use Magento\Setup\Module\Di\Code\Reader\ClassesScanner;
 
 class RepositoryGenerator implements OperationInterface
 {
@@ -63,9 +63,8 @@ class RepositoryGenerator implements OperationInterface
         }
 
         $this->classesScanner->getList($this->data['path']);
-
-        $files = $this->directoryScanner->scan($this->data['path'], $this->data['filePatterns']);
         $this->repositoryScanner->setUseAutoload(false);
+        $files = $this->directoryScanner->scan($this->data['path'], $this->data['filePatterns']);
         $repositories = $this->repositoryScanner->collectEntities($files['di']);
         foreach ($repositories as $entityName) {
             class_exists($entityName);
diff --git a/dev/tools/Magento/Tools/Di/App/Task/OperationException.php b/setup/src/Magento/Setup/Module/Di/App/Task/OperationException.php
similarity index 84%
rename from dev/tools/Magento/Tools/Di/App/Task/OperationException.php
rename to setup/src/Magento/Setup/Module/Di/App/Task/OperationException.php
index 5896bf352ee702a5fe75900d65b46806866e7a79..1d36fd456cb8d37869bfa830f47c7004c0034611 100644
--- a/dev/tools/Magento/Tools/Di/App/Task/OperationException.php
+++ b/setup/src/Magento/Setup/Module/Di/App/Task/OperationException.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\App\Task;
+namespace Magento\Setup\Module\Di\App\Task;
 
 class OperationException extends \Exception
 {
diff --git a/dev/tools/Magento/Tools/Di/App/Task/OperationFactory.php b/setup/src/Magento/Setup/Module/Di/App/Task/OperationFactory.php
similarity index 65%
rename from dev/tools/Magento/Tools/Di/App/Task/OperationFactory.php
rename to setup/src/Magento/Setup/Module/Di/App/Task/OperationFactory.php
index 94fc7702689755f8e9d7477df0cf72eba40739e3..a2505bad47a0ed289a2040e1a11ec9f401319d4b 100644
--- a/dev/tools/Magento/Tools/Di/App/Task/OperationFactory.php
+++ b/setup/src/Magento/Setup/Module/Di/App/Task/OperationFactory.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\App\Task;
+namespace Magento\Setup\Module\Di\App\Task;
 
 class OperationFactory
 {
@@ -43,19 +43,19 @@ class OperationFactory
      * @var array
      */
     private $operationsDefinitions = [
-        self::AREA_CONFIG_GENERATOR => 'Magento\Tools\Di\App\Task\Operation\Area',
-        self::APPLICATION_CODE_GENERATOR => 'Magento\Tools\Di\App\Task\Operation\ApplicationCodeGenerator',
-        self::INTERCEPTION => 'Magento\Tools\Di\App\Task\Operation\Interception',
-        self::INTERCEPTION_CACHE => 'Magento\Tools\Di\App\Task\Operation\InterceptionCache',
-        self::REPOSITORY_GENERATOR => 'Magento\Tools\Di\App\Task\Operation\RepositoryGenerator'
+        self::AREA_CONFIG_GENERATOR => 'Magento\Setup\Module\Di\App\Task\Operation\Area',
+        self::APPLICATION_CODE_GENERATOR => 'Magento\Setup\Module\Di\App\Task\Operation\ApplicationCodeGenerator',
+        self::INTERCEPTION => 'Magento\Setup\Module\Di\App\Task\Operation\Interception',
+        self::INTERCEPTION_CACHE => 'Magento\Setup\Module\Di\App\Task\Operation\InterceptionCache',
+        self::REPOSITORY_GENERATOR => 'Magento\Setup\Module\Di\App\Task\Operation\RepositoryGenerator'
     ];
 
     /**
-     * @param \Magento\Framework\ObjectManagerInterface $objectManager
+     * @param \Magento\Setup\Model\ObjectManagerProvider $objectManagerProvider
      */
-    public function __construct(\Magento\Framework\ObjectManagerInterface $objectManager)
+    public function __construct(\Magento\Setup\Model\ObjectManagerProvider $objectManagerProvider)
     {
-        $this->objectManager = $objectManager;
+        $this->objectManager = $objectManagerProvider->get();
     }
 
     /**
diff --git a/dev/tools/Magento/Tools/Di/App/Task/OperationInterface.php b/setup/src/Magento/Setup/Module/Di/App/Task/OperationInterface.php
similarity index 84%
rename from dev/tools/Magento/Tools/Di/App/Task/OperationInterface.php
rename to setup/src/Magento/Setup/Module/Di/App/Task/OperationInterface.php
index c81638f52c372579eabc43f1d74c03eb364793b1..0ce7cd3344c4684d5455a0c2044c8f254468862e 100644
--- a/dev/tools/Magento/Tools/Di/App/Task/OperationInterface.php
+++ b/setup/src/Magento/Setup/Module/Di/App/Task/OperationInterface.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\App\Task;
+namespace Magento\Setup\Module\Di\App\Task;
 
 interface OperationInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Generator.php b/setup/src/Magento/Setup/Module/Di/Code/Generator.php
similarity index 96%
rename from dev/tools/Magento/Tools/Di/Code/Generator.php
rename to setup/src/Magento/Setup/Module/Di/Code/Generator.php
index a33d2f74dc024dd0df2fc55f095eb844dcadec58..75954e180b1d2c5c8d1b6e5e563b4fdfa5551da3 100644
--- a/dev/tools/Magento/Tools/Di/Code/Generator.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Generator.php
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Code;
+namespace Magento\Setup\Module\Di\Code;
 
 use Magento\Framework\Code\Generator as FrameworkGenerator;
 use Magento\Framework\Code\Generator\DefinedClasses;
@@ -13,7 +13,7 @@ use Magento\Framework\ObjectManagerInterface;
 
 /**
  * Class Generator
- * @package Magento\Tools\Di\Code
+ * @package Magento\Setup\Module\Di\Code
  */
 class Generator extends FrameworkGenerator
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Generator/InterceptionConfigurationBuilder.php b/setup/src/Magento/Setup/Module/Di/Code/Generator/InterceptionConfigurationBuilder.php
similarity index 98%
rename from dev/tools/Magento/Tools/Di/Code/Generator/InterceptionConfigurationBuilder.php
rename to setup/src/Magento/Setup/Module/Di/Code/Generator/InterceptionConfigurationBuilder.php
index b3ecacc8264fc4d0e689161689fd567a9f24a5c9..5935e77fa8e7109d1265e5f76335fe35394f1953 100644
--- a/dev/tools/Magento/Tools/Di/Code/Generator/InterceptionConfigurationBuilder.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Generator/InterceptionConfigurationBuilder.php
@@ -5,13 +5,13 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Code\Generator;
+namespace Magento\Setup\Module\Di\Code\Generator;
 
 use Magento\Framework\App\Area;
 use Magento\Framework\App\Cache\Manager;
 use Magento\Framework\App\Interception\Cache\CompiledConfig;
 use Magento\Framework\Interception\Config\Config as InterceptionConfig;
-use Magento\Tools\Di\Code\Reader\Type;
+use Magento\Setup\Module\Di\Code\Reader\Type;
 
 class InterceptionConfigurationBuilder
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Generator/Interceptor.php b/setup/src/Magento/Setup/Module/Di/Code/Generator/Interceptor.php
similarity index 94%
rename from dev/tools/Magento/Tools/Di/Code/Generator/Interceptor.php
rename to setup/src/Magento/Setup/Module/Di/Code/Generator/Interceptor.php
index 2a87b3a0b8dc8b570362029e87edc33fd92e4207..d02068614b28feef0e506a4c5ca430c54bb2ad2f 100644
--- a/dev/tools/Magento/Tools/Di/Code/Generator/Interceptor.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Generator/Interceptor.php
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Code\Generator;
+namespace Magento\Setup\Module\Di\Code\Generator;
 
 use Magento\Framework\Interception\Code\Generator\Interceptor as FrameworkInterceptor;
 
diff --git a/dev/tools/Magento/Tools/Di/Code/Generator/PluginList.php b/setup/src/Magento/Setup/Module/Di/Code/Generator/PluginList.php
similarity index 96%
rename from dev/tools/Magento/Tools/Di/Code/Generator/PluginList.php
rename to setup/src/Magento/Setup/Module/Di/Code/Generator/PluginList.php
index d59f9525b1340f04c5a815fbeddc392900faf765..ab48bcc0d795ce69ca7fb079c07d3d2e1c7ee056 100644
--- a/dev/tools/Magento/Tools/Di/Code/Generator/PluginList.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Generator/PluginList.php
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Code\Generator;
+namespace Magento\Setup\Module\Di\Code\Generator;
 
 use Magento\Framework\Interception;
 
diff --git a/dev/tools/Magento/Tools/Di/Code/GeneratorFactory.php b/setup/src/Magento/Setup/Module/Di/Code/GeneratorFactory.php
similarity index 81%
rename from dev/tools/Magento/Tools/Di/Code/GeneratorFactory.php
rename to setup/src/Magento/Setup/Module/Di/Code/GeneratorFactory.php
index b3e8135210754ce3887440887207853f7c4200c2..bbc7a9763a5d1723fa5900bb69b75623bddb5e90 100644
--- a/dev/tools/Magento/Tools/Di/Code/GeneratorFactory.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/GeneratorFactory.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code;
+namespace Magento\Setup\Module\Di\Code;
 
 use Magento\Framework\ObjectManagerInterface;
 
@@ -30,6 +30,6 @@ class GeneratorFactory
      */
     public function create($arguments = [])
     {
-        return $this->objectManager->create('Magento\Tools\Di\Code\Generator', $arguments);
+        return $this->objectManager->create('Magento\Setup\Module\Di\Code\Generator', $arguments);
     }
 }
diff --git a/dev/tools/Magento/Tools/Di/Code/Reader/ClassReaderDecorator.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassReaderDecorator.php
similarity index 93%
rename from dev/tools/Magento/Tools/Di/Code/Reader/ClassReaderDecorator.php
rename to setup/src/Magento/Setup/Module/Di/Code/Reader/ClassReaderDecorator.php
index 00aeb167ffed2262598b7384df7f79e853573520..bc38862c555c2b92a267335db4b4e272df794849 100644
--- a/dev/tools/Magento/Tools/Di/Code/Reader/ClassReaderDecorator.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassReaderDecorator.php
@@ -4,9 +4,9 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Code\Reader;
+namespace Magento\Setup\Module\Di\Code\Reader;
 
-use Magento\Tools\Di\Compiler\ConstructorArgument;
+use Magento\Setup\Module\Di\Compiler\ConstructorArgument;
 
 class ClassReaderDecorator implements \Magento\Framework\Code\Reader\ClassReaderInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Reader/ClassesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php
similarity index 96%
rename from dev/tools/Magento/Tools/Di/Code/Reader/ClassesScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php
index 5b0204813ccb1b6c6a94922ea50bbe9b3be59448..8e52fc761c4d2ce3fa21ea902bf2cd396298ab5b 100644
--- a/dev/tools/Magento/Tools/Di/Code/Reader/ClassesScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScanner.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Reader;
+namespace Magento\Setup\Module\Di\Code\Reader;
 
 use Magento\Framework\Exception\FileSystemException;
 use Zend\Code\Scanner\FileScanner;
@@ -45,9 +45,8 @@ class ClassesScanner implements ClassesScannerInterface
     {
         $realPath = realpath($path);
         if (!(bool)$realPath) {
-            throw new FileSystemException(new \Magento\Framework\Phrase('Invalid path: %1', $path));
+            throw new FileSystemException(new \Magento\Framework\Phrase('Invalid path: %1', [$path]));
         }
-
         $recursiveIterator = new \RecursiveIteratorIterator(
             new \RecursiveDirectoryIterator($realPath, \FilesystemIterator::FOLLOW_SYMLINKS),
             \RecursiveIteratorIterator::SELF_FIRST
diff --git a/dev/tools/Magento/Tools/Di/Code/Reader/ClassesScannerInterface.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScannerInterface.php
similarity index 79%
rename from dev/tools/Magento/Tools/Di/Code/Reader/ClassesScannerInterface.php
rename to setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScannerInterface.php
index 0812ceaf2a4beba1fcfb9d3a3d6cf7025ad18c23..8ed036a38d561b6aafdd84da88a512b6d7f6a526 100644
--- a/dev/tools/Magento/Tools/Di/Code/Reader/ClassesScannerInterface.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/ClassesScannerInterface.php
@@ -3,12 +3,12 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Reader;
+namespace Magento\Setup\Module\Di\Code\Reader;
 
 /**
  * Interface ClassesScannerInterface
  *
- * @package Magento\Tools\Di\Code\Reader
+ * @package Magento\Setup\Module\Di\Code\Reader
  */
 interface ClassesScannerInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Reader/Decorator/Area.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/Decorator/Area.php
similarity index 78%
rename from dev/tools/Magento/Tools/Di/Code/Reader/Decorator/Area.php
rename to setup/src/Magento/Setup/Module/Di/Code/Reader/Decorator/Area.php
index 5830fc4e79ba8e318f9ccb6c94b6c61279ce9e81..13755f5776b5ca15cdb9c21249bd93d90c0e5605 100644
--- a/dev/tools/Magento/Tools/Di/Code/Reader/Decorator/Area.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/Decorator/Area.php
@@ -3,18 +3,18 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Reader\Decorator;
+namespace Magento\Setup\Module\Di\Code\Reader\Decorator;
 
-use Magento\Tools\Di\Code\Reader\ClassesScanner;
-use Magento\Tools\Di\Code\Reader\ClassReaderDecorator;
+use Magento\Setup\Module\Di\Code\Reader\ClassesScanner;
+use Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator;
 use Magento\Framework\Exception\FileSystemException;
 
 /**
  * Class Area
  *
- * @package Magento\Tools\Di\Code\Reader\Decorator
+ * @package Magento\Setup\Module\Di\Code\Reader\Decorator
  */
-class Area implements \Magento\Tools\Di\Code\Reader\ClassesScannerInterface
+class Area implements \Magento\Setup\Module\Di\Code\Reader\ClassesScannerInterface
 {
     /**
      * @var ClassReaderDecorator
diff --git a/dev/tools/Magento/Tools/Di/Code/Reader/Decorator/Directory.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/Decorator/Directory.php
similarity index 79%
rename from dev/tools/Magento/Tools/Di/Code/Reader/Decorator/Directory.php
rename to setup/src/Magento/Setup/Module/Di/Code/Reader/Decorator/Directory.php
index 430ec71706199009fcbba18fad6f03acbd1c805e..89a50609589f42c279edb26fc0e4ceb0444e6f29 100644
--- a/dev/tools/Magento/Tools/Di/Code/Reader/Decorator/Directory.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/Decorator/Directory.php
@@ -3,16 +3,16 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Reader\Decorator;
+namespace Magento\Setup\Module\Di\Code\Reader\Decorator;
 
-use Magento\Tools\Di\Compiler\Log\Log;
+use Magento\Setup\Module\Di\Compiler\Log\Log;
 
 /**
  * Class Directory
  *
- * @package Magento\Tools\Di\Code\Reader\Decorator
+ * @package Magento\Setup\Module\Di\Code\Reader\Decorator
  */
-class Directory implements \Magento\Tools\Di\Code\Reader\ClassesScannerInterface
+class Directory implements \Magento\Setup\Module\Di\Code\Reader\ClassesScannerInterface
 {
     /**
      * @var string
@@ -20,7 +20,7 @@ class Directory implements \Magento\Tools\Di\Code\Reader\ClassesScannerInterface
     private $current;
 
     /**
-     * @var \Magento\Tools\Di\Compiler\Log\Log
+     * @var \Magento\Setup\Module\Di\Compiler\Log\Log
      */
     private $log;
 
@@ -40,21 +40,21 @@ class Directory implements \Magento\Tools\Di\Code\Reader\ClassesScannerInterface
     private $classReader;
 
     /**
-     * @var \Magento\Tools\Di\Code\Reader\ClassesScanner
+     * @var \Magento\Setup\Module\Di\Code\Reader\ClassesScanner
      */
     private $classesScanner;
 
     /**
-     * @param \Magento\Tools\Di\Compiler\Log\Log $log Logging object
+     * @param \Magento\Setup\Module\Di\Compiler\Log\Log $log Logging object
      * @param \Magento\Framework\Code\Reader\ClassReader $classReader
-     * @param \Magento\Tools\Di\Code\Reader\ClassesScanner $classesScanner
+     * @param \Magento\Setup\Module\Di\Code\Reader\ClassesScanner $classesScanner
      * @param \Magento\Framework\Code\Validator $validator
      * @param string $generationDir directory where generated files is
      */
     public function __construct(
-        \Magento\Tools\Di\Compiler\Log\Log $log,
+        \Magento\Setup\Module\Di\Compiler\Log\Log $log,
         \Magento\Framework\Code\Reader\ClassReader $classReader,
-        \Magento\Tools\Di\Code\Reader\ClassesScanner $classesScanner,
+        \Magento\Setup\Module\Di\Code\Reader\ClassesScanner $classesScanner,
         \Magento\Framework\Code\Validator $validator,
         $generationDir
     ) {
diff --git a/dev/tools/Magento/Tools/Di/Code/Reader/Decorator/Interceptions.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/Decorator/Interceptions.php
similarity index 79%
rename from dev/tools/Magento/Tools/Di/Code/Reader/Decorator/Interceptions.php
rename to setup/src/Magento/Setup/Module/Di/Code/Reader/Decorator/Interceptions.php
index 84e4ce0038e8c6b300ae0648cc6a16472180bb21..e7636d06f8c9ba4bd59dd70c7db1920ea1a3e3f2 100644
--- a/dev/tools/Magento/Tools/Di/Code/Reader/Decorator/Interceptions.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/Decorator/Interceptions.php
@@ -3,29 +3,29 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Reader\Decorator;
+namespace Magento\Setup\Module\Di\Code\Reader\Decorator;
 
-use Magento\Tools\Di\Compiler\Log\Log;
+use Magento\Setup\Module\Di\Compiler\Log\Log;
 
 /**
  * Class Interceptions
  *
- * @package Magento\Tools\Di\Code\Reader\Decorator
+ * @package Magento\Setup\Module\Di\Code\Reader\Decorator
  */
-class Interceptions implements \Magento\Tools\Di\Code\Reader\ClassesScannerInterface
+class Interceptions implements \Magento\Setup\Module\Di\Code\Reader\ClassesScannerInterface
 {
     /**
-     * @var \Magento\Tools\Di\Code\Reader\ClassReaderDecorator
+     * @var \Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator
      */
     private $classReader;
 
     /**
-     * @var \Magento\Tools\Di\Code\Reader\ClassesScanner
+     * @var \Magento\Setup\Module\Di\Code\Reader\ClassesScanner
      */
     private $classesScanner;
 
     /**
-     * @var \Magento\Tools\Di\Compiler\Log\Log
+     * @var \Magento\Setup\Module\Di\Compiler\Log\Log
      */
     private $log;
 
@@ -35,7 +35,7 @@ class Interceptions implements \Magento\Tools\Di\Code\Reader\ClassesScannerInter
     private $validator;
 
     /**
-     * @param \Magento\Tools\Di\Code\Reader\ClassesScanner $classesScanner
+     * @param \Magento\Setup\Module\Di\Code\Reader\ClassesScanner $classesScanner
      * @param \Magento\Framework\Code\Reader\ClassReader $classReader
      * @param \Magento\Framework\Code\Validator $validator
      * @param \Magento\Framework\Code\Validator\ConstructorIntegrity $constructorIntegrityValidator
@@ -43,7 +43,7 @@ class Interceptions implements \Magento\Tools\Di\Code\Reader\ClassesScannerInter
      * @param Log $log
      */
     public function __construct(
-        \Magento\Tools\Di\Code\Reader\ClassesScanner $classesScanner,
+        \Magento\Setup\Module\Di\Code\Reader\ClassesScanner $classesScanner,
         \Magento\Framework\Code\Reader\ClassReader $classReader,
         \Magento\Framework\Code\Validator $validator,
         \Magento\Framework\Code\Validator\ConstructorIntegrity $constructorIntegrityValidator,
diff --git a/dev/tools/Magento/Tools/Di/Code/Reader/Type.php b/setup/src/Magento/Setup/Module/Di/Code/Reader/Type.php
similarity index 89%
rename from dev/tools/Magento/Tools/Di/Code/Reader/Type.php
rename to setup/src/Magento/Setup/Module/Di/Code/Reader/Type.php
index 707ff19ce387ade6a970f2e5406f3629824ebe2e..a2ea1d3bf1df1e2979b3b3d83b7a2d1614e31f18 100644
--- a/dev/tools/Magento/Tools/Di/Code/Reader/Type.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Reader/Type.php
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Code\Reader;
+namespace Magento\Setup\Module\Di\Code\Reader;
 
 class Type
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/ArrayScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/ArrayScanner.php
similarity index 91%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/ArrayScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/ArrayScanner.php
index b2f52b36a83bae862e77eee060324bd83e47f42a..6feaa595d1c221a80cf15a802992359724058d17 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/ArrayScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/ArrayScanner.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
 
 class ArrayScanner implements ScannerInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/CompositeScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/CompositeScanner.php
similarity index 95%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/CompositeScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/CompositeScanner.php
index ed28b1fe2d2fb87cda4802becaf3e8b6d6285790..fb8785f22a7fc9ae3e4582db1c1ade769475699d 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/CompositeScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/CompositeScanner.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
 
 class CompositeScanner implements ScannerInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/DirectoryScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/DirectoryScanner.php
similarity index 96%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/DirectoryScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/DirectoryScanner.php
index 45a9fb36a9b943c3a3a45c834221252778e5bf7a..6d67146fc2597bb221298658ce343623bc2b85cf 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/DirectoryScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/DirectoryScanner.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
 
 class DirectoryScanner
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/InheritanceInterceptorScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/InheritanceInterceptorScanner.php
similarity index 60%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/InheritanceInterceptorScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/InheritanceInterceptorScanner.php
index 5d13d98be35d4ef9a74fb34dd59a5724f4342b7e..29a17eb86277b53cc769eca93019b0d6f5a2b9c3 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/InheritanceInterceptorScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/InheritanceInterceptorScanner.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
 
 class InheritanceInterceptorScanner implements ScannerInterface
 {
@@ -20,7 +20,9 @@ class InheritanceInterceptorScanner implements ScannerInterface
         foreach ($classes as $class) {
             foreach ($interceptedEntities as $interceptorClass) {
                 $interceptedEntity = substr($interceptorClass, 0, -12);
-                if (is_subclass_of($class, $interceptedEntity)) {
+                if (is_subclass_of($class, $interceptedEntity)
+                    && !$this->endsWith($class, 'RepositoryInterface\\Proxy')
+                    && !$this->endsWith($class, '\\Interceptor')) {
                     $reflectionClass = new \ReflectionClass($class);
                     if (!$reflectionClass->isAbstract() && !$reflectionClass->isFinal()) {
                         $output[] = $class . '\\Interceptor';
@@ -32,4 +34,18 @@ class InheritanceInterceptorScanner implements ScannerInterface
         $output = array_unique($output);
         return $output;
     }
+
+    /**
+     * Check if a string ends with a substring
+     *
+     * @param string $haystack
+     * @param string $needle
+     * @return bool
+     */
+    private function endsWith($haystack, $needle)
+    {
+        // search forward starting from end minus needle length characters
+        return $needle === ""
+        || (($temp = strlen($haystack) - strlen($needle)) >= 0 && strpos($haystack, $needle, $temp) !== false);
+    }
 }
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/InterceptedInstancesScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/InterceptedInstancesScanner.php
similarity index 96%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/InterceptedInstancesScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/InterceptedInstancesScanner.php
index c6004454cf2d7db0e718412313489908cc92de8d..831f5389ff30732e432dae8aef8e72cc362e036c 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/InterceptedInstancesScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/InterceptedInstancesScanner.php
@@ -4,7 +4,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
 
 class InterceptedInstancesScanner implements ScannerInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/PhpScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/PhpScanner.php
similarity index 98%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/PhpScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/PhpScanner.php
index ee0379367000787eb84f78feb03a03176fa9cc22..64f1a8ac90c205464ac95c14260675353c05453a 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/PhpScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/PhpScanner.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
 
-use Magento\Tools\Di\Compiler\Log\Log;
+use Magento\Setup\Module\Di\Compiler\Log\Log;
 use Magento\Framework\Api\Code\Generator\ExtensionAttributesGenerator;
 use Magento\Framework\Api\Code\Generator\ExtensionAttributesInterfaceGenerator;
 use Magento\Framework\ObjectManager\Code\Generator\Factory as FactoryGenerator;
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/PluginScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/PluginScanner.php
similarity index 95%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/PluginScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/PluginScanner.php
index d8190a83ff468f408b2f10143febb733cd5f8b23..5831ce61fcd516b8634c1520bdb77d23d6cd20f1 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/PluginScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/PluginScanner.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
 
 class PluginScanner implements ScannerInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/RepositoryScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/RepositoryScanner.php
similarity index 91%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/RepositoryScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/RepositoryScanner.php
index da58536126739c68d9cc420f5e3c6b36727889b0..acad623d61a4cc04d15b59018226ec635ad62cdc 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/RepositoryScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/RepositoryScanner.php
@@ -3,7 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
+
+use Magento\Framework\Autoload\AutoloaderRegistry;
 
 /**
  * Class RepositoryScanner
@@ -37,7 +39,8 @@ class RepositoryScanner implements ScannerInterface
                     && $replacementType !== null
                     && (substr($forType->nodeValue, -19) == 'RepositoryInterface')
                 ) {
-                    if (!class_exists($replacementType->nodeValue, $this->useAutoload)) {
+                    if (!class_exists($replacementType->nodeValue, false)
+                        && !AutoloaderRegistry::getAutoloader()->loadClass($replacementType->nodeValue)) {
                         $persistor = str_replace('\\Repository', 'InterfacePersistor', $replacementType->nodeValue);
                         $factory = str_replace('\\Repository', 'InterfaceFactory', $replacementType->nodeValue);
                         $searchResultFactory
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/ScannerInterface.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/ScannerInterface.php
similarity index 85%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/ScannerInterface.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/ScannerInterface.php
index 5bc2113eb78c6ef4d1f2db810255195ce80d26d3..ceb6003dbd284e1ee17293afa0e344e02aa4217b 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/ScannerInterface.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/ScannerInterface.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
 
 interface ScannerInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/XmlInterceptorScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlInterceptorScanner.php
similarity index 97%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/XmlInterceptorScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlInterceptorScanner.php
index 7de7b4315b892f44da3929b5853a4a86d6b070f2..d5c43af177651e0e5d1a3b17c74513187bd41a10 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/XmlInterceptorScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlInterceptorScanner.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
 
 class XmlInterceptorScanner implements ScannerInterface
 {
@@ -41,7 +41,7 @@ class XmlInterceptorScanner implements ScannerInterface
         foreach ($xpath->query('//type[plugin]|//virtualType[plugin]') as $entityNode) {
             $attributes = $entityNode->attributes;
             $type = $attributes->getNamedItem('type');
-            if (!is_null($type)) {
+            if ($type !== null) {
                 array_push($output, $type->nodeValue);
             } else {
                 array_push($output, $attributes->getNamedItem('name')->nodeValue);
diff --git a/dev/tools/Magento/Tools/Di/Code/Scanner/XmlScanner.php b/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php
similarity index 88%
rename from dev/tools/Magento/Tools/Di/Code/Scanner/XmlScanner.php
rename to setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php
index 6ca33d3f08c846116affee7d238d5c60ddc839e3..adc5a452ca9bb4bb8a96b552d9976d6a92954a17 100644
--- a/dev/tools/Magento/Tools/Di/Code/Scanner/XmlScanner.php
+++ b/setup/src/Magento/Setup/Module/Di/Code/Scanner/XmlScanner.php
@@ -3,21 +3,21 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Code\Scanner;
+namespace Magento\Setup\Module\Di\Code\Scanner;
 
 use Magento\Framework\ObjectManager\Code\Generator\Proxy as ProxyGenerator;
 
 class XmlScanner implements ScannerInterface
 {
     /**
-     * @var \Magento\Tools\Di\Compiler\Log\Log $log
+     * @var \Magento\Setup\Module\Di\Compiler\Log\Log $log
      */
     protected $_log;
 
     /**
-     * @param \Magento\Tools\Di\Compiler\Log\Log $log
+     * @param \Magento\Setup\Module\Di\Compiler\Log\Log $log
      */
-    public function __construct(\Magento\Tools\Di\Compiler\Log\Log $log)
+    public function __construct(\Magento\Setup\Module\Di\Compiler\Log\Log $log)
     {
         $this->_log = $log;
     }
@@ -75,7 +75,7 @@ class XmlScanner implements ScannerInterface
                     array_push($filteredEntities, $className);
                 } else {
                     $this->_log->add(
-                        \Magento\Tools\Di\Compiler\Log\Log::CONFIGURATION_ERROR,
+                        \Magento\Setup\Module\Di\Compiler\Log\Log::CONFIGURATION_ERROR,
                         $className,
                         'Invalid proxy class for ' . substr($className, 0, -5)
                     );
diff --git a/dev/tools/Magento/Tools/Di/Compiler/ArgumentsResolver.php b/setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolver.php
similarity index 99%
rename from dev/tools/Magento/Tools/Di/Compiler/ArgumentsResolver.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolver.php
index 37579cd287245ba202017ee08dca9cddac7b4fb2..423157a9aa0386efd276b5c5b46db1ebcac100af 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/ArgumentsResolver.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolver.php
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Compiler;
+namespace Magento\Setup\Module\Di\Compiler;
 
 class ArgumentsResolver
 {
diff --git a/dev/tools/Magento/Tools/Di/Compiler/ArgumentsResolverFactory.php b/setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolverFactory.php
similarity index 88%
rename from dev/tools/Magento/Tools/Di/Compiler/ArgumentsResolverFactory.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolverFactory.php
index 8a5adb49b2fe6455c5ae0ceb8f7632ba82d7e70c..603b63f7b038715ead1fbec1a0f7daf0f6814fdf 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/ArgumentsResolverFactory.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolverFactory.php
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Compiler;
+namespace Magento\Setup\Module\Di\Compiler;
 
 class ArgumentsResolverFactory
 {
@@ -31,7 +31,7 @@ class ArgumentsResolverFactory
      * Create class instance with config
      *
      * @param \Magento\Framework\ObjectManager\ConfigInterface $diContainerConfig
-     * @return \Magento\Tools\Di\Compiler\ArgumentsResolver
+     * @return \Magento\Setup\Module\Di\Compiler\ArgumentsResolver
      */
     public function create(\Magento\Framework\ObjectManager\ConfigInterface $diContainerConfig)
     {
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Config/Chain/ArgumentsSerialization.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/ArgumentsSerialization.php
similarity index 83%
rename from dev/tools/Magento/Tools/Di/Compiler/Config/Chain/ArgumentsSerialization.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/ArgumentsSerialization.php
index c19d07de807bb5b742ee0a0f12fce7001a917522..16b317a63dc03726046d80164fc46b38e4278e7f 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/Config/Chain/ArgumentsSerialization.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/ArgumentsSerialization.php
@@ -4,9 +4,9 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Compiler\Config\Chain;
+namespace Magento\Setup\Module\Di\Compiler\Config\Chain;
 
-use Magento\Tools\Di\Compiler\Config\ModificationInterface;
+use Magento\Setup\Module\Di\Compiler\Config\ModificationInterface;
 
 class ArgumentsSerialization implements ModificationInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Config/Chain/BackslashTrim.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/BackslashTrim.php
similarity index 92%
rename from dev/tools/Magento/Tools/Di/Compiler/Config/Chain/BackslashTrim.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/BackslashTrim.php
index b7500e4fb0cacd34e051dcd847cccb7b321c1f7e..d741d004b9d652078496117b9d91244f9dceac1b 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/Config/Chain/BackslashTrim.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/BackslashTrim.php
@@ -4,9 +4,9 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Compiler\Config\Chain;
+namespace Magento\Setup\Module\Di\Compiler\Config\Chain;
 
-use Magento\Tools\Di\Compiler\Config\ModificationInterface;
+use Magento\Setup\Module\Di\Compiler\Config\ModificationInterface;
 
 class BackslashTrim implements ModificationInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Config/Chain/InterceptorSubstitution.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/InterceptorSubstitution.php
similarity index 94%
rename from dev/tools/Magento/Tools/Di/Compiler/Config/Chain/InterceptorSubstitution.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/InterceptorSubstitution.php
index 26e6464858f590aa6b7ec639c495f213c7ffff89..324a7724702249636f737011142a2f8db0c95c09 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/Config/Chain/InterceptorSubstitution.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/InterceptorSubstitution.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Compiler\Config\Chain;
+namespace Magento\Setup\Module\Di\Compiler\Config\Chain;
 
-use Magento\Tools\Di\Compiler\Config\ModificationInterface;
+use Magento\Setup\Module\Di\Compiler\Config\ModificationInterface;
 
 class InterceptorSubstitution implements ModificationInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Config/Chain/PreferencesResolving.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/PreferencesResolving.php
similarity index 91%
rename from dev/tools/Magento/Tools/Di/Compiler/Config/Chain/PreferencesResolving.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/PreferencesResolving.php
index 3600ea3ea8360b1a24e569e6131cb73c99f78d52..9d58a69cd6ebf5fea3a41f70bf0f1f9ffa1cb0f4 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/Config/Chain/PreferencesResolving.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Chain/PreferencesResolving.php
@@ -4,9 +4,9 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Compiler\Config\Chain;
+namespace Magento\Setup\Module\Di\Compiler\Config\Chain;
 
-use Magento\Tools\Di\Compiler\Config\ModificationInterface;
+use Magento\Setup\Module\Di\Compiler\Config\ModificationInterface;
 
 class PreferencesResolving implements ModificationInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Config/ModificationChain.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/ModificationChain.php
similarity index 95%
rename from dev/tools/Magento/Tools/Di/Compiler/Config/ModificationChain.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/Config/ModificationChain.php
index fcdec2563e9ade96276b5e6e030bd5db2f74fe6d..666ee682c05cd71232cb68432d4584eac26a02b4 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/Config/ModificationChain.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/ModificationChain.php
@@ -4,7 +4,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Compiler\Config;
+namespace Magento\Setup\Module\Di\Compiler\Config;
 
 class ModificationChain implements ModificationInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Config/ModificationInterface.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/ModificationInterface.php
similarity index 84%
rename from dev/tools/Magento/Tools/Di/Compiler/Config/ModificationInterface.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/Config/ModificationInterface.php
index 5e8f124bffef89ec316e3100585565e92dea6544..5f2b2d067cad581c8360fe56b423a6b574e726fe 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/Config/ModificationInterface.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/ModificationInterface.php
@@ -4,7 +4,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Compiler\Config;
+namespace Magento\Setup\Module\Di\Compiler\Config;
 
 interface ModificationInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Config/Reader.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Reader.php
similarity index 93%
rename from dev/tools/Magento/Tools/Di/Compiler/Config/Reader.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/Config/Reader.php
index b143705afa34968f86859ab358643fc8b4c059ce..3321115dd6cf57ea4a88a8ec8c16e78277d3d6a3 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/Config/Reader.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Reader.php
@@ -4,18 +4,18 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Compiler\Config;
+namespace Magento\Setup\Module\Di\Compiler\Config;
 
 use Magento\Framework\App;
 use Magento\Framework\ObjectManager\ConfigInterface;
-use Magento\Tools\Di\Code\Reader\ClassReaderDecorator;
-use Magento\Tools\Di\Code\Reader\Type;
-use Magento\Tools\Di\Compiler\ArgumentsResolverFactory;
-use Magento\Tools\Di\Definition\Collection as DefinitionsCollection;
+use Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator;
+use Magento\Setup\Module\Di\Code\Reader\Type;
+use Magento\Setup\Module\Di\Compiler\ArgumentsResolverFactory;
+use Magento\Setup\Module\Di\Definition\Collection as DefinitionsCollection;
 
 /**
  * Class Reader
- * @package Magento\Tools\Di\Compiler\Config
+ * @package Magento\Setup\Module\Di\Compiler\Config
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class Reader
diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php
new file mode 100644
index 0000000000000000000000000000000000000000..c90c1582bc57b95e1dbca5aab0bc861490bf564b
--- /dev/null
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/Writer/Filesystem.php
@@ -0,0 +1,56 @@
+<?php
+/**
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Setup\Module\Di\Compiler\Config\Writer;
+
+use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Setup\Module\Di\Compiler\Config\WriterInterface;
+
+class Filesystem implements WriterInterface
+{
+    /**
+     * @var DirectoryList
+     */
+    private $directoryList;
+
+    /**
+     * Constructor
+     *
+     * @param DirectoryList $directoryList
+     */
+    public function __construct(DirectoryList $directoryList)
+    {
+        $this->directoryList = $directoryList;
+    }
+
+    /**
+     * Writes config in storage
+     *
+     * @param string $key
+     * @param array $config
+     * @return void
+     */
+    public function write($key, array $config)
+    {
+        $this->initialize();
+
+        $serialized = serialize($config);
+        file_put_contents($this->directoryList->getPath(DirectoryList::DI) . '/' . $key . '.ser', $serialized);
+    }
+
+    /**
+     * Initializes writer
+     *
+     * @return void
+     */
+    private function initialize()
+    {
+        if (!file_exists($this->directoryList->getPath(DirectoryList::DI))) {
+            mkdir($this->directoryList->getPath(DirectoryList::DI));
+        }
+    }
+}
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Config/WriterInterface.php b/setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php
similarity index 86%
rename from dev/tools/Magento/Tools/Di/Compiler/Config/WriterInterface.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php
index 0e54e3585f7ad4dbddcde43548edee556ab9f341..431d3ceb7da7295824089dd1a13137f29645d1b1 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/Config/WriterInterface.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Config/WriterInterface.php
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Compiler\Config;
+namespace Magento\Setup\Module\Di\Compiler\Config;
 
 interface WriterInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Compiler/ConstructorArgument.php b/setup/src/Magento/Setup/Module/Di/Compiler/ConstructorArgument.php
similarity index 96%
rename from dev/tools/Magento/Tools/Di/Compiler/ConstructorArgument.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/ConstructorArgument.php
index 39b38dc37a186d66f9ca4fb4ee4f983ccaa8fe4e..646d3ccd3565529357e9c0aad4b4eace5a8ac98c 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/ConstructorArgument.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/ConstructorArgument.php
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Compiler;
+namespace Magento\Setup\Module\Di\Compiler;
 
 class ConstructorArgument
 {
diff --git a/dev/tools/Magento/Tools/Di/Compiler/Log/Log.php b/setup/src/Magento/Setup/Module/Di/Compiler/Log/Log.php
similarity index 85%
rename from dev/tools/Magento/Tools/Di/Compiler/Log/Log.php
rename to setup/src/Magento/Setup/Module/Di/Compiler/Log/Log.php
index 963632f686a3b5a471f846597e33ce8e0eecab73..67d93bfd6304e2c15d3a4e14b873ffe60ef0e83f 100644
--- a/dev/tools/Magento/Tools/Di/Compiler/Log/Log.php
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Log/Log.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Compiler\Log;
+namespace Magento\Setup\Module\Di\Compiler\Log;
 
 
 class Log
@@ -19,14 +19,14 @@ class Log
     /**
      * Success log writer
      *
-     * @var Writer\WriterInterface
+     * @var Writer\Console
      */
     protected $_successWriter;
 
     /**
      * Error log writer
      *
-     * @var Writer\WriterInterface
+     * @var Writer\Console
      */
     protected $_errorWriter;
 
@@ -45,10 +45,10 @@ class Log
     protected $_errorEntries = [];
 
     /**
-     * @param Writer\WriterInterface $successWriter
-     * @param Writer\WriterInterface $errorWriter
+     * @param Writer\Console $successWriter
+     * @param Writer\Console $errorWriter
      */
-    public function __construct(Writer\WriterInterface $successWriter, Writer\WriterInterface $errorWriter)
+    public function __construct(Writer\Console $successWriter, Writer\Console $errorWriter)
     {
         $this->_successWriter = $successWriter;
         $this->_errorWriter = $errorWriter;
diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/Log/Writer/Console.php b/setup/src/Magento/Setup/Module/Di/Compiler/Log/Writer/Console.php
new file mode 100644
index 0000000000000000000000000000000000000000..4c484cd841b81c2478f752d1b1cad8f23f96532f
--- /dev/null
+++ b/setup/src/Magento/Setup/Module/Di/Compiler/Log/Writer/Console.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Module\Di\Compiler\Log\Writer;
+
+use Magento\Setup\Module\Di\Compiler\Log\Log;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class Console
+{
+    /**
+     * Report messages by type
+     *
+     * @var array
+     */
+    protected $_messages = [
+        Log::GENERATION_SUCCESS => 'Generated classes:',
+        Log::GENERATION_ERROR => 'Errors during class generation:',
+        Log::COMPILATION_ERROR => 'Errors during compilation:',
+        Log::CONFIGURATION_ERROR => 'Errors during configuration scanning:',
+    ];
+
+    /**
+     * Console
+     *
+     * @var OutputInterface
+     */
+    protected $console;
+
+    /**
+     * @param OutputInterface $output
+     */
+    public function __construct(OutputInterface $output)
+    {
+        $this->console = $output;
+    }
+
+    /**
+     * Output log data
+     *
+     * @param array $data
+     * @return void
+     */
+    public function write(array $data)
+    {
+        $errorsCount = 0;
+        foreach ($data as $type => $classes) {
+            if (!count($classes)) {
+                continue;
+            }
+            $this->console->writeln($this->getStartTag($type) . $this->_messages[$type] . $this->getEndTag($type));
+            foreach ($classes as $className => $messages) {
+                if (count($messages)) {
+                    $this->console->writeln($this->getStartTag($type) . "\t" . $className . $this->getEndTag($type));
+                    foreach ($messages as $message) {
+                        if ($message) {
+                            $this->console->writeln(
+                                $this->getStartTag($type) . "\t\t" . $message . $this->getEndTag($type)
+                            );
+                            if ($type != Log::GENERATION_SUCCESS) {
+                                $errorsCount++;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if ($errorsCount) {
+            $this->console->writeln('<error>' . 'Total Errors Count: ' . $errorsCount . '</error>');
+        }
+    }
+
+    /**
+     * Retrieve starting output tag
+     *
+     * @param string $type
+     * @return string
+     */
+    private function getStartTag($type)
+    {
+        if ($type === Log::GENERATION_SUCCESS) {
+            return '<info>';
+        } else {
+            return '<error>';
+        }
+    }
+
+    /**
+     * Retrieve ending output tag
+     *
+     * @param string $type
+     * @return string
+     */
+    private function getEndTag($type)
+    {
+        if ($type === Log::GENERATION_SUCCESS) {
+            return '</info>';
+        } else {
+            return '</error>';
+        }
+    }
+}
diff --git a/dev/tools/Magento/Tools/Di/Definition/Collection.php b/setup/src/Magento/Setup/Module/Di/Definition/Collection.php
similarity index 97%
rename from dev/tools/Magento/Tools/Di/Definition/Collection.php
rename to setup/src/Magento/Setup/Module/Di/Definition/Collection.php
index 580f930d24cdd59584306f0cd3eb62e696f0a170..a18f8fb47795ebb9c6e035a8579366e3330dd708 100644
--- a/dev/tools/Magento/Tools/Di/Definition/Collection.php
+++ b/setup/src/Magento/Setup/Module/Di/Definition/Collection.php
@@ -4,7 +4,7 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Definition;
+namespace Magento\Setup\Module\Di\Definition;
 
 class Collection
 {
diff --git a/dev/tools/Magento/Tools/Di/Definition/Compressor.php b/setup/src/Magento/Setup/Module/Di/Definition/Compressor.php
similarity index 96%
rename from dev/tools/Magento/Tools/Di/Definition/Compressor.php
rename to setup/src/Magento/Setup/Module/Di/Definition/Compressor.php
index f29ee3779c23e85ff3b2942d2d1ebeecb9e64bad..6ee28a3e42e24b664022fb99ba4933adbf87168f 100644
--- a/dev/tools/Magento/Tools/Di/Definition/Compressor.php
+++ b/setup/src/Magento/Setup/Module/Di/Definition/Compressor.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Definition;
+namespace Magento\Setup\Module\Di\Definition;
 
 class Compressor
 {
diff --git a/dev/tools/Magento/Tools/Di/Definition/Compressor/UniqueList.php b/setup/src/Magento/Setup/Module/Di/Definition/Compressor/UniqueList.php
similarity index 93%
rename from dev/tools/Magento/Tools/Di/Definition/Compressor/UniqueList.php
rename to setup/src/Magento/Setup/Module/Di/Definition/Compressor/UniqueList.php
index 7f743353ece5cfc17e5b520d9478b72cbfe746ac..cdc4578824d2bc99f04533097796c1fd0d4c8e29 100644
--- a/dev/tools/Magento/Tools/Di/Definition/Compressor/UniqueList.php
+++ b/setup/src/Magento/Setup/Module/Di/Definition/Compressor/UniqueList.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Definition\Compressor;
+namespace Magento\Setup\Module\Di\Definition\Compressor;
 
 class UniqueList
 {
diff --git a/dev/tools/Magento/Tools/Di/Definition/Serializer/Igbinary.php b/setup/src/Magento/Setup/Module/Di/Definition/Serializer/Igbinary.php
similarity index 91%
rename from dev/tools/Magento/Tools/Di/Definition/Serializer/Igbinary.php
rename to setup/src/Magento/Setup/Module/Di/Definition/Serializer/Igbinary.php
index bfcf90322aecb3441faba643398327cf5365bb7e..db8e0e7ad0fb55ca3c957a9c824d69cd8fb2ea9e 100644
--- a/dev/tools/Magento/Tools/Di/Definition/Serializer/Igbinary.php
+++ b/setup/src/Magento/Setup/Module/Di/Definition/Serializer/Igbinary.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Definition\Serializer;
+namespace Magento\Setup\Module\Di\Definition\Serializer;
 
 class Igbinary implements SerializerInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Definition/Serializer/SerializerInterface.php b/setup/src/Magento/Setup/Module/Di/Definition/Serializer/SerializerInterface.php
similarity index 82%
rename from dev/tools/Magento/Tools/Di/Definition/Serializer/SerializerInterface.php
rename to setup/src/Magento/Setup/Module/Di/Definition/Serializer/SerializerInterface.php
index e722e0f7f4f20d42d85383346c647fa849c711cc..e4daa07f17b25641d49c0315474d051b386f8377 100644
--- a/dev/tools/Magento/Tools/Di/Definition/Serializer/SerializerInterface.php
+++ b/setup/src/Magento/Setup/Module/Di/Definition/Serializer/SerializerInterface.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Definition\Serializer;
+namespace Magento\Setup\Module\Di\Definition\Serializer;
 
 interface SerializerInterface
 {
diff --git a/dev/tools/Magento/Tools/Di/Definition/Serializer/Standard.php b/setup/src/Magento/Setup/Module/Di/Definition/Serializer/Standard.php
similarity index 87%
rename from dev/tools/Magento/Tools/Di/Definition/Serializer/Standard.php
rename to setup/src/Magento/Setup/Module/Di/Definition/Serializer/Standard.php
index 4862fce3e367eff36650e13afab90dd38d430566..5c98d658e776b6a5753417b8045a852e315ea268 100644
--- a/dev/tools/Magento/Tools/Di/Definition/Serializer/Standard.php
+++ b/setup/src/Magento/Setup/Module/Di/Definition/Serializer/Standard.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Definition\Serializer;
+namespace Magento\Setup\Module\Di\Definition\Serializer;
 
 class Standard implements SerializerInterface
 {
diff --git a/dev/tools/Magento/Tools/I18n/Context.php b/setup/src/Magento/Setup/Module/I18n/Context.php
similarity index 98%
rename from dev/tools/Magento/Tools/I18n/Context.php
rename to setup/src/Magento/Setup/Module/I18n/Context.php
index 839fd699f2b3d60866f8f28d4ef7f8a4593b7b3f..165669bbced84a6cb7490065bee00257ec6c780a 100644
--- a/dev/tools/Magento/Tools/I18n/Context.php
+++ b/setup/src/Magento/Setup/Module/I18n/Context.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n;
+namespace Magento\Setup\Module\I18n;
 
 /**
  *  Context
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary.php b/setup/src/Magento/Setup/Module/I18n/Dictionary.php
similarity index 85%
rename from dev/tools/Magento/Tools/I18n/Dictionary.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary.php
index 0026cf5ecaf8fc0da0aef0cdb689d6b85357a94a..86f9b06145d7aa5a4c884221ee1ca40cf2ea7177 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n;
+namespace Magento\Setup\Module\I18n;
 
-use Magento\Tools\I18n\Dictionary\Phrase;
+use Magento\Setup\Module\I18n\Dictionary\Phrase;
 
 /**
  *  Dictionary
@@ -29,7 +29,7 @@ class Dictionary
     /**
      * Add phrase to pack container
      *
-     * @param \Magento\Tools\I18n\Dictionary\Phrase $phrase
+     * @param Phrase $phrase
      * @return void
      */
     public function addPhrase(Phrase $phrase)
@@ -41,7 +41,7 @@ class Dictionary
     /**
      * Get phrases
      *
-     * @return \Magento\Tools\I18n\Dictionary\Phrase[]
+     * @return Phrase[]
      */
     public function getPhrases()
     {
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/Generator.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Generator.php
similarity index 88%
rename from dev/tools/Magento/Tools/I18n/Dictionary/Generator.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/Generator.php
index 85d2ec14cb5679d82eb5d12c5932a6267d937c73..81a8b8dc2649ce18cd835fb3d41d338e0922dfae 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/Generator.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Generator.php
@@ -3,10 +3,10 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary;
+namespace Magento\Setup\Module\I18n\Dictionary;
 
-use Magento\Tools\I18n\Factory;
-use Magento\Tools\I18n\ParserInterface;
+use Magento\Setup\Module\I18n\Factory;
+use Magento\Setup\Module\I18n\ParserInterface;
 
 /**
  * Dictionary generator
@@ -16,21 +16,21 @@ class Generator
     /**
      * Parser
      *
-     * @var \Magento\Tools\I18n\ParserInterface
+     * @var \Magento\Setup\Module\I18n\ParserInterface
      */
     protected $parser;
 
     /**
      * Contextual parser
      *
-     * @var \Magento\Tools\I18n\ParserInterface
+     * @var \Magento\Setup\Module\I18n\ParserInterface
      */
     protected $contextualParser;
 
     /**
      * Domain abstract factory
      *
-     * @var \Magento\Tools\I18n\Factory
+     * @var \Magento\Setup\Module\I18n\Factory
      */
     protected $factory;
 
@@ -108,7 +108,7 @@ class Generator
      * Get actual parser
      *
      * @param bool $withContext
-     * @return \Magento\Tools\I18n\ParserInterface
+     * @return \Magento\Setup\Module\I18n\ParserInterface
      */
     protected function getActualParser($withContext)
     {
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/Loader/File/AbstractFile.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Loader/File/AbstractFile.php
similarity index 89%
rename from dev/tools/Magento/Tools/I18n/Dictionary/Loader/File/AbstractFile.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/Loader/File/AbstractFile.php
index 3cd27234bab0ed3810a654c6265b3c23ad9940b9..79bdbb6f7b04e0645aed3410a7a51dde08ab2dd0 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/Loader/File/AbstractFile.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Loader/File/AbstractFile.php
@@ -3,10 +3,10 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary\Loader\File;
+namespace Magento\Setup\Module\I18n\Dictionary\Loader\File;
 
-use Magento\Tools\I18n\Dictionary\Loader\FileInterface;
-use Magento\Tools\I18n\Factory;
+use Magento\Setup\Module\I18n\Dictionary\Loader\FileInterface;
+use Magento\Setup\Module\I18n\Factory;
 
 /**
  *  Abstract dictionary loader from file
@@ -16,7 +16,7 @@ abstract class AbstractFile implements FileInterface
     /**
      * Domain abstract factory
      *
-     * @var \Magento\Tools\I18n\Factory
+     * @var \Magento\Setup\Module\I18n\Factory
      */
     protected $_factory;
 
@@ -106,7 +106,7 @@ abstract class AbstractFile implements FileInterface
     /**
      * Create dictionary
      *
-     * @return \Magento\Tools\I18n\Dictionary
+     * @return \Magento\Setup\Module\I18n\Dictionary
      */
     protected function _createDictionary()
     {
@@ -117,7 +117,7 @@ abstract class AbstractFile implements FileInterface
      * Create phrase
      *
      * @param array $data
-     * @return \Magento\Tools\I18n\Dictionary\Phrase
+     * @return \Magento\Setup\Module\I18n\Dictionary\Phrase
      * @throws \RuntimeException
      */
     protected function _createPhrase($data)
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/Loader/File/Csv.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Loader/File/Csv.php
similarity index 76%
rename from dev/tools/Magento/Tools/I18n/Dictionary/Loader/File/Csv.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/Loader/File/Csv.php
index aa62de706c41cfac55350242b2dfee48a1c1e989..91a02c11056f3d1d23b011aa2b3edf376c63d037 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/Loader/File/Csv.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Loader/File/Csv.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary\Loader\File;
+namespace Magento\Setup\Module\I18n\Dictionary\Loader\File;
 
-use Magento\Tools\I18n\Dictionary;
+use Magento\Setup\Module\I18n\Dictionary;
 
 /**
  *  Dictionary loader from csv
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/Loader/FileInterface.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Loader/FileInterface.php
similarity index 74%
rename from dev/tools/Magento/Tools/I18n/Dictionary/Loader/FileInterface.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/Loader/FileInterface.php
index 923c555929adb287b18bfc504be5a2eaa511e244..3365e2ffd7d3dce5ba7d47435cfa4596317abc72 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/Loader/FileInterface.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Loader/FileInterface.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary\Loader;
+namespace Magento\Setup\Module\I18n\Dictionary\Loader;
 
 /**
  * Dictionary loader interface
@@ -14,7 +14,7 @@ interface FileInterface
      * Load dictionary
      *
      * @param string $file
-     * @return \Magento\Tools\I18n\Dictionary
+     * @return \Magento\Setup\Module\I18n\Dictionary
      * @throws \InvalidArgumentException
      */
     public function load($file);
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/Options/Resolver.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Options/Resolver.php
similarity index 98%
rename from dev/tools/Magento/Tools/I18n/Dictionary/Options/Resolver.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/Options/Resolver.php
index bbc43b8f4313aaaf5cf2fa79d006720da8d01ea8..d257486fc3a3c1692798174e43ebde6822952078 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/Options/Resolver.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Options/Resolver.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary\Options;
+namespace Magento\Setup\Module\I18n\Dictionary\Options;
 
 /**
  * Dictionary generator options resolver
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/Options/ResolverFactory.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Options/ResolverFactory.php
similarity index 87%
rename from dev/tools/Magento/Tools/I18n/Dictionary/Options/ResolverFactory.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/Options/ResolverFactory.php
index 5ea187e0e63d6b06b6b3d23a0dfce2eb8b36bbd6..0068ac187a7c9ae16c7643e8080eb306bc04fedc 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/Options/ResolverFactory.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Options/ResolverFactory.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary\Options;
+namespace Magento\Setup\Module\I18n\Dictionary\Options;
 
 /**
  * Options resolver factory
@@ -13,7 +13,7 @@ class ResolverFactory
     /**
      * Default option resolver class
      */
-    const DEFAULT_RESOLVER = 'Magento\Tools\I18n\Dictionary\Options\Resolver';
+    const DEFAULT_RESOLVER = 'Magento\Setup\Module\I18n\Dictionary\Options\Resolver';
 
     /**
      * @var string
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/Options/ResolverInterface.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Options/ResolverInterface.php
similarity index 82%
rename from dev/tools/Magento/Tools/I18n/Dictionary/Options/ResolverInterface.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/Options/ResolverInterface.php
index 932d5efd892d596b6faa1d85a132c40f72d1460c..17d418af1b9c3e61eb8726efb0e42d5eb106166b 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/Options/ResolverInterface.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Options/ResolverInterface.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary\Options;
+namespace Magento\Setup\Module\I18n\Dictionary\Options;
 
 /**
  * Generator options resolver interface
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/Phrase.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Phrase.php
similarity index 98%
rename from dev/tools/Magento/Tools/I18n/Dictionary/Phrase.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/Phrase.php
index 1186e1096b44516562815a8533def41a255a6556..011de2e22c01ae7a3414b8e73a28eb54914aecf5 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/Phrase.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Phrase.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary;
+namespace Magento\Setup\Module\I18n\Dictionary;
 
 /**
  *  Phrase
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/Writer/Csv.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Writer/Csv.php
similarity index 92%
rename from dev/tools/Magento/Tools/I18n/Dictionary/Writer/Csv.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/Writer/Csv.php
index e27da55c58f8e07228d363cad82dca219976a555..b77daa5fd3512e5fac1e0e0defe8e84362d3b088 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/Writer/Csv.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Writer/Csv.php
@@ -3,10 +3,10 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary\Writer;
+namespace Magento\Setup\Module\I18n\Dictionary\Writer;
 
-use Magento\Tools\I18n\Dictionary\Phrase;
-use Magento\Tools\I18n\Dictionary\WriterInterface;
+use Magento\Setup\Module\I18n\Dictionary\Phrase;
+use Magento\Setup\Module\I18n\Dictionary\WriterInterface;
 
 /**
  * Csv writer
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/Writer/Csv/Stdo.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/Writer/Csv/Stdo.php
similarity index 73%
rename from dev/tools/Magento/Tools/I18n/Dictionary/Writer/Csv/Stdo.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/Writer/Csv/Stdo.php
index 3a2ed9acb9ba327eeb1371cb4c3a90bf803d7cf0..ffc2d5356231204a60f5a8e858e82fa79306af56 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/Writer/Csv/Stdo.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/Writer/Csv/Stdo.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary\Writer\Csv;
+namespace Magento\Setup\Module\I18n\Dictionary\Writer\Csv;
 
-use Magento\Tools\I18n\Dictionary\Writer\Csv;
+use Magento\Setup\Module\I18n\Dictionary\Writer\Csv;
 
 /**
  * Stdout writer
diff --git a/dev/tools/Magento/Tools/I18n/Dictionary/WriterInterface.php b/setup/src/Magento/Setup/Module/I18n/Dictionary/WriterInterface.php
similarity index 86%
rename from dev/tools/Magento/Tools/I18n/Dictionary/WriterInterface.php
rename to setup/src/Magento/Setup/Module/I18n/Dictionary/WriterInterface.php
index fe3f82f44f5f8ffa7b4e7947a317bd23fe2e748c..ac9ffade5bf2d5010fb919ad813e9293e23a9145 100644
--- a/dev/tools/Magento/Tools/I18n/Dictionary/WriterInterface.php
+++ b/setup/src/Magento/Setup/Module/I18n/Dictionary/WriterInterface.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Dictionary;
+namespace Magento\Setup\Module\I18n\Dictionary;
 
 /**
  * Writer interface
diff --git a/dev/tools/Magento/Tools/I18n/Factory.php b/setup/src/Magento/Setup/Module/I18n/Factory.php
similarity index 84%
rename from dev/tools/Magento/Tools/I18n/Factory.php
rename to setup/src/Magento/Setup/Module/I18n/Factory.php
index 35aec2a076a92b8e0253215e230ea78d20a23163..f6e27614734fc07843a7e258c8c1dc108849e75f 100644
--- a/dev/tools/Magento/Tools/I18n/Factory.php
+++ b/setup/src/Magento/Setup/Module/I18n/Factory.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n;
+namespace Magento\Setup\Module\I18n;
 
 /**
  *  Abstract Factory
@@ -14,7 +14,7 @@ class Factory
      * Create dictionary writer
      *
      * @param string $filename
-     * @return \Magento\Tools\I18n\Dictionary\WriterInterface
+     * @return \Magento\Setup\Module\I18n\Dictionary\WriterInterface
      * @throws \InvalidArgumentException
      */
     public function createDictionaryWriter($filename = null)
@@ -36,7 +36,7 @@ class Factory
      * Create locale
      *
      * @param string $locale
-     * @return \Magento\Tools\I18n\Locale
+     * @return \Magento\Setup\Module\I18n\Locale
      */
     public function createLocale($locale)
     {
@@ -46,7 +46,7 @@ class Factory
     /**
      * Create dictionary
      *
-     * @return \Magento\Tools\I18n\Dictionary
+     * @return \Magento\Setup\Module\I18n\Dictionary
      */
     public function createDictionary()
     {
@@ -57,7 +57,7 @@ class Factory
      * Create Phrase
      *
      * @param array $data
-     * @return \Magento\Tools\I18n\Dictionary\Phrase
+     * @return \Magento\Setup\Module\I18n\Dictionary\Phrase
      */
     public function createPhrase(array $data)
     {
diff --git a/dev/tools/Magento/Tools/I18n/FilesCollector.php b/setup/src/Magento/Setup/Module/I18n/FilesCollector.php
similarity index 97%
rename from dev/tools/Magento/Tools/I18n/FilesCollector.php
rename to setup/src/Magento/Setup/Module/I18n/FilesCollector.php
index da8684ac0485c567e7bd0f1b2c725df8fb1a433e..3c01889dfd11d4d5b701ad6f3845086e3a02a409 100644
--- a/dev/tools/Magento/Tools/I18n/FilesCollector.php
+++ b/setup/src/Magento/Setup/Module/I18n/FilesCollector.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n;
+namespace Magento\Setup\Module\I18n;
 
 /**
  *  Files collector
diff --git a/dev/tools/Magento/Tools/I18n/Locale.php b/setup/src/Magento/Setup/Module/I18n/Locale.php
similarity index 96%
rename from dev/tools/Magento/Tools/I18n/Locale.php
rename to setup/src/Magento/Setup/Module/I18n/Locale.php
index a5fca0b75cd9c0efa50118e3261fa737950d0b45..e3bb79e9adb2fd6007dfef92bb711394aa85244e 100644
--- a/dev/tools/Magento/Tools/I18n/Locale.php
+++ b/setup/src/Magento/Setup/Module/I18n/Locale.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n;
+namespace Magento\Setup\Module\I18n;
 
 /**
  *  Locale
diff --git a/dev/tools/Magento/Tools/I18n/Pack/Generator.php b/setup/src/Magento/Setup/Module/I18n/Pack/Generator.php
similarity index 78%
rename from dev/tools/Magento/Tools/I18n/Pack/Generator.php
rename to setup/src/Magento/Setup/Module/I18n/Pack/Generator.php
index bc257a637ace6c67ebb2fe1575e88915bc7ea9fa..bbc0cecfa9ce6de7bc74c7fae3dd45acf35f8cc7 100644
--- a/dev/tools/Magento/Tools/I18n/Pack/Generator.php
+++ b/setup/src/Magento/Setup/Module/I18n/Pack/Generator.php
@@ -3,11 +3,11 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Pack;
+namespace Magento\Setup\Module\I18n\Pack;
 
-use Magento\Tools\I18n\Dictionary;
-use Magento\Tools\I18n\Factory;
-use Magento\Tools\I18n\Pack;
+use Magento\Setup\Module\I18n\Dictionary;
+use Magento\Setup\Module\I18n\Factory;
+use Magento\Setup\Module\I18n\Pack;
 
 /**
  * Pack generator
@@ -17,30 +17,30 @@ class Generator
     /**
      * Dictionary loader
      *
-     * @var \Magento\Tools\I18n\Dictionary\Loader\FileInterface
+     * @var \Magento\Setup\Module\I18n\Dictionary\Loader\FileInterface
      */
     protected $dictionaryLoader;
 
     /**
      * Pack writer
      *
-     * @var \Magento\Tools\I18n\Pack\WriterInterface
+     * @var \Magento\Setup\Module\I18n\Pack\WriterInterface
      */
     protected $packWriter;
 
     /**
      * Domain abstract factory
      *
-     * @var \Magento\Tools\I18n\Factory
+     * @var \Magento\Setup\Module\I18n\Factory
      */
     protected $factory;
 
     /**
      * Loader construct
      *
-     * @param \Magento\Tools\I18n\Dictionary\Loader\FileInterface $dictionaryLoader
-     * @param \Magento\Tools\I18n\Pack\WriterInterface $packWriter
-     * @param \Magento\Tools\I18n\Factory $factory
+     * @param \Magento\Setup\Module\I18n\Dictionary\Loader\FileInterface $dictionaryLoader
+     * @param \Magento\Setup\Module\I18n\Pack\WriterInterface $packWriter
+     * @param \Magento\Setup\Module\I18n\Factory $factory
      */
     public function __construct(
         Dictionary\Loader\FileInterface $dictionaryLoader,
@@ -97,7 +97,7 @@ class Generator
     {
         $error = '';
         foreach ($duplicates as $phrases) {
-            /** @var \Magento\Tools\I18n\Dictionary\Phrase $phrase */
+            /** @var \Magento\Setup\Module\I18n\Dictionary\Phrase $phrase */
             $phrase = $phrases[0];
             $error .= sprintf(
                 "The phrase \"%s\" is translated in %d places.\n",
diff --git a/dev/tools/Magento/Tools/I18n/Pack/Writer/File/AbstractFile.php b/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/AbstractFile.php
similarity index 86%
rename from dev/tools/Magento/Tools/I18n/Pack/Writer/File/AbstractFile.php
rename to setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/AbstractFile.php
index 98307f0d4dbc900c409b0c973707e9b39347cf8b..599b806f09930500af793a6ba54f965650079624 100644
--- a/dev/tools/Magento/Tools/I18n/Pack/Writer/File/AbstractFile.php
+++ b/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/AbstractFile.php
@@ -3,13 +3,13 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Pack\Writer\File;
+namespace Magento\Setup\Module\I18n\Pack\Writer\File;
 
-use Magento\Tools\I18n\Context;
-use Magento\Tools\I18n\Dictionary;
-use Magento\Tools\I18n\Factory;
-use Magento\Tools\I18n\Locale;
-use Magento\Tools\I18n\Pack\WriterInterface;
+use Magento\Setup\Module\I18n\Context;
+use Magento\Setup\Module\I18n\Dictionary;
+use Magento\Setup\Module\I18n\Factory;
+use Magento\Setup\Module\I18n\Locale;
+use Magento\Setup\Module\I18n\Pack\WriterInterface;
 
 /**
  * Abstract pack writer
@@ -19,21 +19,21 @@ abstract class AbstractFile implements WriterInterface
     /**
      * Context
      *
-     * @var \Magento\Tools\I18n\Context
+     * @var \Magento\Setup\Module\I18n\Context
      */
     protected $_context;
 
     /**
      * Dictionary loader. This object is need for read dictionary for merge mode
      *
-     * @var \Magento\Tools\I18n\Dictionary\Loader\FileInterface
+     * @var \Magento\Setup\Module\I18n\Dictionary\Loader\FileInterface
      */
     protected $_dictionaryLoader;
 
     /**
      * Domain abstract factory
      *
-     * @var \Magento\Tools\I18n\Factory
+     * @var \Magento\Setup\Module\I18n\Factory
      */
     protected $_factory;
 
@@ -47,7 +47,7 @@ abstract class AbstractFile implements WriterInterface
     /**
      * Locale
      *
-     * @var \Magento\Tools\I18n\Locale
+     * @var \Magento\Setup\Module\I18n\Locale
      */
     protected $_locale;
 
@@ -112,7 +112,7 @@ abstract class AbstractFile implements WriterInterface
                 throw new \RuntimeException(
                     sprintf('Missed context in row #%d.', $key + 1)
                     . "\n"
-                    . 'Each row has to consist of 3 columns: original phrase, translation, context'
+                    . 'Each row has to consist of 4 columns: original phrase, translation, context type, context value'
                 );
             }
             foreach ($phrase->getContextValue() as $context) {
diff --git a/dev/tools/Magento/Tools/I18n/Pack/Writer/File/Csv.php b/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/Csv.php
similarity index 87%
rename from dev/tools/Magento/Tools/I18n/Pack/Writer/File/Csv.php
rename to setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/Csv.php
index 7889cb8eefc96348015a99e07417e1eab417d4e9..2e799f09b25c5c258f3513e8f39ef1053d7ddcd2 100644
--- a/dev/tools/Magento/Tools/I18n/Pack/Writer/File/Csv.php
+++ b/setup/src/Magento/Setup/Module/I18n/Pack/Writer/File/Csv.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Pack\Writer\File;
+namespace Magento\Setup\Module\I18n\Pack\Writer\File;
 
 /**
  * Pack writer csv
@@ -25,7 +25,7 @@ class Csv extends AbstractFile
         }
 
         $writer = $this->_factory->createDictionaryWriter($file);
-        /** @var \Magento\Tools\I18n\Dictionary\Phrase $phrase */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Phrase $phrase */
         foreach ($phrases as $phrase) {
             $phrase->setContextType(null);
             $phrase->setContextValue(null);
@@ -52,7 +52,7 @@ class Csv extends AbstractFile
         foreach ($dictionary->getPhrases() as $phrase) {
             $merged[$phrase->getPhrase()] = $phrase;
         }
-        /** @var \Magento\Tools\I18n\Dictionary\Phrase $phrase */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Phrase $phrase */
         foreach ($phrases as $phrase) {
             $merged[$phrase->getPhrase()] = $phrase;
         }
diff --git a/dev/tools/Magento/Tools/I18n/Pack/WriterInterface.php b/setup/src/Magento/Setup/Module/I18n/Pack/WriterInterface.php
similarity index 70%
rename from dev/tools/Magento/Tools/I18n/Pack/WriterInterface.php
rename to setup/src/Magento/Setup/Module/I18n/Pack/WriterInterface.php
index eda2715b1f0df3a67a7d3962958751ad17d92400..19159add87aeca0b17f2207ad2b47079faa733fa 100644
--- a/dev/tools/Magento/Tools/I18n/Pack/WriterInterface.php
+++ b/setup/src/Magento/Setup/Module/I18n/Pack/WriterInterface.php
@@ -3,10 +3,10 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Pack;
+namespace Magento\Setup\Module\I18n\Pack;
 
-use Magento\Tools\I18n\Dictionary;
-use Magento\Tools\I18n\Locale;
+use Magento\Setup\Module\I18n\Dictionary;
+use Magento\Setup\Module\I18n\Locale;
 
 /**
  * Pack writer interface
@@ -25,9 +25,9 @@ interface WriterInterface
     /**
      * Write dictionary data to language pack
      *
-     * @param \Magento\Tools\I18n\Dictionary $dictionary
+     * @param \Magento\Setup\Module\I18n\Dictionary $dictionary
      * @param string $packPath
-     * @param \Magento\Tools\I18n\Locale $locale
+     * @param \Magento\Setup\Module\I18n\Locale $locale
      * @param string $mode One of const of WriterInterface::MODE_
      * @return void
      */
diff --git a/dev/tools/Magento/Tools/I18n/Parser/AbstractParser.php b/setup/src/Magento/Setup/Module/I18n/Parser/AbstractParser.php
similarity index 92%
rename from dev/tools/Magento/Tools/I18n/Parser/AbstractParser.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/AbstractParser.php
index 9ee0c24ac2787ce6c9a47ccd7cd8184221318f29..3c38c17e1656a464058110a4bec513c067562a89 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/AbstractParser.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/AbstractParser.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser;
+namespace Magento\Setup\Module\I18n\Parser;
 
-use Magento\Tools\I18n;
+use Magento\Setup\Module\I18n;
 
 /**
  * Abstract parser
@@ -15,21 +15,21 @@ abstract class AbstractParser implements I18n\ParserInterface
     /**
      * Files collector
      *
-     * @var \Magento\Tools\I18n\FilesCollector
+     * @var \Magento\Setup\Module\I18n\FilesCollector
      */
     protected $_filesCollector = [];
 
     /**
      * Domain abstract factory
      *
-     * @var \Magento\Tools\I18n\Factory
+     * @var \Magento\Setup\Module\I18n\Factory
      */
     protected $_factory;
 
     /**
      * Adapters
      *
-     * @var \Magento\Tools\I18n\Parser\AdapterInterface[]
+     * @var \Magento\Setup\Module\I18n\Parser\AdapterInterface[]
      */
     protected $_adapters = [];
 
diff --git a/dev/tools/Magento/Tools/I18n/Parser/Adapter/AbstractAdapter.php b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/AbstractAdapter.php
similarity index 94%
rename from dev/tools/Magento/Tools/I18n/Parser/Adapter/AbstractAdapter.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/Adapter/AbstractAdapter.php
index 1b10e7b06282359b54c88ff274f5a14ca60f46db..3faf4f513bcb2124ac139d46b415c7d87fedd001 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/Adapter/AbstractAdapter.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/AbstractAdapter.php
@@ -3,10 +3,10 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser\Adapter;
+namespace Magento\Setup\Module\I18n\Parser\Adapter;
 
-use Magento\Tools\I18n\Dictionary\Phrase;
-use Magento\Tools\I18n\Parser\AdapterInterface;
+use Magento\Setup\Module\I18n\Dictionary\Phrase;
+use Magento\Setup\Module\I18n\Parser\AdapterInterface;
 
 /**
  * Abstract parser adapter
diff --git a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Js.php b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Js.php
similarity index 94%
rename from dev/tools/Magento/Tools/I18n/Parser/Adapter/Js.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Js.php
index 5db512b0d1dc914cde9ec0308b1b811571b98ddc..98b45bf38541f952ccfd5bd9a37d7aa638e9ccd8 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Js.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Js.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser\Adapter;
+namespace Magento\Setup\Module\I18n\Parser\Adapter;
 
 /**
  * Js parser adapter
diff --git a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Php.php b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php.php
similarity index 70%
rename from dev/tools/Magento/Tools/I18n/Parser/Adapter/Php.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php.php
index fa9af6e339496c263464bff74663be2050907aa5..7164a871b85834c83be44c63383ce85e273128b0 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Php.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser\Adapter;
+namespace Magento\Setup\Module\I18n\Parser\Adapter;
 
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector;
+use Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector;
 
 /**
  * Php parser adapter
@@ -15,14 +15,14 @@ class Php extends AbstractAdapter
     /**
      * Phrase collector
      *
-     * @var \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
+     * @var \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
      */
     protected $_phraseCollector;
 
     /**
      * Adapter construct
      *
-     * @param \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector $phraseCollector
+     * @param \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector $phraseCollector
      */
     public function __construct(PhraseCollector $phraseCollector)
     {
diff --git a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer.php b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer.php
similarity index 93%
rename from dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer.php
index 84c0f1bde5ffea3bb8ccb7d0dfa82fb52cc7f0d3..a59845bdd8f9a603c56b82a8d066945a780d71fa 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser\Adapter\Php;
+namespace Magento\Setup\Module\I18n\Parser\Adapter\Php;
 
 /**
  * Tokenizer
@@ -158,7 +158,7 @@ class Tokenizer
     /**
      * Get current token
      *
-     * @return \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token
+     * @return \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token
      */
     public function getCurrentToken()
     {
@@ -168,7 +168,7 @@ class Tokenizer
     /**
      * Get next token
      *
-     * @return bool|\Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token
+     * @return bool|\Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token
      */
     public function getNextToken()
     {
@@ -178,7 +178,7 @@ class Tokenizer
     /**
      * Get next token skipping all whitespaces
      *
-     * @return \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token|false
+     * @return \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token|false
      */
     public function getNextRealToken()
     {
@@ -202,7 +202,7 @@ class Tokenizer
      * Create token from array|string
      *
      * @param array|string $tokenData
-     * @return \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token
+     * @return \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token
      */
     private function _createToken($tokenData)
     {
diff --git a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollector.php b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollector.php
similarity index 93%
rename from dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollector.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollector.php
index 297177e1071c7a2eea19118382e9ffef9a5ec97a..ee7ecd15e0c5fdc8ed9f24c2eb4a3092dffe0371 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollector.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollector.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer;
+namespace Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer;
 
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer;
+use Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer;
 
 /**
  * PhraseCollector
@@ -13,7 +13,7 @@ use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer;
 class PhraseCollector
 {
     /**
-     * @var \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer
+     * @var \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer
      */
     protected $_tokenizer;
 
@@ -137,7 +137,7 @@ class PhraseCollector
     {
         $phrase = [];
         if ($phraseTokens) {
-            /** @var \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token $phraseToken */
+            /** @var \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token $phraseToken */
             foreach ($phraseTokens as $phraseToken) {
                 if ($phraseToken->isConstantEncapsedString()) {
                     $phrase[] = $phraseToken->getValue();
diff --git a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer/Token.php b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/Token.php
similarity index 97%
rename from dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer/Token.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/Token.php
index 3aa9091008b5f5c163b2f2ab09e4cb4cb2c5eb40..a36b8b1e885307150ba4ef9d95ccd8381bfd2137 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer/Token.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/Token.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer;
+namespace Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer;
 
 /**
  * Token
diff --git a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollector.php b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollector.php
similarity index 83%
rename from dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollector.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollector.php
index dffc693d299dc6af8304e3c230e7087aa87741b9..6bd31c61b83f500c37dc48e50f474832fe2684d5 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollector.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Php/Tokenizer/Translate/MethodCollector.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Translate;
+namespace Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Translate;
 
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector;
+use Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector;
 
 /**
  * MethodCollector
@@ -33,7 +33,7 @@ class MethodCollector extends PhraseCollector
     /**
      * Check if token is translated function
      *
-     * @param \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token $token
+     * @param \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token $token
      * @return bool
      */
     protected function _isTranslateFunction($token)
diff --git a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Xml.php b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Xml.php
similarity index 96%
rename from dev/tools/Magento/Tools/I18n/Parser/Adapter/Xml.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Xml.php
index df7d5f5ba57d901fc4c8b25d8585717355ed8e28..dd20f551d553560fdbd42dd77b870926970c98b6 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/Adapter/Xml.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/Adapter/Xml.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser\Adapter;
+namespace Magento\Setup\Module\I18n\Parser\Adapter;
 
 /**
  * Xml parser adapter
diff --git a/dev/tools/Magento/Tools/I18n/Parser/AdapterInterface.php b/setup/src/Magento/Setup/Module/I18n/Parser/AdapterInterface.php
similarity index 89%
rename from dev/tools/Magento/Tools/I18n/Parser/AdapterInterface.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/AdapterInterface.php
index 30b31f2805da70bc55a3b6267980cabf6b629ba1..5621552a72090afbd636127f1e7843ce0a81c254 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/AdapterInterface.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/AdapterInterface.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser;
+namespace Magento\Setup\Module\I18n\Parser;
 
 /**
  * Adapter Interface
diff --git a/dev/tools/Magento/Tools/I18n/Parser/Contextual.php b/setup/src/Magento/Setup/Module/I18n/Parser/Contextual.php
similarity index 91%
rename from dev/tools/Magento/Tools/I18n/Parser/Contextual.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/Contextual.php
index 8d6987f146541be38e7cc50845d66c28b9025c6d..1642f3b1683c04a3a50586226a5f873c27c43d02 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/Contextual.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/Contextual.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser;
+namespace Magento\Setup\Module\I18n\Parser;
 
-use Magento\Tools\I18n;
+use Magento\Setup\Module\I18n;
 
 /**
  * Contextual Parser
@@ -15,7 +15,7 @@ class Contextual extends AbstractParser
     /**
      * Context
      *
-     * @var \Magento\Tools\I18n\Context
+     * @var \Magento\Setup\Module\I18n\Context
      */
     protected $_context;
 
@@ -66,7 +66,7 @@ class Contextual extends AbstractParser
         $phraseKey = $contextType . $phraseData['phrase'];
 
         if (isset($this->_phrases[$phraseKey])) {
-            /** @var \Magento\Tools\I18n\Dictionary\Phrase $phrase */
+            /** @var \Magento\Setup\Module\I18n\Dictionary\Phrase $phrase */
             $phrase = $this->_phrases[$phraseKey];
             $phrase->addContextValue($contextValue);
         } else {
diff --git a/dev/tools/Magento/Tools/I18n/Parser/Parser.php b/setup/src/Magento/Setup/Module/I18n/Parser/Parser.php
similarity index 95%
rename from dev/tools/Magento/Tools/I18n/Parser/Parser.php
rename to setup/src/Magento/Setup/Module/I18n/Parser/Parser.php
index e125c2734b95d59320fe11d21c7c5edca369acab..5766154cd9196908d6ec6430a8b9a0a69a206cfc 100644
--- a/dev/tools/Magento/Tools/I18n/Parser/Parser.php
+++ b/setup/src/Magento/Setup/Module/I18n/Parser/Parser.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Parser;
+namespace Magento\Setup\Module\I18n\Parser;
 
 /**
  * Parser
diff --git a/dev/tools/Magento/Tools/I18n/ParserInterface.php b/setup/src/Magento/Setup/Module/I18n/ParserInterface.php
similarity index 92%
rename from dev/tools/Magento/Tools/I18n/ParserInterface.php
rename to setup/src/Magento/Setup/Module/I18n/ParserInterface.php
index 038cfc22475db1a113ffa4570f339b061a9635b9..026542170d9f4a65c82a8faa09cc650030adb9b2 100644
--- a/dev/tools/Magento/Tools/I18n/ParserInterface.php
+++ b/setup/src/Magento/Setup/Module/I18n/ParserInterface.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n;
+namespace Magento\Setup\Module\I18n;
 
 /**
  * Parser Interface
diff --git a/dev/tools/Magento/Tools/I18n/ServiceLocator.php b/setup/src/Magento/Setup/Module/I18n/ServiceLocator.php
similarity index 83%
rename from dev/tools/Magento/Tools/I18n/ServiceLocator.php
rename to setup/src/Magento/Setup/Module/I18n/ServiceLocator.php
index 021493b0155b1c5802cf1878330998b6bc0ab8b6..cbbbc7fed9f974dec1be8506198ab52227684566 100644
--- a/dev/tools/Magento/Tools/I18n/ServiceLocator.php
+++ b/setup/src/Magento/Setup/Module/I18n/ServiceLocator.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n;
+namespace Magento\Setup\Module\I18n;
 
 
 /**
@@ -15,35 +15,35 @@ class ServiceLocator
     /**
      * Domain abstract factory
      *
-     * @var \Magento\Tools\I18n\Factory
+     * @var \Magento\Setup\Module\I18n\Factory
      */
     private static $_factory;
 
     /**
      * Context manager
      *
-     * @var \Magento\Tools\I18n\Factory
+     * @var \Magento\Setup\Module\I18n\Factory
      */
     private static $_context;
 
     /**
      * Dictionary generator
      *
-     * @var \Magento\Tools\I18n\Dictionary\Generator
+     * @var \Magento\Setup\Module\I18n\Dictionary\Generator
      */
     private static $_dictionaryGenerator;
 
     /**
      * Pack generator
      *
-     * @var \Magento\Tools\I18n\Pack\Generator
+     * @var \Magento\Setup\Module\I18n\Pack\Generator
      */
     private static $_packGenerator;
 
     /**
      * Get dictionary generator
      *
-     * @return \Magento\Tools\I18n\Dictionary\Generator
+     * @return \Magento\Setup\Module\I18n\Dictionary\Generator
      */
     public static function getDictionaryGenerator()
     {
@@ -77,7 +77,7 @@ class ServiceLocator
     /**
      * Get pack generator
      *
-     * @return \Magento\Tools\I18n\Pack\Generator
+     * @return \Magento\Setup\Module\I18n\Pack\Generator
      */
     public static function getPackGenerator()
     {
@@ -93,12 +93,12 @@ class ServiceLocator
     /**
      * Get factory
      *
-     * @return \Magento\Tools\I18n\Factory
+     * @return \Magento\Setup\Module\I18n\Factory
      */
     private static function _getFactory()
     {
         if (null === self::$_factory) {
-            self::$_factory = new \Magento\Tools\I18n\Factory();
+            self::$_factory = new \Magento\Setup\Module\I18n\Factory();
         }
         return self::$_factory;
     }
@@ -106,7 +106,7 @@ class ServiceLocator
     /**
      * Get context
      *
-     * @return \Magento\Tools\I18n\Context
+     * @return \Magento\Setup\Module\I18n\Context
      */
     private static function _getContext()
     {
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/DeployStaticContentCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/DeployStaticContentCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f8d24d51667c62a7d37b3bedce1bf53124617a0
--- /dev/null
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/DeployStaticContentCommandTest.php
@@ -0,0 +1,109 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Test\Unit\Console\Command;
+
+use Magento\Setup\Console\Command\DeployStaticContentCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class DeployStaticContentCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\DeploymentConfig|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $deploymentConfig;
+
+    /**
+     * @var \Magento\Setup\Model\ObjectManagerProvider|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManagerProvider;
+
+    /**
+     * @var \Magento\Setup\Model\Deployer|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $deployer;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManager;
+
+    /**
+     * @var \Magento\Framework\App\Utility\Files|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filesUtil;
+
+    /**
+     * @var DeployStaticContentCommand
+     */
+    private $command;
+
+    protected function setUp()
+    {
+        $this->objectManagerProvider = $this->getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false);
+        $this->objectManager = $this->getMockForAbstractClass('Magento\Framework\ObjectManagerInterface');
+        $this->deployer = $this->getMock('Magento\Setup\Model\Deployer', [], [], '', false);
+        $this->deploymentConfig = $this->getMock('Magento\Framework\App\DeploymentConfig', [], [], '', false);
+        $this->filesUtil = $this->getMock('Magento\Framework\App\Utility\Files', [], [], '', false);
+        $this->command = new DeployStaticContentCommand($this->objectManagerProvider, $this->deploymentConfig);
+    }
+
+    public function testExecute()
+    {
+        $omFactory = $this->getMock('Magento\Framework\App\ObjectManagerFactory', [], [], '', false);
+        $this->objectManagerProvider->expects($this->any())
+            ->method('get')
+            ->will($this->returnValue($this->objectManager));
+
+        $this->objectManagerProvider->expects($this->once())
+            ->method('getObjectManagerFactory')
+            ->with([])
+            ->willReturn($omFactory);
+
+        $this->deployer->expects($this->once())->method('deploy');
+
+        $this->objectManager->expects($this->at(0))
+            ->method('create')
+            ->willReturn($this->filesUtil);
+
+        $this->objectManager->expects($this->at(1))
+            ->method('create')
+            ->willReturn($this->deployer);
+
+        $this->deploymentConfig->expects($this->once())
+            ->method('isAvailable')
+            ->will($this->returnValue(true));
+        $tester = new CommandTester($this->command);
+        $tester->execute([]);
+    }
+
+    public function testExecuteNotInstalled()
+    {
+        $this->deploymentConfig->expects($this->once())
+            ->method('isAvailable')
+            ->will($this->returnValue(false));
+        $this->objectManagerProvider->expects($this->never())->method('get');
+        $tester = new CommandTester($this->command);
+        $tester->execute([]);
+        $this->assertStringMatchesFormat(
+            'You need to install the Magento application before running this utility.%w',
+            $tester->getDisplay()
+        );
+    }
+
+    /**
+     * @expectedException \InvalidArgumentException
+     * @expectedExceptionMessage ARG_IS_WRONG argument has invalid value format
+     */
+    public function testExecuteInvalidLanguageArgument()
+    {
+        $this->deploymentConfig->expects($this->once())
+            ->method('isAvailable')
+            ->will($this->returnValue(true));
+        $wrongParam = ['languages' => ['ARG_IS_WRONG']];
+        $commandTester = new CommandTester($this->command);
+        $commandTester->execute($wrongParam);
+    }
+}
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b2c5e9a65254d11e3eb2a18f778a9276c022aed1
--- /dev/null
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/DiCompileCommandTest.php
@@ -0,0 +1,85 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Setup\Test\Unit\Console\Command;
+
+use Magento\Setup\Console\Command\DiCompileCommand;
+use Symfony\Component\Console\Tester\CommandTester;
+
+class DiCompileCommandTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\App\DeploymentConfig|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $deploymentConfig;
+
+    /**
+     * @var \Magento\Setup\Module\Di\App\Task\Manager|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $manager;
+
+    /**
+     * @var \Magento\Framework\ObjectManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $objectManager;
+
+    /**
+     * @var DiCompileCommand
+     */
+    private $command;
+
+    public function setUp()
+    {
+        $this->deploymentConfig = $this->getMock('Magento\Framework\App\DeploymentConfig', [], [], '', false);
+        $objectManagerProvider = $this->getMock(
+            'Magento\Setup\Model\ObjectManagerProvider',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->objectManager = $this->getMockForAbstractClass(
+            'Magento\Framework\ObjectManagerInterface',
+            [],
+            '',
+            false
+        );
+        $objectManagerProvider->expects($this->once())->method('get')->willReturn($this->objectManager);
+        $this->manager = $this->getMock('Magento\Setup\Module\Di\App\Task\Manager', [], [], '', false);
+        $directoryList = $this->getMock('Magento\Framework\App\Filesystem\DirectoryList', [], [], '', false);
+        $directoryList->expects($this->exactly(3))->method('getPath');
+        $this->command = new DiCompileCommand(
+            $this->deploymentConfig,
+            $directoryList,
+            $this->manager,
+            $objectManagerProvider
+        );
+    }
+
+    public function testExecuteNotInstalled()
+    {
+        $this->deploymentConfig->expects($this->once())->method('isAvailable')->willReturn(false);
+        $tester = new CommandTester($this->command);
+        $tester->execute([]);
+        $this->assertEquals(
+            'You cannot run this command because the Magento application is not installed.' . PHP_EOL,
+            $tester->getDisplay()
+        );
+    }
+
+    public function testExecute()
+    {
+        $this->deploymentConfig->expects($this->once())->method('isAvailable')->willReturn(true);
+        $this->objectManager->expects($this->once())->method('configure');
+        $this->manager->expects($this->exactly(5))->method('addOperation');
+        $this->manager->expects($this->once())->method('process');
+        $tester = new CommandTester($this->command);
+        $tester->execute([]);
+        $this->assertEquals(
+            'Generated code and dependency injection configuration successfully.' . PHP_EOL,
+            $tester->getDisplay()
+        );
+    }
+}
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/CommandListTest.php b/setup/src/Magento/Setup/Test/Unit/Console/CommandListTest.php
index 39e78dc660683bd3b555ed6553dfc9e09f591c63..65d1fa6db2ad81617ea7952cf5eff63f678bd5c9 100644
--- a/setup/src/Magento/Setup/Test/Unit/Console/CommandListTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Console/CommandListTest.php
@@ -28,33 +28,8 @@ class CommandListTest extends \PHPUnit_Framework_TestCase
 
     public function testGetCommands()
     {
-        $commands = [
-            'Magento\Setup\Console\Command\AdminUserCreateCommand',
-            'Magento\Setup\Console\Command\ConfigSetCommand',
-            'Magento\Setup\Console\Command\DbDataUpgradeCommand',
-            'Magento\Setup\Console\Command\DbSchemaUpgradeCommand',
-            'Magento\Setup\Console\Command\DbStatusCommand',
-            'Magento\Setup\Console\Command\InfoCurrencyListCommand',
-            'Magento\Setup\Console\Command\InfoLanguageListCommand',
-            'Magento\Setup\Console\Command\InfoTimezoneListCommand',
-            'Magento\Setup\Console\Command\InstallCommand',
-            'Magento\Setup\Console\Command\InstallStoreConfigurationCommand',
-            'Magento\Setup\Console\Command\ModuleEnableCommand',
-            'Magento\Setup\Console\Command\ModuleDisableCommand',
-            'Magento\Setup\Console\Command\ModuleStatusCommand',
-            'Magento\Setup\Console\Command\MaintenanceAllowIpsCommand',
-            'Magento\Setup\Console\Command\MaintenanceDisableCommand',
-            'Magento\Setup\Console\Command\MaintenanceEnableCommand',
-            'Magento\Setup\Console\Command\MaintenanceStatusCommand',
-            'Magento\Setup\Console\Command\UpgradeCommand',
-            'Magento\Setup\Console\Command\UninstallCommand',
-        ];
-        $index = 0;
-        foreach ($commands as $command) {
-            $this->serviceManager->expects($this->at($index++))
-                ->method('create')
-                ->with($command);
-        }
+        $this->serviceManager->expects($this->atLeastOnce())
+            ->method('create');
 
         $this->commandList->getCommands();
     }
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php
index 553c5c8ed4c1ec544a824a240237a1b0eb505dca..e3e44ebd20a3b43114e32d7df801c2c86591bf02 100644
--- a/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Model/InstallerTest.php
@@ -234,12 +234,21 @@ class InstallerTest extends \PHPUnit_Framework_TestCase
         $cacheManager = $this->getMock('Magento\Framework\App\Cache\Manager', [], [], '', false);
         $cacheManager->expects($this->once())->method('getAvailableTypes')->willReturn(['foo', 'bar']);
         $cacheManager->expects($this->once())->method('setEnabled')->willReturn(['foo', 'bar']);
+        $appState = (new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this))->getObject(
+            'Magento\Framework\App\State'
+        );
         $this->objectManager->expects($this->any())
             ->method('create')
             ->will($this->returnValueMap([
                 ['Magento\Setup\Module\Setup', ['resource' => $resource], $setup],
                 ['Magento\Setup\Module\DataSetup', [], $dataSetup],
                 ['Magento\Framework\App\Cache\Manager', [], $cacheManager],
+                ['Magento\Framework\App\State', [], $appState],
+            ]));
+        $this->objectManager->expects($this->any())
+            ->method('get')
+            ->will($this->returnValueMap([
+                ['Magento\Framework\App\State', $appState],
             ]));
         $this->adminFactory->expects($this->once())->method('create')->willReturn(
             $this->getMock('Magento\Setup\Model\AdminAccount', [], [], '', false)
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/App/Task/AreaTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php
similarity index 81%
rename from dev/tools/Magento/Tools/Di/Test/Unit/App/Task/AreaTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php
index c55f63e8ab9cefa9dc2ed4d3d64bc812b8c11c4d..f4a83fd3a97acfdfe3f08be0ce55ce51b4bc13ac 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/App/Task/AreaTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/AreaTest.php
@@ -3,13 +3,11 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\App\Task;
+namespace Magento\Setup\Test\Unit\Module\Di\App\Task;
 
 use Magento\Framework\App;
-use Magento\Tools\Di\App\Task\Operation\Area;
-use Magento\Tools\Di\Code\Reader\ClassesScanner;
-use Magento\Tools\Di\Compiler\Config;
-use Magento\Tools\Di\Definition\Collection as DefinitionsCollection;
+use Magento\Setup\Module\Di\App\Task\Operation\Area;
+use Magento\Setup\Module\Di\Compiler\Config;
 
 class AreaTest extends \PHPUnit_Framework_TestCase
 {
@@ -19,7 +17,7 @@ class AreaTest extends \PHPUnit_Framework_TestCase
     private $areaListMock;
 
     /**
-     * @var \Magento\Tools\Di\Code\Reader\Decorator\Area | \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\Di\Code\Reader\Decorator\Area | \PHPUnit_Framework_MockObject_MockObject
      */
     private $areaInstancesNamesList;
 
@@ -34,7 +32,7 @@ class AreaTest extends \PHPUnit_Framework_TestCase
     private $configWriterMock;
 
     /**
-     * @var \Magento\Tools\Di\Compiler\Config\ModificationChain | \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\Di\Compiler\Config\ModificationChain | \PHPUnit_Framework_MockObject_MockObject
      */
     private $configChain;
 
@@ -43,16 +41,16 @@ class AreaTest extends \PHPUnit_Framework_TestCase
         $this->areaListMock = $this->getMockBuilder('Magento\Framework\App\AreaList')
             ->disableOriginalConstructor()
             ->getMock();
-        $this->areaInstancesNamesList = $this->getMockBuilder('\Magento\Tools\Di\Code\Reader\Decorator\Area')
+        $this->areaInstancesNamesList = $this->getMockBuilder('\Magento\Setup\Module\Di\Code\Reader\Decorator\Area')
             ->disableOriginalConstructor()
             ->getMock();
-        $this->configReaderMock = $this->getMockBuilder('Magento\Tools\Di\Compiler\Config\Reader')
+        $this->configReaderMock = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Config\Reader')
             ->disableOriginalConstructor()
             ->getMock();
-        $this->configWriterMock = $this->getMockBuilder('Magento\Tools\Di\Compiler\Config\WriterInterface')
+        $this->configWriterMock = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Config\WriterInterface')
             ->disableOriginalConstructor()
             ->getMock();
-        $this->configChain = $this->getMockBuilder('Magento\Tools\Di\Compiler\Config\ModificationChain')
+        $this->configChain = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Config\ModificationChain')
             ->disableOriginalConstructor()
             ->getMock();
     }
@@ -99,7 +97,7 @@ class AreaTest extends \PHPUnit_Framework_TestCase
         $this->configReaderMock->expects($this->once())
             ->method('generateCachePerScope')
             ->with(
-                $this->isInstanceOf('Magento\Tools\Di\Definition\Collection'),
+                $this->isInstanceOf('Magento\Setup\Module\Di\Definition\Collection'),
                 App\Area::AREA_GLOBAL
             )
             ->willReturn($generatedConfig);
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/App/Task/InterceptionCacheTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/InterceptionCacheTest.php
similarity index 89%
rename from dev/tools/Magento/Tools/Di/Test/Unit/App/Task/InterceptionCacheTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/InterceptionCacheTest.php
index 9d86c20b3b38195b16344fe00cec12b97d2c6ee8..a60932145180e39b0896a32146b9fbd62c1b6225 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/App/Task/InterceptionCacheTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/InterceptionCacheTest.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\App\Task;
+namespace Magento\Setup\Test\Unit\Module\Di\App\Task;
 
-use Magento\Tools\Di\App\Task\Operation\InterceptionCache;
+use Magento\Setup\Module\Di\App\Task\Operation\InterceptionCache;
 
 class InterceptionCacheTest extends \PHPUnit_Framework_TestCase
 {
@@ -15,7 +15,7 @@ class InterceptionCacheTest extends \PHPUnit_Framework_TestCase
     private $configMock;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Tools\Di\Code\Reader\Decorator\Interceptions
+     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Setup\Module\Di\Code\Reader\Decorator\Interceptions
      */
     private $interceptionsListMock;
 
@@ -26,7 +26,7 @@ class InterceptionCacheTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->getMock();
         $this->interceptionsListMock = $this->getMockBuilder(
-            'Magento\Tools\Di\Code\Reader\Decorator\Interceptions'
+            'Magento\Setup\Module\Di\Code\Reader\Decorator\Interceptions'
         )
             ->setMethods([])
             ->disableOriginalConstructor()
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/App/Task/OperationFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/OperationFactoryTest.php
similarity index 65%
rename from dev/tools/Magento/Tools/Di/Test/Unit/App/Task/OperationFactoryTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/OperationFactoryTest.php
index 0e9645a97822480eb1a9168f57b66257964a1793..9acc4b3cfdf35b66018b7edb0777b31031a56986 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/App/Task/OperationFactoryTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/OperationFactoryTest.php
@@ -6,10 +6,10 @@
 
 // @codingStandardsIgnoreFile
 
-namespace Magento\Tools\Di\Test\Unit\App\Task;
+namespace Magento\Setup\Test\Unit\Module\Di\App\Task;
 
-use Magento\Tools\Di\App\Task\OperationFactory;
-use Magento\Tools\Di\App\Task\OperationException;
+use Magento\Setup\Module\Di\App\Task\OperationFactory;
+use Magento\Setup\Module\Di\App\Task\OperationException;
 
 class OperationFactoryTest extends \PHPUnit_Framework_TestCase
 {
@@ -28,8 +28,10 @@ class OperationFactoryTest extends \PHPUnit_Framework_TestCase
         $this->objectManagerMock = $this->getMockBuilder('Magento\Framework\ObjectManagerInterface')
             ->setMethods([])
             ->getMock();
+        $objectManagerProviderMock = $this->getMock('Magento\Setup\Model\ObjectManagerProvider', [], [], '', false);
+        $objectManagerProviderMock->expects($this->once())->method('get')->willReturn($this->objectManagerMock);
         $this->factory = new OperationFactory(
-            $this->objectManagerMock
+            $objectManagerProviderMock
         );
     }
 
@@ -40,7 +42,7 @@ class OperationFactoryTest extends \PHPUnit_Framework_TestCase
      */
     public function testCreateSuccess($alias, $arguments, $instanceName)
     {
-        $operationInstance = $this->getMockBuilder('Magento\Tools\Di\App\Task\OperationInterface')
+        $operationInstance = $this->getMockBuilder('Magento\Setup\Module\Di\App\Task\OperationInterface')
             ->getMock();
 
         $this->objectManagerMock->expects($this->once())
@@ -55,7 +57,7 @@ class OperationFactoryTest extends \PHPUnit_Framework_TestCase
     {
         $notRegisteredOperation = 'coffee';
         $this->setExpectedException(
-            'Magento\Tools\Di\App\Task\OperationException',
+            'Magento\Setup\Module\Di\App\Task\OperationException',
             sprintf('Unrecognized operation "%s"', $notRegisteredOperation),
             OperationException::UNAVAILABLE_OPERATION
         );
@@ -68,9 +70,9 @@ class OperationFactoryTest extends \PHPUnit_Framework_TestCase
     public function aliasesDataProvider()
     {
         return  [
-            [OperationFactory::AREA_CONFIG_GENERATOR, [], 'Magento\Tools\Di\App\Task\Operation\Area'],
-            [OperationFactory::INTERCEPTION, null, 'Magento\Tools\Di\App\Task\Operation\Interception'],
-            [OperationFactory::INTERCEPTION_CACHE, 1, 'Magento\Tools\Di\App\Task\Operation\InterceptionCache'],
+            [OperationFactory::AREA_CONFIG_GENERATOR, [], 'Magento\Setup\Module\Di\App\Task\Operation\Area'],
+            [OperationFactory::INTERCEPTION, null, 'Magento\Setup\Module\Di\App\Task\Operation\Interception'],
+            [OperationFactory::INTERCEPTION_CACHE, 1, 'Magento\Setup\Module\Di\App\Task\Operation\InterceptionCache'],
         ];
     }
 
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/App/Task/RepositoryGeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/RepositoryGeneratorTest.php
similarity index 88%
rename from dev/tools/Magento/Tools/Di/Test/Unit/App/Task/RepositoryGeneratorTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/RepositoryGeneratorTest.php
index 37ec47ce228e737092040de57d9575972d2b16c2..0b2b5310c67b2e57fd168ec618b3626397cce02e 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/App/Task/RepositoryGeneratorTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/App/Task/RepositoryGeneratorTest.php
@@ -4,11 +4,11 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Test\Unit\App\Task;
+namespace Magento\Setup\Test\Unit\Module\Di\App\Task;
 
-use Magento\Tools\Di\App\Task\Operation\RepositoryGenerator;
-use Magento\Tools\Di\Code\Scanner;
-use Magento\Tools\Di\Code\Reader\ClassesScanner;
+use Magento\Setup\Module\Di\App\Task\Operation\RepositoryGenerator;
+use Magento\Setup\Module\Di\Code\Scanner;
+use Magento\Setup\Module\Di\Code\Reader\ClassesScanner;
 
 class RepositoryGeneratorTest extends \PHPUnit_Framework_TestCase
 {
@@ -29,15 +29,15 @@ class RepositoryGeneratorTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->directoryScannerMock = $this->getMockBuilder('Magento\Tools\Di\Code\Scanner\DirectoryScanner')
+        $this->directoryScannerMock = $this->getMockBuilder('Magento\Setup\Module\Di\Code\Scanner\DirectoryScanner')
             ->setMethods([])
             ->disableOriginalConstructor()
             ->getMock();
-        $this->repositoryScannerMock = $this->getMockBuilder('Magento\Tools\Di\Code\Scanner\RepositoryScanner')
+        $this->repositoryScannerMock = $this->getMockBuilder('Magento\Setup\Module\Di\Code\Scanner\RepositoryScanner')
             ->setMethods([])
             ->disableOriginalConstructor()
             ->getMock();
-        $this->classesScannerMock = $this->getMockBuilder('Magento\Tools\Di\Code\Reader\ClassesScanner')
+        $this->classesScannerMock = $this->getMockBuilder('Magento\Setup\Module\Di\Code\Reader\ClassesScanner')
             ->setMethods([])
             ->disableOriginalConstructor()
             ->getMock();
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Generator/InterceptionConfigurationBuilderTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Generator/InterceptionConfigurationBuilderTest.php
similarity index 87%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Generator/InterceptionConfigurationBuilderTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Generator/InterceptionConfigurationBuilderTest.php
index a8196935b92ad31806eb12602d83b48e92bbfae0..928afe76a0685ea8302b069ecbcc873782f51f99 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Generator/InterceptionConfigurationBuilderTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Generator/InterceptionConfigurationBuilderTest.php
@@ -3,14 +3,14 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Code\Generator;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Generator;
 
 use Magento\Framework\App\Interception\Cache\CompiledConfig;
 
 class InterceptionConfigurationBuilderTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Generator\InterceptionConfigurationBuilder
+     * @var \Magento\Setup\Module\Di\Code\Generator\InterceptionConfigurationBuilder
      */
     protected $model;
     /**
@@ -43,7 +43,7 @@ class InterceptionConfigurationBuilderTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->pluginList = $this->getMock(
-            'Magento\Tools\Di\Code\Generator\PluginList',
+            'Magento\Setup\Module\Di\Code\Generator\PluginList',
             ['setInterceptedClasses', 'setScopePriorityScheme', 'getPluginsConfig'],
             [],
             '',
@@ -57,8 +57,8 @@ class InterceptionConfigurationBuilderTest extends \PHPUnit_Framework_TestCase
             false
         );
 
-        $this->typeReader = $this->getMock('Magento\Tools\Di\Code\Reader\Type', ['isConcrete'], [], '', false);
-        $this->model = new \Magento\Tools\Di\Code\Generator\InterceptionConfigurationBuilder(
+        $this->typeReader = $this->getMock('Magento\Setup\Module\Di\Code\Reader\Type', ['isConcrete'], [], '', false);
+        $this->model = new \Magento\Setup\Module\Di\Code\Generator\InterceptionConfigurationBuilder(
             $this->interceptionConfig,
             $this->pluginList,
             $this->typeReader,
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/ClassReaderDecoratorTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassReaderDecoratorTest.php
similarity index 86%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/ClassReaderDecoratorTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassReaderDecoratorTest.php
index 2cbbbc173adb4b92b3cc6481b0c805b27f838e3c..9965a50ec82ca22cf0ad7dbcec589cd20a677378 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/ClassReaderDecoratorTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/ClassReaderDecoratorTest.php
@@ -3,14 +3,14 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Code\Reader;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader;
 
-use Magento\Tools\Di\Compiler\ConstructorArgument;
+use Magento\Setup\Module\Di\Compiler\ConstructorArgument;
 
 class ClassReaderDecoratorTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Reader\ClassReaderDecorator
+     * @var \Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator
      */
     private $model;
 
@@ -25,7 +25,7 @@ class ClassReaderDecoratorTest extends \PHPUnit_Framework_TestCase
             ->disableOriginalConstructor()
             ->setMethods([])
             ->getMock();
-        $this->model = new \Magento\Tools\Di\Code\Reader\ClassReaderDecorator($this->classReaderMock);
+        $this->model = new \Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator($this->classReaderMock);
     }
 
     /**
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/InstancesNamesList/AreaTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/AreaTest.php
similarity index 74%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/InstancesNamesList/AreaTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/AreaTest.php
index 8a74b8a4dbe7a6a8aa5ced6f3743e4db54e6d704..1ef35e58f13fdbf857f2d11975e2afd3662574cd 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/InstancesNamesList/AreaTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/AreaTest.php
@@ -3,24 +3,24 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Code\Reader\InstancesNamesList;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader\InstancesNamesList;
 
-use \Magento\Tools\Di\Code\Reader\Decorator\Area;
+use \Magento\Setup\Module\Di\Code\Reader\Decorator\Area;
 
 /**
  * Class AreaTest
  *
- * @package Magento\Tools\Di\Code\Reader\Decorator
+ * @package Magento\Setup\Module\Di\Code\Reader\Decorator
  */
 class AreaTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Reader\ClassesScanner | \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\Di\Code\Reader\ClassesScanner | \PHPUnit_Framework_MockObject_MockObject
      */
     private $classesScannerMock;
 
     /**
-     * @var \Magento\Tools\Di\Code\Reader\ClassReaderDecorator | \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator | \PHPUnit_Framework_MockObject_MockObject
      */
     private $classReaderDecoratorMock;
 
@@ -31,17 +31,19 @@ class AreaTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->classesScannerMock = $this->getMockBuilder('\Magento\Tools\Di\Code\Reader\ClassesScanner')
+        $this->classesScannerMock = $this->getMockBuilder('\Magento\Setup\Module\Di\Code\Reader\ClassesScanner')
             ->disableOriginalConstructor()
             ->setMethods(['getList'])
             ->getMock();
 
-        $this->classReaderDecoratorMock = $this->getMockBuilder('\Magento\Tools\Di\Code\Reader\ClassReaderDecorator')
+        $this->classReaderDecoratorMock = $this->getMockBuilder(
+            '\Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator'
+        )
             ->disableOriginalConstructor()
             ->setMethods(['getConstructor'])
             ->getMock();
 
-        $this->model = new \Magento\Tools\Di\Code\Reader\Decorator\Area(
+        $this->model = new \Magento\Setup\Module\Di\Code\Reader\Decorator\Area(
             $this->classesScannerMock,
             $this->classReaderDecoratorMock
         );
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/InstancesNamesList/DirectoryTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/DirectoryTest.php
similarity index 88%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/InstancesNamesList/DirectoryTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/DirectoryTest.php
index aaa02faa6f70e79bfa7793ebfc05903cf3cc2535..759f25d2a2499f62422aa8a381a8d9f2c9a97ad6 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/InstancesNamesList/DirectoryTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/DirectoryTest.php
@@ -3,19 +3,19 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Code\Reader\InstancesNamesList;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader\InstancesNamesList;
 
-use Magento\Tools\Di\Compiler\Log\Log;
+use Magento\Setup\Module\Di\Compiler\Log\Log;
 
 /**
  * Class DirectoryTest
  *
- * @package Magento\Tools\Di\Code\Reader\Decorator
+ * @package Magento\Setup\Module\Di\Code\Reader\Decorator
  */
 class DirectoryTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Reader\ClassesScanner | \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\Di\Code\Reader\ClassesScanner | \PHPUnit_Framework_MockObject_MockObject
      */
     private $classesScanner;
 
@@ -25,7 +25,7 @@ class DirectoryTest extends \PHPUnit_Framework_TestCase
     private $classReaderMock;
 
     /**
-     * @var \Magento\Tools\Di\Code\Reader\Decorator\Directory
+     * @var \Magento\Setup\Module\Di\Code\Reader\Decorator\Directory
      */
     private $model;
 
@@ -35,18 +35,18 @@ class DirectoryTest extends \PHPUnit_Framework_TestCase
     private $validatorMock;
 
     /**
-     * @var \Magento\Tools\Di\Compiler\Log\Log | \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\Di\Compiler\Log\Log | \PHPUnit_Framework_MockObject_MockObject
      */
     private $logMock;
 
     protected function setUp()
     {
-        $this->logMock = $this->getMockBuilder('Magento\Tools\Di\Compiler\Log\Log')
+        $this->logMock = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Log\Log')
             ->disableOriginalConstructor()
             ->setMethods(['add'])
             ->getMock();
 
-        $this->classesScanner = $this->getMockBuilder('\Magento\Tools\Di\Code\Reader\ClassesScanner')
+        $this->classesScanner = $this->getMockBuilder('\Magento\Setup\Module\Di\Code\Reader\ClassesScanner')
             ->disableOriginalConstructor()
             ->setMethods(['getList'])
             ->getMock();
@@ -61,7 +61,7 @@ class DirectoryTest extends \PHPUnit_Framework_TestCase
             ->setMethods(['validate'])
             ->getMock();
 
-        $this->model = new \Magento\Tools\Di\Code\Reader\Decorator\Directory(
+        $this->model = new \Magento\Setup\Module\Di\Code\Reader\Decorator\Directory(
             $this->logMock,
             $this->classReaderMock,
             $this->classesScanner,
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/InstancesNamesList/InterceptionsTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/InterceptionsTest.php
similarity index 86%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/InstancesNamesList/InterceptionsTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/InterceptionsTest.php
index 238274ff5f804db60ec726ede11fdba3b0c23936..b50cc6e71b012cdf2c1db79796903afe161ba94c 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Reader/InstancesNamesList/InterceptionsTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Reader/InstancesNamesList/InterceptionsTest.php
@@ -3,19 +3,19 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Code\Reader\InstancesNamesList;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Reader\InstancesNamesList;
 
-use Magento\Tools\Di\Compiler\Log\Log;
+use Magento\Setup\Module\Di\Compiler\Log\Log;
 
 /**
  * Class InterceptionsTest
  *
- * @package Magento\Tools\Di\Code\Reader\Decorator
+ * @package Magento\Setup\Module\Di\Code\Reader\Decorator
  */
 class InterceptionsTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Reader\ClassesScanner | \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\Di\Code\Reader\ClassesScanner | \PHPUnit_Framework_MockObject_MockObject
      */
     private $classesScanner;
 
@@ -25,7 +25,7 @@ class InterceptionsTest extends \PHPUnit_Framework_TestCase
     private $classReaderMock;
 
     /**
-     * @var \Magento\Tools\Di\Code\Reader\Decorator\Directory
+     * @var \Magento\Setup\Module\Di\Code\Reader\Decorator\Directory
      */
     private $model;
 
@@ -35,18 +35,18 @@ class InterceptionsTest extends \PHPUnit_Framework_TestCase
     private $validatorMock;
 
     /**
-     * @var \Magento\Tools\Di\Compiler\Log\Log | \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\Di\Compiler\Log\Log | \PHPUnit_Framework_MockObject_MockObject
      */
     private $logMock;
 
     protected function setUp()
     {
-        $this->logMock = $this->getMockBuilder('Magento\Tools\Di\Compiler\Log\Log')
+        $this->logMock = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Log\Log')
             ->disableOriginalConstructor()
             ->setMethods(['add', 'report'])
             ->getMock();
 
-        $this->classesScanner = $this->getMockBuilder('\Magento\Tools\Di\Code\Reader\ClassesScanner')
+        $this->classesScanner = $this->getMockBuilder('\Magento\Setup\Module\Di\Code\Reader\ClassesScanner')
             ->disableOriginalConstructor()
             ->setMethods(['getList'])
             ->getMock();
@@ -61,7 +61,7 @@ class InterceptionsTest extends \PHPUnit_Framework_TestCase
             ->setMethods(['validate', 'add'])
             ->getMock();
 
-        $this->model = new \Magento\Tools\Di\Code\Reader\Decorator\Interceptions(
+        $this->model = new \Magento\Setup\Module\Di\Code\Reader\Decorator\Interceptions(
             $this->classesScanner,
             $this->classReaderMock,
             $this->validatorMock,
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/ArrayScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/ArrayScannerTest.php
similarity index 76%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/ArrayScannerTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/ArrayScannerTest.php
index 9ecc4d54674817e047eaa7b738324890587422c6..b8891faf39af49dff6c725517556746baa8b4d04 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/ArrayScannerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/ArrayScannerTest.php
@@ -3,12 +3,12 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Code\Scanner;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
 
 class ArrayScannerTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Scanner\ArrayScanner
+     * @var \Magento\Setup\Module\Di\Code\Scanner\ArrayScanner
      */
     protected $_model;
 
@@ -19,7 +19,7 @@ class ArrayScannerTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->_model = new \Magento\Tools\Di\Code\Scanner\ArrayScanner();
+        $this->_model = new \Magento\Setup\Module\Di\Code\Scanner\ArrayScanner();
         $this->_testDir = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files');
     }
 
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/CompositeScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/CompositeScannerTest.php
similarity index 77%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/CompositeScannerTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/CompositeScannerTest.php
index 6d8c24373d5755870a6bf5b64caf5f1da08d64cd..e681c6d55d0864138f0ab41409deb07b6257a8b6 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/CompositeScannerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/CompositeScannerTest.php
@@ -3,18 +3,18 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Code\Scanner;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
 
 class CompositeScannerTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Scanner\CompositeScanner
+     * @var \Magento\Setup\Module\Di\Code\Scanner\CompositeScanner
      */
     protected $_model;
 
     protected function setUp()
     {
-        $this->_model = new \Magento\Tools\Di\Code\Scanner\CompositeScanner();
+        $this->_model = new \Magento\Setup\Module\Di\Code\Scanner\CompositeScanner();
     }
 
     public function testScan()
@@ -23,8 +23,8 @@ class CompositeScannerTest extends \PHPUnit_Framework_TestCase
         $configFiles = ['one/file/config', 'two/file/config'];
         $files = ['php' => $phpFiles, 'config' => $configFiles];
 
-        $scannerPhp = $this->getMock('Magento\Tools\Di\Code\Scanner\ScannerInterface');
-        $scannerXml = $this->getMock('Magento\Tools\Di\Code\Scanner\ScannerInterface');
+        $scannerPhp = $this->getMock('Magento\Setup\Module\Di\Code\Scanner\ScannerInterface');
+        $scannerXml = $this->getMock('Magento\Setup\Module\Di\Code\Scanner\ScannerInterface');
 
         $scannerPhpExpected = ['Model_OneProxy', 'Model_TwoFactory'];
         $scannerXmlExpected = ['Model_OneProxy', 'Model_ThreeFactory'];
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/DirectoryScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/DirectoryScannerTest.php
similarity index 91%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/DirectoryScannerTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/DirectoryScannerTest.php
index 86c924b1f325a21b6c032f4b250217e1511e3af2..b44d3243065b6d44bbe8b2930f07c9a7740d9c5b 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/DirectoryScannerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/DirectoryScannerTest.php
@@ -3,12 +3,12 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Code\Scanner;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
 
 class DirectoryScannerTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Scanner\DirectoryScanner
+     * @var \Magento\Setup\Module\Di\Code\Scanner\DirectoryScanner
      */
     protected $_model;
 
@@ -19,7 +19,7 @@ class DirectoryScannerTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->_model = new \Magento\Tools\Di\Code\Scanner\DirectoryScanner();
+        $this->_model = new \Magento\Setup\Module\Di\Code\Scanner\DirectoryScanner();
         $this->_testDir = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files');
     }
 
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/PhpScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/PhpScannerTest.php
similarity index 83%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/PhpScannerTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/PhpScannerTest.php
index 6c148c6aba3bab32643523ce4fbb5d33634c4ae5..6403592e0aaf10104226b39e593eede5e1090964 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/PhpScannerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/PhpScannerTest.php
@@ -3,14 +3,14 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Code\Scanner;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
 
 require_once __DIR__ . '/../../_files/app/code/Magento/SomeModule/Helper/Test.php';
 require_once __DIR__ . '/../../_files/app/code/Magento/SomeModule/ElementFactory.php';
 class PhpScannerTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Scanner\PhpScanner
+     * @var \Magento\Setup\Module\Di\Code\Scanner\PhpScanner
      */
     protected $_model;
 
@@ -31,8 +31,8 @@ class PhpScannerTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->_model = new \Magento\Tools\Di\Code\Scanner\PhpScanner(
-            $this->_logMock = $this->getMock('\Magento\Tools\Di\Compiler\Log\Log', [], [], '', false)
+        $this->_model = new \Magento\Setup\Module\Di\Code\Scanner\PhpScanner(
+            $this->_logMock = $this->getMock('\Magento\Setup\Module\Di\Compiler\Log\Log', [], [], '', false)
         );
         $this->_testDir = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files');
         $this->_testFiles = [$this->_testDir . '/app/code/Magento/SomeModule/Helper/Test.php'];
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/PluginScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/PluginScannerTest.php
similarity index 85%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/PluginScannerTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/PluginScannerTest.php
index adc1ebf2eaa69c83ebad7a3bba9926d09141ac49..1ac34de3b4296e4ef04dc875ce6a23c0ce3cfac5 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/PluginScannerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/PluginScannerTest.php
@@ -6,13 +6,13 @@
 
 // @codingStandardsIgnoreFile
 
-namespace Magento\Tools\Di\Test\Unit\Code\Scanner;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
 
 class PluginScannerTest extends \PHPUnit_Framework_TestCase
 {
     protected function setUp()
     {
-        $this->_model = new \Magento\Tools\Di\Code\Scanner\PluginScanner();
+        $this->_model = new \Magento\Setup\Module\Di\Code\Scanner\PluginScanner();
         $this->_testDir = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files');
         $this->_testFiles = [
             $this->_testDir . '/app/code/Magento/SomeModule/etc/di.xml',
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/XmlInterceptorScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/XmlInterceptorScannerTest.php
similarity index 81%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/XmlInterceptorScannerTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/XmlInterceptorScannerTest.php
index 70556e0f9e7a5dcd7f1a9fa6e34e6a287e0261da..7ac2c227a243ca07bc72274604595f0cca0fe1f7 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/XmlInterceptorScannerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/XmlInterceptorScannerTest.php
@@ -3,12 +3,12 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Code\Scanner;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
 
 class XmlInterceptorScannerTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Scanner\XmlInterceptorScanner
+     * @var \Magento\Setup\Module\Di\Code\Scanner\XmlInterceptorScanner
      */
     protected $_model;
 
@@ -24,7 +24,7 @@ class XmlInterceptorScannerTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->_model = new \Magento\Tools\Di\Code\Scanner\XmlInterceptorScanner();
+        $this->_model = new \Magento\Setup\Module\Di\Code\Scanner\XmlInterceptorScanner();
         $this->_testDir = str_replace('\\', '/', realpath(__DIR__ . '/../../') . '/_files');
         $this->_testFiles = [
             $this->_testDir . '/app/code/Magento/SomeModule/etc/di.xml',
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/XmlScannerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/XmlScannerTest.php
similarity index 85%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/XmlScannerTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/XmlScannerTest.php
index b1cd9b3dac280b565d3d152a5c49c2d9b9da1688..71b447e1c644e7e9745ef66d3a51c269b54668d3 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Code/Scanner/XmlScannerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Code/Scanner/XmlScannerTest.php
@@ -6,12 +6,12 @@
 
 // @codingStandardsIgnoreFile
 
-namespace Magento\Tools\Di\Test\Unit\Code\Scanner;
+namespace Magento\Setup\Test\Unit\Module\Di\Code\Scanner;
 
 class XmlScannerTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Code\Scanner\XmlScanner
+     * @var \Magento\Setup\Module\Di\Code\Scanner\XmlScanner
      */
     protected $_model;
 
@@ -27,8 +27,8 @@ class XmlScannerTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->_model = new \Magento\Tools\Di\Code\Scanner\XmlScanner(
-            $this->_logMock = $this->getMock('\Magento\Tools\Di\Compiler\Log\Log', [], [], '', false)
+        $this->_model = new \Magento\Setup\Module\Di\Code\Scanner\XmlScanner(
+            $this->_logMock = $this->getMock('\Magento\Setup\Module\Di\Compiler\Log\Log', [], [], '', false)
         );
         $testDir = __DIR__ . '/../../' . '/_files';
         $this->_testFiles = [
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/ArgumentsResolverTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ArgumentsResolverTest.php
similarity index 96%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Compiler/ArgumentsResolverTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ArgumentsResolverTest.php
index 128ef2adab42fe267cb82a97258b2c8beb09db42..b0924f54d382aed67b96bd0aa3339344282363bb 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/ArgumentsResolverTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ArgumentsResolverTest.php
@@ -4,14 +4,14 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Test\Unit\Compiler;
+namespace Magento\Setup\Test\Unit\Module\Di\Compiler;
 
-use Magento\Tools\Di\Compiler\ConstructorArgument;
+use Magento\Setup\Module\Di\Compiler\ConstructorArgument;
 
 class ArgumentsResolverTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Compiler\ArgumentsResolver
+     * @var \Magento\Setup\Module\Di\Compiler\ArgumentsResolver
      */
     protected $model;
 
@@ -29,7 +29,7 @@ class ArgumentsResolverTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $this->model = new \Magento\Tools\Di\Compiler\ArgumentsResolver($this->diContainerConfig);
+        $this->model = new \Magento\Setup\Module\Di\Compiler\ArgumentsResolver($this->diContainerConfig);
     }
 
     public function testGetResolvedArgumentsConstructorFormat()
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/ArgumentsSerializationTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/ArgumentsSerializationTest.php
similarity index 86%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/ArgumentsSerializationTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/ArgumentsSerializationTest.php
index 390c0854f7ef06205109b41905d8b87b78ad908e..01018b451e36d73943d90bf1a517cdc7353bbab9 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/ArgumentsSerializationTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/ArgumentsSerializationTest.php
@@ -4,9 +4,9 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Test\Unit\Compiler\Config\Chain;
+namespace Magento\Setup\Test\Unit\Module\Di\Compiler\Config\Chain;
 
-use \Magento\Tools\Di\Compiler\Config\Chain\ArgumentsSerialization;
+use \Magento\Setup\Module\Di\Compiler\Config\Chain\ArgumentsSerialization;
 
 class ArgumentsSerializationTest extends \PHPUnit_Framework_TestCase
 {
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/BackslashTrimTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/BackslashTrimTest.php
similarity index 94%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/BackslashTrimTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/BackslashTrimTest.php
index 14b95be2dee16a75d87214f8785a1ee1bc101d96..847a0f38627eb1494cb004f09b62c6cb773de0ef 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/BackslashTrimTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/BackslashTrimTest.php
@@ -4,9 +4,9 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Test\Unit\Compiler\Config\Chain;
+namespace Magento\Setup\Test\Unit\Module\Di\Compiler\Config\Chain;
 
-use \Magento\Tools\Di\Compiler\Config\Chain\BackslashTrim;
+use \Magento\Setup\Module\Di\Compiler\Config\Chain\BackslashTrim;
 
 class BackslashTrimTest extends \PHPUnit_Framework_TestCase
 {
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/InterceptorSubstitutionTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/InterceptorSubstitutionTest.php
similarity index 96%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/InterceptorSubstitutionTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/InterceptorSubstitutionTest.php
index d30437d6eef1b258edec843676aade8171fadd37..9376f8334a02dcb0455581513d591ff17a628c48 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/InterceptorSubstitutionTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/InterceptorSubstitutionTest.php
@@ -3,9 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Compiler\Config\Chain;
+namespace Magento\Setup\Test\Unit\Module\Di\Compiler\Config\Chain;
 
-use Magento\Tools\Di\Compiler\Config\Chain\InterceptorSubstitution;
+use Magento\Setup\Module\Di\Compiler\Config\Chain\InterceptorSubstitution;
 
 class InterceptorSubstitutionTest extends \PHPUnit_Framework_TestCase
 {
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/PreferencesResolvingTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/PreferencesResolvingTest.php
similarity index 97%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/PreferencesResolvingTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/PreferencesResolvingTest.php
index c4cdc2f672ec4e70a88709061589df6f0c457abc..c73ff5109d07ad3047aa7c01cd2cd3dc225a1504 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/Chain/PreferencesResolvingTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/Chain/PreferencesResolvingTest.php
@@ -4,9 +4,9 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Test\Unit\Compiler\Config\Chain;
+namespace Magento\Setup\Test\Unit\Module\Di\Compiler\Config\Chain;
 
-use Magento\Tools\Di\Compiler\Config\Chain\PreferencesResolving;
+use Magento\Setup\Module\Di\Compiler\Config\Chain\PreferencesResolving;
 
 class PreferencesResolvingTest extends \PHPUnit_Framework_TestCase
 {
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/ModificationChainTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/ModificationChainTest.php
similarity index 64%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/ModificationChainTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/ModificationChainTest.php
index 5cc1e2085feb262b5a2d798996be41d2ffbcf57f..42eebce83645b2e1d8cc2877f32e3479e2589e21 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/ModificationChainTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/ModificationChainTest.php
@@ -4,18 +4,18 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Tools\Di\Test\Unit\Compiler\Config;
+namespace Magento\Setup\Test\Unit\Module\Di\Compiler\Config;
 
-use \Magento\Tools\Di\Compiler\Config\ModificationChain;
+use \Magento\Setup\Module\Di\Compiler\Config\ModificationChain;
 
 class ModificationChainTest extends \PHPUnit_Framework_TestCase
 {
     public function testConstructor()
     {
         $modificationsList = [];
-        $modificationsList[] = $this->getMockBuilder('Magento\Tools\Di\Compiler\Config\ModificationInterface')
+        $modificationsList[] = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Config\ModificationInterface')
             ->getMock();
-        $modificationsList[] = $this->getMockBuilder('Magento\Tools\Di\Compiler\Config\ModificationInterface')
+        $modificationsList[] = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Config\ModificationInterface')
             ->getMock();
 
         new ModificationChain($modificationsList);
@@ -25,9 +25,9 @@ class ModificationChainTest extends \PHPUnit_Framework_TestCase
     {
         $this->setExpectedException('InvalidArgumentException', 'Wrong modifier provided');
         $modificationsList = [];
-        $modificationsList[] = $this->getMockBuilder('Magento\Tools\Di\Compiler\Config\ModificationInterface')
+        $modificationsList[] = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Config\ModificationInterface')
             ->getMock();
-        $modificationsList[] = $this->getMockBuilder('Magento\Tools\Di\Compiler\Config\ModificationInterface')
+        $modificationsList[] = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Config\ModificationInterface')
             ->getMock();
         $modificationsList[] = 'banana';
 
@@ -48,9 +48,9 @@ class ModificationChainTest extends \PHPUnit_Framework_TestCase
             'data' => [1, 2, 3, 1, 1]
         ];
 
-        $modifier1 = $this->getMockBuilder('Magento\Tools\Di\Compiler\Config\ModificationInterface')
+        $modifier1 = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Config\ModificationInterface')
             ->getMock();
-        $modifier2 = $this->getMockBuilder('Magento\Tools\Di\Compiler\Config\ModificationInterface')
+        $modifier2 = $this->getMockBuilder('Magento\Setup\Module\Di\Compiler\Config\ModificationInterface')
             ->getMock();
 
         $modificationsList = [$modifier1, $modifier2];
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/ReaderTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/ReaderTest.php
similarity index 90%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/ReaderTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/ReaderTest.php
index b0e35f72991d94e7b50b3242c2dcf467fb6fce59..ff05209a0769d3ac1662d642f0b7f7cf871b031e 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/Config/ReaderTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/Config/ReaderTest.php
@@ -3,15 +3,15 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Compiler\Config;
+namespace Magento\Setup\Test\Unit\Module\Di\Compiler\Config;
 
 use Magento\Framework\App\Area;
-use Magento\Tools\Di\Definition\Collection;
+use Magento\Setup\Module\Di\Definition\Collection;
 
 class ReaderTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Compiler\Config\Reader
+     * @var \Magento\Setup\Module\Di\Compiler\Config\Reader
      */
     protected $model;
 
@@ -50,26 +50,32 @@ class ReaderTest extends \PHPUnit_Framework_TestCase
         $this->diContainerConfig = $this->getMock('Magento\Framework\ObjectManager\ConfigInterface', [], [], '', false);
         $this->configLoader = $this->getMock('Magento\Framework\App\ObjectManager\ConfigLoader', [], [], '', false);
         $this->argumentsResolverFactory = $this->getMock(
-            'Magento\Tools\Di\Compiler\ArgumentsResolverFactory',
+            'Magento\Setup\Module\Di\Compiler\ArgumentsResolverFactory',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->argumentsResolver = $this->getMock(
+            'Magento\Setup\Module\Di\Compiler\ArgumentsResolver',
             [],
             [],
             '',
             false
         );
-        $this->argumentsResolver = $this->getMock('Magento\Tools\Di\Compiler\ArgumentsResolver', [], [], '', false);
         $this->argumentsResolverFactory->expects($this->any())
             ->method('create')
             ->willReturn($this->argumentsResolver);
         $this->classReaderDecorator = $this->getMock(
-            'Magento\Tools\Di\Code\Reader\ClassReaderDecorator',
+            'Magento\Setup\Module\Di\Code\Reader\ClassReaderDecorator',
             [],
             [],
             '',
             false
         );
-        $this->typeReader = $this->getMock('Magento\Tools\Di\Code\Reader\Type', [], [], '', false);
+        $this->typeReader = $this->getMock('Magento\Setup\Module\Di\Code\Reader\Type', [], [], '', false);
 
-        $this->model = new \Magento\Tools\Di\Compiler\Config\Reader(
+        $this->model = new \Magento\Setup\Module\Di\Compiler\Config\Reader(
             $this->diContainerConfig,
             $this->configLoader,
             $this->argumentsResolverFactory,
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/ConstructorArgumentTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ConstructorArgumentTest.php
similarity index 78%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Compiler/ConstructorArgumentTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ConstructorArgumentTest.php
index b8209a222ffcbcd757e1e880a034a17891c74ea1..4f574217b480c65f05f0089bbb6e8f4e2c325c1d 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Compiler/ConstructorArgumentTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ConstructorArgumentTest.php
@@ -3,14 +3,14 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\Di\Test\Unit\Compiler;
+namespace Magento\Setup\Test\Unit\Module\Di\Compiler;
 
 class ConstructorArgumentTest extends \PHPUnit_Framework_TestCase
 {
     public function testInterface()
     {
         $argument = ['configuration', 'array', true, null];
-        $model = new \Magento\Tools\Di\Compiler\ConstructorArgument($argument);
+        $model = new \Magento\Setup\Module\Di\Compiler\ConstructorArgument($argument);
         $this->assertEquals($argument[0], $model->getName());
         $this->assertEquals($argument[1], $model->getType());
         $this->assertTrue($model->isRequired());
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/Definition/CollectionTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Definition/CollectionTest.php
similarity index 87%
rename from dev/tools/Magento/Tools/Di/Test/Unit/Definition/CollectionTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/Definition/CollectionTest.php
index 96fd2a754093fa650ee6b41e7b7626a880e26dd9..87821d22b1a1b7537d4580b737612d5974551d24 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/Definition/CollectionTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Definition/CollectionTest.php
@@ -6,21 +6,21 @@
 
 // @codingStandardsIgnoreFile
 
-namespace Magento\Tools\Di\Test\Unit\Definition;
+namespace Magento\Setup\Test\Unit\Module\Di\Definition;
 
 /**
  * Class CollectionTest
- * @package Magento\Tools\Di\Definition
+ * @package Magento\Setup\Module\Di\Definition
  */
 class CollectionTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\Di\Definition\Collection
+     * @var \Magento\Setup\Module\Di\Definition\Collection
      */
     private $model;
 
     /**
-     * @var \Magento\Tools\Di\Definition\Collection | \PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\Di\Definition\Collection | \PHPUnit_Framework_MockObject_MockObject
      */
     private $collectionMock;
 
@@ -56,9 +56,9 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
-        $this->collectionMock = $this->getMockBuilder('\Magento\Tools\Di\Definition\Collection')
+        $this->collectionMock = $this->getMockBuilder('\Magento\Setup\Module\Di\Definition\Collection')
             ->setMethods([])->getMock();
-        $this->model = new \Magento\Tools\Di\Definition\Collection();
+        $this->model = new \Magento\Setup\Module\Di\Definition\Collection();
     }
 
     public function testAddDefinition()
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/additional.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/additional.php
similarity index 100%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/additional.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/additional.php
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/bootstrap.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/bootstrap.php
similarity index 100%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/bootstrap.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/bootstrap.php
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/Element.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/Element.php
similarity index 100%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/Element.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/Element.php
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/ElementFactory.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/ElementFactory.php
similarity index 100%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/ElementFactory.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/ElementFactory.php
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/Helper/Test.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/Helper/Test.php
similarity index 100%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/Helper/Test.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/Helper/Test.php
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/Model/Test.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/Model/Test.php
similarity index 100%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/Model/Test.php
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/Model/Test.php
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/etc/adminhtml/system.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/adminhtml/system.xml
similarity index 94%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/etc/adminhtml/system.xml
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/adminhtml/system.xml
index cec22db9c722334136b1018cc07df7a8e7a17f82..d5b7796b99db9e40bb52a40e4270b2a3b2628081 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/etc/adminhtml/system.xml
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/adminhtml/system.xml
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../../../../../../app/code/Magento/Config/etc/system_file.xsd">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../../../../../../../app/code/Magento/Config/etc/system_file.xsd">
     <system>
         <section id="advanced" translate="label" type="text" sortOrder="910" showInDefault="1" showInWebsite="1" showInStore="1">
             <label>Advanced</label>
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/etc/di.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/di.xml
similarity index 94%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/etc/di.xml
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/di.xml
index 5466e9a385bc24a8e1766bf54613aae8c10701c1..ec1a122e8f6cd08f459b64b651d49baf87a188c1 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/etc/di.xml
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/etc/di.xml
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
     <preference for="Magento\Framework\App\RequestInterface" type="Magento\Framework\App\Request\Http\Proxy" />
     <preference for="Magento\Store\Model\Config\InvalidatorInterface" type="Magento\Store\Model\Config\Invalidator\Proxy" />
     <preference for="Magento\Framework\App\CacheInterface" type="Magento\Framework\App\Cache\Proxy" />
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/view/frontend/default.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/view/frontend/default.xml
similarity index 86%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/view/frontend/default.xml
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/view/frontend/default.xml
index 4033324ce46b1a54aee06c3c24588d15b2c7c3b8..4664b27f04c42eb6c3d71dd3bef5ae5c6280574f 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/code/Magento/SomeModule/view/frontend/default.xml
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/code/Magento/SomeModule/view/frontend/default.xml
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 -->
-<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_layout.xsd">
+<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../../../../../../../lib/internal/Magento/Framework/View/Layout/etc/page_layout.xsd">
     <referenceBlock name="root">
         <block class="Magento\Backend\Block\Menu\Proxy" name="menu" as="menu" template="Magento_Backend::menu.phtml" />
     </referenceBlock>
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/design/adminhtml/default/backend/layout.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/design/adminhtml/default/backend/layout.xml
similarity index 100%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/design/adminhtml/default/backend/layout.xml
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/design/adminhtml/default/backend/layout.xml
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/etc/additional.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/additional.xml
similarity index 100%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/etc/additional.xml
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/additional.xml
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/etc/config.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/config.xml
similarity index 100%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/etc/config.xml
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/config.xml
diff --git a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/etc/di/config.xml b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/di/config.xml
similarity index 87%
rename from dev/tools/Magento/Tools/Di/Test/Unit/_files/app/etc/di/config.xml
rename to setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/di/config.xml
index 8638b10700e02310375a9dc43efe0a89b50eb15d..0b1395817de460ea28f44a6e79eadef1adf1446b 100644
--- a/dev/tools/Magento/Tools/Di/Test/Unit/_files/app/etc/di/config.xml
+++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/_files/app/etc/di/config.xml
@@ -5,7 +5,7 @@
  * See COPYING.txt for license details.
  */
 -->
-<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
     <type name="Magento\Framework\App\Cache">
         <arguments>
             <argument name="storeManager" xsi:type="object">customStoreManagerProxy</argument>
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/ContextTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/ContextTest.php
similarity index 93%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/ContextTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/ContextTest.php
index 1b89c9d07bf9d6bb10c9fc0375a976848eed9c23..5a641e556ff5539b2f3b25aa82fbe71b08913090 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/ContextTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/ContextTest.php
@@ -3,22 +3,21 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit;
-
-use \Magento\Tools\I18n\Context;
+namespace Magento\Setup\Test\Unit\Module\I18n;
 
+use \Magento\Setup\Module\I18n\Context;
 
 class ContextTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Context
+     * @var \Magento\Setup\Module\I18n\Context
      */
     protected $context;
 
     protected function setUp()
     {
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->context = $objectManagerHelper->getObject('Magento\Tools\I18n\Context');
+        $this->context = $objectManagerHelper->getObject('Magento\Setup\Module\I18n\Context');
     }
 
     /**
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/GeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/GeneratorTest.php
similarity index 73%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/GeneratorTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/GeneratorTest.php
index 6d77f2ab112f15f9fc15c2c5d10d3534f2bf43e7..5d56db8c8f2b7793f377bd0829e8c5a24ba1668c 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/GeneratorTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/GeneratorTest.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Dictionary;
+namespace Magento\Setup\Test\Unit\Module\I18n\Dictionary;
 
 /**
  * Generator test
@@ -11,53 +11,53 @@ namespace Magento\Tools\I18n\Test\Unit\Dictionary;
 class GeneratorTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Parser\Parser|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Parser\Parser|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $parserMock;
 
     /**
-     * @var \Magento\Tools\I18n\Parser\Contextual|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Parser\Contextual|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $contextualParserMock;
 
     /**
-     * @var \Magento\Tools\I18n\Factory|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Factory|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $factoryMock;
 
     /**
-     * @var \Magento\Tools\I18n\Dictionary\WriterInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Dictionary\WriterInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $writerMock;
 
     /**
-     * @var \Magento\Tools\I18n\Dictionary\Generator
+     * @var \Magento\Setup\Module\I18n\Dictionary\Generator
      */
     protected $generator;
 
     /**
-     * @var \Magento\Tools\I18n\Dictionary\Options\ResolverFactory|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Dictionary\Options\ResolverFactory|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $optionsResolverFactory;
 
     protected function setUp()
     {
-        $this->parserMock = $this->getMock('Magento\Tools\I18n\Parser\Parser', [], [], '', false);
+        $this->parserMock = $this->getMock('Magento\Setup\Module\I18n\Parser\Parser', [], [], '', false);
         $this->contextualParserMock = $this->getMock(
-            'Magento\Tools\I18n\Parser\Contextual',
+            'Magento\Setup\Module\I18n\Parser\Contextual',
             [],
             [],
             '',
             false
         );
-        $this->writerMock = $this->getMock('Magento\Tools\I18n\Dictionary\WriterInterface');
-        $this->factoryMock = $this->getMock('Magento\Tools\I18n\Factory', [], [], '', false);
+        $this->writerMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\WriterInterface');
+        $this->factoryMock = $this->getMock('Magento\Setup\Module\I18n\Factory', [], [], '', false);
         $this->factoryMock->expects($this->any())
             ->method('createDictionaryWriter')
             ->will($this->returnValue($this->writerMock));
 
         $this->optionsResolverFactory = $this->getMock(
-            'Magento\Tools\I18n\Dictionary\Options\ResolverFactory',
+            'Magento\Setup\Module\I18n\Dictionary\Options\ResolverFactory',
             [],
             [],
             '',
@@ -66,7 +66,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
 
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->generator = $objectManagerHelper->getObject(
-            'Magento\Tools\I18n\Dictionary\Generator',
+            'Magento\Setup\Module\I18n\Dictionary\Generator',
             [
                 'parser' => $this->parserMock,
                 'contextualParser' => $this->contextualParserMock,
@@ -80,14 +80,14 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
     {
         $outputFilename = 'test';
 
-        $phrase = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
+        $phrase = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
         $this->factoryMock->expects($this->once())
             ->method('createDictionaryWriter')
             ->with($outputFilename)
             ->will($this->returnSelf());
         $this->parserMock->expects($this->any())->method('getPhrases')->will($this->returnValue([$phrase]));
         $options = [];
-        $optionResolver = $this->getMock('Magento\Tools\I18n\Dictionary\Options\Resolver', [], [], '', false);
+        $optionResolver = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Options\Resolver', [], [], '', false);
         $optionResolver->expects($this->once())
             ->method('getOptions')
             ->will($this->returnValue($options));
@@ -106,7 +106,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
         $baseDir = 'right_parser';
         $outputFilename = 'file.csv';
         $filesOptions = ['file1', 'file2'];
-        $optionResolver = $this->getMock('Magento\Tools\I18n\Dictionary\Options\Resolver', [], [], '', false);
+        $optionResolver = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Options\Resolver', [], [], '', false);
         $optionResolver->expects($this->once())
             ->method('getOptions')
             ->will($this->returnValue($filesOptions));
@@ -121,7 +121,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
             ->with($this->equalTo($baseDir), $this->equalTo(false))
             ->will($this->returnValue($optionResolver));
         $this->parserMock->expects($this->once())->method('parse')->with($filesOptions);
-        $phrase = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
+        $phrase = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
         $this->parserMock->expects($this->once())->method('getPhrases')->will($this->returnValue([$phrase]));
         $this->generator->generate($baseDir, $outputFilename);
     }
@@ -131,7 +131,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
         $baseDir = 'right_parser2';
         $outputFilename = 'file.csv';
         $filesOptions = ['file1', 'file2'];
-        $optionResolver = $this->getMock('Magento\Tools\I18n\Dictionary\Options\Resolver', [], [], '', false);
+        $optionResolver = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Options\Resolver', [], [], '', false);
         $optionResolver->expects($this->once())
             ->method('getOptions')
             ->will($this->returnValue($filesOptions));
@@ -141,7 +141,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue($optionResolver));
 
         $this->contextualParserMock->expects($this->once())->method('parse')->with($filesOptions);
-        $phrase = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
+        $phrase = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
         $this->contextualParserMock->expects($this->once())->method('getPhrases')->will($this->returnValue([$phrase]));
 
         $this->factoryMock->expects($this->once())
@@ -156,7 +156,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
     {
         $baseDir = 'WritingPhrases';
         $filesOptions = ['file1', 'file2'];
-        $optionResolver = $this->getMock('Magento\Tools\I18n\Dictionary\Options\Resolver', [], [], '', false);
+        $optionResolver = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Options\Resolver', [], [], '', false);
         $optionResolver->expects($this->once())
             ->method('getOptions')
             ->will($this->returnValue($filesOptions));
@@ -166,8 +166,8 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
             ->will($this->returnValue($optionResolver));
 
         $phrases = [
-            $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false),
-            $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false),
+            $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false),
+            $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false),
         ];
 
         $this->parserMock->expects($this->once())->method('getPhrases')->will($this->returnValue($phrases));
@@ -186,7 +186,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
         $baseDir = 'no_phrases';
         $outputFilename = 'no_file.csv';
         $filesOptions = ['file1', 'file2'];
-        $optionResolver = $this->getMock('Magento\Tools\I18n\Dictionary\Options\Resolver', [], [], '', false);
+        $optionResolver = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Options\Resolver', [], [], '', false);
         $optionResolver->expects($this->once())
             ->method('getOptions')
             ->will($this->returnValue($filesOptions));
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Loader/File/AbstractFileTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Loader/File/AbstractFileTest.php
similarity index 73%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Loader/File/AbstractFileTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Loader/File/AbstractFileTest.php
index 84659fb6e2db5b319bac1d2ca8ffdaaa94562f3e..fc4666d9dce9905eb74199c4ce1843f4f62a9586 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Loader/File/AbstractFileTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Loader/File/AbstractFileTest.php
@@ -3,29 +3,29 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Dictionary\Loader\File;
+namespace Magento\Setup\Test\Unit\Module\I18n\Dictionary\Loader\File;
 
 class AbstractFileTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Dictionary|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Dictionary|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_dictionaryMock;
 
     /**
-     * @var \Magento\Tools\I18n\Factory|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Factory|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_factoryMock;
 
     /**
-     * @var \Magento\Tools\I18n\Dictionary\Loader\File\AbstractFile|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Dictionary\Loader\File\AbstractFile|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_abstractLoaderMock;
 
     protected function setUp()
     {
-        $this->_dictionaryMock = $this->getMock('Magento\Tools\I18n\Dictionary', [], [], '', false);
-        $this->_factoryMock = $this->getMock('Magento\Tools\I18n\Factory', [], [], '', false);
+        $this->_dictionaryMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary', [], [], '', false);
+        $this->_factoryMock = $this->getMock('Magento\Setup\Module\I18n\Factory', [], [], '', false);
     }
 
     /**
@@ -35,20 +35,20 @@ class AbstractFileTest extends \PHPUnit_Framework_TestCase
     public function testLoadWrongFile()
     {
         $abstractLoaderMock = $this->getMockForAbstractClass(
-            'Magento\Tools\I18n\Dictionary\Loader\File\AbstractFile',
+            'Magento\Setup\Module\I18n\Dictionary\Loader\File\AbstractFile',
             [],
             '',
             false
         );
 
-        /** @var \Magento\Tools\I18n\Dictionary\Loader\File\AbstractFile $abstractLoaderMock */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Loader\File\AbstractFile $abstractLoaderMock */
         $abstractLoaderMock->load('wrong_file.csv');
     }
 
     public function testLoad()
     {
         $abstractLoaderMock = $this->getMockForAbstractClass(
-            'Magento\Tools\I18n\Dictionary\Loader\File\AbstractFile',
+            'Magento\Setup\Module\I18n\Dictionary\Loader\File\AbstractFile',
             [$this->_factoryMock],
             '',
             true,
@@ -71,8 +71,8 @@ class AbstractFileTest extends \PHPUnit_Framework_TestCase
             $this->returnValue(['phrase2', 'translation2', 'context_type2', 'context_value2'])
         );
 
-        $phraseFirstMock = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
-        $phraseSecondMock = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
+        $phraseFirstMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
+        $phraseSecondMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
 
         $this->_factoryMock->expects(
             $this->once()
@@ -108,7 +108,7 @@ class AbstractFileTest extends \PHPUnit_Framework_TestCase
         $this->_dictionaryMock->expects($this->at(0))->method('addPhrase')->with($phraseFirstMock);
         $this->_dictionaryMock->expects($this->at(1))->method('addPhrase')->with($phraseSecondMock);
 
-        /** @var \Magento\Tools\I18n\Dictionary\Loader\File\AbstractFile $abstractLoaderMock */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Loader\File\AbstractFile $abstractLoaderMock */
         $this->assertEquals($this->_dictionaryMock, $abstractLoaderMock->load('test.csv'));
     }
 
@@ -119,7 +119,7 @@ class AbstractFileTest extends \PHPUnit_Framework_TestCase
     public function testErrorsInPhraseCreating()
     {
         $abstractLoaderMock = $this->getMockForAbstractClass(
-            'Magento\Tools\I18n\Dictionary\Loader\File\AbstractFile',
+            'Magento\Setup\Module\I18n\Dictionary\Loader\File\AbstractFile',
             [$this->_factoryMock],
             '',
             true,
@@ -150,7 +150,7 @@ class AbstractFileTest extends \PHPUnit_Framework_TestCase
             $this->throwException(new \DomainException('exception_message'))
         );
 
-        /** @var \Magento\Tools\I18n\Dictionary\Loader\File\AbstractFile $abstractLoaderMock */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Loader\File\AbstractFile $abstractLoaderMock */
         $this->assertEquals($this->_dictionaryMock, $abstractLoaderMock->load('test.csv'));
     }
 }
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/ResolverFactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/ResolverFactoryTest.php
similarity index 65%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/ResolverFactoryTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/ResolverFactoryTest.php
index 3a01474be5f4889621fe415f95af3284d2f88dbd..82e905624d8a39f3e684145f302cb38869018045 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/ResolverFactoryTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/ResolverFactoryTest.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Dictionary\Options;
+namespace Magento\Setup\Test\Unit\Module\I18n\Dictionary\Options;
 
 /**
  * Class ResolverTest
@@ -13,11 +13,11 @@ class ResolverFactoryTest extends \PHPUnit_Framework_TestCase
     public function testCreate()
     {
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        /** @var \Magento\Tools\I18n\Dictionary\Options\ResolverFactory $resolverFactory */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Options\ResolverFactory $resolverFactory */
         $resolverFactory = $objectManagerHelper
-            ->getObject('Magento\Tools\I18n\Dictionary\Options\ResolverFactory');
+            ->getObject('Magento\Setup\Module\I18n\Dictionary\Options\ResolverFactory');
         $this->assertInstanceOf(
-            \Magento\Tools\I18n\Dictionary\Options\ResolverFactory::DEFAULT_RESOLVER,
+            \Magento\Setup\Module\I18n\Dictionary\Options\ResolverFactory::DEFAULT_RESOLVER,
             $resolverFactory->create('some_dir', true)
         );
     }
@@ -29,9 +29,9 @@ class ResolverFactoryTest extends \PHPUnit_Framework_TestCase
     public function testCreateException()
     {
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        /** @var \Magento\Tools\I18n\Dictionary\Options\ResolverFactory $resolverFactory */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Options\ResolverFactory $resolverFactory */
         $resolverFactory = $objectManagerHelper->getObject(
-            'Magento\Tools\I18n\Dictionary\Options\ResolverFactory',
+            'Magento\Setup\Module\I18n\Dictionary\Options\ResolverFactory',
             [
                 'resolverClass' => 'stdClass'
             ]
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/ResolverTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/ResolverTest.php
similarity index 90%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/ResolverTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/ResolverTest.php
index b3994660d05fe723c3b5b72c69fb3c84c50a6ed8..bb6ba63cfb35fbf044fa59243939ade462cd1af8 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/ResolverTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/ResolverTest.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Dictionary\Options;
+namespace Magento\Setup\Test\Unit\Module\I18n\Dictionary\Options;
 
 /**
  * Class ResolverTest
@@ -19,9 +19,9 @@ class ResolverTest extends \PHPUnit_Framework_TestCase
     public function testGetOptions($directory, $withContext, $result)
     {
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        /** @var \Magento\Tools\I18n\Dictionary\Options\Resolver $resolver */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Options\Resolver $resolver */
         $resolver = $objectManagerHelper->getObject(
-            'Magento\Tools\I18n\Dictionary\Options\Resolver',
+            'Magento\Setup\Module\I18n\Dictionary\Options\Resolver',
             [
                 'directory' => $directory,
                 'withContext' => $withContext,
@@ -85,9 +85,9 @@ class ResolverTest extends \PHPUnit_Framework_TestCase
     public function testGetOptionsWrongDir($directory, $withContext, $message)
     {
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        /** @var \Magento\Tools\I18n\Dictionary\Options\Resolver $resolver */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Options\Resolver $resolver */
         $resolver = $objectManagerHelper->getObject(
-            'Magento\Tools\I18n\Dictionary\Options\Resolver',
+            'Magento\Setup\Module\I18n\Dictionary\Options\Resolver',
             [
                 'directory' => $directory,
                 'withContext' => $withContext,
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/_files/source/app/code/.gitignore b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/_files/source/app/code/.gitignore
similarity index 100%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/_files/source/app/code/.gitignore
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/_files/source/app/code/.gitignore
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/_files/source/app/design/.gitignore b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/_files/source/app/design/.gitignore
similarity index 100%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/_files/source/app/design/.gitignore
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/_files/source/app/design/.gitignore
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/_files/source/lib/web/mage/.gitignore b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/_files/source/lib/web/mage/.gitignore
similarity index 100%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/_files/source/lib/web/mage/.gitignore
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/_files/source/lib/web/mage/.gitignore
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/_files/source/lib/web/varien/.gitignore b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/_files/source/lib/web/varien/.gitignore
similarity index 100%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Options/_files/source/lib/web/varien/.gitignore
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Options/_files/source/lib/web/varien/.gitignore
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/PhraseTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/PhraseTest.php
similarity index 94%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/PhraseTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/PhraseTest.php
index fa919d12c52dc9cbe437eeddae6f4d74b9dc818b..309478e36978baa6c0eb174c44f237bde3ac2851 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/PhraseTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/PhraseTest.php
@@ -3,10 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Dictionary;
-
-use \Magento\Tools\I18n\Dictionary\Phrase;
+namespace Magento\Setup\Test\Unit\Module\I18n\Dictionary;
 
+use \Magento\Setup\Module\I18n\Dictionary\Phrase;
 
 class PhraseTest extends \PHPUnit_Framework_TestCase
 {
@@ -18,7 +17,7 @@ class PhraseTest extends \PHPUnit_Framework_TestCase
      */
     public function testPhraseCreation($constructArguments, $getter, $result)
     {
-        $reflectionClass = new \ReflectionClass('Magento\Tools\I18n\Dictionary\Phrase');
+        $reflectionClass = new \ReflectionClass('Magento\Setup\Module\I18n\Dictionary\Phrase');
         $phrase = $reflectionClass->newInstanceArgs($constructArguments);
         $this->assertEquals($result, $phrase->{$getter}());
     }
@@ -59,7 +58,7 @@ class PhraseTest extends \PHPUnit_Framework_TestCase
     {
         $this->setExpectedException('DomainException', $message);
 
-        $reflectionClass = new \ReflectionClass('Magento\Tools\I18n\Dictionary\Phrase');
+        $reflectionClass = new \ReflectionClass('Magento\Setup\Module\I18n\Dictionary\Phrase');
         $reflectionClass->newInstanceArgs($constructArguments);
     }
 
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Writer/Csv/StdoTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/Csv/StdoTest.php
similarity index 68%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Writer/Csv/StdoTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/Csv/StdoTest.php
index 95cb7cabdc59de61ac53fc2280c78cd37e361343..2ea739d71453bd509ad993cb6143219a306c5bc9 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Writer/Csv/StdoTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/Csv/StdoTest.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Dictionary\Writer\Csv;
+namespace Magento\Setup\Test\Unit\Module\I18n\Dictionary\Writer\Csv;
 
 class StdoTest extends \PHPUnit_Framework_TestCase
 {
@@ -20,8 +20,8 @@ class StdoTest extends \PHPUnit_Framework_TestCase
     public function testThatHandlerIsRight()
     {
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        /** @var \Magento\Tools\I18n\Dictionary\Writer\Csv $writer */
-        $writer = $objectManagerHelper->getObject('Magento\Tools\I18n\Dictionary\Writer\Csv\Stdo');
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Writer\Csv $writer */
+        $writer = $objectManagerHelper->getObject('Magento\Setup\Module\I18n\Dictionary\Writer\Csv\Stdo');
 
         $this->assertAttributeEquals($this->_handler, '_fileHandler', $writer);
     }
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Writer/CsvTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/CsvTest.php
similarity index 87%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Writer/CsvTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/CsvTest.php
index 72033add5315e18349da8079ff02c7a203e3202e..5edc74cb629394097225f22bc7d8e42211d7fdd1 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Writer/CsvTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/CsvTest.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Dictionary\Writer;
+namespace Magento\Setup\Test\Unit\Module\I18n\Dictionary\Writer;
 
 class CsvTest extends \PHPUnit_Framework_TestCase
 {
@@ -13,12 +13,12 @@ class CsvTest extends \PHPUnit_Framework_TestCase
     protected $_testFile;
 
     /**
-     * @var \Magento\Tools\I18n\Dictionary\Phrase|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Dictionary\Phrase|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_phraseFirstMock;
 
     /**
-     * @var \Magento\Tools\I18n\Dictionary\Phrase|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Dictionary\Phrase|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_phraseSecondMock;
 
@@ -27,14 +27,14 @@ class CsvTest extends \PHPUnit_Framework_TestCase
         $this->_testFile = str_replace('\\', '/', realpath(dirname(__FILE__))) . '/_files/test.csv';
 
         $this->_phraseFirstMock = $this->getMock(
-            'Magento\Tools\I18n\Dictionary\Phrase',
+            'Magento\Setup\Module\I18n\Dictionary\Phrase',
             [],
             [],
             '',
             false
         );
         $this->_phraseSecondMock = $this->getMock(
-            'Magento\Tools\I18n\Dictionary\Phrase',
+            'Magento\Setup\Module\I18n\Dictionary\Phrase',
             [],
             [],
             '',
@@ -57,7 +57,7 @@ class CsvTest extends \PHPUnit_Framework_TestCase
     {
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $objectManagerHelper->getObject(
-            'Magento\Tools\I18n\Dictionary\Writer\Csv',
+            'Magento\Setup\Module\I18n\Dictionary\Writer\Csv',
             ['outputFilename' => 'wrong/path']
         );
     }
@@ -123,9 +123,9 @@ class CsvTest extends \PHPUnit_Framework_TestCase
         );
 
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        /** @var \Magento\Tools\I18n\Dictionary\Writer\Csv $writer */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Writer\Csv $writer */
         $writer = $objectManagerHelper->getObject(
-            'Magento\Tools\I18n\Dictionary\Writer\Csv',
+            'Magento\Setup\Module\I18n\Dictionary\Writer\Csv',
             ['outputFilename' => $this->_testFile]
         );
         $writer->write($this->_phraseFirstMock);
@@ -176,9 +176,9 @@ EXPECTED;
         );
 
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        /** @var \Magento\Tools\I18n\Dictionary\Writer\Csv $writer */
+        /** @var \Magento\Setup\Module\I18n\Dictionary\Writer\Csv $writer */
         $writer = $objectManagerHelper->getObject(
-            'Magento\Tools\I18n\Dictionary\Writer\Csv',
+            'Magento\Setup\Module\I18n\Dictionary\Writer\Csv',
             ['outputFilename' => $this->_testFile]
         );
         $writer->write($this->_phraseFirstMock);
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Writer/_files/.gitignore b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/_files/.gitignore
similarity index 100%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Dictionary/Writer/_files/.gitignore
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Dictionary/Writer/_files/.gitignore
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/DictionaryTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/DictionaryTest.php
similarity index 66%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/DictionaryTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/DictionaryTest.php
index a901907b0d86f533bd9919be3134f48c209002f7..9ed72a939fd7e3b977e6a28bd89d86da2d7c20ba 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/DictionaryTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/DictionaryTest.php
@@ -3,25 +3,25 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit;
+namespace Magento\Setup\Test\Unit\Module\I18n;
 
 class DictionaryTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Dictionary
+     * @var \Magento\Setup\Module\I18n\Dictionary
      */
     protected $_dictionary;
 
     protected function setUp()
     {
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->_dictionary = $objectManagerHelper->getObject('Magento\Tools\I18n\Dictionary');
+        $this->_dictionary = $objectManagerHelper->getObject('Magento\Setup\Module\I18n\Dictionary');
     }
 
     public function testPhraseCollecting()
     {
-        $phraseFirstMock = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
-        $phraseSecondMock = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
+        $phraseFirstMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
+        $phraseSecondMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
 
         $this->_dictionary->addPhrase($phraseFirstMock);
         $this->_dictionary->addPhrase($phraseSecondMock);
@@ -31,11 +31,11 @@ class DictionaryTest extends \PHPUnit_Framework_TestCase
 
     public function testGetDuplicates()
     {
-        $phraseFirstMock = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
+        $phraseFirstMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
         $phraseFirstMock->expects($this->once())->method('getKey')->will($this->returnValue('key_1'));
-        $phraseSecondMock = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
+        $phraseSecondMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
         $phraseSecondMock->expects($this->once())->method('getKey')->will($this->returnValue('key_1'));
-        $phraseThirdMock = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
+        $phraseThirdMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
         $phraseThirdMock->expects($this->once())->method('getKey')->will($this->returnValue('key_3'));
 
         $this->_dictionary->addPhrase($phraseFirstMock);
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/FactoryTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/FactoryTest.php
similarity index 75%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/FactoryTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/FactoryTest.php
index 9d7b19a228b410627c063090415fa43932b97442..fbce20193f2746455eeb02a3714263c90f9c316d 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/FactoryTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/FactoryTest.php
@@ -3,19 +3,19 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit;
+namespace Magento\Setup\Test\Unit\Module\I18n;
 
 class FactoryTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Factory
+     * @var \Magento\Setup\Module\I18n\Factory
      */
     protected $factory;
 
     protected function setUp()
     {
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->factory = $objectManagerHelper->getObject('Magento\Tools\I18n\Factory');
+        $this->factory = $objectManagerHelper->getObject('Magento\Setup\Module\I18n\Factory');
     }
 
     /**
@@ -38,19 +38,19 @@ class FactoryTest extends \PHPUnit_Framework_TestCase
     {
         return [
             [
-                'Magento\Tools\I18n\Dictionary\Writer\Csv',
+                'Magento\Setup\Module\I18n\Dictionary\Writer\Csv',
                 TESTS_TEMP_DIR . '/filename.invalid_type',
             ],
             [
-                'Magento\Tools\I18n\Dictionary\Writer\Csv',
+                'Magento\Setup\Module\I18n\Dictionary\Writer\Csv',
                 TESTS_TEMP_DIR . '/filename'
             ],
             [
-                'Magento\Tools\I18n\Dictionary\Writer\Csv',
+                'Magento\Setup\Module\I18n\Dictionary\Writer\Csv',
                 TESTS_TEMP_DIR . '/filename.csv'
             ],
             [
-                'Magento\Tools\I18n\Dictionary\Writer\Csv\Stdo',
+                'Magento\Setup\Module\I18n\Dictionary\Writer\Csv\Stdo',
                 ''
             ],
         ];
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/FilesCollectorTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/FilesCollectorTest.php
similarity index 88%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/FilesCollectorTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/FilesCollectorTest.php
index b21dbe6971cdcb5b8e108c984e1cbcfc796ba858..5d1f5cfe4857f49b632e38be6cf85a988a12e8a3 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/FilesCollectorTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/FilesCollectorTest.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit;
+namespace Magento\Setup\Test\Unit\Module\I18n;
 
 class FilesCollectorTest extends \PHPUnit_Framework_TestCase
 {
@@ -13,7 +13,7 @@ class FilesCollectorTest extends \PHPUnit_Framework_TestCase
     protected $_testDir;
 
     /**
-     * @var \Magento\Tools\I18n\FilesCollector
+     * @var \Magento\Setup\Module\I18n\FilesCollector
      */
     protected $_filesCollector;
 
@@ -22,7 +22,7 @@ class FilesCollectorTest extends \PHPUnit_Framework_TestCase
         $this->_testDir = str_replace('\\', '/', realpath(dirname(__FILE__))) . '/_files/files_collector/';
 
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->_filesCollector = $objectManagerHelper->getObject('Magento\Tools\I18n\FilesCollector');
+        $this->_filesCollector = $objectManagerHelper->getObject('Magento\Setup\Module\I18n\FilesCollector');
     }
 
     public function testGetFilesWithoutMask()
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/LocaleTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/LocaleTest.php
similarity index 90%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/LocaleTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/LocaleTest.php
index 816773c05ac7db073044cc2381106fe143266ee9..09914f7863146d54f3256457a71523da26c7889e 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/LocaleTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/LocaleTest.php
@@ -3,10 +3,9 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit;
-
-use \Magento\Tools\I18n\Locale;
+namespace Magento\Setup\Test\Unit\Module\I18n;
 
+use \Magento\Setup\Module\I18n\Locale;
 
 class LocaleTest extends \PHPUnit_Framework_TestCase
 {
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Pack/GeneratorTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Pack/GeneratorTest.php
similarity index 70%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Pack/GeneratorTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Pack/GeneratorTest.php
index 4ca23c946a99bd976d17deee464cf886ffe5ff8c..0866b50cf75aa2843100f24c9d9be920e510b6c4 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Pack/GeneratorTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Pack/GeneratorTest.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Pack;
+namespace Magento\Setup\Test\Unit\Module\I18n\Pack;
 
 /**
  * Generator test
@@ -11,40 +11,40 @@ namespace Magento\Tools\I18n\Test\Unit\Pack;
 class GeneratorTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Dictionary\Loader\FileInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Dictionary\Loader\FileInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $dictionaryLoaderMock;
 
     /**
-     * @var \Magento\Tools\I18n\Pack\WriterInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Pack\WriterInterface|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $packWriterMock;
 
     /**
-     * @var \Magento\Tools\I18n\Factory|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Factory|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $factoryMock;
 
     /**
-     * @var \Magento\Tools\I18n\Dictionary|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Dictionary|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $dictionaryMock;
 
     /**
-     * @var \Magento\Tools\I18n\Pack\Generator
+     * @var \Magento\Setup\Module\I18n\Pack\Generator
      */
     protected $_generator;
 
     protected function setUp()
     {
-        $this->dictionaryLoaderMock = $this->getMock('Magento\Tools\I18n\Dictionary\Loader\FileInterface');
-        $this->packWriterMock = $this->getMock('Magento\Tools\I18n\Pack\WriterInterface');
-        $this->factoryMock = $this->getMock('Magento\Tools\I18n\Factory', [], [], '', false);
-        $this->dictionaryMock = $this->getMock('Magento\Tools\I18n\Dictionary', [], [], '', false);
+        $this->dictionaryLoaderMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Loader\FileInterface');
+        $this->packWriterMock = $this->getMock('Magento\Setup\Module\I18n\Pack\WriterInterface');
+        $this->factoryMock = $this->getMock('Magento\Setup\Module\I18n\Factory', [], [], '', false);
+        $this->dictionaryMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary', [], [], '', false);
 
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->_generator = $objectManagerHelper->getObject(
-            'Magento\Tools\I18n\Pack\Generator',
+            'Magento\Setup\Module\I18n\Pack\Generator',
             [
                 'dictionaryLoader' => $this->dictionaryLoaderMock,
                 'packWriter' => $this->packWriterMock,
@@ -60,9 +60,9 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
         $localeString = 'locale';
         $mode = 'mode';
         $allowDuplicates = true;
-        $localeMock = $this->getMock('Magento\Tools\I18n\Locale', [], [], '', false);
+        $localeMock = $this->getMock('Magento\Setup\Module\I18n\Locale', [], [], '', false);
 
-        $phrases = [$this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false)];
+        $phrases = [$this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false)];
         $this->dictionaryMock->expects($this->once())
             ->method('getPhrases')
             ->will($this->returnValue([$phrases]));
@@ -93,7 +93,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
         $localeString = 'locale';
         $mode = 'mode';
         $allowDuplicates = true;
-        $localeMock = $this->getMock('Magento\Tools\I18n\Locale', [], [], '', false);
+        $localeMock = $this->getMock('Magento\Setup\Module\I18n\Locale', [], [], '', false);
 
         $this->factoryMock->expects($this->once())
             ->method('createLocale')
@@ -116,15 +116,15 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
 
         $allowDuplicates = false;
 
-        $phraseFirstMock = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
+        $phraseFirstMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
         $phraseFirstMock->expects($this->once())->method('getPhrase')->will($this->returnValue('phrase1'));
-        $phraseSecondMock = $this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false);
+        $phraseSecondMock = $this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false);
         $phraseSecondMock->expects($this->once())->method('getPhrase')->will($this->returnValue('phrase2'));
 
         $this->dictionaryLoaderMock->expects($this->any())
             ->method('load')
             ->will($this->returnValue($this->dictionaryMock));
-        $phrases = [$this->getMock('Magento\Tools\I18n\Dictionary\Phrase', [], [], '', false)];
+        $phrases = [$this->getMock('Magento\Setup\Module\I18n\Dictionary\Phrase', [], [], '', false)];
         $this->dictionaryMock->expects($this->once())
             ->method('getPhrases')
             ->will($this->returnValue([$phrases]));
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/AbstractParserTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/AbstractParserTest.php
similarity index 84%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/AbstractParserTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/AbstractParserTest.php
index dc2bdcc6a8a197eca62dbedb1a204d46233a7c4d..3e43fbdb86e6008c5867a9cdfc74137c8fd28038 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/AbstractParserTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/AbstractParserTest.php
@@ -3,19 +3,19 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Parser;
+namespace Magento\Setup\Test\Unit\Module\I18n\Parser;
 
 class AbstractParserTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Parser\AbstractParser|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Parser\AbstractParser|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_parserMock;
 
     protected function setUp()
     {
         $this->_parserMock = $this->getMockForAbstractClass(
-            'Magento\Tools\I18n\Parser\AbstractParser',
+            'Magento\Setup\Module\I18n\Parser\AbstractParser',
             [],
             '',
             false
@@ -31,7 +31,7 @@ class AbstractParserTest extends \PHPUnit_Framework_TestCase
     {
         $this->setExpectedException('InvalidArgumentException', $message);
 
-        $this->_parserMock->addAdapter('php', $this->getMock('Magento\Tools\I18n\Parser\AdapterInterface'));
+        $this->_parserMock->addAdapter('php', $this->getMock('Magento\Setup\Module\I18n\Parser\AdapterInterface'));
         $this->_parserMock->parse($options);
     }
 
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/AbstractAdapterTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/AbstractAdapterTest.php
similarity index 74%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/AbstractAdapterTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/AbstractAdapterTest.php
index d56d8c7e9232f6056c78799151c44ff1657980ba..676c24fb0877979d663a511342ddd4055685401d 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/AbstractAdapterTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/AbstractAdapterTest.php
@@ -3,19 +3,19 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Parser\Adapter;
+namespace Magento\Setup\Test\Unit\Module\I18n\Parser\Adapter;
 
 class AbstractAdapterTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Parser\Adapter\AbstractAdapter|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Parser\Adapter\AbstractAdapter|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $_adapterMock;
 
     protected function setUp()
     {
         $this->_adapterMock = $this->getMockForAbstractClass(
-            'Magento\Tools\I18n\Parser\Adapter\AbstractAdapter',
+            'Magento\Setup\Module\I18n\Parser\Adapter\AbstractAdapter',
             [],
             '',
             false,
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/JsTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/JsTest.php
similarity index 85%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/JsTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/JsTest.php
index 7ed1d77bf9cfb91cf1ca535377c5c0eac3ab8a7c..5494f0d4cb1dc427a73521f2cb71876f244202d0 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/JsTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/JsTest.php
@@ -3,10 +3,10 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Parser\Adapter;
+namespace Magento\Setup\Test\Unit\Module\I18n\Parser\Adapter;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
-use Magento\Tools\I18n\Dictionary\Phrase;
+use Magento\Setup\Module\I18n\Dictionary\Phrase;
 
 class JsTest extends \PHPUnit_Framework_TestCase
 {
@@ -21,7 +21,7 @@ class JsTest extends \PHPUnit_Framework_TestCase
     protected $_stringsCount;
 
     /**
-     * @var \Magento\Tools\I18n\Parser\Adapter\Js
+     * @var \Magento\Setup\Module\I18n\Parser\Adapter\Js
      */
     protected $_adapter;
 
@@ -30,7 +30,7 @@ class JsTest extends \PHPUnit_Framework_TestCase
         $this->_testFile = str_replace('\\', '/', realpath(dirname(__FILE__))) . '/_files/file.js';
         $this->_stringsCount = count(file($this->_testFile));
 
-        $this->_adapter = (new ObjectManager($this))->getObject('Magento\Tools\I18n\Parser\Adapter\Js');
+        $this->_adapter = (new ObjectManager($this))->getObject('Magento\Setup\Module\I18n\Parser\Adapter\Js');
     }
 
     public function testParse()
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php
similarity index 89%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php
index 22d394b40a74f13b179e983b982d03c142991c3c..954bcc013ade66bfdd3c10c10597fe205f6f5e58 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/Tokenizer/PhraseCollectorTest.php
@@ -3,15 +3,15 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Parser\Adapter\Php\Tokenizer;
+namespace Magento\Setup\Test\Unit\Module\I18n\Parser\Adapter\Php\Tokenizer;
 
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector;
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token;
+use Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector;
+use Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer;
+use Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer;
 
 /**
- * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
+ * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
  */
 class PhraseCollectorTest extends \PHPUnit_Framework_TestCase
 {
@@ -33,11 +33,11 @@ class PhraseCollectorTest extends \PHPUnit_Framework_TestCase
     protected function setUp()
     {
         $this->objectManager = new ObjectManager($this);
-        $this->tokenizerMock = $this->getMockBuilder('Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer')
+        $this->tokenizerMock = $this->getMockBuilder('Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer')
             ->disableOriginalConstructor()
             ->getMock();
         $this->phraseCollector = $this->objectManager->getObject(
-            'Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector',
+            'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector',
             [
                 'tokenizer' => $this->tokenizerMock
             ]
@@ -45,7 +45,7 @@ class PhraseCollectorTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector::parse
+     * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector::parse
      *
      * @param string $file
      * @param array $isEndOfLoopReturnValues
@@ -180,7 +180,7 @@ class PhraseCollectorTest extends \PHPUnit_Framework_TestCase
         $value,
         $line = null
     ) {
-        $token = $this->getMockBuilder('Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token')
+        $token = $this->getMockBuilder('Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token')
             ->disableOriginalConstructor()
             ->getMock();
         $token->expects($this->any())
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/Tokenizer/TokenTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/Tokenizer/TokenTest.php
similarity index 84%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/Tokenizer/TokenTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/Tokenizer/TokenTest.php
index 7bb0366e99dd9e5e6a71a59ca7f5bd5429786f17..26bcea7516dd2495526e0b75202c3082591a77c6 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/Tokenizer/TokenTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/Tokenizer/TokenTest.php
@@ -3,13 +3,13 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Parser\Adapter\Php\Tokenizer;
+namespace Magento\Setup\Test\Unit\Module\I18n\Parser\Adapter\Php\Tokenizer;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
-use Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token;
+use Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token;
 
 /**
- * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token
+ * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token
  */
 class TokenTest extends \PHPUnit_Framework_TestCase
 {
@@ -24,7 +24,7 @@ class TokenTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token::isNew
+     * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token::isNew
      *
      * @param int $name
      * @param string $value
@@ -38,7 +38,7 @@ class TokenTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token::isNamespaceSeparator
+     * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token::isNamespaceSeparator
      *
      * @param int $name
      * @param string $value
@@ -52,7 +52,7 @@ class TokenTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token::isIdentifier
+     * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token::isIdentifier
      *
      * @param int $name
      * @param string $value
@@ -110,7 +110,7 @@ class TokenTest extends \PHPUnit_Framework_TestCase
     {
         $line = 110;
         return $this->objectManager->getObject(
-            'Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\Token',
+            'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\Token',
             [
                 'name' => $name,
                 'value' => $value,
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/TokenizerTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/TokenizerTest.php
similarity index 87%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/TokenizerTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/TokenizerTest.php
index a55a23be8af49366538d181bea2f8ad2fe995339..553f6b4143172af1e5effda8cafd4718e6be3806 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/TokenizerTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/TokenizerTest.php
@@ -3,14 +3,14 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Parser\Adapter\Php;
+namespace Magento\Setup\Test\Unit\Module\I18n\Parser\Adapter\Php;
 
-use \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer;
+use \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 /**
- * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer
+ * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer
  */
 class TokenizerTest extends \PHPUnit_Framework_TestCase
 {
@@ -28,12 +28,12 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
     {
         $this->objectManager = new ObjectManager($this);
         $this->tokenizer = $this->objectManager->getObject(
-            'Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer'
+            'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer'
         );
     }
 
     /**
-     * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer::isMatchingClass
+     * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer::isMatchingClass
      */
     public function testIsMatchingClass()
     {
@@ -56,7 +56,7 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer::getNextRealToken
+     * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer::getNextRealToken
      */
     public function testGetNextRealToken()
     {
@@ -75,7 +75,7 @@ class TokenizerTest extends \PHPUnit_Framework_TestCase
     }
 
     /**
-     * @covers \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer::isEndOfLoop
+     * @covers \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer::isEndOfLoop
      */
     public function testIsEndOfLoop()
     {
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/_files/objectsCode.php.txt b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/_files/objectsCode.php.txt
similarity index 100%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/Php/_files/objectsCode.php.txt
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/Php/_files/objectsCode.php.txt
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/PhpTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/PhpTest.php
similarity index 79%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/PhpTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/PhpTest.php
index 998295d16256308250579f0d43909b2fbad16e88..822749f27463694d1622f55f0759bb8d1695178d 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/PhpTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/PhpTest.php
@@ -3,25 +3,25 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Parser\Adapter;
+namespace Magento\Setup\Test\Unit\Module\I18n\Parser\Adapter;
 
 class PhpTest extends \PHPUnit_Framework_TestCase
 {
     /**
      * @var \PHPUnit_Framework_MockObject_MockObject|
-     * \Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
+     * \Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector
      */
     protected $_phraseCollectorMock;
 
     /**
-     * @var \Magento\Tools\I18n\Parser\Adapter\Php
+     * @var \Magento\Setup\Module\I18n\Parser\Adapter\Php
      */
     protected $_adapter;
 
     protected function setUp()
     {
         $this->_phraseCollectorMock = $this->getMock(
-            'Magento\Tools\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector',
+            'Magento\Setup\Module\I18n\Parser\Adapter\Php\Tokenizer\PhraseCollector',
             [],
             [],
             '',
@@ -30,7 +30,7 @@ class PhpTest extends \PHPUnit_Framework_TestCase
 
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->_adapter = $objectManagerHelper->getObject(
-            'Magento\Tools\I18n\Parser\Adapter\Php',
+            'Magento\Setup\Module\I18n\Parser\Adapter\Php',
             ['phraseCollector' => $this->_phraseCollectorMock]
         );
     }
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/XmlTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/XmlTest.php
similarity index 86%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/XmlTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/XmlTest.php
index 3d15878c33195e605e75c52939dc67c17e4bf3d5..2ccc135e4ffa7dfd4714c45cd48b92d0b5aad178 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/XmlTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/XmlTest.php
@@ -3,7 +3,7 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Tools\I18n\Test\Unit\Parser\Adapter;
+namespace Magento\Setup\Test\Unit\Module\I18n\Parser\Adapter;
 
 class XmlTest extends \PHPUnit_Framework_TestCase
 {
@@ -13,7 +13,7 @@ class XmlTest extends \PHPUnit_Framework_TestCase
     protected $_testFile;
 
     /**
-     * @var \Magento\Tools\I18n\Parser\Adapter\Xml
+     * @var \Magento\Setup\Module\I18n\Parser\Adapter\Xml
      */
     protected $_adapter;
 
@@ -22,7 +22,7 @@ class XmlTest extends \PHPUnit_Framework_TestCase
         $this->_testFile = str_replace('\\', '/', realpath(dirname(__FILE__))) . '/_files/default.xml';
 
         $objectManagerHelper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
-        $this->_adapter = $objectManagerHelper->getObject('Magento\Tools\I18n\Parser\Adapter\Xml');
+        $this->_adapter = $objectManagerHelper->getObject('Magento\Setup\Module\I18n\Parser\Adapter\Xml');
     }
 
     public function testParse()
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/_files/default.xml b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/default.xml
similarity index 100%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/_files/default.xml
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/default.xml
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/_files/file.js b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/file.js
similarity index 100%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/Adapter/_files/file.js
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/Adapter/_files/file.js
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/ParserTest.php b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/ParserTest.php
similarity index 90%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/Parser/ParserTest.php
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/ParserTest.php
index b7a6794b931c989ad12717bd6dce9baed2e85c33..5b03113a86248211a8c24a2910b57d142305a3b3 100644
--- a/dev/tools/Magento/Tools/I18n/Test/Unit/Parser/ParserTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Module/I18n/Parser/ParserTest.php
@@ -6,32 +6,32 @@
 
 // @codingStandardsIgnoreFile
 
-namespace Magento\Tools\I18n\Test\Unit\Parser;
+namespace Magento\Setup\Test\Unit\Module\I18n\Parser;
 
-use Magento\Tools\I18n\Parser as Parser;
+use Magento\Setup\Module\I18n\Parser as Parser;
 
 class ParserTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Tools\I18n\Parser\AbstractParser|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Setup\Module\I18n\Parser\AbstractParser|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $parser;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Tools\I18n\FilesCollector
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Setup\Module\I18n\FilesCollector
      */
     protected $filesCollector;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Tools\I18n\Factory
+     * @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Setup\Module\I18n\Factory
      */
     protected $factory;
 
 
     protected function setUp()
     {
-        $this->filesCollector = $this->getMock('Magento\Tools\I18n\FilesCollector');
-        $this->factory = $this->getMock('Magento\Tools\I18n\Factory');
+        $this->filesCollector = $this->getMock('Magento\Setup\Module\I18n\FilesCollector');
+        $this->factory = $this->getMock('Magento\Setup\Module\I18n\Factory');
 
         $this->parser = new Parser\Parser($this->filesCollector, $this->factory);
     }
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/_files/files_collector/default.xml b/setup/src/Magento/Setup/Test/Unit/Module/I18n/_files/files_collector/default.xml
similarity index 100%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/_files/files_collector/default.xml
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/_files/files_collector/default.xml
diff --git a/dev/tools/Magento/Tools/I18n/Test/Unit/_files/files_collector/file.js b/setup/src/Magento/Setup/Test/Unit/Module/I18n/_files/files_collector/file.js
similarity index 100%
rename from dev/tools/Magento/Tools/I18n/Test/Unit/_files/files_collector/file.js
rename to setup/src/Magento/Setup/Test/Unit/Module/I18n/_files/files_collector/file.js
diff --git a/setup/view/magento/setup/readiness-check/progress.phtml b/setup/view/magento/setup/readiness-check/progress.phtml
index 275d677b1c8795c019e4122da50dd8274a775de2..d247f60402d7bb0a46cdd36ecf4361f7c3f5d6aa 100644
--- a/setup/view/magento/setup/readiness-check/progress.phtml
+++ b/setup/view/magento/setup/readiness-check/progress.phtml
@@ -75,7 +75,7 @@
                     </a>
                 </p>
                 <p ng-show="version.expanded">
-                    Donwload and install PHP version {{version.data.required}} from <a href="http://www.php.net" target="_blank">www.php.net</a> using this <a href="http://www.php.net/docs.php" target="_blank">PHP Documentation</a>.
+                    Download and install PHP version {{version.data.required}} from <a href="http://www.php.net" target="_blank">www.php.net</a> using this <a href="http://www.php.net/docs.php" target="_blank">PHP Documentation</a>.
                 </p>
                 <p ng-show="version.expanded">If you need more help please call your hosting provider.</p>
             </div>
@@ -86,15 +86,15 @@
 
 </div>
 
-<div id="php-rawpost" class="rediness-check-item" ng-show="rawpost.visible">
+<div id="php-settings" class="rediness-check-item" ng-show="settings.visible">
 
-    <h3 class="readiness-check-title" ng-hide="version.processed">
+    <h3 class="readiness-check-title" ng-hide="settings.processed">
         Checking PHP Settings...
     </h3>
 
-    <div ng-show="rawpost.processed" ng-switch="rawpost.responseType">
+    <div ng-show="settings.processed" ng-switch="settings.responseType">
 
-        <div ng-switch-when="success" ng-init="updateOnSuccess(rawpost)">
+        <div ng-switch-when="success" ng-init="updateOnSuccess(settings)">
 
             <span class="readiness-check-icon icon-success-round"></span>
 
@@ -107,31 +107,22 @@
 
         </div>
 
-        <div class="readiness-check-item" ng-switch-default ng-init="updateOnError(rawpost)">
-
-            <div class="rediness-check-side">
-                <p class="side-title">Need Help?</p>
-                <a href="http://php.net/manual/en/ini.core.php#ini.always-populate-raw-post-data" target="_blank">PHP Documentation</a>
-            </div>
+        <div class="readiness-check-item" ng-switch-default ng-init="updateOnError(settings)">
 
             <span class="readiness-check-icon icon-failed-round"></span>
+            <h3 class="readiness-check-title">PHP Settings Check</h3>
 
-            <div class="readiness-check-content">
-                <h3 class="readiness-check-title">PHP Settings Check</h3>
-                <p>
-                    Your PHP Version is {{rawpost.data.version}}, but always_populate_raw_post_data = {{rawpost.data.ini}}.
-                    <a href="#php-rawpost" ng-click="updateOnExpand(rawpost)">
-                        <span ng-hide="rawpost.expanded">Show detail</span>
-                        <span ng-show="rawpost.expanded">Hide detail</span>
-                    </a>
-                </p>
-                <p ng-show="rawpost.expanded">
-                    $HTTP_RAW_POST_DATA is deprecated from PHP 5.6 onwards and will stop the installer from running.
-                    Please open your php.ini file and set always_populate_raw_post_data to -1.
-                </p>
-                <p ng-show="rawpost.expanded">If you need more help please call your hosting provider.</p>
+            <div ng-repeat="setting in settings.data">
+                <div ng-show="setting.error && setting.helpUrl" class="rediness-check-side">
+                    <p class="side-title">Need Help?</p>
+                    <a href="{{setting.helpUrl}}" target="_blank">PHP Documentation</a>
+                </div>
+                <div ng-show="setting.error" class="readiness-check-content">
+                    <p>
+                        {{setting.message}}
+                    </p>
+                </div>
             </div>
-
         </div>
 
     </div>