diff --git a/.travis.yml b/.travis.yml
index 900ffd8e62069a940fe271aeab4ce8d00b643b88..5aa3b310f5faf85ef65dec2f9647e6aa0c1d189f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -28,7 +28,7 @@ before_script:
   # Create DB for Integration tests
   - sh -c "if [ '$TEST_SUITE' = 'integration' ] || [ '$TEST_SUITE' = 'integration_integrity' ]; then mysql -e 'create database magento_integration_tests;'; mv dev/tests/integration/etc/local-mysql.travis.xml.dist dev/tests/integration/etc/local-mysql.xml; fi"
   # Install tools for static tests
-  - sh -c "if [ '$TEST_SUITE' = 'static_phpcs' ] || [ '$TEST_SUITE' = 'static_annotation' ]; then pear install pear/PHP_CodeSniffer-1.4.7; fi"
+  - sh -c "if [ '$TEST_SUITE' = 'static_phpcs' ] || [ '$TEST_SUITE' = 'static_annotation' ]; then pear install pear/PHP_CodeSniffer-1.5.2; fi"
   - phpenv rehash;
 script:
   # Unit tests
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 23ebdb30c7178609670777c48768322c328d892f..74d8042f568dc77ce7862a5c682ffa6a541e7f99 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,42 @@
+2.0.0.0-dev83
+=============
+* Created the Service API for the Magento_Catalog Module:
+   * Product Attribute Media API
+   * Product Group Price API
+* Tax calculation updates:
+  * Fixed tax calculation rounding issues which appeared when a discount was applied
+  * Fixed extra penny issue which appeared when exact tax amount ended with 0.5 cent
+  * Fixed tax calculation issues which appeared when a customer tax rate was different from the store tax rate
+  * Fixed price inconsistencies between catalog and shopping cart
+  * Added support for maintaining consistent prices including tax for customers with different tax rates
+  * Added support for applying tax rules with different priorities to be applied to subtotal only
+  * Added support for tax rounding at individual tax rate
+* Porting Tax Features from Magento 1.x:
+  * Price consistency UX and algorithm
+  * Canadian provincial sales taxes
+  * Fixed issues with bundle product price inconsistency across the system
+  * Added warnings if invalid tax configuration is created in the Admin panel
+  * Fixed issues with regards to hidden tax
+* Fixed bugs:
+  * Fixed an issue where grouped price was not applied for grouped products
+  * Fixed an issue where a fatal error occurred when opening a grouped product page without assigned products on the frontend
+  * Fixed an issue where it was possible to apply an inactive discount coupon
+  * Fixed an issue where the linked products information was lost when exporting products
+  * Fixed non-informative error messages for "Attribute Group Service"
+  * Fixed the invalid default value of the "apply_after_discount" tax setting
+  * Fixed an issue where the integration tests coverage whitelist was broken
+  * Fixed Admin panel UI issues: grids, headers and footers
+* Added the following functional tests:
+  * Create Product Url Rewrite
+  * Delete Catalog Price Rule
+  * Delete Category Url Rewrite
+  * Delete CMS Page Rewrite
+  * Delete Product Rating
+  * Delete Sales Rule
+  * Delete Tax Rate
+  * Update Catalog Price Rule
+  * Update Shopping Cart
+
 2.0.0.0-dev82
 =============
 * Added support for MTF Reporting Tool
diff --git a/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml b/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml
index 7c7dbf54fa7b43b3070ad20af536818a91e53a74..f54c5cc9f724c0aae45f4c9d62ac8a010b741e1e 100644
--- a/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml
+++ b/app/code/Magento/AdminNotification/view/adminhtml/layout/default.xml
@@ -30,7 +30,7 @@
         <block class="Magento\AdminNotification\Block\Window" name="notification_window" as="notification_window" acl="Magento_AdminNotification::show_toolbar" template="notification/window.phtml"/>
     </referenceContainer>
     <referenceContainer name="header">
-        <block class="Magento\AdminNotification\Block\ToolbarEntry" template="toolbar_entry.phtml" />
+        <block class="Magento\AdminNotification\Block\ToolbarEntry" before="user" template="toolbar_entry.phtml" />
     </referenceContainer>
     <referenceBlock name="head">
         <block class="Magento\Theme\Block\Html\Head\Script" name="magento-adminnotification-toolbar-entry-js" after="jquery-jquery-js">
diff --git a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
index 511001916c643ede7e24bb613cf7ee2a31b1100a..02ecf79e0bc6e1e97c938b8f77e4aa4b00b278be 100644
--- a/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
+++ b/app/code/Magento/Bundle/Block/Catalog/Product/View/Type/Bundle.php
@@ -24,12 +24,31 @@
 namespace Magento\Bundle\Block\Catalog\Product\View\Type;
 
 use Magento\Framework\Pricing\PriceCurrencyInterface;
+use Magento\Tax\Model\Calculation;
 
 /**
  * Catalog bundle product info block
  */
 class Bundle extends \Magento\Catalog\Block\Product\View\AbstractView
 {
+    /**
+     * constants for different rounding methods
+     */
+    const UNIT_ROUNDING = 0;
+    const ROW_ROUNDING = 1;
+    const TOTAL_ROUNDING = 2;
+
+    /**
+     * Mapping between constants in \Magento\Tax\Model\Calculation and this class
+     *
+     * @var array
+     */
+    protected $mapping = [
+        Calculation::CALC_UNIT_BASE => self::UNIT_ROUNDING,
+        Calculation::CALC_ROW_BASE => self::ROW_ROUNDING,
+        Calculation::CALC_TOTAL_BASE => self::TOTAL_ROUNDING,
+    ];
+
     /**
      * @var array
      */
@@ -305,4 +324,16 @@ class Bundle extends \Magento\Catalog\Block\Product\View\AbstractView
         }
         return $optionBlock->setOption($option)->toHtml();
     }
+
+    /**
+     * Return the rounding method based on tax calculation
+     * This is a workaround as the proper way is to always call tax service to get taxed price
+     *
+     * @return int
+     */
+    public function getRoundingMethod()
+    {
+        $algorithm = $this->_taxData->getCalculationAgorithm();
+        return isset($this->mapping[$algorithm]) ? $this->mapping[$algorithm] : self::TOTAL_ROUNDING;
+    }
 }
diff --git a/app/code/Magento/Bundle/Pricing/Adjustment/Calculator.php b/app/code/Magento/Bundle/Pricing/Adjustment/Calculator.php
index 0c32a23043f7aabb6ff8d2e971ade43e57ccf0c3..ac700c144f5744c488a603e4ea38d0da939a7eac 100644
--- a/app/code/Magento/Bundle/Pricing/Adjustment/Calculator.php
+++ b/app/code/Magento/Bundle/Pricing/Adjustment/Calculator.php
@@ -31,6 +31,9 @@ use Magento\Bundle\Pricing\Price\BundleSelectionFactory;
 use Magento\Framework\Pricing\Adjustment\Calculator as CalculatorBase;
 use Magento\Bundle\Model\Product\Price;
 use Magento\Bundle\Pricing\Price\BundleOptionPrice;
+use Magento\Tax\Model\Calculation as TaxCalculation;
+use Magento\Store\Model\Store;
+use Magento\Tax\Helper\Data as TaxHelper;
 
 /**
  * Bundle price calculator
@@ -52,20 +55,29 @@ class Calculator implements BundleCalculatorInterface
      */
     protected $selectionFactory;
 
+    /**
+     * Tax helper, needed to get rounding setting
+     *
+     * @var TaxHelper
+     */
+    protected $taxHelper;
     /**
      * @param CalculatorBase $calculator
      * @param AmountFactory $amountFactory
      * @param BundleSelectionFactory $bundleSelectionFactory
+     * @param TaxHelper $taxHelper
      * @return Calculator
      */
     public function __construct(
         CalculatorBase $calculator,
         AmountFactory $amountFactory,
-        BundleSelectionFactory $bundleSelectionFactory
+        BundleSelectionFactory $bundleSelectionFactory,
+        TaxHelper $taxHelper
     ) {
         $this->calculator = $calculator;
         $this->amountFactory = $amountFactory;
         $this->selectionFactory = $bundleSelectionFactory;
+        $this->taxHelper = $taxHelper;
     }
 
     /**
@@ -254,11 +266,24 @@ class Calculator implements BundleCalculatorInterface
         foreach ($selectionPriceList as $selectionPrice) {
             $amountList[] = $selectionPrice->getAmount();
         }
+        /** @var  Store $store */
+        $store = $bundleProduct->getStore();
+        $roundingMethod = $this->taxHelper->getCalculationAgorithm($store);
         /** @var \Magento\Framework\Pricing\Amount\AmountInterface $itemAmount */
         foreach ($amountList as $itemAmount) {
-            $fullAmount += $itemAmount->getValue();
-            foreach ($itemAmount->getAdjustmentAmounts() as $code => $adjustment) {
-                $adjustments[$code] = isset($adjustments[$code]) ? $adjustments[$code] + $adjustment : $adjustment;
+            if ($roundingMethod != TaxCalculation::CALC_TOTAL_BASE) {
+                //We need to round the individual selection first
+                $fullAmount += $store->roundPrice($itemAmount->getValue());
+                foreach ($itemAmount->getAdjustmentAmounts() as $code => $adjustment) {
+                    $adjustment = $store->roundPrice($adjustment);
+                    $adjustments[$code] = isset($adjustments[$code]) ? $adjustments[$code] + $adjustment : $adjustment;
+                }
+            } else {
+                $fullAmount += $itemAmount->getValue();
+                foreach ($itemAmount->getAdjustmentAmounts() as $code => $adjustment) {
+                    $adjustments[$code] = isset($adjustments[$code]) ? $adjustments[$code] + $adjustment : $adjustment;
+                }
+
             }
         }
         if ($exclude && isset($adjustments[$exclude])) {
diff --git a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle.phtml b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle.phtml
index c6fcace245b5db528c00c5d53c455ad3e6b1074a..29926a7a454c2502a7b9c8796fca41cb9601ba6d 100644
--- a/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle.phtml
+++ b/app/code/Magento/Bundle/view/frontend/templates/catalog/product/view/type/bundle.phtml
@@ -32,6 +32,7 @@
             $(document).ready(function() {
                 $('#product_addtocart_form').mage('bundleOption', {
                     "bundleConfig": <?php echo $this->getJsonConfig() ?>,
+                    "roundingMethod" : "<?php echo $this->getRoundingMethod() ?>",
                     "bundleOptionQtyPrefix": "#bundle-option-",
                     "bundleOptionQtySuffix": "-qty-input",
                     "priceSelectors": {
diff --git a/app/code/Magento/Bundle/view/frontend/web/bundle.js b/app/code/Magento/Bundle/view/frontend/web/bundle.js
index 4ac75e5ae6083585dff48cf70122164ed15bb78e..0310fe5aa0687b5822757ac0a4d5f3430f4e4787 100644
--- a/app/code/Magento/Bundle/view/frontend/web/bundle.js
+++ b/app/code/Magento/Bundle/view/frontend/web/bundle.js
@@ -251,6 +251,10 @@
         },
 
         selectionPrice: function(optionId, selectionId) {
+            //Those constants need to be in sync with Magento\Bundle\Block\Catalog\Product\View\Type\Bundle
+            var TOTAL_ROUNDING = 2;
+            var ROW_ROUNDING = 1;
+            var UNIT_ROUNDING = 0;
             var qty = null,
                 config = this.options.bundleConfig,
                 configOption = config.options[optionId];
@@ -281,7 +285,19 @@
                 });
             }
 
-            return [price * qty, exclTaxPrice * qty, inclTaxPrice * qty];
+            if (this.options.bundleConfig.isFixedPrice || this.options.roundingMethod == TOTAL_ROUNDING) {
+                return [price * qty, exclTaxPrice * qty, inclTaxPrice * qty];
+            } else if (this.options.roundingMethod == UNIT_ROUNDING) {
+                price = Math.round(price * 100) / 100;
+                exclTaxPrice = Math.round(exclTaxPrice * 100) / 100;
+                inclTaxPrice = Math.round(inclTaxPrice * 100) / 100;
+                return [price * qty, exclTaxPrice * qty, inclTaxPrice * qty];
+            } else {
+                var rowTotal = Math.round(price * qty * 100) /100;
+                var rowTotalExclTax = Math.round(exclTaxPrice * qty * 100) /100;
+                var rowTotalInclTax = Math.round(inclTaxPrice * qty * 100) /100;
+                return [rowTotal, rowTotalExclTax, rowTotalInclTax];
+            }
         },
 
         populateQty: function(optionId, selectionId) {
diff --git a/app/code/Magento/Catalog/Block/Product/View.php b/app/code/Magento/Catalog/Block/Product/View.php
index 546eaa128f4c1742bec617e0d6171d25347ce3a9..031273808fa6bf81a497a3e3829ca3fc637798ad 100644
--- a/app/code/Magento/Catalog/Block/Product/View.php
+++ b/app/code/Magento/Catalog/Block/Product/View.php
@@ -236,7 +236,7 @@ class View extends AbstractProduct implements \Magento\Framework\View\Block\Iden
             return $this->_jsonEncoder->encode($config);
         }
 
-        $request = $this->_taxCalculation->getRateRequest(false, false, false);
+        $request = $this->_taxCalculation->getDefaultRateRequest();
         /* @var $product \Magento\Catalog\Model\Product */
         $product = $this->getProduct();
         $request->setProductClassId($product->getTaxClassId());
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Groupprice/AbstractGroupprice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Groupprice/AbstractGroupprice.php
index 93e54cbbd9e723ea27a957f29f2b7479c8d9380b..8f726dfda1b6db7c6d0f8cf6f8910d20fbab7fb3 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Groupprice/AbstractGroupprice.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Groupprice/AbstractGroupprice.php
@@ -169,6 +169,11 @@ abstract class AbstractGroupprice extends Price
             if (isset($duplicates[$compare])) {
                 throw new \Magento\Framework\Model\Exception($this->_getDuplicateErrorMessage());
             }
+
+            if (!preg_match('/^\d*(\.|,)?\d{0,4}$/i', $priceRow['price']) || $priceRow['price'] < 0) {
+                return __('Group price must be a number greater than 0.');
+            }
+
             $duplicates[$compare] = true;
         }
 
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php
index a6b2cd70383d98c4f2a7ee9df06cf4227eac4967..3f007f47d416f3d5d642621a7759d24b6b1193d9 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Media.php
@@ -346,6 +346,7 @@ class Media extends \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
 
         $this->_getResource()->deleteGallery($recordsToDelete);
         $this->removeDeletedImages($filesToDelete);
+        $object->setData($attrCode, $value);
     }
 
     /**
diff --git a/app/code/Magento/Catalog/Model/Product/PriceModifier.php b/app/code/Magento/Catalog/Model/Product/PriceModifier.php
new file mode 100644
index 0000000000000000000000000000000000000000..01373135fa1038be0c3783fcd69104279650e211
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/Product/PriceModifier.php
@@ -0,0 +1,109 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Framework\Exception\CouldNotSaveException;
+
+class PriceModifier
+{
+    /**
+     * @param \Magento\Catalog\Model\Product $product
+     * @param int $customerGroupId
+     * @param int $websiteId
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\CouldNotSaveException
+     * @return void
+     */
+    public function removeGroupPrice(\Magento\Catalog\Model\Product $product, $customerGroupId, $websiteId)
+    {
+        $prices = $product->getData('group_price');
+        if (is_null($prices)) {
+            throw new NoSuchEntityException("This product doesn't have group price");
+        }
+        $groupPriceQty = count($prices);
+
+        foreach ($prices as $key => $groupPrice) {
+            if ($groupPrice['cust_group'] == $customerGroupId
+                && intval($groupPrice['website_id']) === intval($websiteId)) {
+                unset ($prices[$key]);
+            }
+        }
+        if ($groupPriceQty == count($prices)) {
+            throw new NoSuchEntityException(
+                "Product hasn't group price with such data: customerGroupId = '$customerGroupId',"
+                . "website = $websiteId."
+            );
+        }
+        $product->setData('group_price', $prices);
+        try {
+            $product->save();
+        } catch (\Exception $exception) {
+            throw new CouldNotSaveException("Invalid data provided for group price");
+        }
+    }
+
+    /**
+     * @param \Magento\Catalog\Model\Product $product
+     * @param int|string $customerGroupId
+     * @param int $qty
+     * @param int $websiteId
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\CouldNotSaveException
+     * @return void
+     */
+    public function removeTierPrice(\Magento\Catalog\Model\Product $product, $customerGroupId, $qty, $websiteId)
+    {
+        $prices = $product->getData('tier_price');
+        // verify if price exist
+        if (is_null($prices)) {
+            throw new NoSuchEntityException("This product doesn't have tier price");
+        }
+        $tierPricesQty = count($prices);
+
+        foreach ($prices as $key => $tierPrice) {
+            if ($customerGroupId == 'all' && $tierPrice['price_qty'] == $qty
+                && $tierPrice['all_groups'] == 1 && intval($tierPrice['website_id']) === intval($websiteId)) {
+                unset ($prices[$key]);
+            } elseif ($tierPrice['price_qty'] == $qty && $tierPrice['cust_group'] == $customerGroupId
+                && intval($tierPrice['website_id']) === intval($websiteId)) {
+                unset ($prices[$key]);
+            }
+        }
+
+        if ($tierPricesQty == count($prices)) {
+            throw new NoSuchEntityException(
+                "Product hasn't group price with such data: customerGroupId = '$customerGroupId',"
+                . "website = $websiteId, qty = $qty"
+            );
+        }
+        $product->setData('tier_price', $prices);
+        try {
+            $product->save();
+        } catch (\Exception $exception) {
+            throw new CouldNotSaveException("Invalid data provided for tier_price");
+        }
+    }
+}
diff --git a/app/code/Magento/Catalog/Model/ProductRepository.php b/app/code/Magento/Catalog/Model/ProductRepository.php
new file mode 100644
index 0000000000000000000000000000000000000000..8dc31bb44c1bf020747e3879ca223e22dca0d223
--- /dev/null
+++ b/app/code/Magento/Catalog/Model/ProductRepository.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Model;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+
+class ProductRepository
+{
+    /**
+     * @var ProductFactory
+     */
+    protected $productFactory;
+
+    /**
+     * @var Product[]
+     */
+    protected $instances = array();
+
+    /**
+     * @param ProductFactory $productFactory
+     */
+    public function __construct(ProductFactory $productFactory)
+    {
+        $this->productFactory = $productFactory;
+    }
+
+    /**
+     * Retrieve product instance by sku
+     *
+     * @param string $sku
+     * @param boolean $editMode
+     * @return Product
+     * @throws NoSuchEntityException
+     */
+    public function get($sku, $editMode = false)
+    {
+        if (!isset($this->instances[$sku])) {
+            $product = $this->productFactory->create();
+            $productId = $product->getIdBySku($sku);
+            if (!$productId) {
+                throw new NoSuchEntityException('Requested product doesn\'t exist');
+            }
+            if ($editMode) {
+                $product->setData('_edit_mode', true);
+            }
+            $product->load($productId);
+            $this->instances[$sku] = $product;
+        }
+        return $this->instances[$sku];
+    }
+}
diff --git a/app/code/Magento/Catalog/Pricing/Price/GroupPrice.php b/app/code/Magento/Catalog/Pricing/Price/GroupPrice.php
index 9fcec9c00de511f86bceabfb232a4a91d3e59ce7..626f76151d28ec16bbbb1229be13a3f7e785f36a 100644
--- a/app/code/Magento/Catalog/Pricing/Price/GroupPrice.php
+++ b/app/code/Magento/Catalog/Pricing/Price/GroupPrice.php
@@ -100,21 +100,16 @@ class GroupPrice extends AbstractPrice implements GroupPriceInterface, BasePrice
      */
     public function getStoredGroupPrice()
     {
-        if (null !== $this->storedGroupPrice) {
-            return $this->storedGroupPrice;
-        }
-
-        $this->storedGroupPrice = $this->product->getData('group_price');
-
         if (null === $this->storedGroupPrice) {
-            $attribute = $this->product->getResource()->getAttribute('group_price');
+            $resource = $this->product->getResource();
+            $attribute =  $resource->getAttribute('group_price');
             if ($attribute) {
                 $attribute->getBackend()->afterLoad($this->product);
                 $this->storedGroupPrice = $this->product->getData('group_price');
             }
-        }
-        if (null === $this->storedGroupPrice || !is_array($this->storedGroupPrice)) {
-            $this->storedGroupPrice = [];
+            if (null === $this->storedGroupPrice || !is_array($this->storedGroupPrice)) {
+                $this->storedGroupPrice = [];
+            }
         }
         return $this->storedGroupPrice;
     }
diff --git a/app/code/Magento/Catalog/Service/V1/Data/Product/GroupPrice.php b/app/code/Magento/Catalog/Service/V1/Data/Product/GroupPrice.php
new file mode 100644
index 0000000000000000000000000000000000000000..83e8212c9e919061dd54b1cad2d5474790b336ec
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Data/Product/GroupPrice.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Data\Product;
+
+use Magento\Framework\Service\Data\AbstractObject;
+
+class GroupPrice extends AbstractObject
+{
+    const CUSTOMER_GROUP_ID = 'customer_group_id';
+    const VALUE = 'value';
+
+    /**
+     * Retrieve customer group id
+     *
+     * @return int
+     */
+    public function getCustomerGroupId()
+    {
+        return $this->_get(self::CUSTOMER_GROUP_ID);
+    }
+
+    /**
+     * Retrieve price value
+     *
+     * @return float
+     */
+    public function getValue()
+    {
+        return $this->_get(self::VALUE);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Data/Product/GroupPriceBuilder.php b/app/code/Magento/Catalog/Service/V1/Data/Product/GroupPriceBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..3210e1dc84f71da1488fdccd3c7ccf7874f98a09
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Data/Product/GroupPriceBuilder.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Data\Product;
+
+use Magento\Framework\Service\Data\AbstractObjectBuilder;
+
+class GroupPriceBuilder extends AbstractObjectBuilder
+{
+    /**
+     * Set customer group id
+     *
+     * @param int $customerGroupId
+     * @return $this
+     */
+    public function setCustomerGroupId($customerGroupId)
+    {
+        $this->_set(GroupPrice::CUSTOMER_GROUP_ID, $customerGroupId);
+        return $this;
+    }
+
+    /**
+     * Set price value
+     *
+     * @param float $value
+     * @return $this
+     */
+    public function setValue($value)
+    {
+        $this->_set(GroupPrice::VALUE, $value);
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Data/Product/TierPrice.php b/app/code/Magento/Catalog/Service/V1/Data/Product/TierPrice.php
new file mode 100644
index 0000000000000000000000000000000000000000..75e554ed306e3a39797d449a7f684cfe759b0d63
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Data/Product/TierPrice.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Data\Product;
+
+use Magento\Framework\Service\Data\AbstractObject;
+
+class TierPrice extends AbstractObject
+{
+    const QTY = 'qty';
+
+    const VALUE = 'value';
+
+    /**
+     * Retrieve tier qty
+     *
+     * @return float
+     */
+    public function getQty()
+    {
+        return $this->_get(self::QTY);
+    }
+
+    /**
+     * Retrieve price value
+     *
+     * @return float
+     */
+    public function getValue()
+    {
+        return $this->_get(self::VALUE);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Data/Product/TierPriceBuilder.php b/app/code/Magento/Catalog/Service/V1/Data/Product/TierPriceBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..4903056618bd1f070c711a392589b8c0d400f6e8
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Data/Product/TierPriceBuilder.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Data\Product;
+
+use Magento\Framework\Service\Data\AbstractObjectBuilder;
+
+class TierPriceBuilder extends AbstractObjectBuilder
+{
+    /**
+     * Set Quantity
+     *
+     * @param float $qty
+     * @return $this
+     */
+    public function setQty($qty)
+    {
+        $this->_set(TierPrice::QTY, $qty);
+        return $this;
+    }
+
+    /**
+     * Set Value
+     *
+     * @param float $value
+     * @return $this
+     */
+    public function setValue($value)
+    {
+        $this->_set(TierPrice::VALUE, $value);
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntry.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntry.php
new file mode 100644
index 0000000000000000000000000000000000000000..489990c592608f6c226c5f7dfdbc2ccfc28d9e22
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntry.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Product Media Attribute
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media\Data;
+
+use \Magento\Framework\Service\Data\AbstractObject;
+
+class GalleryEntry extends AbstractObject
+{
+    const ID = 'id';
+    const LABEL = 'label';
+    const POSITION = 'position';
+    const DISABLED = 'disabled';
+    const TYPES = 'types';
+    const FILE = 'file';
+
+    /**
+     * Retrieve gallery entry ID
+     *
+     * @return int|null
+     */
+    public function getId()
+    {
+        return $this->_get(self::ID);
+    }
+
+    /**
+     * Retrieve gallery entry alternative text
+     *
+     * @return string|null
+     */
+    public function getLabel()
+    {
+        return $this->_get(self::LABEL);
+    }
+
+    /**
+     * Retrieve gallery entry position (sort order)
+     *
+     * @return int
+     */
+    public function getPosition()
+    {
+        return $this->_get(self::POSITION);
+    }
+
+    /**
+     * Check if gallery entry is hidden from product page
+     *
+     * @return bool
+     */
+    public function isDisabled()
+    {
+        return $this->_get(self::DISABLED);
+    }
+
+    /**
+     * Retrieve gallery entry image types (thumbnail, image, small_image etc)
+     *
+     * @return string[]|null
+     */
+    public function getTypes()
+    {
+        return $this->_get(self::TYPES);
+    }
+
+    /**
+     * Get file path
+     *
+     * @return string|null
+     */
+    public function getFile()
+    {
+        return $this->_get(self::FILE);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryBuilder.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..b613592fe078053de3d7bf5d81ac1d0d9699705e
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryBuilder.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * Builder for media attribute
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media\Data;
+
+use Magento\Framework\Service\Data\AbstractObjectBuilder;
+
+class GalleryEntryBuilder extends AbstractObjectBuilder
+{
+    /**
+     * Set gallery entity ID
+     *
+     * @param int $entityId
+     * @return $this
+     */
+    public function setId($entityId)
+    {
+        return $this->_set(GalleryEntry::ID, $entityId);
+    }
+
+    /**
+     * Set media alternative text
+     *
+     * @param string $label
+     * @return $this
+     */
+    public function setLabel($label)
+    {
+        return $this->_set(GalleryEntry::LABEL, $label);
+    }
+
+    /**
+     * Set gallery entity position (sort order)
+     *
+     * @param int $position
+     * @return $this
+     */
+    public function setPosition($position)
+    {
+        return $this->_set(GalleryEntry::POSITION, $position);
+    }
+
+    /**
+     * Set disabled flag that shows if gallery entity is hidden from product page
+     *
+     * @param bool $isDisabled
+     * @return $this
+     */
+    public function setDisabled($isDisabled)
+    {
+        return $this->_set(GalleryEntry::DISABLED, $isDisabled);
+    }
+
+    /**
+     * Set gallery entry types (thumbnail, image, small_image etc)
+     *
+     * @param array $roles
+     * @return $this
+     */
+    public function setTypes(array $roles)
+    {
+        return $this->_set(GalleryEntry::TYPES, $roles);
+    }
+
+    /**
+     * Set file path
+     *
+     * @param string $file
+     * @return $this
+     */
+    public function setFile($file)
+    {
+        return $this->_set(GalleryEntry::FILE, $file);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContent.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContent.php
new file mode 100644
index 0000000000000000000000000000000000000000..87777694aa15db1ada8636cc787f8c958a6c89ab
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContent.php
@@ -0,0 +1,65 @@
+<?php
+/**
+ * Product Media Content
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media\Data;
+
+use \Magento\Framework\Service\Data\AbstractObject;
+
+class GalleryEntryContent extends AbstractObject
+{
+    const DATA = 'data';
+    const MIME_TYPE = 'mime_type';
+    const NAME = 'name';
+
+    /**
+     * Retrieve media data (base64 encoded content)
+     *
+     * @return string
+     */
+    public function getData()
+    {
+        return $this->_get(self::DATA);
+    }
+
+    /**
+     * Retrieve MIME type
+     *
+     * @return string
+     */
+    public function getMimeType()
+    {
+        return $this->_get(self::MIME_TYPE);
+    }
+
+    /**
+     * Retrieve image name
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->_get(self::NAME);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContentBuilder.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContentBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..16ee223a7ac95fad837a9b0c9167d4399c9a1307
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContentBuilder.php
@@ -0,0 +1,64 @@
+<?php
+/**
+ * Product Media Content Builder
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media\Data;
+
+use Magento\Framework\Service\Data\AbstractObjectBuilder;
+
+class GalleryEntryContentBuilder extends AbstractObjectBuilder
+{
+    /**
+     * Set media data (base64 encoded content)
+     *
+     * @param string $data
+     * @return $this
+     */
+    public function setData($data)
+    {
+        return $this->_set(GalleryEntryContent::DATA, $data);
+    }
+
+    /**
+     * Set MIME type
+     *
+     * @param string $mimeType
+     * @return $this
+     */
+    public function setMimeType($mimeType)
+    {
+        return $this->_set(GalleryEntryContent::MIME_TYPE, $mimeType);
+    }
+
+    /**
+     * Set image name (without extension)
+     *
+     * @param string $name
+     * @return $this
+     */
+    public function setName($name)
+    {
+        return $this->_set(GalleryEntryContent::NAME, $name);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContentValidator.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContentValidator.php
new file mode 100644
index 0000000000000000000000000000000000000000..170b53b0aee02ccd6b7831d964827e755862b7ba
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContentValidator.php
@@ -0,0 +1,108 @@
+<?php
+/**
+ * Product Media Content Validator
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media\Data;
+
+use \Magento\Framework\Exception\InputException;
+
+class GalleryEntryContentValidator
+{
+    /**
+     * @var array
+     */
+    private $defaultMimeTypes = array(
+        'image/jpg',
+        'image/jpeg',
+        'image/gif',
+        'image/png',
+    );
+
+    /**
+     * @var array
+     */
+    private $allowedMimeTypes;
+
+    /**
+     * @param array $allowedMimeTypes
+     */
+    public function __construct(
+        array $allowedMimeTypes = array()
+    ) {
+        $this->allowedMimeTypes = array_merge($this->defaultMimeTypes, $allowedMimeTypes);
+    }
+
+    /**
+     * Check if gallery entry content is valid
+     *
+     * @param GalleryEntryContent $entryContent
+     * @return bool
+     * @throws InputException
+     */
+    public function isValid(GalleryEntryContent $entryContent)
+    {
+        $fileContent = @base64_decode($entryContent->getData(), true);
+        if (empty($fileContent)) {
+            throw new InputException('The image content must be valid base64 encoded data.');
+        }
+        $imageProperties = @getimagesizefromstring($fileContent);
+        if (empty($imageProperties)) {
+            throw new InputException('The image content must be valid base64 encoded data.');
+        }
+        $sourceMimeType = $imageProperties['mime'];
+        if ($sourceMimeType != $entryContent->getMimeType() || !$this->isMimeTypeValid($sourceMimeType)) {
+            throw new InputException('The image MIME type is not valid or not supported.');
+        }
+        if (!$this->isNameValid($entryContent->getName())) {
+            throw new InputException('Provided image name contains forbidden characters.');
+        }
+        return true;
+    }
+
+    /**
+     * Check if given mime type is valid
+     *
+     * @param string $mimeType
+     * @return bool
+     */
+    protected function isMimeTypeValid($mimeType)
+    {
+        return in_array($mimeType, $this->allowedMimeTypes);
+    }
+
+    /**
+     * Check if given filename is valid
+     *
+     * @param string $name
+     * @return bool
+     */
+    protected function isNameValid($name)
+    {
+        // Cannot contain \ / : * ? " < > |
+        if (!preg_match('/^[^\\/?*:";<>()|{}\\\\]+$/', $name)) {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/MediaImage.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/MediaImage.php
new file mode 100644
index 0000000000000000000000000000000000000000..6b4769a693e64290186b16c9628e08371f8fb3db
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/MediaImage.php
@@ -0,0 +1,78 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media\Data;
+
+/**
+ * Contains media_image attribute info
+ */
+class MediaImage extends \Magento\Framework\Service\Data\AbstractObject
+{
+    const CODE = 'code';
+
+    const SCOPE = 'scope';
+
+    const LABEL = 'frontend_label';
+
+    const IS_USER_DEFINED = 'is_user_defined';
+
+    /**
+     * attribute code
+     *
+     * @return string
+     */
+    public function getCode()
+    {
+        return $this->_get(self::CODE);
+    }
+
+    /**
+     * Return values are 'Global', 'Website' or 'Store View'
+     *
+     * @return string
+     */
+    public function getScope()
+    {
+        return $this->_get(self::SCOPE);
+    }
+
+    /**
+     * Frontend label for attribute
+     *
+     * @return string
+     */
+    public function getFrontendLabel()
+    {
+        return $this->_get(self::LABEL);
+    }
+
+    /**
+     * User defined or system attribute
+     *
+     * @return int 0 or 1
+     */
+    public function getIsUserDefined()
+    {
+        return (int)(bool)$this->_get(self::IS_USER_DEFINED);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/MediaImageBuilder.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/MediaImageBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..3689228c4731a281708db43d85c21a2aeabe2a13
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/MediaImageBuilder.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media\Data;
+
+/**
+ * Builder for media_image
+ */
+class MediaImageBuilder extends \Magento\Framework\Service\Data\AbstractObjectBuilder
+{
+    /**
+     * Set attribute code
+     *
+     * @param string $code
+     * @return $this
+     */
+    public function setCode($code)
+    {
+        return $this->_set(MediaImage::CODE, $code);
+    }
+
+    /**
+     * Set attribute frontend label
+     *
+     * @param string $label
+     * @return $this
+     */
+    public function setFrontendLabel($label)
+    {
+        return $this->_set(MediaImage::LABEL, $label);
+    }
+
+    /**
+     * Set attribute scope. Valid values are 'Global', 'Website' and 'Store View'
+     *
+     * @param string $scope
+     * @return $this
+     */
+    public function setScope($scope)
+    {
+        return $this->_set(MediaImage::SCOPE, $scope);
+    }
+
+    /**
+     * Set true for user attributes or false for system attributes
+     *
+     * @param bool $isUserDefined
+     * @return $this
+     */
+    public function setIsUserDefined($isUserDefined)
+    {
+        return $this->_set(MediaImage::IS_USER_DEFINED, $isUserDefined);
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/GalleryEntryResolver.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/GalleryEntryResolver.php
new file mode 100644
index 0000000000000000000000000000000000000000..95cea9d34bce06f66cb14b37cc6259468376c45a
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/GalleryEntryResolver.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Product Media Gallery Entry Resolver
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media;
+
+use \Magento\Catalog\Model\Product;
+
+class GalleryEntryResolver
+{
+    /**
+     * Retrieve file path that corresponds to the given gallery entry ID
+     *
+     * @param Product $product
+     * @param int $entryId
+     * @return string|null
+     */
+    public function getEntryFilePathById(Product $product, $entryId)
+    {
+        $mediaGalleryData = $product->getData('media_gallery');
+        if (!isset($mediaGalleryData['images']) || !is_array($mediaGalleryData['images'])) {
+            return null;
+        }
+
+        foreach ($mediaGalleryData['images'] as $image) {
+            if (isset($image['value_id']) && $image['value_id'] == $entryId) {
+                return isset($image['file']) ? $image['file'] : null;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Retrieve gallery entry ID that corresponds to the given file path
+     *
+     * @param Product $product
+     * @param string $filePath
+     * @return int|null
+     */
+    public function getEntryIdByFilePath(Product $product, $filePath)
+    {
+        $mediaGalleryData = $product->getData('media_gallery');
+        if (!isset($mediaGalleryData['images']) || !is_array($mediaGalleryData['images'])) {
+            return null;
+        }
+
+        foreach ($mediaGalleryData['images'] as $image) {
+            if (isset($image['file']) && $image['file'] == $filePath) {
+                return isset($image['value_id']) ? $image['value_id'] : null;
+            }
+        }
+        return null;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/ReadService.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/ReadService.php
new file mode 100644
index 0000000000000000000000000000000000000000..22794baae06cc76865a54cb6fd83001c50bc3567
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/ReadService.php
@@ -0,0 +1,242 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media;
+
+use Magento\Catalog\Service\V1\Product\Attribute\Media\Data\MediaImageBuilder;
+use Magento\Framework\Exception\NoSuchEntityException;
+use Magento\Framework\Exception\InputException;
+use Magento\Framework\Exception\StateException;
+use \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntryBuilder;
+use \Magento\Catalog\Model\Product;
+
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class ReadService implements ReadServiceInterface
+{
+    /**
+     * @var \Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory
+     */
+    protected $collectionFactory;
+
+    /**
+     * @var \Magento\Eav\Model\Entity\Attribute\SetFactory
+     */
+    protected $setFactory;
+
+    /** @var \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\MediaImageBuilder */
+    protected $builder;
+
+    /**
+     * @var \Magento\Eav\Model\Config
+     */
+    protected $eavConfig;
+
+    /**
+     * @var \Magento\Catalog\Model\ProductRepository
+     */
+    protected $productRepository;
+
+    /**
+     * @var GalleryEntryBuilder
+     */
+    protected $galleryEntryBuilder;
+    
+    /**
+     * @var \Magento\Catalog\Model\Resource\Product\Attribute\Backend\Media
+     */
+    protected $mediaGallery;
+
+    /**
+     * @var \Magento\Catalog\Model\Resource\Eav\AttributeFactory
+     */
+    protected $attributeFactory;
+
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface
+     */
+    protected $storeManager;
+
+    /**
+     * @param \Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory $collectionFactory
+     * @param \Magento\Eav\Model\Entity\Attribute\SetFactory $setFactory
+     * @param \Magento\Eav\Model\Config $eavConfig
+     * @param \Magento\Catalog\Model\Resource\Product\Attribute\Backend\Media $mediaGallery
+     * @param \Magento\Catalog\Model\Resource\Eav\AttributeFactory $attributeFactory
+     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
+     * @param MediaImageBuilder $mediaImageBuilder
+     * @param \Magento\Catalog\Model\ProductRepository $productRepository
+     * @param GalleryEntryBuilder $galleryEntryBuilder
+     */
+    public function __construct(
+        \Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory $collectionFactory,
+        \Magento\Eav\Model\Entity\Attribute\SetFactory $setFactory,
+        \Magento\Eav\Model\Config $eavConfig,
+        \Magento\Catalog\Model\Resource\Product\Attribute\Backend\Media $mediaGallery,
+        \Magento\Catalog\Model\Resource\Eav\AttributeFactory $attributeFactory,
+        \Magento\Store\Model\StoreManagerInterface $storeManager,
+        MediaImageBuilder $mediaImageBuilder,
+        \Magento\Catalog\Model\ProductRepository $productRepository,
+        GalleryEntryBuilder $galleryEntryBuilder
+    ) {
+        $this->collectionFactory = $collectionFactory;
+        $this->setFactory = $setFactory;
+        $this->eavConfig = $eavConfig;
+        $this->mediaGallery = $mediaGallery;
+        $this->attributeFactory = $attributeFactory;
+        $this->storeManager = $storeManager;
+        $this->builder = $mediaImageBuilder;
+        $this->productRepository = $productRepository;
+        $this->galleryEntryBuilder = $galleryEntryBuilder;
+    }
+
+    /**
+     * Convert data from array to data object
+     *
+     * @param \Magento\Catalog\Model\Resource\Eav\Attribute[] $items
+     * @return array|\Magento\Catalog\Model\Resource\Eav\Attribute[]
+     * @throws \Magento\Framework\Exception\StateException
+     */
+    protected function prepareData($items)
+    {
+        $data = [];
+        /** @var \Magento\Catalog\Model\Resource\Eav\Attribute $attribute */
+        foreach ($items as $attribute) {
+            $this->builder->setFrontendLabel($attribute->getStoreLabel());
+            $this->builder->setCode($attribute->getData('attribute_code'));
+            $this->builder->setIsUserDefined($attribute->getData('is_user_defined'));
+            if ($attribute->getIsGlobal()) {
+                $scope = 'Global';
+            } elseif ($attribute->isScopeWebsite()) {
+                $scope = 'Website';
+            } elseif ($attribute->isScopeStore()) {
+                $scope = 'Store View';
+            } else {
+                throw new StateException('Attribute has invalid scope. Id = ' . $attribute->getId());
+            }
+            $this->builder->setScope($scope);
+            $data[] = $this->builder->create();
+        }
+        return $data;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function types($attributeSetId)
+    {
+        $attributeSet = $this->setFactory->create()->load($attributeSetId);
+        if (!$attributeSet->getId()) {
+            throw NoSuchEntityException::singleField('attribute_set_id', $attributeSetId);
+        }
+
+        $productEntityId = $this->eavConfig->getEntityType(\Magento\Catalog\Model\Product::ENTITY)->getId();
+        if ($attributeSet->getEntityTypeId() != $productEntityId) {
+            throw InputException::invalidFieldValue('entity_type_id', $attributeSetId);
+        }
+
+        $collection = $this->collectionFactory->create();
+        $collection->setAttributeSetFilter($attributeSetId);
+        $collection->setFrontendInputTypeFilter('media_image');
+        $collection->addStoreLabel($this->storeManager->getStore()->getId());
+
+        return $this->prepareData($collection->getItems());
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getList($productSku)
+    {
+        $result = array();
+        /** @var \Magento\Catalog\Model\Product $product */
+        $product = $this->productRepository->get($productSku);
+
+        $galleryAttribute = $this->attributeFactory->create()->loadByCode(
+            $this->eavConfig->getEntityType(\Magento\Catalog\Model\Product::ENTITY),
+            'media_gallery'
+        );
+
+        $container = new \Magento\Framework\Object(array('attribute' => $galleryAttribute));
+        $gallery = $this->mediaGallery->loadGallery($product, $container);
+
+        $productImages = $this->getMediaAttributeValues($product);
+
+        foreach ($gallery as $image) {
+            $this->galleryEntryBuilder->setId($image['value_id']);
+            $this->galleryEntryBuilder->setLabel($image['label_default']);
+            $this->galleryEntryBuilder->setTypes(array_keys($productImages, $image['file']));
+            $this->galleryEntryBuilder->setDisabled($image['disabled_default']);
+            $this->galleryEntryBuilder->setPosition($image['position_default']);
+            $this->galleryEntryBuilder->setFile($image['file']);
+            $result[] = $this->galleryEntryBuilder->create();
+        }
+        return $result;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function info($productSku, $imageId)
+    {
+        try {
+            $product = $this->productRepository->get($productSku);
+        } catch (\Exception $exception) {
+            throw new NoSuchEntityException("Such product doesn't exist");
+        }
+
+        $output = null;
+        $productImages = $this->getMediaAttributeValues($product);
+        foreach ((array)$product->getMediaGallery('images') as $image) {
+            if (intval($image['value_id']) == intval($imageId)) {
+                $image['types'] = array_keys($productImages, $image['file']);
+                $output = $this->galleryEntryBuilder->populateWithArray($image)->create();
+                break;
+            }
+        }
+
+        if (is_null($output)) {
+            throw new NoSuchEntityException("Such image doesn't exist");
+        }
+        return $output;
+    }
+
+    /**
+     * Retrieve assoc array that contains media attribute values of the given product
+     *
+     * @param Product $product
+     * @return array
+     */
+    protected function getMediaAttributeValues(Product $product)
+    {
+        $mediaAttributeCodes = array_keys($product->getMediaAttributes());
+        $mediaAttributeValues = array();
+        foreach ($mediaAttributeCodes as $attributeCode) {
+            $mediaAttributeValues[$attributeCode] = $product->getData($attributeCode);
+        }
+        return $mediaAttributeValues;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/ReadServiceInterface.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/ReadServiceInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..020e95b2e2a4896dc722e4f4d0d4af63b4eb4cc6
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/ReadServiceInterface.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media;
+
+interface ReadServiceInterface
+{
+    /**
+     * Return all media attributes for pointed attribute set
+     *
+     * @param int $attributeSetId
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\InputException
+     * @return \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\MediaImage[]
+     */
+    public function types($attributeSetId);
+
+    /**
+     * @param string $productSku
+     * @return \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntry[]
+     */
+    public function getList($productSku);
+
+    /**
+     * Return information about gallery entity
+     *
+     * @param string $productSku
+     * @param int $imageId
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @return \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntry
+     */
+    public function info($productSku, $imageId);
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/WriteService.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/WriteService.php
new file mode 100644
index 0000000000000000000000000000000000000000..0c80699b6dd34e83229f698a99fe6b4d00dccdcb
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/WriteService.php
@@ -0,0 +1,225 @@
+<?php
+/**
+ * Product Media Attribute
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media;
+
+use \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntry;
+use \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntryContent;
+use \Magento\Framework\App\Filesystem;
+use \Magento\Catalog\Service\V1\Product\ProductLoader;
+use \Magento\Catalog\Model\Product\Media\Config as MediaConfig;
+use \Magento\Catalog\Model\Product;
+use \Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
+use \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntryContentValidator;
+use \Magento\Store\Model\StoreFactory;
+use \Magento\Framework\Exception\InputException;
+use \Magento\Framework\Exception\StateException;
+use \Magento\Framework\Exception\NoSuchEntityException;
+
+/**
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class WriteService implements WriteServiceInterface
+{
+    /**
+     * MIME type/extension map
+     *
+     * @var array
+     */
+    private $mimeTypeExtensionMap = array(
+        'image/jpg' => 'jpg',
+        'image/jpeg' => 'jpg',
+        'image/gif' => 'gif',
+        'image/png' => 'png',
+    );
+
+    /**
+     * @var GalleryEntryContentValidator
+     */
+    private $contentValidator;
+
+    /**
+     * @var Filesystem
+     */
+    private $filesystem;
+
+    /**
+     * @var MediaConfig
+     */
+    private $mediaConfig;
+
+    /**
+     * @var ProductLoader
+     */
+    private $productLoader;
+
+    /**
+     * @var StoreFactory
+     */
+    private $storeFactory;
+
+    /**
+     * @var GalleryEntryResolver
+     */
+    private $entryResolver;
+
+    /**
+     * @param GalleryEntryContentValidator $contentValidator
+     * @param Filesystem $filesystem
+     * @param ProductLoader $productLoader
+     * @param MediaConfig $mediaConfig
+     * @param StoreFactory $storeFactory
+     * @param GalleryEntryResolver $entryResolver
+     */
+    public function __construct(
+        GalleryEntryContentValidator $contentValidator,
+        Filesystem $filesystem,
+        ProductLoader $productLoader,
+        MediaConfig $mediaConfig,
+        StoreFactory $storeFactory,
+        GalleryEntryResolver $entryResolver
+    ) {
+        $this->contentValidator = $contentValidator;
+        $this->filesystem = $filesystem;
+        $this->productLoader = $productLoader;
+        $this->mediaConfig = $mediaConfig;
+        $this->storeFactory = $storeFactory;
+        $this->entryResolver = $entryResolver;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function create($productSku, GalleryEntry $entry, GalleryEntryContent $entryContent, $storeId = 0)
+    {
+        $store = $this->storeFactory->create()->load($storeId);
+        if ($store->getId() != $storeId) {
+            throw new NoSuchEntityException('There is no store with provided ID.');
+        }
+        if (!$this->contentValidator->isValid($entryContent)) {
+            throw new InputException('The image content is not valid.');
+        }
+        $product = $this->productLoader->load($productSku);
+
+        $fileContent = @base64_decode($entryContent->getData(), true);
+        $mediaTmpPath = $this->mediaConfig->getBaseTmpMediaPath();
+        $mediaDirectory = $this->filesystem->getDirectoryWrite(Filesystem::MEDIA_DIR);
+        $mediaDirectory->create($mediaTmpPath);
+        $fileName = $entryContent->getName() . '.' . $this->mimeTypeExtensionMap[$entryContent->getMimeType()];
+        $relativeFilePath = $mediaTmpPath . DIRECTORY_SEPARATOR . $fileName;
+        $absoluteFilePath = $mediaDirectory->getAbsolutePath($relativeFilePath);
+        $mediaDirectory->writeFile($relativeFilePath, $fileContent);
+
+        /** @var $productMediaGallery \Magento\Catalog\Model\Product\Attribute\Backend\Media */
+        $productMediaGallery = $this->getGalleryAttributeBackend($product);
+        $imageFileUri = $productMediaGallery->addImage(
+            $product,
+            $absoluteFilePath,
+            $entry->getTypes(),
+            true,
+            $entry->isDisabled()
+        );
+        // Update additional fields that are still empty after addImage call
+        $productMediaGallery->updateImage($product, $imageFileUri, array(
+            'label' => $entry->getLabel(),
+            'position' => $entry->getPosition(),
+            'disabled' => $entry->isDisabled(),
+        ));
+        $product->setStoreId($storeId);
+        $product->save();
+        // Remove all temporary files
+        $mediaDirectory->delete($relativeFilePath);
+        // File could change its name during the move from tmp dir
+        return $this->entryResolver->getEntryIdByFilePath(
+            $product,
+            $productMediaGallery->getRenamedImage($imageFileUri)
+        );
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function update($productSku, GalleryEntry $entry, $storeId = 0)
+    {
+        $store = $this->storeFactory->create()->load($storeId);
+        if ($store->getId() != $storeId) {
+            throw new NoSuchEntityException('There is no store with provided ID.');
+        }
+        $product = $this->productLoader->load($productSku);
+        /** @var $productMediaGallery \Magento\Catalog\Model\Product\Attribute\Backend\Media */
+        $productMediaGallery = $this->getGalleryAttributeBackend($product);
+        $filePath = $this->entryResolver->getEntryFilePathById($product, $entry->getId());
+        if (is_null($filePath)) {
+            throw new NoSuchEntityException('There is no image with provided ID.');
+        }
+
+        $productMediaGallery->updateImage($product, $filePath, array(
+            'label' => $entry->getLabel(),
+            'position' => $entry->getPosition(),
+            'disabled' => $entry->isDisabled(),
+        ));
+        $productMediaGallery->clearMediaAttribute($product, array_keys($product->getMediaAttributes()));
+        $productMediaGallery->setMediaAttribute($product, $entry->getTypes(), $filePath);
+        $product->setStoreId($storeId);
+        $product->save();
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delete($productSku, $entryId)
+    {
+        $product = $this->productLoader->load($productSku);
+        /** @var $productMediaGallery \Magento\Catalog\Model\Product\Attribute\Backend\Media */
+        $productMediaGallery = $this->getGalleryAttributeBackend($product);
+        $filePath = $this->entryResolver->getEntryFilePathById($product, $entryId);
+        if (is_null($filePath)) {
+            throw new NoSuchEntityException('There is no image with provided ID.');
+        }
+
+        $productMediaGallery->removeImage($product, $filePath);
+        $product->save();
+        return true;
+    }
+
+    /**
+     * Retrieve backend model of product media gallery attribute
+     *
+     * @param Product $product
+     * @return \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend
+     * @throws StateException
+     */
+    protected function getGalleryAttributeBackend(Product $product)
+    {
+        $attributes = $product->getTypeInstance()->getSetAttributes($product);
+        if (!isset($attributes['media_gallery']) || !($attributes['media_gallery'] instanceof AbstractAttribute)) {
+            throw new StateException('Requested product does not support images.');
+        }
+        /** @var $galleryAttribute AbstractAttribute */
+        $galleryAttribute = $attributes['media_gallery'];
+        return $galleryAttribute->getBackend();
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/WriteServiceInterface.php b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/WriteServiceInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..c5672db0f63843291a87661690c016ac8c020fe9
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/Attribute/Media/WriteServiceInterface.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Product Media Attribute Write Service
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media;
+
+use \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntry;
+use \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntryContent;
+
+interface WriteServiceInterface
+{
+    /**
+     * Create new gallery entry
+     *
+     * @param string $productSku
+     * @param \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntry $entry
+     * @param \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntryContent $entryContent
+     * @param int $storeId
+     * @return int gallery entry ID
+     * @throws \Magento\Framework\Exception\InputException
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\StateException
+     */
+    public function create($productSku, GalleryEntry $entry, GalleryEntryContent $entryContent, $storeId = 0);
+
+    /**
+     * Update gallery entry
+     *
+     * @param string $productSku
+     * @param \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntry $entry
+     * @param int $storeId
+     * @return bool
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\StateException
+     */
+    public function update($productSku, GalleryEntry $entry, $storeId = 0);
+
+    /**
+     * Remove gallery entry
+     *
+     * @param string $productSku
+     * @param int $entryId
+     * @return bool
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\StateException
+     */
+    public function delete($productSku, $entryId);
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadService.php b/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadService.php
index 3307a26979be8018d9c019a38e41d343f1c84f2c..03ebc1a45e876ab18ba09d4c3b73725303c39dc3 100644
--- a/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadService.php
+++ b/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadService.php
@@ -27,6 +27,8 @@ namespace Magento\Catalog\Service\V1\Product\AttributeGroup;
 
 use \Magento\Catalog\Service\V1\Data;
 use \Magento\Eav\Model\Resource\Entity\Attribute\Group\CollectionFactory as AttributeGroupCollectionFactory;
+use \Magento\Eav\Model\Entity\Attribute\SetFactory as AttributeSetFactory;
+use \Magento\Framework\Exception\NoSuchEntityException;
 
 class ReadService implements ReadServiceInterface
 {
@@ -35,6 +37,11 @@ class ReadService implements ReadServiceInterface
      */
     protected $groupListFactory;
 
+    /**
+     * @var \Magento\Eav\Model\Entity\Attribute\SetFactory
+     */
+    protected $attributeSetFactory;
+
     /**
      * @var \Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder
      */
@@ -42,13 +49,16 @@ class ReadService implements ReadServiceInterface
 
     /**
      * @param AttributeGroupCollectionFactory $groupListFactory
-     * @param \Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder $groupBuilder
+     * @param AttributeSetFactory $attributeSetFactory
+     * @param Data\Eav\AttributeGroupBuilder $groupBuilder
      */
     public function __construct(
         AttributeGroupCollectionFactory $groupListFactory,
+        AttributeSetFactory $attributeSetFactory,
         Data\Eav\AttributeGroupBuilder $groupBuilder
     ) {
         $this->groupListFactory = $groupListFactory;
+        $this->attributeSetFactory = $attributeSetFactory;
         $this->groupBuilder = $groupBuilder;
     }
 
@@ -57,6 +67,10 @@ class ReadService implements ReadServiceInterface
      */
     public function getList($attributeSetId)
     {
+        if (!$this->attributeSetFactory->create()->load($attributeSetId)->getId()) {
+            throw NoSuchEntityException::singleField('attributeSetId', $attributeSetId);
+        }
+
         $collection = $this->groupListFactory->create();
         $collection->setAttributeSetFilter($attributeSetId);
         $collection->setSortOrder();
diff --git a/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadServiceInterface.php b/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadServiceInterface.php
index ae4eaba782b5766f4cf6f420f229772742e4a6ee..74dc98351c95ee0a0ee21e4363250b0fc368cd5b 100644
--- a/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadServiceInterface.php
+++ b/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadServiceInterface.php
@@ -31,6 +31,7 @@ interface ReadServiceInterface
      *
      * @param string $attributeSetId
      * @return \Magento\Catalog\Service\V1\Data\Eav\AttributeGroup[]
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
      */
     public function getList($attributeSetId);
 }
diff --git a/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteService.php b/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteService.php
index b6074d36a26e9031a464d611874b7b2693fd11cd..df387169387b373549f7e0c41390a93394f72ceb 100644
--- a/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteService.php
+++ b/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteService.php
@@ -26,10 +26,11 @@ namespace Magento\Catalog\Service\V1\Product\AttributeGroup;
 
 use \Magento\Catalog\Model\Product\Attribute\GroupFactory;
 use \Magento\Catalog\Model\Product\Attribute\Group;
-use Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder;
-use Magento\Framework\Exception\CouldNotSaveException;
-use Magento\Framework\Exception\NoSuchEntityException;
-use Magento\Framework\Exception\StateException;
+use \Magento\Eav\Model\Entity\Attribute\SetFactory;
+use \Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder;
+use \Magento\Framework\Exception\CouldNotSaveException;
+use \Magento\Framework\Exception\NoSuchEntityException;
+use \Magento\Framework\Exception\StateException;
 
 class WriteService implements WriteServiceInterface
 {
@@ -43,13 +44,23 @@ class WriteService implements WriteServiceInterface
      */
     protected $groupBuilder;
 
+    /**
+     * @var \Magento\Eav\Model\Entity\Attribute\SetFactory
+     */
+    protected $setFactory;
+
     /**
      * @param GroupFactory $groupFactory
+     * @param SetFactory $attributeSetFactory
      * @param AttributeGroupBuilder $groupBuilder
      */
-    public function __construct(GroupFactory $groupFactory, AttributeGroupBuilder $groupBuilder)
-    {
+    public function __construct(
+        GroupFactory $groupFactory,
+        SetFactory $attributeSetFactory,
+        AttributeGroupBuilder $groupBuilder
+    ) {
         $this->groupFactory = $groupFactory;
+        $this->setFactory = $attributeSetFactory;
         $this->groupBuilder = $groupBuilder;
     }
 
@@ -58,6 +69,10 @@ class WriteService implements WriteServiceInterface
      */
     public function create($attributeSetId, \Magento\Catalog\Service\V1\Data\Eav\AttributeGroup $groupData)
     {
+        if (!$this->setFactory->create()->load($attributeSetId)->getId()) {
+            throw NoSuchEntityException::singleField('attributeSetId', $attributeSetId);
+        }
+
         try {
             /** @var Group $attributeGroup */
             $attributeGroup = $this->groupFactory->create();
@@ -70,23 +85,28 @@ class WriteService implements WriteServiceInterface
                 $attributeGroup->getAttributeGroupName()
             )->create();
         } catch (\Exception $e) {
-            throw new CouldNotSaveException('Could not create attribute group');
+            throw new CouldNotSaveException(
+                'Could not create attribute group. Maybe group with such name already exists'
+            );
         }
     }
 
     /**
      * {@inheritdoc}
      */
-    public function update($groupId, \Magento\Catalog\Service\V1\Data\Eav\AttributeGroup $groupData)
+    public function update($attributeSetId, $groupId, \Magento\Catalog\Service\V1\Data\Eav\AttributeGroup $groupData)
     {
         /** @var Group $attributeGroup */
         $attributeGroup = $this->groupFactory->create();
         $attributeGroup->load($groupId);
         if (!$attributeGroup->getId()) {
-            throw new NoSuchEntityException();
+            throw NoSuchEntityException::singleField('attributeGroupId', $attributeGroup->getId());
+        }
+        if ($attributeGroup->getAttributeSetId() != $attributeSetId) {
+            throw new StateException('Attribute group does not belong to provided attribute set');
         }
         try {
-            $attributeGroup->setId($groupData->getId());
+            $attributeGroup->setId($groupId);
             $attributeGroup->setAttributeGroupName($groupData->getName());
             $attributeGroup->save();
         } catch (\Exception $e) {
@@ -97,17 +117,22 @@ class WriteService implements WriteServiceInterface
     /**
      * {@inheritdoc}
      */
-    public function delete($groupId)
+    public function delete($attributeSetId, $groupId)
     {
         /** @var Group $attributeGroup */
         $attributeGroup = $this->groupFactory->create();
         $attributeGroup->load($groupId);
+
+        if (!$attributeGroup->getId()) {
+            throw NoSuchEntityException::singleField('attributeGroupId', $groupId);
+        }
         if ($attributeGroup->hasSystemAttributes()) {
             throw new StateException('Attribute group that contains system attributes can not be deleted');
         }
-        if (!$attributeGroup->getId()) {
-            throw new NoSuchEntityException();
+        if ($attributeGroup->getAttributeSetId() != $attributeSetId) {
+            throw new StateException('Attribute group does not belong to provided attribute set');
         }
         $attributeGroup->delete();
+        return true;
     }
 }
diff --git a/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteServiceInterface.php b/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteServiceInterface.php
index 3d3c396539eed9b409fb70fb23af30355f5982fa..9a2515a06e3672d21bb89024fb7e72056da98f25 100644
--- a/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteServiceInterface.php
+++ b/app/code/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteServiceInterface.php
@@ -33,27 +33,31 @@ interface WriteServiceInterface
      * @param \Magento\Catalog\Service\V1\Data\Eav\AttributeGroup $groupData
      * @return \Magento\Catalog\Service\V1\Data\Eav\AttributeGroup
      * @throws \Magento\Framework\Exception\CouldNotSaveException
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
      */
     public function create($attributeSetId, \Magento\Catalog\Service\V1\Data\Eav\AttributeGroup $groupData);
 
     /**
      * Update attribute group
      *
+     * @param string $attributeSetId
      * @param string $groupId
      * @param \Magento\Catalog\Service\V1\Data\Eav\AttributeGroup $groupData
      * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\StateException
      * @throws \Magento\Framework\Exception\CouldNotSaveException
      * @return bool
      */
-    public function update($groupId, \Magento\Catalog\Service\V1\Data\Eav\AttributeGroup $groupData);
+    public function update($attributeSetId, $groupId, \Magento\Catalog\Service\V1\Data\Eav\AttributeGroup $groupData);
 
     /**
      * Remove attribute group
      *
+     * @param string $attributeSetId
      * @param string $groupId
      * @throws \Magento\Framework\Exception\NoSuchEntityException
      * @throws \Magento\Framework\Exception\StateException
      * @return bool
      */
-    public function delete($groupId);
+    public function delete($attributeSetId, $groupId);
 }
diff --git a/app/code/Magento/Catalog/Service/V1/Product/GroupPriceService.php b/app/code/Magento/Catalog/Service/V1/Product/GroupPriceService.php
new file mode 100644
index 0000000000000000000000000000000000000000..41729855bc5f65cf981a153967c4de250f4ba421
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/GroupPriceService.php
@@ -0,0 +1,175 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product;
+
+use Magento\Catalog\Model\ProductFactory;
+use Magento\Catalog\Model\ProductRepository;
+use Magento\Framework\Exception\CouldNotSaveException;
+use Magento\Framework\Exception\InputException;
+use Magento\Catalog\Service\V1\Data\Product;
+
+class GroupPriceService implements GroupPriceServiceInterface
+{
+    /**
+     * @var \Magento\Catalog\Model\ProductRepository
+     */
+    protected $productRepository;
+
+    /**
+     * @var \Magento\Catalog\Service\V1\Data\Product\GroupPriceBuilder
+     */
+    protected $groupPriceBuilder;
+
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface
+     */
+    protected $storeManager;
+
+    /**
+     * @var \Magento\Customer\Service\V1\CustomerGroupServiceInterface
+     */
+    protected $customerGroupService;
+
+    /**
+     * @var \Magento\Catalog\Model\Product\PriceModifier
+     */
+    protected $priceModifier;
+
+    /**
+     * @var \Magento\Framework\App\Config\ScopeConfigInterface
+     */
+    protected $config;
+
+    /**
+     * @param ProductRepository $productRepository
+     * @param Product\GroupPriceBuilder $groupPriceBuilder
+     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
+     * @param \Magento\Customer\Service\V1\CustomerGroupServiceInterface $customerGroupService
+     * @param \Magento\Catalog\Model\Product\PriceModifier $priceModifier
+     * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
+     */
+    public function __construct(
+        ProductRepository $productRepository,
+        Product\GroupPriceBuilder $groupPriceBuilder,
+        \Magento\Store\Model\StoreManagerInterface $storeManager,
+        \Magento\Customer\Service\V1\CustomerGroupServiceInterface $customerGroupService,
+        \Magento\Catalog\Model\Product\PriceModifier $priceModifier,
+        \Magento\Framework\App\Config\ScopeConfigInterface $config
+    ) {
+        $this->productRepository = $productRepository;
+        $this->groupPriceBuilder = $groupPriceBuilder;
+        $this->storeManager = $storeManager;
+        $this->customerGroupService = $customerGroupService;
+        $this->priceModifier = $priceModifier;
+        $this->config = $config;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     */
+    public function set($productSku, \Magento\Catalog\Service\V1\Data\Product\GroupPrice $price)
+    {
+        $customerGroup = $this->customerGroupService->getGroup($price->getCustomerGroupId());
+        $product = $this->productRepository->get($productSku, true);
+
+        $groupPrices = $product->getData('group_price');
+        $websiteId = 0;
+        if ($this->config->getValue('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE) != 0) {
+            $websiteId = $this->storeManager->getWebsite()->getId();
+        }
+        $found = false;
+        foreach ($groupPrices as &$currentPrice) {
+            if (intval($currentPrice['cust_group']) === $price->getCustomerGroupId()
+                && intval($currentPrice['website_id']) === intval($websiteId)
+            ) {
+                $currentPrice['price'] = $price->getValue();
+                $found = true;
+                break;
+            }
+        }
+        if (!$found) {
+            $groupPrices[] = array(
+                'cust_group' => $customerGroup->getId(),
+                'website_id' => $websiteId,
+                'price' => $price->getValue(),
+            );
+        }
+
+        $product->setData('group_price', $groupPrices);
+        $errors = $product->validate();
+        if (is_array($errors) && count($errors)) {
+            $errorAttributeCodes = implode(', ', array_keys($errors));
+            throw new InputException(
+                sprintf('Values of following attributes are invalid: %s', $errorAttributeCodes)
+            );
+        }
+        try {
+            $product->save();
+        } catch (\Exception $e) {
+            throw new CouldNotSaveException('Could not save group price');
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delete($productSku, $customerGroupId)
+    {
+        $product = $this->productRepository->get($productSku, true);
+        if ($this->config->getValue('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE) == 0) {
+            $websiteId = 0;
+        } else {
+            $websiteId = $this->storeManager->getWebsite()->getId();
+        }
+        $this->priceModifier->removeGroupPrice($product, $customerGroupId, $websiteId);
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getList($productSku)
+    {
+        $product = $this->productRepository->get($productSku, true);
+        $priceKey = 'website_price';
+        if ($this->config->getValue('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE) == 0) {
+            $priceKey = 'price';
+        }
+
+        $prices = array();
+        foreach ($product->getData('group_price') as $price) {
+            $this->groupPriceBuilder->populateWithArray(array(
+                Product\GroupPrice::CUSTOMER_GROUP_ID => $price['all_groups'] ? 'all' : $price['cust_group'],
+                Product\GroupPrice::VALUE => $price[$priceKey],
+            ));
+            $prices[] = $this->groupPriceBuilder->create();
+        }
+        return $prices;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/GroupPriceServiceInterface.php b/app/code/Magento/Catalog/Service/V1/Product/GroupPriceServiceInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..fa8a40f81122c91deecb20b9a062a8b55b7b545f
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/GroupPriceServiceInterface.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product;
+
+interface GroupPriceServiceInterface
+{
+    /**
+     * Set group price for product
+     *
+     * @param string $productSku
+     * @param \Magento\Catalog\Service\V1\Data\Product\GroupPrice $price
+     * @return boolean
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function set($productSku, \Magento\Catalog\Service\V1\Data\Product\GroupPrice $price);
+
+    /**
+     * Remove group price from product
+     *
+     * @param string $productSku
+     * @param int $customerGroupId
+     * @return boolean
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function delete($productSku, $customerGroupId);
+
+    /**
+     * Retrieve list of product prices
+     *
+     * @param string $productSku
+     * @return \Magento\Catalog\Service\V1\Data\Product\GroupPrice[]
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function getList($productSku);
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/TierPriceService.php b/app/code/Magento/Catalog/Service/V1/Product/TierPriceService.php
new file mode 100644
index 0000000000000000000000000000000000000000..c45a24f22a6294654c1b7f797c6080c082f82e50
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/TierPriceService.php
@@ -0,0 +1,192 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product;
+
+use Magento\Catalog\Model\ProductFactory;
+use Magento\Catalog\Model\ProductRepository;
+use Magento\Framework\Exception\InputException;
+use Magento\Framework\Exception\CouldNotSaveException;
+use Magento\Catalog\Service\V1\Data\Product;
+
+class TierPriceService implements TierPriceServiceInterface
+{
+    /**
+     * @var \Magento\Catalog\Model\ProductRepository
+     */
+    protected $productRepository;
+
+    /**
+     * @var \Magento\Catalog\Service\V1\Data\Product\TierPriceBuilder
+     */
+    protected $priceBuilder;
+
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface
+     */
+    protected $storeManager;
+
+    /**
+     * @var \Magento\Catalog\Model\Product\PriceModifier
+     */
+    protected $priceModifier;
+
+    /**
+     * @var \Magento\Framework\App\Config\ScopeConfigInterface
+     */
+    protected $config;
+
+    /**
+     * @var \Magento\Customer\Service\V1\CustomerGroupServiceInterface
+     */
+    protected $customerGroupService;
+
+    /**
+     * @param ProductRepository $productRepository
+     * @param Product\TierPriceBuilder $priceBuilder
+     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
+     * @param \Magento\Catalog\Model\Product\PriceModifier $priceModifier
+     * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
+     * @param \Magento\Customer\Service\V1\CustomerGroupServiceInterface $customerGroupService
+     */
+    public function __construct(
+        ProductRepository $productRepository,
+        Product\TierPriceBuilder $priceBuilder,
+        \Magento\Store\Model\StoreManagerInterface $storeManager,
+        \Magento\Catalog\Model\Product\PriceModifier $priceModifier,
+        \Magento\Framework\App\Config\ScopeConfigInterface $config,
+        \Magento\Customer\Service\V1\CustomerGroupServiceInterface $customerGroupService
+    ) {
+        $this->productRepository = $productRepository;
+        $this->priceBuilder = $priceBuilder;
+        $this->storeManager = $storeManager;
+        $this->priceModifier = $priceModifier;
+        $this->config = $config;
+        $this->customerGroupService = $customerGroupService;
+    }
+
+    /**
+     * {@inheritdoc}
+     *
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @SuppressWarnings(PHPMD.NPathComplexity)
+     */
+    public function set($productSku, $customerGroupId, \Magento\Catalog\Service\V1\Data\Product\TierPrice $price)
+    {
+        $product = $this->productRepository->get($productSku, true);
+        $customerGroup = $this->customerGroupService->getGroup($customerGroupId);
+
+        $tierPrices = $product->getData('tier_price');
+        $websiteId = 0;
+        if ($this->config->getValue('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE) != 0) {
+            $websiteId = $this->storeManager->getWebsite()->getId();
+        }
+
+        $found = false;
+
+        foreach ($tierPrices as &$item) {
+            if ('all' == $customerGroupId) {
+                $isGroupValid = ($item['all_groups'] == 1);
+            } else {
+                $isGroupValid = ($item['cust_group'] == $customerGroupId);
+            }
+
+            if ($isGroupValid && $item['website_id'] == $websiteId && $item['price_qty'] == $price->getQty()) {
+                $item['price'] = $price->getValue();
+                $found = true;
+                break;
+            }
+        }
+        if (!$found) {
+            $mappedCustomerGroupId = 'all' == $customerGroupId
+                ? \Magento\Customer\Service\V1\CustomerGroupServiceInterface::CUST_GROUP_ALL
+                : $customerGroup->getId();
+
+            $tierPrices[] = array(
+                'cust_group' => $mappedCustomerGroupId,
+                'price' => $price->getValue(),
+                'website_price' => $price->getValue(),
+                'website_id' => $websiteId,
+                'price_qty' => $price->getQty()
+            );
+        }
+
+        $product->setData('tier_price', $tierPrices);
+        $errors = $product->validate();
+        if (is_array($errors) && count($errors)) {
+            $errorAttributeCodes = implode(', ', array_keys($errors));
+            throw new InputException(
+                sprintf('Values of following attributes are invalid: %s', $errorAttributeCodes)
+            );
+        }
+        try {
+            $product->save();
+        } catch (\Exception $e) {
+            throw new CouldNotSaveException('Could not save group price');
+        }
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function delete($productSku, $customerGroupId, $qty)
+    {
+        $product = $this->productRepository->get($productSku, true);
+        if ($this->config->getValue('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE) == 0) {
+            $websiteId = 0;
+        } else {
+            $websiteId = $this->storeManager->getWebsite()->getId();
+        }
+        $this->priceModifier->removeTierPrice($product, $customerGroupId, $qty, $websiteId);
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getList($productSku, $customerGroupId)
+    {
+        $product = $this->productRepository->get($productSku, true);
+
+        $priceKey = 'website_price';
+        if ($this->config->getValue('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE) == 0) {
+            $priceKey = 'price';
+        }
+
+        $prices = array();
+        foreach ($product->getData('tier_price') as $price) {
+            if ((is_numeric($customerGroupId) && intval($price['cust_group']) === intval($customerGroupId))
+                || ($customerGroupId === 'all' && $price['all_groups'])
+            ) {
+                $this->priceBuilder->populateWithArray(array(
+                    Product\TierPrice::VALUE => $price[$priceKey],
+                    Product\TierPrice::QTY => $price['price_qty']
+                ));
+                $prices[] = $this->priceBuilder->create();
+            }
+        }
+        return $prices;
+    }
+}
diff --git a/app/code/Magento/Catalog/Service/V1/Product/TierPriceServiceInterface.php b/app/code/Magento/Catalog/Service/V1/Product/TierPriceServiceInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..83a941fdd5cdc5c3e72d61c6d1dae355cfc7ec49
--- /dev/null
+++ b/app/code/Magento/Catalog/Service/V1/Product/TierPriceServiceInterface.php
@@ -0,0 +1,62 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product;
+
+interface TierPriceServiceInterface
+{
+    /**
+     * Create tire price for product
+     *
+     * @param string $productSku
+     * @param string $customerGroupId
+     * @param \Magento\Catalog\Service\V1\Data\Product\TierPrice $price
+     * @return boolean
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function set($productSku, $customerGroupId, \Magento\Catalog\Service\V1\Data\Product\TierPrice $price);
+
+    /**
+     * Remove tire price from product
+     *
+     * @param string $productSku
+     * @param string $customerGroupId
+     * @param float $qty
+     * @return boolean
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     * @throws \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function delete($productSku, $customerGroupId, $qty);
+
+    /**
+     * Get tire price of product
+     *
+     * @param string $productSku
+     * @param string $customerGroupId
+     * @return \Magento\Catalog\Service\V1\Data\Product\TierPrice[]
+     * @throws \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function getList($productSku, $customerGroupId);
+}
diff --git a/app/code/Magento/Catalog/etc/di.xml b/app/code/Magento/Catalog/etc/di.xml
index 37365f8cb6596c5e96276ae8853c9376a51c1751..e38c660f426e7632c4f8ad0f91101301148df774 100644
--- a/app/code/Magento/Catalog/etc/di.xml
+++ b/app/code/Magento/Catalog/etc/di.xml
@@ -42,9 +42,13 @@
     <preference for="Magento\Catalog\Service\V1\Product\AttributeSet\ReadServiceInterface" type="Magento\Catalog\Service\V1\Product\AttributeSet\ReadService" />
     <preference for="Magento\Catalog\Service\V1\Product\AttributeSet\WriteServiceInterface" type="Magento\Catalog\Service\V1\Product\AttributeSet\WriteService" />
     <preference for="Magento\Catalog\Service\V1\Product\AttributeSet\AttributeServiceInterface" type="Magento\Catalog\Service\V1\Product\AttributeSet\AttributeService" />
+    <preference for="Magento\Catalog\Service\V1\Product\Attribute\Media\ReadServiceInterface" type="\Magento\Catalog\Service\V1\Product\Attribute\Media\ReadService" />
+    <preference for="\Magento\Catalog\Service\V1\Product\Attribute\Media\WriteServiceInterface" type="\Magento\Catalog\Service\V1\Product\Attribute\Media\WriteService" />
     <preference for="Magento\Catalog\Service\V1\Product\Link\ReadServiceInterface" type="Magento\Catalog\Service\V1\Product\Link\ReadService" />
     <preference for="Magento\Catalog\Service\V1\Product\Link\WriteServiceInterface" type="Magento\Catalog\Service\V1\Product\Link\WriteService" />
     <preference for="Magento\Catalog\Service\V1\Product\Link\Data\ProductLink\DataMapperInterface" type="Magento\Catalog\Service\V1\Product\Link\Data\ProductLink\DataMapper\Composite" />
+    <preference for="Magento\Catalog\Service\V1\Product\GroupPriceServiceInterface" type="Magento\Catalog\Service\V1\Product\GroupPriceService" />
+    <preference for="Magento\Catalog\Service\V1\Product\TierPriceServiceInterface" type="Magento\Catalog\Service\V1\Product\TierPriceService" />
     <type name="Magento\Log\Model\Resource\Log">
         <plugin name="catalogLog" type="Magento\Catalog\Model\Plugin\Log" />
     </type>
diff --git a/app/code/Magento/Catalog/etc/webapi.xml b/app/code/Magento/Catalog/etc/webapi.xml
index cd647e5e9e761151cd6b6c9d5f60195ae4824721..aa3c9ec05ca239ee2395fd1b4e2c7cb1295d04ed 100644
--- a/app/code/Magento/Catalog/etc/webapi.xml
+++ b/app/code/Magento/Catalog/etc/webapi.xml
@@ -181,4 +181,76 @@
             <resource ref="Magento_Catalog::catalog"/>
         </resources>
     </route>
+    <route url="/V1/products/media/types/:attributeSetId" method="GET">
+        <service class="Magento\Catalog\Service\V1\Product\Attribute\Media\ReadServiceInterface" method="types"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/media/:imageId" method="GET">
+        <service class="Magento\Catalog\Service\V1\Product\Attribute\Media\ReadServiceInterface" method="info"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/media" method="POST">
+        <service class="Magento\Catalog\Service\V1\Product\Attribute\Media\WriteServiceInterface" method="create"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/media" method="PUT">
+        <service class="Magento\Catalog\Service\V1\Product\Attribute\Media\WriteServiceInterface" method="update"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/media/:entryId" method="DELETE">
+        <service class="Magento\Catalog\Service\V1\Product\Attribute\Media\WriteServiceInterface" method="delete"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/media" method="GET">
+        <service class="Magento\Catalog\Service\V1\Product\Attribute\Media\ReadServiceInterface" method="getList"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/group-prices" method="GET">
+        <service class="Magento\Catalog\Service\V1\Product\GroupPriceServiceInterface" method="getList"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/group-prices" method="POST">
+        <service class="Magento\Catalog\Service\V1\Product\GroupPriceServiceInterface" method="set"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/group-prices/:customerGroupId" method="DELETE">
+        <service class="Magento\Catalog\Service\V1\Product\GroupPriceServiceInterface" method="delete"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/group-prices/:customerGroupId/tiers" method="GET">
+        <service class="Magento\Catalog\Service\V1\Product\TierPriceServiceInterface" method="getList"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/group-prices/:customerGroupId/tiers" method="POST">
+        <service class="Magento\Catalog\Service\V1\Product\TierPriceServiceInterface" method="set"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
+    <route url="/V1/products/:productSku/group-prices/:customerGroupId/tiers/:qty" method="DELETE">
+        <service class="Magento\Catalog\Service\V1\Product\TierPriceServiceInterface" method="delete"/>
+        <resources>
+            <resource ref="Magento_Catalog::catalog"/>
+        </resources>
+    </route>
 </routes>
diff --git a/app/code/Magento/Eav/Model/Resource/Attribute/Collection.php b/app/code/Magento/Eav/Model/Resource/Attribute/Collection.php
index 1cc178682cbe5d79113e5e7940fd54f74d9ca093..c924148a9e1df9ea0dd477d38b48b1de4b23701c 100644
--- a/app/code/Magento/Eav/Model/Resource/Attribute/Collection.php
+++ b/app/code/Magento/Eav/Model/Resource/Attribute/Collection.php
@@ -201,19 +201,19 @@ abstract class Collection extends \Magento\Eav\Model\Resource\Entity\Attribute\C
                 $scopeColumns['scope_website_id'] = $columnName;
             } else {
                 if (isset($mainColumns[$columnName])) {
-                    $alias = sprintf('scope_%s', $columnName);
-                    $expression = $connection->getCheckSql('main_table.%s IS NULL', 'scope_table.%s', 'main_table.%s');
-                    $expression = sprintf($expression, $columnName, $columnName, $columnName);
+                    $alias = 'scope_' . $columnName;
+                    $condition = 'main_table.' . $columnName . ' IS NULL';
+                    $true = 'scope_table.' . $columnName;
+                    $false = 'main_table.' . $columnName;
+                    $expression = $connection->getCheckSql($condition, $true, $false);
                     $this->addFilterToMap($columnName, $expression);
                     $scopeColumns[$alias] = $columnName;
                 } elseif (isset($extraColumns[$columnName])) {
-                    $alias = sprintf('scope_%s', $columnName);
-                    $expression = $connection->getCheckSql(
-                        'additional_table.%s IS NULL',
-                        'scope_table.%s',
-                        'additional_table.%s'
-                    );
-                    $expression = sprintf($expression, $columnName, $columnName, $columnName);
+                    $alias = 'scope_' . $columnName;
+                    $condition = 'additional_table.' . $columnName . ' IS NULL';
+                    $true = 'scope_table.' . $columnName;
+                    $false = 'additional_table.' . $columnName;
+                    $expression = $connection->getCheckSql($condition, $true, $false);
                     $this->addFilterToMap($columnName, $expression);
                     $scopeColumns[$alias] = $columnName;
                 }
diff --git a/app/code/Magento/GroupedProduct/view/base/templates/product/price/final_price.phtml b/app/code/Magento/GroupedProduct/view/base/templates/product/price/final_price.phtml
index a1f0c46360243e6602f70ffd8ab6cfb8ae47cc9e..aad1419c8822e059ef620d75ee56fbcae9ada3ee 100644
--- a/app/code/Magento/GroupedProduct/view/base/templates/product/price/final_price.phtml
+++ b/app/code/Magento/GroupedProduct/view/base/templates/product/price/final_price.phtml
@@ -31,16 +31,19 @@ $minProduct = $this->getSaleableItem()
     ->getPriceInfo()
     ->getPrice(\Magento\Catalog\Pricing\Price\FinalPrice::PRICE_CODE)
     ->getMinProduct();
-$amountRender = $this->getRendererPool()
-    ->createAmountRender(
-        $minProduct->getPriceInfo()->getPrice('final_price')->getAmount(),
-        $minProduct,
-        $minProduct->getPriceInfo()->getPrice('final_price'),
-        []
-    );
+
+if ($minProduct) {
+    $amountRender = $this->getRendererPool()
+        ->createAmountRender(
+            $minProduct->getPriceInfo()->getPrice('final_price')->getAmount(),
+            $minProduct,
+            $minProduct->getPriceInfo()->getPrice('final_price'),
+            []
+        );
+}
 ?>
 <div class="price-box" itemprop="offers" itemscope itemtype="http://schema.org/Offer">
-    <?php if (\Magento\Framework\Pricing\Render::ZONE_ITEM_VIEW != $this->getZone()): ?>
+    <?php if ($minProduct && \Magento\Framework\Pricing\Render::ZONE_ITEM_VIEW != $this->getZone()): ?>
     <p class="minimal-price">
         <span class="price-label"><?php echo __('Starting at:') . $amountRender->toHtml();?></span>
     </p>
diff --git a/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml b/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml
index 25c562f31744ca156a095090a945abc27560fa91..c68215b765f5727517b1065e6885007296a4c218 100644
--- a/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml
+++ b/app/code/Magento/GroupedProduct/view/frontend/templates/product/view/type/grouped.phtml
@@ -68,10 +68,6 @@
                 <td class="col price">
                     <?php if ($this->getCanShowProductPrice($_item)): ?>
                     <?php echo $this->getProductPrice($_item) ?>
-                        <?php echo $this->getProductPriceHtml(
-                            $_item,
-                            \Magento\Catalog\Pricing\Price\TierPrice::PRICE_CODE
-                        ) ?>
                     <?php endif; ?>
                 </td>
                 <?php endif; ?>
diff --git a/app/code/Magento/Sales/Model/Quote/Item/AbstractItem.php b/app/code/Magento/Sales/Model/Quote/Item/AbstractItem.php
index c3511a5c79729dff1821ecf053f495a61c765ce8..b37c9dd59c850edc5160e304249e3c500e90e3f1 100644
--- a/app/code/Magento/Sales/Model/Quote/Item/AbstractItem.php
+++ b/app/code/Magento/Sales/Model/Quote/Item/AbstractItem.php
@@ -403,7 +403,7 @@ abstract class AbstractItem extends \Magento\Framework\Model\AbstractModel imple
         $qty = $this->getTotalQty();
         // Round unit price before multiplying to prevent losing 1 cent on subtotal
         $total = $this->getStore()->roundPrice($this->getCalculationPriceOriginal()) * $qty;
-        $baseTotal = $this->getBaseCalculationPriceOriginal() * $qty;
+        $baseTotal = $this->getStore()->roundPrice($this->getBaseCalculationPriceOriginal()) * $qty;
 
         $this->setRowTotal($this->getStore()->roundPrice($total));
         $this->setBaseRowTotal($this->getStore()->roundPrice($baseTotal));
diff --git a/app/code/Magento/SalesRule/Model/Validator.php b/app/code/Magento/SalesRule/Model/Validator.php
index 25f7269da75a6fe6a2460fc43785a8fc50a77d17..12367e76dc23821de6355fcc8529f5b84a91d0b2 100644
--- a/app/code/Magento/SalesRule/Model/Validator.php
+++ b/app/code/Magento/SalesRule/Model/Validator.php
@@ -173,7 +173,8 @@ class Validator extends \Magento\Framework\Model\AbstractModel
                 $websiteId,
                 $customerGroupId,
                 $couponCode
-            )->load();
+            )->addFieldToFilter('is_active', 1)
+            ->load();
         }
         return $this;
     }
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 dc44e5abfd065e05b66af6f2ae6bd081de4db604..b5c6352852ab5a325f3508c447184d82f0854d81 100644
--- a/app/code/Magento/Tax/Block/Adminhtml/Rule/Edit/Form.php
+++ b/app/code/Magento/Tax/Block/Adminhtml/Rule/Edit/Form.php
@@ -164,6 +164,20 @@ class Form extends \Magento\Backend\Block\Widget\Form\Generic
             false,
             true
         );
+        
+        $fieldset->addField(
+            'calculate_subtotal',
+            'checkbox',
+            array(
+                'name'  => 'calculate_subtotal',
+                'label' => __('Calculate Off Subtotal Only'),
+                'onclick' => 'this.value = this.checked ? 1 : 0;',
+                'checked' => (int)$model->getCalculateSubtotal()
+            ),
+            false,
+            true
+        );
+
         $fieldset->addField(
             'position',
             'text',
diff --git a/app/code/Magento/Tax/Block/Sales/Order/Tax.php b/app/code/Magento/Tax/Block/Sales/Order/Tax.php
index 911ab864539e908ea9df56be200bad8e094d71b7..49c4d799852b3d884a4ce287af6bc0905e0f6e69 100644
--- a/app/code/Magento/Tax/Block/Sales/Order/Tax.php
+++ b/app/code/Magento/Tax/Block/Sales/Order/Tax.php
@@ -148,14 +148,24 @@ class Tax extends \Magento\Framework\View\Element\Template
             $subtotalIncl = (double)$this->_source->getSubtotalInclTax();
             $baseSubtotalIncl = (double)$this->_source->getBaseSubtotalInclTax();
 
-            if (!$subtotalIncl) {
-                $subtotalIncl = $subtotal + $this->_source->getTaxAmount() - $this->_source->getShippingTaxAmount();
-            }
-            if (!$baseSubtotalIncl) {
-                $baseSubtotalIncl = $baseSubtotal +
-                    $this->_source->getBaseTaxAmount() -
-                    $this->_source->getBaseShippingTaxAmount();
+            if (!$subtotalIncl || !$baseSubtotalIncl) {
+                // Calculate the subtotal if it is not set
+                $subtotalIncl = $subtotal
+                    + $this->_source->getTaxAmount()
+                    - $this->_source->getShippingTaxAmount();
+                $baseSubtotalIncl = $baseSubtotal
+                    + $this->_source->getBaseTaxAmount()
+                    - $this->_source->getBaseShippingTaxAmount();
+
+                if ($this->_source instanceof Order) {
+                    // Adjust for the discount tax compensation
+                    foreach ($this->_source->getAllItems() as $item) {
+                        $subtotalIncl += $item->getHiddenTaxAmount();
+                        $baseSubtotalIncl += $item->getBaseHiddenTaxAmount();
+                    }
+                }
             }
+
             $subtotalIncl = max(0, $subtotalIncl);
             $baseSubtotalIncl = max(0, $baseSubtotalIncl);
             $totalExcl = new \Magento\Framework\Object(
diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Rule.php b/app/code/Magento/Tax/Controller/Adminhtml/Rule.php
index 05f5d442f0c1dd17f4a8c475f64d02abce96f19c..9de72cd297dea671dc07c8b121d33542990c1b74 100644
--- a/app/code/Magento/Tax/Controller/Adminhtml/Rule.php
+++ b/app/code/Magento/Tax/Controller/Adminhtml/Rule.php
@@ -51,6 +51,8 @@ class Rule extends \Magento\Backend\App\Action
     }
 
     /**
+     * Index action
+     *
      * @return $this
      */
     public function indexAction()
@@ -63,6 +65,8 @@ class Rule extends \Magento\Backend\App\Action
     }
 
     /**
+     * Redirects to edit action
+     *
      * @return void
      */
     public function newAction()
@@ -71,6 +75,8 @@ class Rule extends \Magento\Backend\App\Action
     }
 
     /**
+     * Edit action
+     *
      * @return void
      */
     public function editAction()
@@ -106,6 +112,8 @@ class Rule extends \Magento\Backend\App\Action
     }
 
     /**
+     * Save action
+     *
      * @return void
      */
     public function saveAction()
@@ -115,6 +123,7 @@ class Rule extends \Magento\Backend\App\Action
 
             $ruleModel = $this->_objectManager->get('Magento\Tax\Model\Calculation\Rule');
             $ruleModel->setData($postData);
+            $ruleModel->setCalculateSubtotal($this->getRequest()->getParam('calculate_subtotal', 0));
 
             try {
                 $ruleModel->save();
@@ -142,6 +151,8 @@ class Rule extends \Magento\Backend\App\Action
     }
 
     /**
+     * Delete action
+     *
      * @return void
      */
     public function deleteAction()
@@ -191,6 +202,8 @@ class Rule extends \Magento\Backend\App\Action
     }
 
     /**
+     * Check if sales rule is allowed
+     *
      * @return bool
      */
     protected function _isAllowed()
diff --git a/app/code/Magento/Tax/Controller/Adminhtml/Tax.php b/app/code/Magento/Tax/Controller/Adminhtml/Tax.php
index 9d89ee15c1a27ac09992ef8d199fcb711026d5ed..4286cf94cec92b7c5501f912cf4cb2d3e89a436a 100644
--- a/app/code/Magento/Tax/Controller/Adminhtml/Tax.php
+++ b/app/code/Magento/Tax/Controller/Adminhtml/Tax.php
@@ -155,4 +155,24 @@ class Tax extends \Magento\Backend\App\Action
     {
         return $this->_authorization->isAllowed('Magento_Tax::manage_tax');
     }
+
+    /**
+     * Set tax ignore notification flag and redirect back
+     *
+     * @return \Magento\Framework\App\ResponseInterface
+     */
+    public function ignoreTaxNotificationAction()
+    {
+        $section = $this->getRequest()->getParam('section');
+        if ($section) {
+            try {
+                $path = 'tax/notification/ignore_' . $section;
+                $this->_objectManager->get('\Magento\Core\Model\Resource\Config')->saveConfig($path, 1, \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, 0);
+            } catch (Exception $e) {
+                $this->messageManager->addError($e->getMessage());
+            }
+        }
+
+        $this->getResponse()->setRedirect($this->_redirect->getRefererUrl());
+    }
 }
diff --git a/app/code/Magento/Tax/Helper/Data.php b/app/code/Magento/Tax/Helper/Data.php
index c3c4371f52800af9bb27e62fb89a8e06b220660e..60a3902074688bb99fca90c29a37f416b11347a6 100644
--- a/app/code/Magento/Tax/Helper/Data.php
+++ b/app/code/Magento/Tax/Helper/Data.php
@@ -25,6 +25,7 @@ namespace Magento\Tax\Helper;
 
 use Magento\Store\Model\Store;
 use Magento\Customer\Model\Address;
+use Magento\Tax\Model\Calculation;
 use Magento\Tax\Model\Config;
 
 /**
@@ -481,6 +482,42 @@ class Data extends \Magento\Framework\App\Helper\AbstractHelper
         return $this->_coreData->jsonEncode($result);
     }
 
+    /**
+     * Get unrounded product price
+     *
+     * @param   \Magento\Catalog\Model\Product $product
+     * @param   float $price inputed product price
+     * @param   bool $includingTax return price include tax flag
+     * @param   null|Address $shippingAddress
+     * @param   null|Address $billingAddress
+     * @param   null|int $ctc customer tax class
+     * @param   null|string|bool|int|Store $store
+     * @param   bool $priceIncludesTax flag what price parameter contain tax
+     * @return  float
+     */
+    public function getPriceUnrounded(
+        $product,
+        $price,
+        $includingTax = null,
+        $shippingAddress = null,
+        $billingAddress = null,
+        $ctc = null,
+        $store = null,
+        $priceIncludesTax = null
+    ) {
+        return $this->getPrice(
+            $product,
+            $price,
+            $includingTax,
+            $shippingAddress,
+            $billingAddress,
+            $ctc,
+            $store,
+            $priceIncludesTax,
+            false
+        );
+    }
+
     /**
      * Get product price with all tax settings processing
      *
diff --git a/app/code/Magento/Tax/Model/Config.php b/app/code/Magento/Tax/Model/Config.php
index 83aae6075cfec2ec15499e13b9b70d97460dad6a..cf0b53ae8f76d582696b3ab7997515fb02383523 100644
--- a/app/code/Magento/Tax/Model/Config.php
+++ b/app/code/Magento/Tax/Model/Config.php
@@ -33,6 +33,15 @@ use Magento\Store\Model\Store;
 
 class Config
 {
+    // tax notifications
+    const XML_PATH_TAX_NOTIFICATION_IGNORE_DISCOUNT = 'tax/notification/ignore_discount';
+
+    const XML_PATH_TAX_NOTIFICATION_IGNORE_PRICE_DISPLAY = 'tax/notification/ignore_price_display';
+
+    const XML_PATH_TAX_NOTIFICATION_IGNORE_FPT_CONFIGURATION = 'tax/notification/ignore_fpt_configuration';
+
+    const XML_PATH_TAX_NOTIFICATION_INFO_URL = 'tax/notification/info_url';
+
     // tax classes
     const CONFIG_XML_PATH_SHIPPING_TAX_CLASS = 'tax/classes/shipping_tax_class';
 
@@ -683,7 +692,7 @@ class Config
      * @param null|string|bool|int|Store $store
      * @return bool
      */
-    public function displaySalestDiscountExclTax($store = null)
+    public function displaySalesDiscountExclTax($store = null)
     {
         return $this->_scopeConfig->getValue(
             self::XML_PATH_DISPLAY_SALES_DISCOUNT,
@@ -758,4 +767,64 @@ class Config
             $store
         );
     }
+
+    /**
+     * Check if do not show notification about wrong display settings
+     *
+     * @param null|string|bool|int|Store $store
+     * @return bool
+     */
+    public function isWrongDisplaySettingsIgnored($store = null)
+    {
+        return (bool)$this->_scopeConfig->getValue(
+            self::XML_PATH_TAX_NOTIFICATION_IGNORE_PRICE_DISPLAY,
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+            $store
+        );
+    }
+
+    /**
+     * Check if do not show notification about wrong discount settings
+     *
+     * @param null|string|bool|int|Store $store
+     * @return bool
+     */
+    public function isWrongDiscountSettingsIgnored($store = null)
+    {
+        return (bool)$this->_scopeConfig->getValue(
+            self::XML_PATH_TAX_NOTIFICATION_IGNORE_DISCOUNT,
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+            $store
+        );
+    }
+
+    /**
+     * Check if warning about conflicting FPT configuration should be shown
+     *
+     * @param null|string|bool|int|Store $store
+     * @return bool
+     */
+    public function isConflictingFptTaxConfigurationSettingsIgnored($store = null)
+    {
+        return (bool)$this->_scopeConfig->getValue(
+            self::XML_PATH_TAX_NOTIFICATION_IGNORE_FPT_CONFIGURATION,
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+            $store
+        );
+    }
+
+    /**
+     * Return the notification info url
+     *
+     * @param null|string|bool|int|Store $store
+     * @return bool
+     */
+    public function getInfoUrl($store = null)
+    {
+        return (bool)$this->_scopeConfig->getValue(
+            self::XML_PATH_TAX_NOTIFICATION_INFO_URL,
+            \Magento\Store\Model\ScopeInterface::SCOPE_STORE,
+            $store
+        );
+    }
 }
diff --git a/app/code/Magento/Tax/Model/Config/Notification.php b/app/code/Magento/Tax/Model/Config/Notification.php
new file mode 100644
index 0000000000000000000000000000000000000000..0c4805c6ab32a7737b4c74f09200589d4dc2f617
--- /dev/null
+++ b/app/code/Magento/Tax/Model/Config/Notification.php
@@ -0,0 +1,83 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license   http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Tax\Model\Config;
+
+/**
+ * Tax Config Notification
+ */
+class Notification extends \Magento\Framework\App\Config\Value
+{
+    /**
+     * @var \Magento\Core\Model\Resource\Config
+     */
+    protected $resourceConfig;
+
+    /**
+     * @param \Magento\Framework\Model\Context $context
+     * @param \Magento\Framework\Registry $registry
+     * @param \Magento\Framework\App\Config\ScopeConfigInterface $config
+     * @param \Magento\Core\Model\Resource\Config $resourceConfig
+     * @param \Magento\Framework\Model\Resource\AbstractResource $resource
+     * @param \Magento\Framework\Data\Collection\Db $resourceCollection
+     * @param array $data
+     */
+    public function __construct(
+        \Magento\Framework\Model\Context $context,
+        \Magento\Framework\Registry $registry,
+        \Magento\Framework\App\Config\ScopeConfigInterface $config,
+        \Magento\Core\Model\Resource\Config $resourceConfig,
+        \Magento\Framework\Model\Resource\AbstractResource $resource = null,
+        \Magento\Framework\Data\Collection\Db $resourceCollection = null,
+        array $data = array()
+    ) {
+        $this->resourceConfig = $resourceConfig;
+        parent::__construct($context, $registry, $config, $resource, $resourceCollection, $data);
+    }
+
+    /**
+     * Prepare and store cron settings after save
+     *
+     * @return \Magento\Tax\Model\Config\Notification
+     */
+    protected function _afterSave()
+    {
+        if ($this->isValueChanged()) {
+            $this->_resetNotificationFlag(\Magento\Tax\Model\Config::XML_PATH_TAX_NOTIFICATION_IGNORE_DISCOUNT);
+            $this->_resetNotificationFlag(\Magento\Tax\Model\Config::XML_PATH_TAX_NOTIFICATION_IGNORE_PRICE_DISPLAY);
+        }
+        return parent::_afterSave($this);
+    }
+
+    /**
+     * Reset flag for showing tax notifications
+     *
+     * @param string $path
+     * @return \Magento\Tax\Model\Config\Notification
+     */
+    protected function _resetNotificationFlag($path)
+    {
+        $this->resourceConfig->saveConfig($path, 0, \Magento\Framework\App\ScopeInterface::SCOPE_DEFAULT, 0);
+        return $this;
+    }
+}
diff --git a/app/code/Magento/Tax/Model/Sales/Total/Quote/Tax.php b/app/code/Magento/Tax/Model/Sales/Total/Quote/Tax.php
index fc1080efb468a322d559a0476636788f292ca1a4..87a6942814093a8e62fba64a7032ca21179269f8 100644
--- a/app/code/Magento/Tax/Model/Sales/Total/Quote/Tax.php
+++ b/app/code/Magento/Tax/Model/Sales/Total/Quote/Tax.php
@@ -933,7 +933,6 @@ class Tax extends AbstractTotal
         $rateKey = ($taxId == null) ? (string)$rate : $taxId;
         $taxSubtotal = $subtotal = $item->getTaxableAmount() + $item->getExtraRowTaxableAmount();
         $baseTaxSubtotal = $baseSubtotal = $item->getBaseTaxableAmount() + $item->getBaseExtraRowTaxableAmount();
-        $item->setTaxPercent($rate);
 
         if (!isset($taxGroups[$rateKey]['totals'])) {
             $taxGroups[$rateKey]['totals'] = array();
diff --git a/app/code/Magento/Tax/Model/System/Message/Notifications.php b/app/code/Magento/Tax/Model/System/Message/Notifications.php
new file mode 100644
index 0000000000000000000000000000000000000000..4e0d52ef0630cdeff548a424b70eb66012c3f778
--- /dev/null
+++ b/app/code/Magento/Tax/Model/System/Message/Notifications.php
@@ -0,0 +1,337 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license   http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Tax\Model\System\Message;
+
+/**
+ * Notifications class
+ */
+class Notifications implements \Magento\AdminNotification\Model\System\MessageInterface
+{
+    /**
+     * Store manager object
+     *
+     * @var \Magento\Store\Model\StoreManagerInterface
+     */
+    protected $storeManager;
+
+    /**
+     * @var \Magento\Framework\UrlInterface
+     */
+    protected $urlBuilder;
+
+    /**
+     * Tax configuration object
+     *
+     * @var \Magento\Tax\Model\Config
+     */
+    protected $taxConfig;
+
+    /*
+     * Stores with invalid display settings
+     *
+     * @var array
+     */
+    protected $storesWithInvalidDisplaySettings;
+
+    /*
+     * Websites with invalid discount settings
+     *
+     * @var array
+     */
+    protected $storesWithInvalidDiscountSettings;
+
+    /*
+     * Stores with conflicting FPT settings
+     *
+     * @var array
+     */
+    protected $storesWithConflictingFPTSettings;
+
+    /**
+     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
+     * @param \Magento\Framework\UrlInterface $urlBuilder
+     * @param \Magento\Tax\Model\Config $taxConfig
+     */
+    public function __construct(
+        \Magento\Store\Model\StoreManagerInterface $storeManager,
+        \Magento\Framework\UrlInterface $urlBuilder,
+        \Magento\Tax\Model\Config $taxConfig
+    ) {
+        $this->storeManager = $storeManager;
+        $this->urlBuilder = $urlBuilder;
+        $this->taxConfig = $taxConfig;
+    }
+
+    /**
+     * Retrieve unique message identity
+     *
+     * @return string
+     */
+    public function getIdentity()
+    {
+        return md5('TAX_NOTIFICATION');
+    }
+
+    /**
+     * Check if tax calculation type and price display settings are compatible
+     *
+     * Invalid settings if
+     *      Tax Calculation Method Based On 'Total' or 'Row'
+     *      and at least one Price Display Settings has 'Including and Excluding Tax' value
+     *
+     * @param null|int|bool|string|Store $store $store
+     * @return bool
+     */
+    public function checkDisplaySettings($store = null)
+    {
+        if ($this->taxConfig->getAlgorithm($store) == \Magento\Tax\Model\Calculation::CALC_UNIT_BASE) {
+            return true;
+        }
+        return $this->taxConfig->getPriceDisplayType($store) != \Magento\Tax\Model\Config::DISPLAY_TYPE_BOTH
+        && $this->taxConfig->getShippingPriceDisplayType($store) != \Magento\Tax\Model\Config::DISPLAY_TYPE_BOTH
+        && !$this->taxConfig->displayCartPricesBoth($store)
+        && !$this->taxConfig->displayCartSubtotalBoth($store)
+        && !$this->taxConfig->displayCartShippingBoth($store)
+        && !$this->taxConfig->displaySalesPricesBoth($store)
+        && !$this->taxConfig->displaySalesSubtotalBoth($store)
+        && !$this->taxConfig->displaySalesShippingBoth($store);
+    }
+
+    /**
+     * Check if tax discount settings are compatible
+     *
+     * Matrix for invalid discount settings is as follows:
+     *      Before Discount / Excluding Tax
+     *      Before Discount / Including Tax
+     *
+     * @param null|int|bool|string|Store $store $store
+     * @return bool
+     */
+    public function checkDiscountSettings($store = null)
+    {
+        return $this->taxConfig->applyTaxAfterDiscount($store);
+    }
+
+    /**
+     * Get URL for the tax notification documentation
+     *
+     * @return string
+     */
+    public function getInfoUrl()
+    {
+        return $this->taxConfig->getInfoUrl();
+    }
+
+    /**
+     * Get URL to the admin tax configuration page
+     *
+     * @return string
+     */
+    public function getManageUrl()
+    {
+        return $this->urlBuilder->getUrl('adminhtml/system_config/edit/section/tax');
+    }
+
+    /**
+     * Get URL to ignore tax notifications
+     *
+     * @param string $section
+     * @return string
+     */
+    public function getIgnoreTaxNotificationUrl($section)
+    {
+        return $this->urlBuilder->getUrl('tax/tax/ignoreTaxNotification', array('section' => $section));
+    }
+
+    /**
+     * Return list of store names which have not compatible tax calculation type and price display settings.
+     * Return true if settings are wrong for default store.
+     *
+     * @return array
+     */
+    public function getStoresWithWrongDisplaySettings()
+    {
+        $storeNames = array();
+        $storeCollection = $this->storeManager->getStores(true);
+        foreach ($storeCollection as $store) {
+            if (!$this->checkDisplaySettings($store)) {
+                $website = $store->getWebsite();
+                $storeNames[] = $website->getName() . '(' . $store->getName() . ')';
+            }
+        }
+        return $storeNames;
+    }
+
+    /**
+     * Return list of store names where tax discount settings are compatible.
+     * Return true if settings are wrong for default store.
+     *
+     * @return array
+     */
+    public function getStoresWithWrongDiscountSettings()
+    {
+        $storeNames = array();
+        $storeCollection = $this->storeManager->getStores(true);
+        foreach ($storeCollection as $store) {
+            if (!$this->checkDiscountSettings($store)) {
+                $website = $store->getWebsite();
+                $storeNames[] = $website->getName() . '(' . $store->getName() . ')';
+            }
+        }
+        return $storeNames;
+    }
+
+    /**
+     * Return list of store names which have not compatible tax calculation type and price display settings.
+     * Return true if settings are wrong for default store.
+     *
+     * @return array
+     */
+    public function getStoresWithConflictingFptTaxConfigurationSettings()
+    {
+        $storeNames = array();
+
+        // Will enable in future work
+        //$storeCollection = $this->storeManager->getStores(true);
+        //foreach ($storeCollection as $store) {
+        //    if ($this->weeeData->validateCatalogPricesAndFptConfiguration($store)) {
+        //        $website = $store->getWebsite();
+        //        $storeNames[] = $website->getName() . '(' . $store->getName() . ')';
+        //    }
+        //}
+
+        return $storeNames;
+    }
+
+    /**
+     * Check whether notification is displayed
+     * Checks if any of these settings are being ignored or valid:
+     *      1. Wrong discount settings
+     *      2. Wrong display settings
+     *      3. Conflicting FPT settings
+     *
+     * @return bool
+     */
+    public function isDisplayed()
+    {
+        // Check if we are ignoring all notifications
+        if ($this->taxConfig->isWrongDisplaySettingsIgnored() && $this->taxConfig->isWrongDiscountSettingsIgnored()
+            && $this->taxConfig->isConflictingFptTaxConfigurationSettingsIgnored()) {
+            return false;
+        }
+
+        $this->storesWithInvalidDisplaySettings = $this->getStoresWithWrongDisplaySettings();
+        $this->storesWithInvalidDiscountSettings = $this->getStoresWithWrongDiscountSettings();
+        $this->storesWithConflictingFPTSettings = $this->getStoresWithConflictingFptTaxConfigurationSettings();
+
+        // Check if we have valid tax notifications
+        if ((!empty($this->storesWithInvalidDisplaySettings) && !$this->taxConfig->isWrongDisplaySettingsIgnored())
+            || (!empty($this->storesWithInvalidDiscountSettings) && !$this->taxConfig->isWrongDiscountSettingsIgnored())
+            || (!empty($this->storesWithConflictingFPTSettings)
+                && !$this->taxConfig->isConflictingFptTaxConfigurationSettingsIgnored())) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Build message text
+     * Determine which notification and data to display
+     *
+     * @return string
+     */
+    public function getText()
+    {
+        $messageDetails = '';
+
+        if (!empty($this->storesWithInvalidDisplaySettings) && !$this->taxConfig->isWrongDisplaySettingsIgnored()) {
+            $messageDetails .= '<strong>';
+            $messageDetails .= __('Warning tax configuration can result in rounding errors. ');
+            $messageDetails .= '</strong><br>';
+            $messageDetails .= __('Store(s) affected: ');
+            $messageDetails .= implode(', ', $this->storesWithInvalidDisplaySettings);
+            $messageDetails .= '<br><div style="text-align:right">';
+            $messageDetails .= __(
+                'Click on the link to <a href="%1">ignore this notification</a>',
+                $this->getIgnoreTaxNotificationUrl('price_display')
+            );
+            $messageDetails .= "</div><br>";
+        }
+
+        if (!empty($this->storesWithInvalidDiscountSettings) && !$this->taxConfig->isWrongDiscountSettingsIgnored()) {
+            $messageDetails .= '<strong>';
+            $messageDetails .= __(
+                'Warning tax discount configuration might result in different discounts
+                                than a customer might expect. '
+            );
+            $messageDetails .= '</strong><br>';
+            $messageDetails .= __('Store(s) affected: ');
+            $messageDetails .= implode(', ', $this->storesWithInvalidDiscountSettings);
+            $messageDetails .= '<br><div style="text-align:right">';
+            $messageDetails .= __(
+                'Click on the link to <a href="%1">ignore this notification</a>',
+                $this->getIgnoreTaxNotificationUrl('discount')
+            );
+            $messageDetails .= "</div><br>";
+        }
+
+        if (!empty($this->storesWithConflictingFPTSettings)
+            && !$this->taxConfig->isConflictingFptTaxConfigurationSettingsIgnored()
+        ) {
+            $messageDetails .= '<strong>';
+            $messageDetails .= __(
+                'Warning tax configuration can result in unexpected FPT prices on applicable devices. '
+            );
+            $messageDetails .= '</strong><br>';
+            $messageDetails .= __('Store(s) affected: ');
+            $messageDetails .= implode(', ', $this->storesWithConflictingFPTSettings);
+            $messageDetails .= '<br><div style="text-align:right">';
+            $messageDetails .= __(
+                'Click on the link to <a href="%1">ignore this notification</a>',
+                $this->getIgnoreTaxNotificationUrl('fpt_configuration')
+            );
+            $messageDetails .= "</div><br>";
+        }
+
+        $messageDetails .= '<br>';
+        $messageDetails .= __('Please see <a href="%1">documentation</a> for more details. ', $this->getInfoUrl());
+        $messageDetails .= __(
+            'Click here to go to <a href="%1">Tax Configuration</a> and change your settings.',
+            $this->getManageUrl()
+        );
+
+        return $messageDetails;
+    }
+
+    /**
+     * Retrieve message severity
+     *
+     * @return int
+     */
+    public function getSeverity()
+    {
+        return self::SEVERITY_CRITICAL;
+    }
+}
diff --git a/app/code/Magento/Tax/Pricing/Adjustment.php b/app/code/Magento/Tax/Pricing/Adjustment.php
index daa43ca113ed050a5a52b70f73df953880240482..edd8467edf5e0a91267b1721929be69735d04c17 100644
--- a/app/code/Magento/Tax/Pricing/Adjustment.php
+++ b/app/code/Magento/Tax/Pricing/Adjustment.php
@@ -98,7 +98,7 @@ class Adjustment implements AdjustmentInterface
     public function extractAdjustment($amount, SaleableInterface $saleableItem)
     {
         if ($this->taxHelper->priceIncludesTax()) {
-            $adjustedAmount = $this->taxHelper->getPrice($saleableItem, $amount);
+            $adjustedAmount = $this->taxHelper->getPriceUnrounded($saleableItem, $amount);
             $result = $amount - $adjustedAmount;
         } else {
             $result = 0.;
@@ -116,7 +116,7 @@ class Adjustment implements AdjustmentInterface
     public function applyAdjustment($amount, SaleableInterface $saleableItem)
     {
         $includingTax = !$this->taxHelper->priceIncludesTax();
-        return $this->taxHelper->getPrice($saleableItem, $amount, $includingTax);
+        return $this->taxHelper->getPriceUnrounded($saleableItem, $amount, $includingTax);
     }
 
     /**
diff --git a/app/code/Magento/Tax/etc/adminhtml/di.xml b/app/code/Magento/Tax/etc/adminhtml/di.xml
new file mode 100644
index 0000000000000000000000000000000000000000..16e2bb8fa3cff244161ad90987a93dd1711aa5aa
--- /dev/null
+++ b/app/code/Magento/Tax/etc/adminhtml/di.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0"?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
+    <type name="Magento\AdminNotification\Model\System\MessageList">
+        <arguments>
+            <argument name="messages" xsi:type="array">
+                <item name="tax" xsi:type="string">Magento\Tax\Model\System\Message\Notifications</item>
+            </argument>
+        </arguments>
+    </type>
+</config>
\ No newline at end of file
diff --git a/app/code/Magento/Tax/etc/adminhtml/system.xml b/app/code/Magento/Tax/etc/adminhtml/system.xml
index 9c1ec0e5e212de8204e4926ab043ab9d6507c318..0e240d0de7bc7b5f838012e6a4196b8f87223d0e 100644
--- a/app/code/Magento/Tax/etc/adminhtml/system.xml
+++ b/app/code/Magento/Tax/etc/adminhtml/system.xml
@@ -54,6 +54,7 @@
                 <field id="based_on" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="0">
                     <label>Tax Calculation Based On</label>
                     <source_model>Magento\Tax\Model\Config\Source\Basedon</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                 </field>
                 <field id="price_includes_tax" translate="label comment" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="0">
                     <label>Catalog Prices</label>
@@ -70,16 +71,23 @@
                 <field id="apply_after_discount" translate="label comment" type="select" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="0">
                     <label>Apply Customer Tax</label>
                     <source_model>Magento\Tax\Model\System\Config\Source\Apply</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                 </field>
                 <field id="discount_tax" translate="label comment" type="select" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="0">
                     <label>Apply Discount On Prices</label>
                     <source_model>Magento\Tax\Model\System\Config\Source\PriceType</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                     <comment>Apply discount on price including tax is calculated based on store tax, if "Apply Tax after Discount" is selected.</comment>
                 </field>
                 <field id="apply_tax_on" translate="label comment" type="select" sortOrder="60" showInDefault="1" showInWebsite="1" showInStore="0">
                     <label>Apply Tax On</label>
                     <source_model>Magento\Tax\Model\Config\Source\Apply\On</source_model>
                 </field>
+                <field id="cross_border_trade_enabled" translate="label comment" type="select" sortOrder="70" showInDefault="1" showInWebsite="1" showInStore="0">
+                    <label>Enable Cross Border Trade</label>
+                    <source_model>Magento\Backend\Model\Config\Source\Yesno</source_model>
+                    <comment>When catalog price includes tax, enable this setting will fix the price no matter what the customer's tax rate is.</comment>
+                </field>
             </group>
             <group id="defaults" translate="label" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
                 <label>Default Tax Destination Calculation</label>
@@ -101,10 +109,12 @@
                 <field id="type" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Display Product Prices In Catalog</label>
                     <source_model>Magento\Tax\Model\System\Config\Source\Tax\Display\Type</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                 </field>
                 <field id="shipping" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Display Shipping Prices</label>
                     <source_model>Magento\Tax\Model\System\Config\Source\Tax\Display\Type</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                 </field>
             </group>
             <group id="cart_display" translate="label" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
@@ -112,14 +122,17 @@
                 <field id="price" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Display Prices</label>
                     <source_model>Magento\Tax\Model\System\Config\Source\Tax\Display\Type</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                 </field>
                 <field id="subtotal" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Display Subtotal</label>
                     <source_model>Magento\Tax\Model\System\Config\Source\Tax\Display\Type</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                 </field>
                 <field id="shipping" translate="label" type="select" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Display Shipping Amount</label>
                     <source_model>Magento\Tax\Model\System\Config\Source\Tax\Display\Type</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                 </field>
                 <field id="grandtotal" translate="label" type="select" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Include Tax In Grand Total</label>
@@ -139,14 +152,17 @@
                 <field id="price" translate="label" type="select" sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Display Prices</label>
                     <source_model>Magento\Tax\Model\System\Config\Source\Tax\Display\Type</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                 </field>
                 <field id="subtotal" translate="label" type="select" sortOrder="20" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Display Subtotal</label>
                     <source_model>Magento\Tax\Model\System\Config\Source\Tax\Display\Type</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                 </field>
                 <field id="shipping" translate="label" type="select" sortOrder="30" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Display Shipping Amount</label>
                     <source_model>Magento\Tax\Model\System\Config\Source\Tax\Display\Type</source_model>
+                    <backend_model>Magento\Tax\Model\Config\Notification</backend_model>
                 </field>
                 <field id="grandtotal" translate="label" type="select" sortOrder="50" showInDefault="1" showInWebsite="1" showInStore="1">
                     <label>Include Tax In Grand Total</label>
diff --git a/app/code/Magento/Tax/etc/config.xml b/app/code/Magento/Tax/etc/config.xml
index 9df3ec19f8dd80310d351616fea39299aa53f97a..9d4ef0238027de34643fe8e691e2eaeea79e263e 100644
--- a/app/code/Magento/Tax/etc/config.xml
+++ b/app/code/Magento/Tax/etc/config.xml
@@ -31,7 +31,7 @@
             </classes>
             <calculation>
                 <algorithm>TOTAL_BASE_CALCULATION</algorithm>
-                <apply_after_discount>0</apply_after_discount>
+                <apply_after_discount>1</apply_after_discount>
                 <discount_tax>0</discount_tax>
                 <based_on>shipping</based_on>
                 <price_includes_tax>0</price_includes_tax>
@@ -66,6 +66,9 @@
                 <full_summary>0</full_summary>
                 <zero_tax>0</zero_tax>
             </sales_display>
+            <notification>
+                <url>http://www.magentocommerce.com/knowledge-base/entry/magento-ce-18-ee-113-tax-calc</url>
+            </notification>
         </tax>
     </default>
 </config>
diff --git a/app/code/Magento/Tax/etc/module.xml b/app/code/Magento/Tax/etc/module.xml
index 39c8385237c06b43917c1f0d6099460299f72b52..4a737678df7c304d7eb91b968c1d8107d5eced72 100644
--- a/app/code/Magento/Tax/etc/module.xml
+++ b/app/code/Magento/Tax/etc/module.xml
@@ -44,6 +44,7 @@
             <module name="Magento_Reports"/>
             <module name="Magento_Theme"/>
             <module name="Magento_ConfigurableProduct"/>
+            <module name="Magento_AdminNotification"/>
         </depends>
     </module>
 </config>
diff --git a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml
index c64f797803d1ae57802e66f8de09d98001f24dc0..56f0be480113ae2bf17172ab91fc6b79f8db2078 100644
--- a/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml
+++ b/app/code/Magento/Tax/view/adminhtml/layout/tax_rule_block.xml
@@ -94,6 +94,13 @@
                         <argument name="type" xsi:type="string">text</argument>
                     </arguments>
                 </block>
+                <block class="Magento\Backend\Block\Widget\Grid\Column" as="calculate_subtotal">
+                    <arguments>
+                        <argument name="header" xsi:type="string" translate="true">Subtotal Only</argument>
+                        <argument name="index" xsi:type="string">calculate_subtotal</argument>
+                        <argument name="type" xsi:type="string">text</argument>
+                    </arguments>
+                </block>
                 <block class="Magento\Backend\Block\Widget\Grid\Column" as="position">
                     <arguments>
                         <argument name="header" xsi:type="string" translate="true">Sort Order</argument>
diff --git a/app/code/Magento/Weee/Model/Tax.php b/app/code/Magento/Weee/Model/Tax.php
index f9c8fa904b5fc603e8af21e5f653b4824b4ae4ba..c826dbe93b0a02640c5233915603763347e15750 100644
--- a/app/code/Magento/Weee/Model/Tax.php
+++ b/app/code/Magento/Weee/Model/Tax.php
@@ -242,7 +242,7 @@ class Tax extends \Magento\Framework\Model\AbstractModel
         }
 
         $rateRequest = $calculator->getRateRequest($shipping, $billing, $customerTaxClass, $store);
-        $defaultRateRequest = $calculator->getRateRequest(false, false, false, $store);
+        $defaultRateRequest = $calculator->getDefaultRateRequest($store);
 
         $discountPercent = 0;
         if (!$ignoreDiscount && $this->_weeeData->isDiscounted($store)) {
diff --git a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module.less b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module.less
index 09c58867ae82873e61385606b3853b85c149ff20..1c58ab846ef30d7806f35a6b2f57c7e96301339a 100644
--- a/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module.less
+++ b/app/design/adminhtml/Magento/backend/Magento_Backend/web/css/source/module.less
@@ -90,6 +90,7 @@
         text-align: left;
         position: relative;
         z-index: 1;
+        margin: 0 10px;
         &.active {
             z-index: 999;
         }
@@ -122,6 +123,7 @@
         .qty.counter {
             display: inline-block;
             background: #ed4f2e;
+            color: @primary7;
             font-size: 12px;
             line-height: 12px;
             font-weight: bold;
diff --git a/app/design/adminhtml/Magento/backend/web/css/admin.less b/app/design/adminhtml/Magento/backend/web/css/admin.less
index bd89088c42bd7e063b576938aca9fbc45930c22a..6333aaf2fa21753d8fd81d49fe27a973ae86c56e 100644
--- a/app/design/adminhtml/Magento/backend/web/css/admin.less
+++ b/app/design/adminhtml/Magento/backend/web/css/admin.less
@@ -3677,10 +3677,11 @@ tr.dynamic-grid input.input-text {
     float: none;
 }
 
-.fpt-item-container select {
-    width: 100%;
-
-    &:first-child {
+.data-table .fpt-item-container {
+    td {
+        vertical-align: top;
+    }
+    select:first-child {
         margin-bottom: 8px;
     }
 }
@@ -3688,6 +3689,7 @@ tr.dynamic-grid input.input-text {
 .eq-ie9 {
     .col-1-layout,
     .catalog-product-edit,
+    .catalog-product-new,
     .sales-order-view,
     .catalog-category-edit {
         table.data {
diff --git a/app/design/adminhtml/Magento/backend/web/css/source/table.less b/app/design/adminhtml/Magento/backend/web/css/source/table.less
index 2b95c3b3630b756dc103a392e6c4d692111412c6..447c0997800770b1d2a8963e815b45f111a5a70e 100644
--- a/app/design/adminhtml/Magento/backend/web/css/source/table.less
+++ b/app/design/adminhtml/Magento/backend/web/css/source/table.less
@@ -337,7 +337,8 @@ table {
         &.col-time,
         &.col-billing_name,
         &.col-shipping_name,
-        &.col-phone {
+        &.col-phone,
+        &.col-type {
             &:extend(.ellipsis all);
         }
     }
@@ -416,6 +417,11 @@ table {
         &:extend(.col-40 all);
     }
 
+    .col-select,
+    .col-massaction {
+        text-align: center;
+    }
+
     .editable .input-text {
         width: 65px;
     }
@@ -460,7 +466,8 @@ td.col-updated_at,
 td.col-customer_since,
 td.col-session_start_time,
 td.col-time,
-td.col-sku {
+td.col-sku,
+td.col-type {
     &:extend(.nowrap all);
 }
 
@@ -1105,6 +1112,9 @@ td.col-sku {
     .rma-request-details {
         &:extend(.data-table-td-max all);
     }
+    #rma_items_grid_table .headings th {
+        &:extend(.nowrap all);
+    }
 }
 
 .adminhtml-rma-edit {
@@ -1138,6 +1148,10 @@ td.col-sku {
     }
 }
 
+.catalog-product-index .grid .hor-scroll {
+    &:extend(.h-scroll);
+}
+
 .catalog-product-review-index {
     .grid {
         .col-name,
@@ -1561,7 +1575,7 @@ td.col-sku {
 .adminhtml-cache-index,
 .adminhtml-process-list,
 .indexer-indexer-list {
-    .col-select {
+    .grid .col-select {
         width: 10px;
     }
 }
diff --git a/app/design/adminhtml/Magento/backend/web/js/theme.js b/app/design/adminhtml/Magento/backend/web/js/theme.js
index e2992b036202500d3a6562a90cc0f70a62e96b23..01d7ba7252d805787734bc34789e55c41172d13d 100644
--- a/app/design/adminhtml/Magento/backend/web/js/theme.js
+++ b/app/design/adminhtml/Magento/backend/web/js/theme.js
@@ -142,16 +142,22 @@
         },
 
         _leaveEffects: function (e) {
-            var targetSubmenu = $(e.target).closest('.submenu');
+            var targetSubmenu = $(e.target).closest('.submenu'),
+            self = $(this),
+            submenu = $('> .submenu', this);
+
             if(targetSubmenu.length && targetSubmenu.is(':hidden')) {
                 return;
             }
-            var self = $(this);
 
-            $('> .submenu', this)
-                .slideUp('fast', function() {
+            if(submenu.length) {
+                submenu.slideUp('fast', function() {
                     self.removeClass('hover');
                 });
+            } else {
+                self.removeClass('hover');
+            }
+
         }
     });
 
diff --git a/dev/tests/functional/lib/Mtf/Client/Driver/Selenium/Element/MultiselectlistElement.php b/dev/tests/functional/lib/Mtf/Client/Driver/Selenium/Element/MultiselectlistElement.php
index 0b2526fa6f667bfb0e3e6aa327faeb08e268fd1e..8f58e9e552973a0f248686406bebdab0bdea1f8d 100644
--- a/dev/tests/functional/lib/Mtf/Client/Driver/Selenium/Element/MultiselectlistElement.php
+++ b/dev/tests/functional/lib/Mtf/Client/Driver/Selenium/Element/MultiselectlistElement.php
@@ -123,4 +123,22 @@ class MultiselectlistElement extends MultiselectElement
 
         return $options;
     }
+
+    /**
+     * Method that returns array with all options in multiple select list
+     *
+     * @return array
+     */
+    public function getAllValues()
+    {
+        $optionsValue = [];
+        $options = $this->getOptions();
+
+        foreach ($options as $option) {
+            /** @var Element $option */
+            $optionsValue[] = $option->getText();
+        }
+
+        return $optionsValue;
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/FormPageActions.php
index 636a537ea7476c03bfcc15298f4bd5f77e1fa3ca..a17327a5c59d18e0c4de538248f64b40aac512b5 100644
--- a/dev/tests/functional/tests/app/Magento/Backend/Test/Block/FormPageActions.php
+++ b/dev/tests/functional/tests/app/Magento/Backend/Test/Block/FormPageActions.php
@@ -29,7 +29,6 @@ use Mtf\Client\Element\Locator;
 /**
  * Class FormPageActions
  * Form page actions block
- *
  */
 class FormPageActions extends PageActions
 {
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php
index 9360e0d761f52514720b8415d656aa3133f0cdb2..721a1ddb748ff368df831147123767fe03cc024d 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Product/Price.php
@@ -24,7 +24,6 @@
 namespace Magento\Catalog\Test\Block\Product;
 
 use Mtf\Block\Block;
-use Mtf\Factory\Factory;
 use Mtf\Client\Element\Locator;
 
 /**
@@ -171,7 +170,9 @@ class Price extends Block
             $priceElement = $this->_rootElement->find($this->regularPriceClass, Locator::SELECTOR_CSS);
         }
         // return the actual value of the price
-        return $priceElement->find($this->priceClass, Locator::SELECTOR_CSS)->getText();
+        $element = $priceElement->find($this->priceClass, Locator::SELECTOR_CSS);
+        $price = preg_replace('#[^\d\.\s]+#umis', '', $element->getText());
+        return number_format(trim($price), 2);
     }
 
     /**
@@ -181,13 +182,10 @@ class Price extends Block
      */
     public function getSpecialPrice()
     {
-        return $this->_rootElement->find(
-            $this->specialPriceClass,
-            Locator::SELECTOR_CSS
-        )->find(
-            $this->priceClass,
-            Locator::SELECTOR_CSS
-        )->getText();
+        $element = $this->_rootElement->find($this->specialPriceClass, Locator::SELECTOR_CSS)
+            ->find($this->priceClass, Locator::SELECTOR_CSS);
+        $price = preg_replace('#[^\d\.\s]+#umis', '', $element->getText());
+        return number_format(trim($price), 2);
     }
 
     /**
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php
index e72639796d61a7cff6513069a27b51d67c355689..83987d7abd5524e702d421c7268a945bab99f450 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCart.php
@@ -114,7 +114,7 @@ class AssertProductInCart extends AbstractConstraint
 
         $price = $checkoutCart->getCartBlock()->getProductPriceByName($productName);
         \PHPUnit_Framework_Assert::assertEquals(
-            '$' . number_format($priceComparing, 2),
+            number_format($priceComparing, 2),
             $price,
             'Product price in shopping cart is not correct.'
         );
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php
index 58c7fd8faed3742a2ade30d6f42ceb5209acc86d..164eafe6024a2d1312495248c763cdf63427d8e2 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductInCategory.php
@@ -87,9 +87,8 @@ class AssertProductInCategory extends AbstractConstraint
         $price = $catalogCategoryView->getListProductBlock()->getProductPriceBlock($product->getName())
             ->getRegularPrice();
 
-        $priceComparing = '$' . number_format($product->getPrice(), 2);
         \PHPUnit_Framework_Assert::assertEquals(
-            $priceComparing,
+            number_format($product->getPrice(), 2),
             $price,
             'Product regular price on category page is not correct.'
         );
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple/Price.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple/Price.php
index a8726289546e6d7b7c0086674baeb2f699d26c7b..19d881b7ad2be459c7561707865cf077a8f39b48 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple/Price.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Fixture/CatalogProductSimple/Price.php
@@ -107,35 +107,35 @@ class Price implements FixtureInterface
     {
         $presets = [
             'MAGETWO-23062' => [
-                'category_price' => '$100.00',
-                'product_price' => '$100.00',
-                'cart_price' => '$130.00'
+                'category_price' => '100.00',
+                'product_price' => '100.00',
+                'cart_price' => '130.00'
             ],
             'MAGETWO-23063' => [
-                'category_price' => '$100.00',
-                'product_price' => '$100.00',
-                'cart_price' => '$140.00'
+                'category_price' => '100.00',
+                'product_price' => '100.00',
+                'cart_price' => '140.00'
             ],
             'MAGETWO-23029' => [
-                'category_price' => '$100.00',
-                'category_special_price' => '$90.00',
-                'product_price' => '$100.00',
-                'product_special_price' => '$90.00',
-                'cart_price' => '$120.00'
+                'category_price' => '100.00',
+                'category_special_price' => '90.00',
+                'product_price' => '100.00',
+                'product_special_price' => '90.00',
+                'cart_price' => '120.00'
             ],
             'MAGETWO-23030' => [
-                'category_price' => '$100.00',
-                'category_special_price' => '$90.00',
-                'product_price' => '$100.00',
-                'product_special_price' => '$90.00',
-                'cart_price' => '$126.00'
+                'category_price' => '100.00',
+                'category_special_price' => '90.00',
+                'product_price' => '100.00',
+                'product_special_price' => '90.00',
+                'cart_price' => '126.00'
             ],
             'MAGETWO-23036' => [
-                'category_price' => '$100.00',
-                'category_special_price' => '$90.00',
-                'product_price' => '$100.00',
-                'product_special_price' => '$90.00',
-                'cart_price' => '$90.00'
+                'category_price' => '100.00',
+                'category_special_price' => '90.00',
+                'product_price' => '100.00',
+                'product_special_price' => '90.00',
+                'cart_price' => '90.00'
             ]
         ];
         if (!isset($presets[$this->currentPreset])) {
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php
index 8b5a513031685e80f942eee96881e1783a52f073..79e02713099f50fbab0b77d011f4b7f9b9ac581c 100644
--- a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart.php
@@ -73,6 +73,27 @@ class Cart extends Block
      */
     protected $cartProductPrice = '//tr[string(td/div/strong/a)="%s"]/td[@class="col price excl tax"]/span/span';
 
+    /**
+     * 'Update Shopping Cart' button
+     *
+     * @var string
+     */
+    protected $updateShoppingCart = '[name="update_cart_action"]';
+
+    /**
+     * Quantity input selector
+     *
+     * @var string
+     */
+    protected $productQty = '//input[@type="number" and @title="Qty"]';
+
+    /**
+     * Cart item selector
+     *
+     * @var string
+     */
+    protected $cartItem = '//tr[normalize-space(td)="%s"]';
+
     /**
      * Get sub-total for the specified item in the cart
      *
@@ -81,9 +102,7 @@ class Cart extends Block
      */
     public function getCartItemSubTotal($product)
     {
-        $selector = '//tr[normalize-space(td)="' . $this->getProductName(
-            $product
-        ) . '"]' . $this->itemSubTotalSelector;
+        $selector = sprintf($this->cartItem, $this->getProductName($product)) . $this->itemSubTotalSelector;
         return $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->getText();
     }
 
@@ -95,8 +114,9 @@ class Cart extends Block
      */
     public function getCartItemSubTotalByProductName($productName)
     {
-        $selector = '//tr[normalize-space(td)="' . $productName . '"]' . $this->itemSubTotalSelector;
-        return $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->getText();
+        $selector = sprintf($this->cartItem, $productName) . $this->itemSubTotalSelector;
+        $itemSubtotal = $this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->getText();
+        return $this->escapeCurrency($itemSubtotal);
     }
 
     /**
@@ -108,15 +128,9 @@ class Cart extends Block
      */
     public function getCartItemUnitPrice($product, $currency = '$')
     {
-        $selector = '//tr[normalize-space(td)="' . $this->getProductName(
-            $product
-        ) . '"]' . $this->itemUnitPriceSelector;
-
+        $selector = sprintf($this->cartItem, $this->getProductName($product)) . $this->itemUnitPriceSelector;
         $prices = explode("\n", trim($this->_rootElement->find($selector, Locator::SELECTOR_XPATH)->getText()));
-        if (count($prices) == 1) {
-            return floatval(trim($prices[0], $currency));
-        }
-        return $this->formatPricesData($prices, $currency);
+        return floatval(trim($prices[0], $currency));
     }
 
     /**
@@ -236,7 +250,7 @@ class Cart extends Block
     public function isProductInShoppingCart($product)
     {
         return $this->_rootElement->find(
-            '//tr[normalize-space(td)="' . $this->getProductName($product) . '"]',
+            sprintf($this->cartItem, $this->getProductName($product)),
             Locator::SELECTOR_XPATH
         )->isVisible();
     }
@@ -268,6 +282,54 @@ class Cart extends Block
     public function getProductPriceByName($productName)
     {
         $priceSelector = sprintf($this->cartProductPrice, $productName);
-        return $this->_rootElement->find($priceSelector, Locator::SELECTOR_XPATH)->getText();
+        $cartProductPrice = $this->_rootElement->find($priceSelector, Locator::SELECTOR_XPATH)->getText();
+        return $this->escapeCurrency($cartProductPrice);
+    }
+
+    /**
+     * Update shopping cart
+     *
+     * @return void
+     */
+    public function updateShoppingCart()
+    {
+        $this->_rootElement->find($this->updateShoppingCart, Locator::SELECTOR_CSS)->click();
+    }
+
+    /**
+     * Set product quantity
+     *
+     * @param string $productName
+     * @param int $qty
+     * @return void
+     */
+    public function setProductQty($productName, $qty)
+    {
+        $productQtySelector = sprintf($this->cartItem, $productName) . $this->productQty;
+        $this->_rootElement->find($productQtySelector, Locator::SELECTOR_XPATH)->setValue($qty);
+    }
+
+    /**
+     * Get product quantity
+     *
+     * @param string $productName
+     * @return string
+     */
+    public function getProductQty($productName)
+    {
+        $productQtySelector = sprintf($this->cartItem, $productName) . $this->productQty;
+        return $this->_rootElement->find($productQtySelector, Locator::SELECTOR_XPATH)->getValue();
+    }
+
+    /**
+     * Method that escapes currency symbols
+     *
+     * @param string $price
+     * @return string
+     */
+    protected function escapeCurrency($price)
+    {
+        preg_match("/^\\D*\\s*([\\d,\\.]+)\\s*\\D*$/", $price, $matches);
+        return (isset($matches[1])) ? $matches[1] : null;
     }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php
new file mode 100644
index 0000000000000000000000000000000000000000..c557d720fd3fda0ed93fb01f8ed96bb7955ad3c3
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Block/Cart/Sidebar.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Checkout\Test\Block\Cart;
+
+use Mtf\Block\Block;
+use Mtf\Client\Element\Locator;
+
+/**
+ * Class Sidebar
+ * Mini shopping cart block
+ */
+class Sidebar extends Block
+{
+    /**
+     * Quantity input selector
+     *
+     * @var string
+     */
+    protected $qty = '//*[@class="product"]/*[@title="%s"]/following-sibling::*//*[@class="value qty"]';
+
+    /**
+     * Mini cart link selector
+     *
+     * @var string
+     */
+    protected $cartLink = 'a.showcart';
+
+    /**
+     * Mini cart content selector
+     *
+     * @var string
+     */
+    protected $cartContent = 'div.minicart';
+
+    /**
+     * Open mini cart
+     *
+     * @return void
+     */
+    public function openMiniCart()
+    {
+        if (!$this->_rootElement->find($this->cartContent)->isVisible()) {
+            $this->_rootElement->find($this->cartLink)->click();
+        }
+    }
+
+    /**
+     * Get product quantity
+     *
+     * @param string $productName
+     * @return string
+     */
+    public function getProductQty($productName)
+    {
+        $this->openMiniCart();
+        $productQty = sprintf($this->qty, $productName);
+        return $this->_rootElement->find($productQty, Locator::SELECTOR_XPATH)->getText();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php
new file mode 100644
index 0000000000000000000000000000000000000000..96949593e8a2f6e800368ee43601409b3e55859d
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertPriceInShoppingCart.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Checkout\Test\Constraint;
+
+use Mtf\Constraint\AbstractConstraint;
+use Magento\Checkout\Test\Page\CheckoutCart;
+use Magento\Checkout\Test\Fixture\Cart;
+use Magento\Catalog\Test\Fixture\CatalogProductSimple;
+
+/**
+ * Class AssertPriceInShoppingCart
+ */
+class AssertPriceInShoppingCart extends AbstractConstraint
+{
+    /**
+     * Constraint severeness
+     *
+     * @var string
+     */
+    protected $severeness = 'low';
+
+    /**
+     * Assert that price in the shopping cart equals to expected price from data set
+     *
+     * @param CheckoutCart $checkoutCart
+     * @param Cart $cart
+     * @param CatalogProductSimple $product
+     * @return void
+     */
+    public function processAssert(
+        CheckoutCart $checkoutCart,
+        Cart $cart,
+        CatalogProductSimple $product
+    ) {
+        $cartProductPrice = $checkoutCart->open()->getCartBlock()->getProductPriceByName($product->getName());
+        \PHPUnit_Framework_Assert::assertEquals(
+            $cartProductPrice,
+            $cart->getPrice(),
+            'Shopping cart product price: \'' . $cartProductPrice
+            . '\' not equals with price from data set: \'' . $cart->getPrice() . '\''
+        );
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Price in the shopping cart equals to expected price from data set.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInMiniShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInMiniShoppingCart.php
new file mode 100644
index 0000000000000000000000000000000000000000..d13ad0604139484784229f11dd5ef67dbc71912d
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInMiniShoppingCart.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Checkout\Test\Constraint;
+
+use Mtf\Constraint\AbstractConstraint;
+use Magento\Cms\Test\Page\CmsIndex;
+use Magento\Checkout\Test\Fixture\Cart;
+use Magento\Catalog\Test\Fixture\CatalogProductSimple;
+
+/**
+ * Class AssertProductQtyInMiniShoppingCart
+ */
+class AssertProductQtyInMiniShoppingCart extends AbstractConstraint
+{
+    /**
+     * Constraint severeness
+     *
+     * @var string
+     */
+    protected $severeness = 'low';
+
+    /**
+     * Assert that product quantity in the mini shopping cart is equals to expected quantity from data set
+     *
+     * @param CmsIndex $cmsIndex
+     * @param Cart $cart
+     * @param CatalogProductSimple $product
+     * @return void
+     */
+    public function processAssert(
+        CmsIndex $cmsIndex,
+        Cart $cart,
+        CatalogProductSimple $product
+    ) {
+        $productQtyInMiniCart = $cmsIndex->open()->getCartSidebarBlock()->getProductQty($product->getName());
+        \PHPUnit_Framework_Assert::assertEquals(
+            $productQtyInMiniCart,
+            $cart->getQty(),
+            'Mini shopping cart product qty: \'' . $productQtyInMiniCart
+            . '\' not equals with qty from data set: \'' . $cart->getQty() . '\''
+        );
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Quantity in the mini shopping cart equals to expected quantity from data set.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php
new file mode 100644
index 0000000000000000000000000000000000000000..fa27cfce7b78115ef2a39c2a2be782eb5d2230d0
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertProductQtyInShoppingCart.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Checkout\Test\Constraint;
+
+use Mtf\Constraint\AbstractConstraint;
+use Magento\Checkout\Test\Page\CheckoutCart;
+use Magento\Checkout\Test\Fixture\Cart;
+use Magento\Catalog\Test\Fixture\CatalogProductSimple;
+
+/**
+ * Class AssertProductQtyInShoppingCart
+ */
+class AssertProductQtyInShoppingCart extends AbstractConstraint
+{
+    /**
+     * Constraint severeness
+     *
+     * @var string
+     */
+    protected $severeness = 'low';
+
+    /**
+     * Assert that quantity in the shopping cart is equals to expected quantity from data set
+     *
+     * @param CheckoutCart $checkoutCart
+     * @param Cart $cart
+     * @param CatalogProductSimple $product
+     * @return void
+     */
+    public function processAssert(
+        CheckoutCart $checkoutCart,
+        Cart $cart,
+        CatalogProductSimple $product
+    ) {
+        $cartProductQty = $checkoutCart->open()->getCartBlock()->getProductQty($product->getName());
+        \PHPUnit_Framework_Assert::assertEquals(
+            $cartProductQty,
+            $cart->getQty(),
+            'Shopping cart product qty: \'' . $cartProductQty
+            . '\' not equals with qty from data set: \'' . $cart->getQty() . '\''
+        );
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Quantity in the shopping cart equals to expected quantity from data set.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php
new file mode 100644
index 0000000000000000000000000000000000000000..c788bc26dcb83d757f0033698828771be13a2918
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/Constraint/AssertSubtotalInShoppingCart.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Checkout\Test\Constraint;
+
+use Mtf\Constraint\AbstractConstraint;
+use Magento\Checkout\Test\Page\CheckoutCart;
+use Magento\Checkout\Test\Fixture\Cart;
+use Magento\Catalog\Test\Fixture\CatalogProductSimple;
+
+/**
+ * Class AssertSubtotalInShoppingCart
+ */
+class AssertSubtotalInShoppingCart extends AbstractConstraint
+{
+    /**
+     * Constraint severeness
+     *
+     * @var string
+     */
+    protected $severeness = 'low';
+
+    /**
+     * Assert that subtotal total in the shopping cart is equals to expected total from data set
+     *
+     * @param CheckoutCart $checkoutCart
+     * @param Cart $cart
+     * @param CatalogProductSimple $product
+     * @return void
+     */
+    public function processAssert(
+        CheckoutCart $checkoutCart,
+        Cart $cart,
+        CatalogProductSimple $product
+    ) {
+        $cartProductSubtotal = $checkoutCart->open()->getCartBlock()
+            ->getCartItemSubTotalByProductName($product->getName());
+        \PHPUnit_Framework_Assert::assertEquals(
+            $cartProductSubtotal,
+            $cart->getRowTotal(),
+            'Shopping cart subtotal: \'' . $cartProductSubtotal
+            . '\' not equals with total from data set: \'' . $cart->getRowTotal() . '\''
+        );
+    }
+
+    /**
+     * Returns a string representation of the object.
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Subtotal in the shopping cart equals to expected total from data set.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/global/constraint.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/global/constraint.xml
new file mode 100644
index 0000000000000000000000000000000000000000..041a6ac5bf0447f6e039cffe4d00fdf0aeeb11c2
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/global/constraint.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" ?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<constraint>
+    <assertPriceInShoppingCart module="Magento_Checkout">
+        <severeness>low</severeness>
+    </assertPriceInShoppingCart>
+    <assertProductQtyInShoppingCart module="Magento_Checkout">
+        <severeness>low</severeness>
+    </assertProductQtyInShoppingCart>
+    <assertProductQtyInMiniShoppingCart module="Magento_Checkout">
+        <severeness>low</severeness>
+    </assertProductQtyInMiniShoppingCart>
+    <assertSubtotalInShoppingCart module="Magento_Checkout">
+        <severeness>low</severeness>
+    </assertSubtotalInShoppingCart>
+</constraint>
diff --git a/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/global/fixture.xml b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/global/fixture.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e9d8be3cb2647492c57ee1800402a6fbbcbc2a2e
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Checkout/Test/etc/global/fixture.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" ?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<fixture>
+    <cart module="Magento_Checkout">
+        <type>flat</type>
+        <entity_type>sales_flat_quote_item</entity_type>
+        <collection>Magento\Checkout\Model\Resource\Cart</collection>
+    </cart>
+</fixture>
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Actions.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Handler/CmsPage/CmsPageInterface.php
similarity index 70%
rename from dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Actions.php
rename to dev/tests/functional/tests/app/Magento/Cms/Test/Handler/CmsPage/CmsPageInterface.php
index 01ae4c2757b053b0b04ceede2f200266cc18e047..f111082b687369da435a30a649d48520249f1f8a 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Actions.php
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Handler/CmsPage/CmsPageInterface.php
@@ -1,7 +1,5 @@
 <?php
 /**
- * URL rewrite grid actions
- *
  * Magento
  *
  * NOTICE OF LICENSE
@@ -23,24 +21,15 @@
  * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
-namespace Magento\UrlRewrite\Test\Block;
 
-use Mtf\Block\Block;
+namespace Magento\Cms\Test\Handler\CmsPage;
 
-class Actions extends Block
-{
-    /**
-     * Add button
-     *
-     * @var string
-     */
-    protected $addNewButton = '#add';
+use Mtf\Handler\HandlerInterface;
 
-    /**
-     * Add new URL rewrite
-     */
-    public function addNewUrlRewrite()
-    {
-        $this->_rootElement->find($this->addNewButton)->click();
-    }
+/**
+ * Interface CmsPageInterface
+ */
+interface CmsPageInterface extends HandlerInterface
+{
+   //
 }
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Handler/CmsPage/Curl.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Handler/CmsPage/Curl.php
new file mode 100644
index 0000000000000000000000000000000000000000..a9cd22332ce78db1a7138da773ad2d7d5d427214
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Handler/CmsPage/Curl.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Cms\Test\Handler\CmsPage;
+
+use Mtf\Fixture\FixtureInterface;
+use Mtf\Handler\Curl as AbstractCurl;
+use Mtf\Util\Protocol\CurlInterface;
+use Mtf\Util\Protocol\CurlTransport;
+use Mtf\Util\Protocol\CurlTransport\BackendDecorator;
+use Mtf\System\Config;
+
+/**
+ * Class Curl
+ * Curl handler for creating cms page
+ */
+class Curl extends AbstractCurl implements CmsPageInterface
+{
+    /**
+     * Data mapping
+     *
+     * @var array
+     */
+    protected $mappingData = [
+        'status' => ['Published' => 1, 'Disabled' => 0],
+        'store_id' => ['All Store Views' => 0],
+    ];
+
+    /**
+     * Url for save rewrite
+     *
+     * @var string
+     */
+    protected $url = 'admin/cms_page/save/back/edit/active_tab/content_section/';
+
+    /**
+     * Post request for creating cms page
+     *
+     * @param FixtureInterface $fixture
+     * @return array
+     * @throws \Exception
+     */
+    public function persist(FixtureInterface $fixture = null)
+    {
+        $url = $_ENV['app_backend_url'] . $this->url;
+        $data = $this->replaceMappingData($fixture->getData());
+        $curl = new BackendDecorator(new CurlTransport(), new Config());
+        $curl->write(CurlInterface::POST, $url, '1.0', [], $data);
+        $response = $curl->read();
+
+        if (!strpos($response, 'data-ui-id="messages-message-success"')) {
+            throw new \Exception("Page creation by curl handler was not successful! Response: $response");
+        }
+
+        preg_match("~page_id\/(\d*?)\/~", $response, $matches);
+        $id = isset($matches[1]) ? $matches[1] : null;
+        return ['page_id' => $id];
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.php b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.php
index 6c5e2cf5df734df72fe0d34d8657e41692f07951..2e110104a54f9ec3c7d229b76cab0df5dcd3514e 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.php
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.php
@@ -70,6 +70,12 @@ class CmsIndex extends FrontendPage
             'locator' => '[data-ui-id="language-switcher"]',
             'strategy' => 'css selector',
         ],
+        'cartSidebarBlock' => [
+            'name' => 'cartSidebarBlock',
+            'class' => 'Magento\Checkout\Test\Block\Cart\Sidebar',
+            'locator' => '[data-block="minicart"]',
+            'strategy' => 'css selector',
+        ],
     ];
 
     /**
@@ -119,4 +125,12 @@ class CmsIndex extends FrontendPage
     {
         return $this->getBlockInstance('storeSwitcherBlock');
     }
+
+    /**
+     * @return \Magento\Checkout\Test\Block\Cart\Sidebar
+     */
+    public function getCartSidebarBlock()
+    {
+        return $this->getBlockInstance('cartSidebarBlock');
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml
index a28d9698d8828060d9895992d55a369c8a6b0943..0f03a95f956a10066fbaa2e4879f2dfbaf6bb66d 100644
--- a/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml
+++ b/dev/tests/functional/tests/app/Magento/Cms/Test/Page/CmsIndex.xml
@@ -60,4 +60,10 @@
         <locator>//*[@data-ui-id="language-switcher"]</locator>
         <strategy>css selector</strategy>
     </block>
+    <block>
+        <name>cartSidebarBlock</name>
+        <class>Magento\Checkout\Test\Block\Cart\Sidebar</class>
+        <locator>[data-block="minicart"]</locator>
+        <strategy>css selector</strategy>
+    </block>
 </page>
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableInCategory.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableInCategory.php
index 03c60d74f23558c1fffad7614b8543ada98434a1..19b546ec68af83481e6e517ffd0acd2be5b3e22c 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableInCategory.php
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableInCategory.php
@@ -105,7 +105,7 @@ class AssertConfigurableInCategory extends AbstractConstraint
                 ->getProductPriceBlock($configurable->getName())
                 ->getPrice();
             \PHPUnit_Framework_Assert::assertEquals(
-                '$' . $price['price_regular_price'],
+                $price['price_regular_price'],
                 $pricePresetData['category_price'],
                 'Product price on category page is not correct.'
             );
diff --git a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableView.php b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableView.php
index 6a047a0f2ea089678c83b32f9986187b9252a13b..2bb1333dd39276175c222d382b0561f235d6927b 100644
--- a/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableView.php
+++ b/dev/tests/functional/tests/app/Magento/ConfigurableProduct/Test/Constraint/AssertConfigurableView.php
@@ -94,7 +94,7 @@ class AssertConfigurableView extends AbstractConstraint
                 ->getProductPriceBlock($configurable->getName())
                 ->getPrice();
             \PHPUnit_Framework_Assert::assertEquals(
-                '$' . $price['price_regular_price'],
+                $price['price_regular_price'],
                 $pricePresetData['product_price'],
                 'Product price on category page is not correct.'
             );
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php
index c21132f3c50762a83ac8843469abccbbcc1086ba..d6307d1e643154780f3aa50856fea08d58e47b68 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingInGrid.php
@@ -24,6 +24,8 @@
 
 namespace Magento\Review\Test\Constraint;
 
+use Magento\Review\Test\Fixture\Rating;
+use Magento\Review\Test\Page\Adminhtml\RatingIndex;
 use Mtf\Constraint\AbstractConstraint;
 
 /**
@@ -39,18 +41,30 @@ class AssertProductRatingInGrid extends AbstractConstraint
     protected $severeness = 'middle';
 
     /**
+     * Assert product Rating availability in product Rating grid
+     *
+     * @param RatingIndex $ratingIndex
+     * @param Rating $productRating
      * @return void
      */
-    public function processAssert()
+    public function processAssert(RatingIndex $ratingIndex, Rating $productRating)
     {
-        //
+        $filter = ['rating_code' => $productRating->getRatingCode()];
+
+        $ratingIndex->open();
+        \PHPUnit_Framework_Assert::assertTrue(
+            $ratingIndex->getRatingGrid()->isRowVisible($filter),
+            "Product Rating " . $productRating->getRatingCode() . " is absent on product Rating grid."
+        );
     }
 
     /**
+     * Text success exist product Rating in grid
+     *
      * @return string
      */
     public function toString()
     {
-        //
+        return 'Product Rating is present in grid.';
     }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInGrid.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInGrid.php
new file mode 100644
index 0000000000000000000000000000000000000000..41c760abbdf473c3c0d96e2be3afc99621f3a2a1
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingNotInGrid.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Review\Test\Constraint;
+
+use Magento\Review\Test\Fixture\Rating;
+use Magento\Review\Test\Page\Adminhtml\RatingIndex;
+use Mtf\Constraint\AbstractConstraint;
+
+/**
+ * Class AssertProductRatingNotInGrid
+ */
+class AssertProductRatingNotInGrid extends AbstractConstraint
+{
+    /**
+     * Constraint severeness
+     *
+     * @var string
+     */
+    protected $severeness = 'middle';
+
+    /**
+     * Assert product Rating is absent on product Rating grid
+     *
+     * @param RatingIndex $ratingIndex
+     * @param Rating $productRating
+     * @return void
+     */
+    public function processAssert(RatingIndex $ratingIndex, Rating $productRating)
+    {
+        $filter = ['rating_code' => $productRating->getRatingCode()];
+
+        $ratingIndex->open();
+        \PHPUnit_Framework_Assert::assertFalse(
+            $ratingIndex->getRatingGrid()->isRowVisible($filter),
+            "Product Rating " . $productRating->getRatingCode() . " is exist on product Rating grid."
+        );
+    }
+
+    /**
+     * Text success absent product Rating in grid
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Product Rating is absent in grid.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessDeleteMessage.php
new file mode 100644
index 0000000000000000000000000000000000000000..33e9dbcaf4c6b5fa168ddfa412e72d8b927d319a
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Constraint/AssertProductRatingSuccessDeleteMessage.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Review\Test\Constraint;
+
+use Magento\Review\Test\Page\Adminhtml\RatingIndex;
+use Mtf\Constraint\AbstractConstraint;
+
+/**
+ * Class AssertProductRatingSuccessDeleteMessage
+ */
+class AssertProductRatingSuccessDeleteMessage extends AbstractConstraint
+{
+    const SUCCESS_DELETE_MESSAGE = 'You deleted the rating.';
+
+    /**
+     * Constraint severeness
+     *
+     * @var string
+     */
+    protected $severeness = 'high';
+
+    /**
+     * Assert that success message is displayed after rating delete
+     *
+     * @param RatingIndex $ratingIndex
+     * @return void
+     */
+    public function processAssert(RatingIndex $ratingIndex)
+    {
+        $actualMessage = $ratingIndex->getMessagesBlock()->getSuccessMessages();
+        \PHPUnit_Framework_Assert::assertEquals(
+            self::SUCCESS_DELETE_MESSAGE,
+            $actualMessage,
+            'Wrong success message is displayed.'
+            . "\nExpected: " . self::SUCCESS_DELETE_MESSAGE
+            . "\nActual: " . $actualMessage
+        );
+    }
+
+    /**
+     * Text success delete message is displayed
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Rating success delete message is present.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Rating.php b/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Rating.php
index 517aa62be438fb2b0d83a7491b5d93ae65aa8fd7..447987b294d0918079d680608ef0bc276336360b 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Rating.php
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Fixture/Rating.php
@@ -34,12 +34,12 @@ class Rating extends InjectableFixture
     /**
      * @var string
      */
-    protected $repositoryClass = 'Magento\Rating\Test\Repository\Rating';
+    protected $repositoryClass = 'Magento\Review\Test\Repository\Rating';
 
     /**
      * @var string
      */
-    protected $handlerInterface = 'Magento\Rating\Test\Handler\Rating\RatingInterface';
+    protected $handlerInterface = 'Magento\Review\Test\Handler\Rating\RatingInterface';
 
     protected $defaultDataSet = [
         'rating_code' => 'Rating %isolation%',
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Handler/Rating/Curl.php b/dev/tests/functional/tests/app/Magento/Review/Test/Handler/Rating/Curl.php
new file mode 100644
index 0000000000000000000000000000000000000000..2672dc9b45a8517813fd79e1d33d7348cc4a1e22
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Handler/Rating/Curl.php
@@ -0,0 +1,96 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Review\Test\Handler\Rating;
+
+use Magento\Backend\Test\Handler\Extractor;
+use Mtf\Fixture\FixtureInterface;
+use Mtf\Handler\Curl as AbstractCurl;
+use Mtf\System\Config;
+use Mtf\Util\Protocol\CurlInterface;
+use Mtf\Util\Protocol\CurlTransport\BackendDecorator;
+use Mtf\Util\Protocol\CurlTransport;
+
+/**
+ * Class Curl
+ * Curl handler for creating product Rating through backend.
+ */
+class Curl extends AbstractCurl implements RatingInterface
+{
+    /**
+     * Mapping values for data.
+     *
+     * @var array
+     */
+    protected $mappingData = [
+        'is_active' => [
+            'Yes' => 1,
+            'No' => 0,
+        ],
+        'stores' => [
+            'Main Website/Main Website Store/Default Store View' => 1
+        ]
+    ];
+
+    /**
+     * Post request for creating product Rating in backend
+     *
+     * @param FixtureInterface|null $rating
+     * @return array
+     * @throws \Exception
+     */
+    public function persist(FixtureInterface $rating = null)
+    {
+        $url = $_ENV['app_backend_url'] . 'review/rating/save/';
+        $curl = new BackendDecorator(new CurlTransport(), new Config());
+        $data = $this->replaceMappingData($rating->getData());
+
+        $data['stores'] = is_array($data['stores']) ? $data['stores'] : [$data['stores']];
+        $curl->write(CurlInterface::POST, $url, '1.0', [], $data);
+        $response = $curl->read();
+        $curl->close();
+        if (!strpos($response, 'data-ui-id="messages-message-success"')) {
+            throw new \Exception(
+                'Product Rating entity creating by curl handler was not successful! Response:' . $response
+            );
+        }
+
+        return ['id' => $this->getProductRatingId()];
+    }
+
+    /**
+     * Get product Rating id
+     *
+     * @return int|null
+     */
+    protected function getProductRatingId()
+    {
+        $url = 'review/rating/index/sort/rating_id/dir/desc/';
+        $regex = '/data-column="rating_id"[^>]*>\s*([0-9]+)\s*</';
+        $extractor = new Extractor($url, $regex);
+        $match = $extractor->getData();
+
+        return empty($match[1]) ? null : $match[1];
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Handler/Rating/RatingInterface.php b/dev/tests/functional/tests/app/Magento/Review/Test/Handler/Rating/RatingInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..f3bea35c9ae23d692ddd5845ba54183205cd893f
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Handler/Rating/RatingInterface.php
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Review\Test\Handler\Rating;
+
+use Mtf\Handler\HandlerInterface;
+
+/**
+ * Interface RatingInterface
+ */
+interface RatingInterface extends HandlerInterface
+{
+    //
+}
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Rating.php b/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Rating.php
new file mode 100644
index 0000000000000000000000000000000000000000..4141b11447d8f6f30374802b865dcc11fcfcb134
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/Repository/Rating.php
@@ -0,0 +1,48 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Review\Test\Repository;
+
+use Mtf\Repository\AbstractRepository;
+
+/**
+ * Class Rating
+ * Data for creation product Rating
+ */
+class Rating extends AbstractRepository
+{
+    /**
+     * @constructor
+     * @param array $defaultConfig
+     * @param array $defaultData
+     */
+    public function __construct(array $defaultConfig = [], array $defaultData = [])
+    {
+        $this->_data['default'] = [
+            'rating_code' => 'Rating %isolation%',
+            'stores' => ['Main Website/Main Website Store/Default Store View'],
+            'is_active' => 'Yes',
+        ];
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateBackendProductRatingTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductRatingEntityTest.php
similarity index 96%
rename from dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateBackendProductRatingTest.php
rename to dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductRatingEntityTest.php
index e940b1497696dcb3a589694847f1012e8286b874..5d6f3dda381ec87c8609f384f32bcc3208086173 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateBackendProductRatingTest.php
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductRatingEntityTest.php
@@ -50,7 +50,7 @@ use Mtf\TestCase\Injectable;
  * @group Reviews_and_Ratings_(MX)
  * @ZephyrId MAGETWO-23331
  */
-class CreateBackendProductRatingTest extends Injectable
+class CreateProductRatingEntityTest extends Injectable
 {
     /**
      * @var Rating
@@ -97,7 +97,7 @@ class CreateBackendProductRatingTest extends Injectable
      * @param Rating $productRating
      * @return void
      */
-    public function testCreateBackendProductRating(
+    public function testCreateProductRatingEntityTest(
         CatalogProductSimple $product,
         Rating $productRating
     ) {
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateBackendProductRatingTest/testCreateBackendProductRating.csv b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductRatingEntityTest/testCreateProductRatingEntityTest.csv
similarity index 100%
rename from dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateBackendProductRatingTest/testCreateBackendProductRating.csv
rename to dev/tests/functional/tests/app/Magento/Review/Test/TestCase/CreateProductRatingEntityTest/testCreateProductRatingEntityTest.csv
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/DeleteProductRatingEntityTest.php b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/DeleteProductRatingEntityTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a9d58fc44b1775c61641bab82f0befc098d3cb91
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/DeleteProductRatingEntityTest.php
@@ -0,0 +1,105 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Review\Test\TestCase;
+
+use Magento\Catalog\Test\Fixture\CatalogProductSimple;
+use Magento\Review\Test\Fixture\Rating;
+use Magento\Review\Test\Page\Adminhtml\RatingEdit;
+use Magento\Review\Test\Page\Adminhtml\RatingIndex;
+use Mtf\TestCase\Injectable;
+
+/**
+ * Test Creation for DeleteProductRatingEntity
+ *
+ * Test Flow:
+ *
+ * Preconditions:
+ * 1. Simple product is created.
+ * 2. Product rating is created.
+ *
+ * Steps:
+ * 1. Login to backend.
+ * 2. Navigate to Stores->Attributes->Rating.
+ * 3. Search product rating in grid by given data.
+ * 4. Open this product rating by clicking.
+ * 5. Click 'Delete Rating' button.
+ * 6. Perform all asserts.
+ *
+ * @group Reviews_and_Ratings_(MX)
+ * @ZephyrId MAGETWO-23276
+ */
+class DeleteProductRatingEntityTest extends Injectable
+{
+    /**
+     * @var RatingIndex
+     */
+    protected $ratingIndex;
+
+    /**
+     * @var RatingEdit
+     */
+    protected $ratingEdit;
+
+    /**
+     * Prepare data
+     *
+     * @param CatalogProductSimple $product
+     * @return array
+     */
+    public function __prepare(CatalogProductSimple $product)
+    {
+        $product->persist();
+        return ['product' => $product];
+    }
+
+    /**
+     * Inject data
+     *
+     * @param RatingIndex $ratingIndex
+     * @param RatingEdit $ratingEdit
+     * @return void
+     */
+    public function __inject(RatingIndex $ratingIndex, RatingEdit $ratingEdit)
+    {
+        $this->ratingIndex = $ratingIndex;
+        $this->ratingEdit = $ratingEdit;
+    }
+
+    /**
+     * Runs delete product Rating entity test
+     *
+     * @param Rating $productRating
+     * @return void
+     */
+    public function testDeleteProductRatingEntity(Rating $productRating)
+    {
+        // Preconditions
+        $productRating->persist();
+
+        // Steps
+        $this->ratingIndex->open();
+        $this->ratingIndex->getRatingGrid()->searchAndOpen(['rating_code' => $productRating->getRatingCode()]);
+        $this->ratingEdit->getPageActions()->delete();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/DeleteProductRatingEntityTest/testDeleteProductRatingEntity.csv b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/DeleteProductRatingEntityTest/testDeleteProductRatingEntity.csv
new file mode 100644
index 0000000000000000000000000000000000000000..ef9e67e693c33b84579dacbff32ea8c5c0b949a0
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/TestCase/DeleteProductRatingEntityTest/testDeleteProductRatingEntity.csv
@@ -0,0 +1,2 @@
+"productRating/dataSet";"constraint"
+"default";"assertProductRatingSuccessDeleteMessage, assertProductRatingNotInGrid, assertProductRatingNotInProductPage"
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/etc/curl/di.xml b/dev/tests/functional/tests/app/Magento/Review/Test/etc/curl/di.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fa49f6b3789386ee515c6fd3a921cb216d39ad5d
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/etc/curl/di.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" ?>
+<!--
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Academic Free License (AFL 3.0)
+ * that is bundled with this package in the file LICENSE_AFL.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/afl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
+ */
+-->
+<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../../../../../../../../lib/internal/Magento/Framework/ObjectManager/etc/config.xsd">
+    <preference for="Magento\Review\Test\Handler\Rating\RatingInterface" type="\Magento\Review\Test\Handler\Rating\Curl"/>
+</config>
diff --git a/dev/tests/functional/tests/app/Magento/Review/Test/etc/global/constraint.xml b/dev/tests/functional/tests/app/Magento/Review/Test/etc/global/constraint.xml
index d69c444ee7cc43a2aba31af8ae861cdef0b6d4ba..d6f63c99b49b5fea30490965bea1ef2e1c3cd201 100644
--- a/dev/tests/functional/tests/app/Magento/Review/Test/etc/global/constraint.xml
+++ b/dev/tests/functional/tests/app/Magento/Review/Test/etc/global/constraint.xml
@@ -27,9 +27,15 @@
     <assertProductRatingSuccessSaveMessage module="Magento_Review">
         <severeness>high</severeness>
     </assertProductRatingSuccessSaveMessage>
+    <assertProductRatingSuccessDeleteMessage module="Magento_Review">
+        <severeness>high</severeness>
+    </assertProductRatingSuccessDeleteMessage>
     <assertProductRatingInGrid module="Magento_Review">
         <severeness>middle</severeness>
     </assertProductRatingInGrid>
+    <assertProductRatingNotInGrid module="Magento_Review">
+        <severeness>middle</severeness>
+    </assertProductRatingNotInGrid>
     <assertProductRatingInProductPage module="Magento_Review">
         <severeness>middle</severeness>
     </assertProductRatingInProductPage>
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/FormPageActions.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/FormPageActions.php
index 659a93a506a85a1b0541e3a8c24cc42bc045a678..5407bf6cf5f81a1e1d5626989c916d3f5edeac68 100644
--- a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/FormPageActions.php
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rate/Edit/FormPageActions.php
@@ -38,4 +38,11 @@ class FormPageActions extends ParentFormPageActions
      * @var string
      */
     protected $saveButton = '.save-rate';
+
+    /**
+     * "Delete" button
+     *
+     * @var string
+     */
+    protected $deleteButton = '.delete';
 }
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Edit/Form.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Edit/Form.php
index fcf5167241896b40097889093b885cf121f673b3..ed71e7fa8507be0c0322d6ba6f7ddf0e7618c675 100644
--- a/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Edit/Form.php
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Block/Adminhtml/Rule/Edit/Form.php
@@ -238,4 +238,16 @@ class Form extends FormInterface
     {
         $this->_rootElement->find($this->additionalSettings)->click();
     }
+
+    /**
+     * Getting all options in Tax Rate multi select list
+     *
+     * @return array
+     */
+    public function getAllTaxRates()
+    {
+        /** @var \Mtf\Client\Driver\Selenium\Element\MultiselectlistElement $taxRates */
+        $taxRates = $this->_rootElement->find($this->taxRateBlock, Locator::SELECTOR_CSS, 'multiselectlist');
+        return $taxRates->getAllValues();
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInGrid.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInGrid.php
new file mode 100644
index 0000000000000000000000000000000000000000..b327d77bc034a75dbc3df1a3c1acc37a91e6fa77
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInGrid.php
@@ -0,0 +1,74 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Tax\Test\Constraint;
+
+use Mtf\Constraint\AbstractConstraint;
+use Magento\Tax\Test\Page\Adminhtml\TaxRateIndex;
+use Magento\Tax\Test\Fixture\TaxRate;
+
+/**
+ * Class AssertTaxRateNotInGrid
+ */
+class AssertTaxRateNotInGrid extends AbstractConstraint
+{
+    /**
+     * Constraint severeness
+     *
+     * @var string
+     */
+    protected $severeness = 'high';
+
+    /**
+     * Assert that tax rate not available in Tax Rate grid
+     *
+     * @param TaxRateIndex $taxRateIndex
+     * @param TaxRate $taxRate
+     * @return void
+     */
+    public function processAssert(
+        TaxRateIndex $taxRateIndex,
+        TaxRate $taxRate
+    ) {
+        $filter = [
+            'code' => $taxRate->getCode(),
+        ];
+
+        $taxRateIndex->open();
+        \PHPUnit_Framework_Assert::assertFalse(
+            $taxRateIndex->getTaxRateGrid()->isRowVisible($filter),
+            'Tax Rate \'' . $filter['code'] . '\' is present in Tax Rate grid.'
+        );
+    }
+
+    /**
+     * Text of Tax Rate not in grid assert
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Tax rate is absent in grid.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInTaxRule.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInTaxRule.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a8c615c8f5cdecfc97b758721d945596cd3b3a3
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateNotInTaxRule.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Tax\Test\Constraint;
+
+use Magento\Tax\Test\Fixture\TaxRate;
+use Magento\Tax\Test\Page\Adminhtml\TaxRuleNew;
+use Mtf\Constraint\AbstractConstraint;
+
+/**
+ * Class AssertTaxRateNotInTaxRule
+ */
+class AssertTaxRateNotInTaxRule extends AbstractConstraint
+{
+    /**
+     * Constraint severeness
+     *
+     * @var string
+     */
+    protected $severeness = 'high';
+
+    /**
+     * Assert that tax rate is absent in tax rule form
+     *
+     * @param TaxRate $taxRate
+     * @param TaxRuleNew $taxRuleNew
+     * @return void
+     */
+    public function processAssert(
+        TaxRate $taxRate,
+        TaxRuleNew $taxRuleNew
+    ) {
+        $taxRuleNew->open();
+        $taxRatesList = $taxRuleNew->getTaxRuleForm()->getAllTaxRates();
+        \PHPUnit_Framework_Assert::assertFalse(
+            in_array($taxRate->getCode(), $taxRatesList),
+            'Tax Rate \'' . $taxRate->getCode() . '\' is present in Tax Rule form.'
+        );
+    }
+
+    /**
+     * Text of Tax Rate not in Tax Rule form
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Tax rate is absent in tax rule from.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessDeleteMessage.php b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessDeleteMessage.php
new file mode 100644
index 0000000000000000000000000000000000000000..914ea56e28366da7cd3b459199f65048810a7b02
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/Constraint/AssertTaxRateSuccessDeleteMessage.php
@@ -0,0 +1,71 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Tax\Test\Constraint;
+
+use Mtf\Constraint\AbstractConstraint;
+use Magento\Tax\Test\Page\Adminhtml\TaxRateIndex;
+
+/**
+ * Class AssertTaxRateSuccessDeleteMessage
+ */
+class AssertTaxRateSuccessDeleteMessage extends AbstractConstraint
+{
+    const SUCCESS_DELETE_MESSAGE = 'The tax rate has been deleted.';
+
+    /**
+     * Constraint severeness
+     *
+     * @var string
+     */
+    protected $severeness = 'high';
+
+    /**
+     * Assert that success delete message is displayed after tax rate deleted
+     *
+     * @param TaxRateIndex $taxRateIndex
+     * @return void
+     */
+    public function processAssert(TaxRateIndex $taxRateIndex)
+    {
+        $actualMessage = $taxRateIndex->getMessagesBlock()->getSuccessMessages();
+        \PHPUnit_Framework_Assert::assertEquals(
+            self::SUCCESS_DELETE_MESSAGE,
+            $actualMessage,
+            'Wrong success delete message is displayed.'
+            . "\nExpected: " . self::SUCCESS_DELETE_MESSAGE
+            . "\nActual: " . $actualMessage
+        );
+    }
+
+    /**
+     * Text of Deleted Tax Rate Success Message assert
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'Tax rate success delete message is present.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRateEntityTest.php b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRateEntityTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0dc974965c2dd08afb1ae8c22bda8f1403ef0e50
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRateEntityTest.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Tax\Test\TestCase;
+
+use Magento\Tax\Test\Fixture\TaxRate;
+use Magento\Tax\Test\Page\Adminhtml\TaxRateIndex;
+use Magento\Tax\Test\Page\Adminhtml\TaxRateNew;
+use Mtf\TestCase\Injectable;
+
+/**
+ * Test creation for delete TaxRateEntity
+ *
+ * Test Flow:
+ * Preconditions:
+ * 1. Create Tax Rate
+ *
+ * Steps:
+ * 1. Log in as default admin user
+ * 2. Go to Stores -> Taxes -> Tax Zones and Rates
+ * 3. Open created tax rate
+ * 4. Click Delete Rate
+ * 5. Perform all assertions
+ *
+ * @group Tax_(CS)
+ * @ZephyrId MAGETWO-23295
+ */
+class DeleteTaxRateEntityTest extends Injectable
+{
+    /**
+     * Tax Rate grid page
+     *
+     * @var TaxRateIndex
+     */
+    protected $taxRateIndex;
+
+    /**
+     * Tax Rate new/edit page
+     *
+     * @var TaxRateNew
+     */
+    protected $taxRateNew;
+
+    /**
+     * Injection data
+     *
+     * @param TaxRateIndex $taxRateIndex
+     * @param TaxRateNew $taxRateNew
+     * @return void
+     */
+    public function __inject(
+        TaxRateIndex $taxRateIndex,
+        TaxRateNew $taxRateNew
+    ) {
+        $this->taxRateIndex = $taxRateIndex;
+        $this->taxRateNew = $taxRateNew;
+    }
+
+    /**
+     * Delete Tax Rate Entity test
+     *
+     * @param TaxRate $taxRate
+     * @return void
+     */
+    public function testDeleteTaxRate(TaxRate $taxRate)
+    {
+        // Precondition
+        $taxRate->persist();
+
+        // Steps
+        $filter = [
+            'code' => $taxRate->getCode(),
+        ];
+        $this->taxRateIndex->open();
+        $this->taxRateIndex->getTaxRateGrid()->searchAndOpen($filter);
+        $this->taxRateNew->getFormPageActions()->delete();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRateEntityTest/testDeleteTaxRate.csv b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRateEntityTest/testDeleteTaxRate.csv
new file mode 100644
index 0000000000000000000000000000000000000000..ada912bbcb170791b78bffa4052fb635287ad744
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/TestCase/DeleteTaxRateEntityTest/testDeleteTaxRate.csv
@@ -0,0 +1,2 @@
+"taxRate/dataSet";"constraint"
+"default";"assertTaxRateSuccessDeleteMessage, assertTaxRateNotInGrid, assertTaxRateNotInTaxRule"
\ No newline at end of file
diff --git a/dev/tests/functional/tests/app/Magento/Tax/Test/etc/global/constraint.xml b/dev/tests/functional/tests/app/Magento/Tax/Test/etc/global/constraint.xml
index 3e353cf8a61ea01eecae2f6a113b1686e2554592..38f3260709d305403df7f447c54b0f32d8a3d954 100644
--- a/dev/tests/functional/tests/app/Magento/Tax/Test/etc/global/constraint.xml
+++ b/dev/tests/functional/tests/app/Magento/Tax/Test/etc/global/constraint.xml
@@ -95,4 +95,26 @@
             <taxRule class="Magento\Tax\Test\Fixture\TaxRule" />
         </require>
     </assertTaxRuleNotInGrid>
+    <assertTaxRateSuccessDeleteMessage module="Magento_Tax">
+        <severeness>high</severeness>
+        <require>
+            <taxRateIndex class="Magento\Tax\Test\Page\Adminhtml\TaxRateIndex" />
+        </require>
+    </assertTaxRateSuccessDeleteMessage>
+    <assertTaxRateNotInGrid module="Magento_Tax">
+        <severeness>high</severeness>
+        <require>
+            <taxRateIndex class="Magento\Tax\Test\Page\Adminhtml\TaxRateIndex" />
+            <taxRate class="Magento\Tax\Test\Fixture\TaxRate" />
+        </require>
+    </assertTaxRateNotInGrid>
+    <assertTaxRateNotInTaxRule module="Magento_Tax">
+        <severeness>high</severeness>
+        <require>
+            <taxRate class="Magento\Tax\Test\Fixture\TaxRate" />
+            <taxRule class="Magento\Tax\Test\Fixture\TaxRule" />
+            <taxRuleIndex class="Magento\Tax\Test\Page\Adminhtml\TaxRuleIndex" />
+            <taxRuleNew class="Magento\Tax\Test\Page\Adminhtml\TaxRuleNew" />
+        </require>
+    </assertTaxRateNotInTaxRule>
 </constraint>
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Category/Grid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Grid.php
similarity index 81%
rename from dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Category/Grid.php
rename to dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Grid.php
index 499d5a6cc423856b2be7f3052b75debbd74a0d0f..35b318a1b3f5c0cc9765fa003fc9127595b53ff8 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Category/Grid.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Grid.php
@@ -22,24 +22,27 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-namespace Magento\UrlRewrite\Test\Block\Catalog\Category;
+namespace Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Category;
 
-use Magento\Backend\Test\Block\Widget\Grid as GridInterface;
+use Magento\Backend\Test\Block\Widget\Grid as ParentGrid;
 
 /**
  * Class Grid
  * URL Redirect grid
  */
-class Grid extends GridInterface
+class Grid extends ParentGrid
 {
     /**
      * Filters array mapping
      *
-     * @var array $filters
+     * @var array
      */
     protected $filters = [
         'request_path' => [
             'selector' => '#urlrewriteGrid_filter_request_path'
+        ],
+        'id_path' => [
+            'selector' => '#urlrewriteGrid_filter_id_path'
         ]
     ];
 }
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Category/Tree.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Tree.php
similarity index 72%
rename from dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Category/Tree.php
rename to dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Tree.php
index d8f6a9338448f1bbabe46f32df3daeba2e0074b2..6bfad738887dc462e4dde48daa356e950d7de285 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Category/Tree.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Category/Tree.php
@@ -22,7 +22,7 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-namespace Magento\UrlRewrite\Test\Block\Catalog\Category;
+namespace Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Category;
 
 use Mtf\Block\Block;
 use Mtf\Client\Element\Locator;
@@ -30,17 +30,34 @@ use Mtf\Client\Element\Locator;
 /**
  * Class Tree
  * Categories tree block
- *
  */
 class Tree extends Block
 {
+    /**
+     * Locator value for  skip category button
+     *
+     * @var string
+     */
+    protected $skipCategoryButton = '[data-ui-id="urlrewrite-catalog-product-edit-skip-categories"]';
+
     /**
      * Select category by its name
      *
      * @param string $categoryName
+     * @return void
      */
     public function selectCategory($categoryName)
     {
         $this->_rootElement->find("//a[contains(text(),'{$categoryName}')]", Locator::SELECTOR_XPATH)->click();
     }
+
+    /**
+     * Skip category selection
+     *
+     * @return void
+     */
+    public function skipCategorySelection()
+    {
+        $this->_rootElement->find($this->skipCategoryButton, Locator::SELECTOR_CSS)->click();
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Edit/Form.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Edit/Form.php
similarity index 94%
rename from dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Edit/Form.php
rename to dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Edit/Form.php
index bb35b4366b92f29f0970dc2ed2da76e744ac601e..f4489b10a08421dd755f929ccbf26c3aada01145 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Edit/Form.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Edit/Form.php
@@ -22,7 +22,7 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-namespace Magento\UrlRewrite\Test\Block\Catalog\Edit;
+namespace Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Edit;
 
 use Magento\Backend\Test\Block\Widget\Form as FormWidget;
 
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Edit/Form.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Edit/Form.xml
similarity index 100%
rename from dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Edit/Form.xml
rename to dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Edit/Form.xml
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Product/Grid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Product/Grid.php
similarity index 69%
rename from dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Product/Grid.php
rename to dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Product/Grid.php
index 6ababae7f9a6ae7f008d271fa7989254765eb64d..5f9f7baeece3f88c0243ea7000547704e18e069d 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Catalog/Product/Grid.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Catalog/Product/Grid.php
@@ -22,37 +22,41 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-namespace Magento\UrlRewrite\Test\Block\Catalog\Product;
+namespace Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Product;
 
-use Magento\Backend\Test\Block\Widget\Grid as GridInterface;
+use Magento\Backend\Test\Block\Widget\Grid as ParentGrid;
 
 /**
  * Class Grid
  * Product grid
- *
  */
-class Grid extends GridInterface
+class Grid extends ParentGrid
 {
+    /**
+     * An element locator which allows to select entities in grid
+     *
+     * @var string
+     */
+    protected $selectItem = 'tbody tr .col-entity_id';
+
+    /**
+     * Locator value for link in action column
+     *
+     * @var string
+     */
+    protected $editLink = 'td.col-name';
+
     /**
      * Filters array mapping
      *
      * @var array
      */
-    protected $filters = array(
-        'id' => array(
+    protected $filters = [
+        'id' => [
             'selector' => '[id=productGrid_product_filter_entity_id]',
-        ),
-        'sku' => array(
+        ],
+        'sku' => [
             'selector' => '[id=productGrid_product_filter_sku]',
-        ),
-    );
-
-    /**
-     * Initialize block elements
-     */
-    protected function _init()
-    {
-        parent::_init();
-        $this->selectItem = 'tbody tr .col-entity_id';
-    }
+        ],
+    ];
 }
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Cms/Page/Grid.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Cms/Page/Grid.php
new file mode 100644
index 0000000000000000000000000000000000000000..efe4eafe95e10e621baa0b1826b1dc45ea9dd35f
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Cms/Page/Grid.php
@@ -0,0 +1,52 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\UrlRewrite\Test\Block\Adminhtml\Cms\Page;
+
+use Magento\Backend\Test\Block\Widget\Grid as ParentGrid;
+
+/**
+ * Class Grid
+ * URL Redirect grid
+ */
+class Grid extends ParentGrid
+{
+    /**
+     * Locator value for link in action column
+     *
+     * @var string
+     */
+    protected $editLink = 'td.col-title';
+
+    /**
+     * Filters array mapping
+     *
+     * @var array
+     */
+    protected $filters = [
+        'title' => [
+            'selector' => '#cmsPageGrid_filter_title'
+        ]
+    ];
+}
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Selector.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Selector.php
similarity index 96%
rename from dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Selector.php
rename to dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Selector.php
index 4d19b92fdefac88f05f20e6bd92f4ec479ffbe43..d55a83a9a4442ed025005cc3ba8c118f94e13417 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Selector.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Block/Adminhtml/Selector.php
@@ -23,7 +23,7 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
-namespace Magento\UrlRewrite\Test\Block;
+namespace Magento\UrlRewrite\Test\Block\Adminhtml;
 
 use Mtf\Block\Block;
 use Mtf\Client\Element\Locator;
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php
new file mode 100644
index 0000000000000000000000000000000000000000..8a8988192c5009664d7ec988b3b9bd1281fd6bf1
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteCmsPageRedirect.php
@@ -0,0 +1,88 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\UrlRewrite\Test\Constraint;
+
+use Mtf\Client\Browser;
+use Mtf\Constraint\AbstractConstraint;
+use Magento\UrlRewrite\Test\Fixture\UrlRewrite;
+use Magento\Cms\Test\Fixture\CmsPage;
+
+/**
+ * Class AssertUrlRewriteCmsPageRedirect
+ * Assert that created CMS Page URL Redirect lead to appropriate page in frontend
+ */
+class AssertUrlRewriteCmsPageRedirect extends AbstractConstraint
+{
+    /**
+     * Constraint severeness
+     *
+     * @var string
+     */
+    protected $severeness = 'low';
+
+    /**
+     * URL for CMS Page
+     *
+     * @var string
+     */
+    protected $url = 'cms/page/view/page_id/';
+
+    /**
+     * Assert that created CMS Page URL Redirect lead to appropriate page in frontend
+     *
+     * @param UrlRewrite $urlRewrite
+     * @param CmsPage $cmsPage
+     * @param Browser $browser
+     * @return void
+     */
+    public function processAssert(
+        UrlRewrite $urlRewrite,
+        CmsPage $cmsPage,
+        Browser $browser
+    ) {
+        $browser->open($_ENV['app_frontend_url'] . $urlRewrite->getRequestPath());
+        $url = $urlRewrite->getOptions() == 'No'
+            ? $urlRewrite->getRequestPath()
+            : $this->url . $cmsPage->getPageId();
+
+        \PHPUnit_Framework_Assert::assertEquals(
+            $browser->getUrl(),
+            $_ENV['app_frontend_url'] . $url,
+            'URL rewrite CMS Page redirect false.'
+            . "\nExpected: " . $_ENV['app_frontend_url'] . $url
+            . "\nActual: " . $browser->getUrl()
+        );
+    }
+
+    /**
+     * URL Redirect lead to appropriate page in frontend
+     *
+     * @return string
+     */
+    public function toString()
+    {
+        return 'URL Redirect lead to appropriate page in frontend.';
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertProductUrlAvailableOnTheFront.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php
similarity index 82%
rename from dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertProductUrlAvailableOnTheFront.php
rename to dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php
index 298b499c2196664515d0062e7faf88efb34e41ab..12a84e1d84023c013eae6723d732f8449bc5f5f7 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertProductUrlAvailableOnTheFront.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Constraint/AssertUrlRewriteProductRedirect.php
@@ -28,12 +28,13 @@ use Magento\Catalog\Test\Page\Product\CatalogProductView;
 use Mtf\Client\Browser;
 use Mtf\Constraint\AbstractConstraint;
 use Magento\UrlRewrite\Test\Fixture\UrlRewrite;
+use Mtf\Fixture\InjectableFixture;
 
 /**
- * Class AssertProductUrlAvailableOnTheFront
+ * Class AssertUrlRewriteProductRedirect
  * Assert that product available by new URL on the front
  */
-class AssertProductUrlAvailableOnTheFront extends AbstractConstraint
+class AssertUrlRewriteProductRedirect extends AbstractConstraint
 {
     /**
      * Constraint severeness
@@ -47,20 +48,25 @@ class AssertProductUrlAvailableOnTheFront extends AbstractConstraint
      *
      * @param UrlRewrite $urlRewrite
      * @param CatalogProductView $catalogProductView
+     * @param InjectableFixture $product
      * @param Browser $browser
      * @return void
      */
     public function processAssert(
         UrlRewrite $urlRewrite,
         CatalogProductView $catalogProductView,
-        Browser $browser
+        Browser $browser,
+        InjectableFixture $product = null
     ) {
         $browser->open($_ENV['app_frontend_url'] . $urlRewrite->getRequestPath());
+        if ($product === null) {
+            $product = $urlRewrite->getDataFieldConfig('id_path')['source']->getEntity();
+        }
         \PHPUnit_Framework_Assert::assertEquals(
             $catalogProductView->getTitleBlock()->getTitle(),
-            $urlRewrite->getDataFieldConfig('product_id')['source']->getProduct()->getName(),
+            $product->getName(),
             'URL rewrite product redirect false.'
-            . "\nExpected: " . $urlRewrite->getDataFieldConfig('product_id')['source']->getProduct()->getName()
+            . "\nExpected: " . $product->getName()
             . "\nActual: " . $catalogProductView->getTitleBlock()->getTitle()
         );
     }
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.php
index 8ed995d48c50f27881b35411394ef9f9113531b2..8b115150414939e4d6313eda1964fa6186b092a3 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.php
@@ -54,12 +54,7 @@ class UrlRewrite extends InjectableFixture
     protected $id_path = [
         'attribute_code' => 'id_path',
         'backend_type' => 'virtual',
-    ];
-
-    protected $product_id = [
-        'attribute_code' => 'product_id',
-        'backend_type' => 'virtual',
-        'source' => 'Magento\UrlRewrite\Test\Fixture\UrlRewrite\ProductId',
+        'source' => 'Magento\UrlRewrite\Test\Fixture\UrlRewrite\IdPath',
     ];
 
     protected $store_id = [
@@ -102,11 +97,6 @@ class UrlRewrite extends InjectableFixture
         return $this->getData('id_path');
     }
 
-    public function getProductId()
-    {
-        return $this->getData('product_id');
-    }
-
     public function getStoreId()
     {
         return $this->getData('store_id');
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.xml
index 88247b3c1a82dda2523c70fbfc5602702711981b..20e71d8cb3dc84901948caea7e0895f141d1b76d 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.xml
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite.xml
@@ -37,11 +37,8 @@
         <id_path>
             <attribute_code>id_path</attribute_code>
             <backend_type>virtual</backend_type>
+            <source>Magento\UrlRewrite\Test\Fixture\UrlRewrite\IdPath</source>
         </id_path>
-        <product_id>
-            <attribute_code>product_id</attribute_code>
-            <backend_type>virtual</backend_type>
-        </product_id>
         <store_id>
             <attribute_code>store_id</attribute_code>
             <backend_type>virtual</backend_type>
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite/ProductId.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite/IdPath.php
similarity index 74%
rename from dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite/ProductId.php
rename to dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite/IdPath.php
index 17c31ee4ab9f91bf7fcda048cf93bfff98971be9..d67d9cc7dc0cd233b238bfaad4e4918d0ef7fc60 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite/ProductId.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Fixture/UrlRewrite/IdPath.php
@@ -28,10 +28,10 @@ use Mtf\Fixture\FixtureFactory;
 use Mtf\Fixture\FixtureInterface;
 
 /**
- * Class ProductId
- * Prepare product
+ * Class IdPath
+ * Prepare ID Path
  */
-class ProductId implements FixtureInterface
+class IdPath implements FixtureInterface
 {
     /**
      * Resource data
@@ -41,11 +41,11 @@ class ProductId implements FixtureInterface
     protected $data;
 
     /**
-     * Return product
+     * Return category
      *
      * @var FixtureInterface
      */
-    protected $product;
+    protected $entity;
 
     /**
      * @param FixtureFactory $fixtureFactory
@@ -55,14 +55,19 @@ class ProductId implements FixtureInterface
     public function __construct(FixtureFactory $fixtureFactory, array $params, array $data = [])
     {
         $this->params = $params;
-        $explodeValue = explode('::', $data['dataSet']);
+        if (!isset($data['entity'])) {
+            $this->data = array_shift($data);
+            return;
+        }
+        preg_match('`%(.*?)%`', $data['entity'], $dataSet);
+        $explodeValue = explode('::', $dataSet[1]);
         if (!empty($explodeValue) && count($explodeValue) > 1) {
             /** @var FixtureInterface $fixture */
-            $this->product = $fixtureFactory->createByCode($explodeValue[0], ['dataSet' => $explodeValue[1]]);
-            $this->product->persist();
-            $this->data =  $this->product->getId();
+            $this->entity = $fixtureFactory->createByCode($explodeValue[0], ['entity' => $explodeValue[1]]);
+            $this->entity->persist();
+            $this->data = preg_replace('`(%.*?%)`', $this->entity->getId(), $data['entity']);
         } else {
-            $this->data = strval($data['dataSet']);
+            $this->data = strval($data['entity']);
         }
     }
 
@@ -98,12 +103,12 @@ class ProductId implements FixtureInterface
     }
 
     /**
-     * Return product
+     * Return entity
      *
      * @return FixtureInterface
      */
-    public function getProduct()
+    public function getEntity()
     {
-        return $this->product;
+        return $this->entity;
     }
 }
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Handler/UrlRewrite/Curl.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Handler/UrlRewrite/Curl.php
index b34e502aac8206f6ff8fe0929981b55500e858fd..fdd1c3eab70782438e581ce3a618d238de8ec820 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Handler/UrlRewrite/Curl.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Handler/UrlRewrite/Curl.php
@@ -42,7 +42,7 @@ class Curl extends AbstractCurl implements UrlRewriteInterface
      *
      * @var array
      */
-    protected $dataMapping = [
+    protected $mappingData = [
         'store_id' => ['Default Store View' => 1],
         'options' => [
             'Temporary (302)' => 'R',
@@ -68,7 +68,7 @@ class Curl extends AbstractCurl implements UrlRewriteInterface
     public function persist(FixtureInterface $fixture = null)
     {
         $url = $_ENV['app_backend_url'] . $this->url . $fixture->getIdPath();
-        $data = $this->prepareData($fixture->getData());
+        $data = $this->replaceMappingData($fixture->getData());
         $curl = new BackendDecorator(new CurlTransport(), new Config());
         $curl->write(CurlInterface::POST, $url, '1.0', array(), $data);
         $response = $curl->read();
@@ -78,20 +78,4 @@ class Curl extends AbstractCurl implements UrlRewriteInterface
         }
         $curl->close();
     }
-
-    /**
-     * Prepare data
-     *
-     * @param array $data
-     * @return array
-     */
-    protected function prepareData(array $data)
-    {
-        foreach ($data as $key => $value) {
-            if (isset($this->dataMapping[$key])) {
-                $data[$key] = $this->dataMapping[$key][$value];
-            }
-        }
-        return $data;
-    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Handler/UrlRewrite/UrlRewriteInterface.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Handler/UrlRewrite/UrlRewriteInterface.php
index 80dccd6f26f1940cc71994f85070f8bc20885565..8e86e6795ff82f21135abdc9070088eaa19e8191 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Handler/UrlRewrite/UrlRewriteInterface.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Handler/UrlRewrite/UrlRewriteInterface.php
@@ -31,5 +31,5 @@ use Mtf\Handler\HandlerInterface;
  */
 interface UrlRewriteInterface extends HandlerInterface
 {
-   //
+    //
 }
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteEdit.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteEdit.php
index 3ace1a1a09fe16ea16327791ded01a5c905f694c..0ab76c1f45b56f4dc3f4e0b0b39f217d865077ce 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteEdit.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteEdit.php
@@ -36,13 +36,13 @@ class UrlrewriteEdit extends BackendPage
     protected $_blocks = [
         'treeBlock' => [
             'name' => 'treeBlock',
-            'class' => 'Magento\UrlRewrite\Test\Block\Catalog\Category\Tree',
-            'locator' => '[data-ui-id="category-selector"]',
+            'class' => 'Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Category\Tree',
+            'locator' => '[id="page:main-container"]',
             'strategy' => 'css selector',
         ],
         'formBlock' => [
             'name' => 'formBlock',
-            'class' => 'Magento\UrlRewrite\Test\Block\Catalog\Edit\Form',
+            'class' => 'Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Edit\Form',
             'locator' => '#edit_form',
             'strategy' => 'css selector',
         ],
@@ -52,12 +52,6 @@ class UrlrewriteEdit extends BackendPage
             'locator' => '#messages .messages',
             'strategy' => 'css selector',
         ],
-        'buttonBlock' => [
-            'name' => 'buttonBlock',
-            'class' => 'Magento\Backend\Test\Block\Widget\Form',
-            'locator' => '#messages .messages',
-            'strategy' => 'css selector',
-        ],
         'pageMainActions' => [
             'name' => 'pageMainActions',
             'class' => 'Magento\Backend\Test\Block\FormPageActions',
@@ -66,20 +60,26 @@ class UrlrewriteEdit extends BackendPage
         ],
         'productGridBlock' => [
             'name' => 'productGridBlock',
-            'class' => 'Magento\UrlRewrite\Test\Block\Catalog\Product\Grid',
+            'class' => 'Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Product\Grid',
             'locator' => '[id="productGrid"]',
             'strategy' => 'css selector',
         ],
         'urlRewriteTypeSelectorBlock' => [
             'name' => 'urlRewriteTypeSelectorBlock',
-            'class' => 'Magento\UrlRewrite\Test\Block\Selector',
+            'class' => 'Magento\UrlRewrite\Test\Block\Adminhtml\Selector',
             'locator' => '[data-ui-id="urlrewrite-type-selector"]',
             'strategy' => 'css selector',
         ],
+        'cmsGridBlock' => [
+            'name' => 'gridBlock',
+            'class' => 'Magento\UrlRewrite\Test\Block\Adminhtml\Cms\Page\Grid',
+            'locator' => '#cmsPageGrid',
+            'strategy' => 'css selector',
+        ],
     ];
 
     /**
-     * @return \Magento\UrlRewrite\Test\Block\Catalog\Category\Tree
+     * @return \Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Category\Tree
      */
     public function getTreeBlock()
     {
@@ -87,7 +87,7 @@ class UrlrewriteEdit extends BackendPage
     }
 
     /**
-     * @return \Magento\UrlRewrite\Test\Block\Catalog\Edit\Form
+     * @return \Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Edit\Form
      */
     public function getFormBlock()
     {
@@ -102,14 +102,6 @@ class UrlrewriteEdit extends BackendPage
         return $this->getBlockInstance('messagesBlock');
     }
 
-    /**
-     * @return \Magento\Backend\Test\Block\Widget\Form
-     */
-    public function getButtonBlock()
-    {
-        return $this->getBlockInstance('buttonBlock');
-    }
-
     /**
      * @return \Magento\Backend\Test\Block\FormPageActions
      */
@@ -119,7 +111,7 @@ class UrlrewriteEdit extends BackendPage
     }
 
     /**
-     * @return \Magento\UrlRewrite\Test\Block\Catalog\Product\Grid
+     * @return \Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Product\Grid
      */
     public function getProductGridBlock()
     {
@@ -127,10 +119,18 @@ class UrlrewriteEdit extends BackendPage
     }
 
     /**
-     * @return \Magento\UrlRewrite\Test\Block\Selector
+     * @return \Magento\UrlRewrite\Test\Block\Adminhtml\Selector
      */
     public function getUrlRewriteTypeSelectorBlock()
     {
         return $this->getBlockInstance('urlRewriteTypeSelectorBlock');
     }
+
+    /**
+     * @return \Magento\UrlRewrite\Test\Block\Adminhtml\Cms\Page\Grid
+     */
+    public function getCmsGridBlock()
+    {
+        return $this->getBlockInstance('cmsGridBlock');
+    }
 }
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteEdit.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteEdit.xml
index 0eea42abf335b411125876ff5cd1d8dabd47fdad..35c41fe1518e9807ae1e38308e351b9b084d5b64 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteEdit.xml
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteEdit.xml
@@ -26,13 +26,13 @@
 <page mca="admin/urlrewrite/edit">
     <block>
         <name>treeBlock</name>
-        <class>Magento\UrlRewrite\Test\Block\Catalog\Category\Tree</class>
-        <locator>[data-ui-id="category-selector"]</locator>
+        <class>Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Category\Tree</class>
+        <locator>[id="page:main-container"]</locator>
         <strategy>css selector</strategy>
     </block>
     <block>
         <name>formBlock</name>
-        <class>Magento\UrlRewrite\Test\Block\Catalog\Edit\Form</class>
+        <class>Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Edit\Form</class>
         <locator>#edit_form</locator>
         <strategy>css selector</strategy>
     </block>
@@ -42,12 +42,6 @@
         <locator>#messages .messages</locator>
         <strategy>css selector</strategy>
     </block>
-    <block>
-        <name>buttonBlock</name>
-        <class>Magento\Backend\Test\Block\Widget\Form</class>
-        <locator>#messages .messages</locator>
-        <strategy>css selector</strategy>
-    </block>
     <block>
         <name>pageMainActions</name>
         <class>Magento\Backend\Test\Block\FormPageActions</class>
@@ -56,20 +50,20 @@
     </block>
     <block>
         <name>productGridBlock</name>
-        <class>Magento\UrlRewrite\Test\Block\Catalog\Product\Grid</class>
+        <class>Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Product\Grid</class>
         <locator>[id="productGrid"]</locator>
         <strategy>css selector</strategy>
     </block>
     <block>
         <name>urlRewriteTypeSelectorBlock</name>
-        <class>Magento\UrlRewrite\Test\Block\Selector</class>
+        <class>Magento\UrlRewrite\Test\Block\Adminhtml\Selector</class>
         <locator>[data-ui-id="urlrewrite-type-selector"]</locator>
         <strategy>css selector</strategy>
     </block>
     <block>
-        <name>urlRewriteTypeSelectorBlock</name>
-        <class>Magento\UrlRewrite\Test\Block\Selector</class>
-        <locator>[data-ui-id="urlrewrite-type-selector"]</locator>
+        <name>cmsGridBlock</name>
+        <class>Magento\UrlRewrite\Test\Block\Cms\Page\Grid</class>
+        <locator>#cmsPageGrid</locator>
         <strategy>css selector</strategy>
     </block>
 </page>
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteIndex.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteIndex.php
index 452fbb6c4263c711828a24c0f36ddc2b995bb2af..900ecad85e1e20edd86f98a18995ebcfddee786e 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteIndex.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteIndex.php
@@ -42,7 +42,7 @@ class UrlrewriteIndex extends BackendPage
         ],
         'urlRedirectGrid' => [
             'name' => 'urlRedirectGrid',
-            'class' => 'Magento\UrlRewrite\Test\Block\Catalog\Category\Grid',
+            'class' => 'Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Category\Grid',
             'locator' => '#urlrewriteGrid',
             'strategy' => 'css selector',
         ],
@@ -63,7 +63,7 @@ class UrlrewriteIndex extends BackendPage
     }
 
     /**
-     * @return \Magento\UrlRewrite\Test\Block\Catalog\Category\Grid
+     * @return \Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Category\Grid
      */
     public function getUrlRedirectGrid()
     {
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteIndex.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteIndex.xml
index 65cd2bcee95453c4b761d8241c47e6463a26562b..566d5370b3892ab7dab4af81008a0baf110f74ac 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteIndex.xml
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/Page/Adminhtml/UrlrewriteIndex.xml
@@ -32,7 +32,7 @@
     </block>
     <block>
         <name>urlRedirectGrid</name>
-        <class>Magento\UrlRewrite\Test\Block\Catalog\Category\Grid</class>
+        <class>Magento\UrlRewrite\Test\Block\Adminhtml\Catalog\Category\Grid</class>
         <locator>#urlrewriteGrid</locator>
         <strategy>css selector</strategy>
     </block>
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCmsPageRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCmsPageRewriteEntityTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3bb8056bd214e3cd394514dfb83c03f51ba0edea
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCmsPageRewriteEntityTest.php
@@ -0,0 +1,106 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\UrlRewrite\Test\TestCase;
+
+use Magento\UrlRewrite\Test\Page\Adminhtml\EditCmsPage;
+use Mtf\TestCase\Injectable;
+use Magento\Cms\Test\Fixture\CmsPage;
+use Magento\UrlRewrite\Test\Fixture\UrlRewrite;
+use Magento\UrlRewrite\Test\Page\Adminhtml\UrlrewriteEdit;
+use Magento\UrlRewrite\Test\Page\Adminhtml\UrlrewriteIndex;
+
+/**
+ * Test Creation for CreateCmsPageRewriteEntity
+ *
+ * Test Flow:
+ *
+ * Preconditions
+ * 1. Create CMS-Page
+ *
+ * Steps
+ * 1. Login to backend as Admin
+ * 2. Go to the Marketing-> SEO & Search->URL Redirects
+ * 3. Click "Add Url Rewrite" button
+ * 4. Select "For CMS Page" in Create URL Rewrite dropdown
+ * 5. Select CMS page from preconditions in grid
+ * 6. Fill data according to data set
+ * 7. Save Rewrite
+ * 8. Perform all assertions
+ *
+ * @group URL_Rewrites_(PS)
+ * @ZephyrId MAGETWO-24847
+ */
+class CreateCmsPageRewriteEntityTest extends Injectable
+{
+    /**
+     * Url rewrite index page
+     *
+     * @var UrlrewriteIndex
+     */
+    protected $urlRewriteIndex;
+
+    /**
+     * Url rewrite edit page
+     *
+     * @var UrlrewriteEdit
+     */
+    protected $urlRewriteEdit;
+
+    /**
+     * Inject pages
+     *
+     * @param UrlrewriteIndex $urlRewriteIndex
+     * @param UrlrewriteEdit $urlRewriteEdit
+     * @return void
+     */
+    public function __inject(
+        UrlrewriteIndex $urlRewriteIndex,
+        UrlrewriteEdit $urlRewriteEdit
+    ) {
+        $this->urlRewriteIndex = $urlRewriteIndex;
+        $this->urlRewriteEdit = $urlRewriteEdit;
+    }
+
+    /**
+     * Create CMS page rewrites
+     *
+     * @param CmsPage $cmsPage
+     * @param UrlRewrite $urlRewrite
+     * @return void
+     */
+    public function testCmsPageRewrite(CmsPage $cmsPage, UrlRewrite $urlRewrite)
+    {
+        //Preconditions
+        $cmsPage->persist();
+        //Steps
+        $this->urlRewriteIndex->open();
+        $this->urlRewriteIndex->getPageActionsBlock()->addNew();
+        $this->urlRewriteEdit->getUrlRewriteTypeSelectorBlock()->selectType('For CMS page');
+        $filter = ['title' => $cmsPage->getTitle()];
+        $this->urlRewriteEdit->getCmsGridBlock()->searchAndOpen($filter);
+        $this->urlRewriteEdit->getFormBlock()->fill($urlRewrite);
+        $this->urlRewriteEdit->getPageMainActions()->save();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCmsPageRewriteEntityTest/testCmsPageRewrite.csv b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCmsPageRewriteEntityTest/testCmsPageRewrite.csv
new file mode 100644
index 0000000000000000000000000000000000000000..7edd14cc928acdc6f7f02af2592b12b233b0a3f8
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateCmsPageRewriteEntityTest/testCmsPageRewrite.csv
@@ -0,0 +1,5 @@
+"cmsPage/dataSet";"urlRewrite/data/store_id";"urlRewrite/data/request_path";"urlRewrite/data/options";"urlRewrite/data/description";"isRequired";"constraint"
+"default";"-";"request_path%isolation%";"No";"test_description_default";"Yes";"assertUrlRewriteSaveMessage, assertUrlRewriteCmsPageRedirect"
+"default";"-";"request_path%isolation%.html";"Temporary (302)";"test description_302";"Yes";"assertUrlRewriteSaveMessage, assertUrlRewriteCmsPageRedirect"
+"default";"-";"request_path%isolation%.htm";"Permanent (301)";"test description_301";"Yes";"assertUrlRewriteSaveMessage, assertUrlRewriteCmsPageRedirect"
+"default";"-";"request_path%isolation%.aspx";"Permanent (301)";"test description_%isolation%";"Yes";"assertUrlRewriteSaveMessage, assertUrlRewriteCmsPageRedirect"
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..14d5305487823bde357ac979ef76223e558cb366
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\UrlRewrite\Test\TestCase;
+
+use Magento\Catalog\Test\Fixture\CatalogProductSimple;
+use Mtf\TestCase\Injectable;
+use Magento\UrlRewrite\Test\Fixture\UrlRewrite;
+use Magento\UrlRewrite\Test\Page\Adminhtml\UrlrewriteIndex;
+use Magento\UrlRewrite\Test\Page\Adminhtml\UrlrewriteEdit;
+
+/**
+ * Test Creation for Product URL Rewrites Entity
+ *
+ * Test Flow:
+ * Preconditions:
+ * 1. Create custom storeView
+ * 2. Create simple product
+ *
+ * Steps:
+ * 1. Open Backend
+ * 2. Go to Marketing->Url Redirects
+ * 3. Click "Add URL Rewrite" button
+ * 4. Select "For Product" from  "Create URL Rewrite:" dropdown
+ * 5. Select created early product
+ * 6. Click "Skip Category Selection" button
+ * 7. Fill data according to dataSet
+ * 8. Perform all assertions
+ *
+ * @group URL_Rewrites_(PS)
+ * @ZephyrId MAGETWO-25150
+ */
+class CreateProductUrlRewriteEntityTest extends Injectable
+{
+    /**
+     * Url rewrite index page
+     *
+     * @var UrlrewriteIndex
+     */
+    protected $urlRewriteIndex;
+
+    /**
+     * Url rewrite edit page
+     *
+     * @var UrlrewriteEdit
+     */
+    protected $urlRewriteEdit;
+
+    /**
+     * Prepare pages
+     *
+     * @param UrlrewriteIndex $urlRewriteIndex
+     * @param UrlrewriteEdit $urlRewriteEdit
+     * @return void
+     */
+    public function __inject(UrlrewriteIndex $urlRewriteIndex, UrlrewriteEdit $urlRewriteEdit)
+    {
+        $this->urlRewriteIndex = $urlRewriteIndex;
+        $this->urlRewriteEdit = $urlRewriteEdit;
+    }
+
+    /**
+     * Create product URL Rewrite
+     *
+     * @param CatalogProductSimple $product
+     * @param UrlRewrite $urlRewrite
+     * @return void
+     */
+    public function testProductUrlRewrite(CatalogProductSimple $product, UrlRewrite $urlRewrite)
+    {
+        //Precondition
+        $product->persist();
+        $filter = ['id' => $product->getId()];
+        //Steps
+        $this->urlRewriteIndex->open();
+        $this->urlRewriteIndex->getPageActionsBlock()->addNew();
+        $this->urlRewriteEdit->getUrlRewriteTypeSelectorBlock()->selectType('For product');
+        $this->urlRewriteEdit->getProductGridBlock()->searchAndOpen($filter);
+        $this->urlRewriteEdit->getTreeBlock()->skipCategorySelection();
+        $this->urlRewriteEdit->getFormBlock()->fill($urlRewrite);
+        $this->urlRewriteEdit->getPageMainActions()->save();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest/testProductUrlRewrite.csv b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest/testProductUrlRewrite.csv
new file mode 100644
index 0000000000000000000000000000000000000000..5c712f8e5b9083eb18aa38d10627b55d8aa5fe89
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/CreateProductUrlRewriteEntityTest/testProductUrlRewrite.csv
@@ -0,0 +1,4 @@
+"product/dataSet";"urlRewrite/data/store_id";"urlRewrite/data/request_path";"urlRewrite/data/options";"urlRewrite/data/description";"constraint"
+"default";"Main Website/Main Website Store/Default Store View";"test_%isolation%.html";"No";"description_%isolation%";"assertUrlRewriteSaveMessage"
+"default";"Main Website/Main Website Store/Default Store View";"test_%isolation%.html";"Temporary (302)";"description_%isolation%";"assertUrlRewriteSaveMessage, assertUrlRewriteProductRedirect"
+"default";"Main Website/Main Website Store/Default Store View";"test_%isolation%.html";"Permanent (301)";"description_%isolation%";"assertUrlRewriteSaveMessage, assertUrlRewriteProductRedirect"
\ No newline at end of file
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCategoryUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCategoryUrlRewriteEntityTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..02943ff1a55ffa14c607a6f8bcd00d45083ae4e6
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCategoryUrlRewriteEntityTest.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\UrlRewrite\Test\TestCase;
+
+use Magento\UrlRewrite\Test\Fixture\UrlRewrite;
+use Mtf\TestCase\Injectable;
+use Magento\UrlRewrite\Test\Page\Adminhtml\UrlrewriteEdit;
+use Magento\UrlRewrite\Test\Page\Adminhtml\UrlrewriteIndex;
+
+/**
+ * Test Creation for Delete Category URL Rewrites Entity
+ *
+ * Test Flow:
+ * Preconditions:
+ * 1. Create category
+ * 2. Create custom category UrlRewrite
+ *
+ * Steps:
+ * 1. Open Backend
+ * 2. Go to Marketing->URL Redirects
+ * 3. Search and open created URL Redirect
+ * 4. Delete URL Redirect
+ * 5. Perform all assertions
+ *
+ * @group URL_Rewrites_(PS)
+ * @ZephyrId MAGETWO-25086
+ */
+class DeleteCategoryUrlRewriteEntityTest extends Injectable
+{
+    /**
+     * Url rewrite index page
+     *
+     * @var UrlrewriteIndex
+     */
+    protected $urlRewriteIndex;
+
+    /**
+     * Url rewrite edit page
+     *
+     * @var UrlrewriteEdit
+     */
+    protected $urlRewriteEdit;
+
+    /**
+     * Inject pages
+     *
+     * @param UrlrewriteIndex $urlRewriteIndex
+     * @param UrlrewriteEdit $urlRewriteEdit
+     * @return void
+     */
+    public function __inject(UrlrewriteIndex $urlRewriteIndex, UrlrewriteEdit $urlRewriteEdit)
+    {
+        $this->urlRewriteIndex = $urlRewriteIndex;
+        $this->urlRewriteEdit = $urlRewriteEdit;
+    }
+
+    /**
+     * Delete category Url Rewrite
+     *
+     * @param UrlRewrite $urlRewrite
+     * @return void
+     */
+    public function testDeleteCategoryUrlRewrite(UrlRewrite $urlRewrite)
+    {
+        //Precondition
+        $urlRewrite->persist();
+        //Steps
+        $this->urlRewriteIndex->open();
+        if ($urlRewrite->getRequestPath()) {
+            $filter = ['request_path' => $urlRewrite->getRequestPath()];
+        } else {
+            $filter = ['id_path' => $urlRewrite->getIdPath()];
+        }
+        $this->urlRewriteIndex->getUrlRedirectGrid()->searchAndOpen($filter);
+        $this->urlRewriteEdit->getPageMainActions()->delete();
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCategoryUrlRewriteEntityTest/testDeleteCategoryUrlRewrite.csv b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCategoryUrlRewriteEntityTest/testDeleteCategoryUrlRewrite.csv
new file mode 100644
index 0000000000000000000000000000000000000000..d56bf6e45377b2df1b21a9615a87c02b3517f876
--- /dev/null
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteCategoryUrlRewriteEntityTest/testDeleteCategoryUrlRewrite.csv
@@ -0,0 +1,3 @@
+"urlRewrite/data/id_path/entity";"urlRewrite/data/options";"urlRewrite/data/request_path";"constraint"
+"category/%catalogCategory::default%";"No";"-";"assertUrlRewriteDeletedMessage, assertPageByUrlRewriteIsNotFound"
+"category/%catalogCategory::default%";"No";"example%isolation%.html";"assertUrlRewriteDeletedMessage, assertPageByUrlRewriteIsNotFound"
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest.php
index 6b7b8baa82b73ca62d700e53f8b3afaf63964f1f..1c0765dcd669a9fcfd8892c18e7e8e9202631ef3 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest.php
@@ -28,7 +28,6 @@ use Magento\Catalog\Test\Fixture\CatalogProductSimple;
 use Magento\UrlRewrite\Test\Fixture\UrlRewrite;
 use Magento\UrlRewrite\Test\Page\Adminhtml\UrlrewriteEdit;
 use Magento\UrlRewrite\Test\Page\Adminhtml\UrlrewriteIndex;
-use Mtf\Fixture\FixtureFactory;
 use Mtf\TestCase\Injectable;
 
 /**
@@ -66,35 +65,18 @@ class DeleteProductUrlRewriteEntityTest extends Injectable
     protected $urlRewriteEdit;
 
     /**
-     * Prepare dataSets and pages
+     * Prepare pages
      *
-     * @param FixtureFactory $fixtureFactory
      * @param UrlrewriteIndex $urlRewriteIndex
      * @param UrlrewriteEdit $urlRewriteEdit
-     * @return array
+     * @return void
      */
     public function __inject(
-        FixtureFactory $fixtureFactory,
         UrlrewriteIndex $urlRewriteIndex,
         UrlrewriteEdit $urlRewriteEdit
     ) {
-        /** @var CatalogProductSimple $product */
-        $product = $fixtureFactory->createByCode('catalogProductSimple', ['dataSet' => 'product_without_category']);
-        $product->persist();
-
-        /** @var UrlRewrite $productRedirect */
-        $productRedirect = $fixtureFactory->createByCode(
-            'urlRewrite',
-            [
-                'dataSet' => 'default',
-                'data' => ['id_path' => 'product/' . $product->getId()]
-            ]
-        );
-        $productRedirect->persist();
-
         $this->urlRewriteIndex = $urlRewriteIndex;
         $this->urlRewriteEdit = $urlRewriteEdit;
-        return ['productRedirect' => $productRedirect];
     }
 
     /**
@@ -105,6 +87,9 @@ class DeleteProductUrlRewriteEntityTest extends Injectable
      */
     public function testDeleteProductUrlRewrite(UrlRewrite $productRedirect)
     {
+        // Precondition
+        $productRedirect->persist();
+        // Steps
         $this->urlRewriteIndex->open();
         $filter = ['request_path' => $productRedirect->getRequestPath()];
         $this->urlRewriteIndex->getUrlRedirectGrid()->searchAndOpen($filter);
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest/testDeleteProductUrlRewrite.csv b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest/testDeleteProductUrlRewrite.csv
index a0af0ee8456176c7a6ad3413c1c9f39546360b48..102c7b7f215b9acef0ecf7afa19d2e719cc50da2 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest/testDeleteProductUrlRewrite.csv
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/DeleteProductUrlRewriteEntityTest/testDeleteProductUrlRewrite.csv
@@ -1,2 +1,2 @@
-"constraint"
-"assertUrlRewriteDeletedMessage, assertUrlRewriteNotInGrid, assertPageByUrlRewriteIsNotFound"
+"productRedirect/dataSet";"productRedirect/data/id_path/entity";"constraint"
+"default";"product/%catalogProductSimple::100_dollar_product%";"assertUrlRewriteDeletedMessage, assertUrlRewriteNotInGrid, assertPageByUrlRewriteIsNotFound"
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.php
index f27c54428de4115be349fb8145eb91a55b25853c..ae00d41bc8b458067df41f5abc3432dfabcae4aa 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateCategoryUrlRewriteEntityTest.php
@@ -89,7 +89,7 @@ class UpdateCategoryUrlRewriteEntityTest extends Injectable
             'urlRewrite',
             [
                 'dataSet' => 'default',
-                'data' => ['id_path' => 'category/' . $category->getId()]
+                'data' => ['id_path' => ['category/' . $category->getId()]]
             ]
         );
         $categoryRedirect->persist();
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest.php b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest.php
index 88e91acf55ca673c9c9aec9150403e8971007884..bead2feb702647c17a7fe8dbbe67d25ee6f6928d 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest.php
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest.php
@@ -97,7 +97,7 @@ class UpdateProductUrlRewriteEntityTest extends Injectable
             'urlRewrite',
             [
                 'dataSet' => 'default',
-                'data' => ['id_path' => 'product/' . $urlRewrite->getProductId()]
+                'data' => ['id_path' => [$urlRewrite->getIdPath()]]
             ]
         );
         $productRedirect->persist();
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest/testUpdateProductUrlRewrite.csv b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest/testUpdateProductUrlRewrite.csv
index a2149c6d1a899adce9138b1ddad118dad0cc5a28..4a76b6aaf184a03e856300be39f16cfe1b90a5fc 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest/testUpdateProductUrlRewrite.csv
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/TestCase/UpdateProductUrlRewriteEntityTest/testUpdateProductUrlRewrite.csv
@@ -1,3 +1,2 @@
-"urlRewrite/data/product_id/dataSet";"urlRewrite/data/store_id";"urlRewrite/data/request_path";"urlRewrite/data/options";"urlRewrite/data/description";"isRequired";"constraint"
-"catalogProductSimple::100_dollar_product";"Main Website/Main Website Store/Default Store View";"test_%isolation%.html";"Temporary (302)";"description_%isolation%";"Yes";"assertUrlRewriteSaveMessage, assertProductUrlAvailableOnTheFront"
-"catalogProductSimple::100_dollar_product";"Main Website/Main Website Store/Custom Store View";"test_%isolation%.php";"No";"description_%isolation%";"No";"assertUrlRewriteSaveMessage, assertProductUrlAvailableOnTheFront"
\ No newline at end of file
+"urlRewrite/data/id_path/entity";"urlRewrite/data/store_id";"urlRewrite/data/request_path";"urlRewrite/data/options";"urlRewrite/data/description";"isRequired";"constraint"
+"product/%catalogProductSimple::100_dollar_product%";"Main Website/Main Website Store/Default Store View";"test_%isolation%.html";"Temporary (302)";"description_%isolation%";"Yes";"assertUrlRewriteSaveMessage, assertUrlRewriteProductRedirect"
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/global/constraint.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/global/constraint.xml
index 60b2f1620990d65db1753d04b003d960fc0b7319..cba450836dead5a8d33fa44a8cda5badd4038892 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/global/constraint.xml
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/global/constraint.xml
@@ -37,7 +37,7 @@
     <assertUrlRewriteCategoryRedirect module="Magento_UrlRewrite">
         <severeness>low</severeness>
     </assertUrlRewriteCategoryRedirect>
-    <assertProductUrlAvailableOnTheFront module="Magento_UrlRewrite">
+    <assertUrlRewriteProductRedirect module="Magento_UrlRewrite">
         <severeness>low</severeness>
         <require>
             <urlRewrite class="Magento\UrlRewrite\Test\Fixture\UrlRewrite"/>
@@ -45,7 +45,7 @@
             <product class="Mtf\Fixture\FixtureInterface"/>
             <browser class="Mtf\Client\Browser"/>
         </require>
-    </assertProductUrlAvailableOnTheFront>
+    </assertUrlRewriteProductRedirect>
     <assertUrlRewriteDeletedMessage module="Magento_UrlRewrite">
         <severeness>low</severeness>
         <require>
@@ -67,4 +67,12 @@
             <browser class="Mtf\Client\Browser"/>
         </require>
     </assertPageByUrlRewriteIsNotFound>
+    <assertUrlRewriteCmsPageRedirect module="Magento_UrlRewrite">
+        <severeness>low</severeness>
+        <require>
+            <cmsPage class="Magento\Cms\Test\Fixture\CmsPage"/>
+            <urlRewrite class="Magento\UrlRewrite\Test\Fixture\UrlRewrite"/>
+            <browser class="Mtf\Client\Browser"/>
+        </require>
+    </assertUrlRewriteCmsPageRedirect>
 </constraint>
diff --git a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/global/page.xml b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/global/page.xml
index 0e1e33bb730f44a15a9209cbd00d91b71bf7999b..d8be3b72836dde3715635803f25982e39451ebde 100644
--- a/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/global/page.xml
+++ b/dev/tests/functional/tests/app/Magento/UrlRewrite/Test/etc/global/page.xml
@@ -34,4 +34,9 @@
         <area>adminhtml</area>
         <class>Magento\UrlRewrite\Test\Page\Adminhtml\UrlrewriteEdit</class>
     </urlrewriteEdit>
+    <editCmsPage>
+        <mca>admin/urlrewrite/edit/cms_page</mca>
+        <area>adminhtml</area>
+        <class>Magento\UrlRewrite\Test\Page\Adminhtml\EditCmsPage</class>
+    </editCmsPage>
 </page>
diff --git a/dev/tests/integration/phpunit.xml.dist b/dev/tests/integration/phpunit.xml.dist
index 51962f3c709996f811a768cd7ef8df18964ff1e2..2f406070a79352973b0856157a0a62ba33d08ea5 100644
--- a/dev/tests/integration/phpunit.xml.dist
+++ b/dev/tests/integration/phpunit.xml.dist
@@ -40,7 +40,7 @@
     <filter>
         <whitelist addUncoveredFilesFromWhiteList="true">
             <directory suffix=".php">../../../app/code/Magento</directory>
-            <directory suffix=".php">../../../lib/Magento</directory>
+            <directory suffix=".php">../../../lib/internal/Magento</directory>
             <exclude>
                 <directory suffix=".php">../../../app/code/Magento/*/sql</directory>
                 <directory suffix=".php">../../../app/code/Magento/*/data</directory>
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/AbstractTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/AbstractTest.php
index 15ecca48c353e87ee28bc06b6c71e4c060d76af0..2a13632919c6782165b5236c4003f008459827fd 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/AbstractTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Block/Product/AbstractTest.php
@@ -26,8 +26,7 @@ namespace Magento\Catalog\Block\Product;
 /**
  * Test class for \Magento\Catalog\Block\Product\Abstract.
  *
- * @magentoDataFixture Magento/Catalog/_files/product_simple.php
- * @magentoDataFixture Magento/Catalog/_files/product_image.php
+ * @magentoDataFixture Magento/Catalog/_files/product_with_image.php
  */
 class AbstractTest extends \PHPUnit_Framework_TestCase
 {
@@ -144,7 +143,7 @@ class AbstractTest extends \PHPUnit_Framework_TestCase
 
     public function testGetImageLabel()
     {
-        $this->assertEquals($this->_product->getName(), $this->_block->getImageLabel());
+        $this->assertEquals('Image Alt Text', $this->_block->getImageLabel());
     }
 
     public function testGetProductUrl()
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php
index 7667a487a686df189c01995f87de19b9e57f92ab..00e57c0ff3055bdcb8d57eaf8ed5ede21a339ab5 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Attribute/Backend/TierpriceTest.php
@@ -119,7 +119,7 @@ class TierpriceTest extends \PHPUnit_Framework_TestCase
         $this->_model->afterLoad($product);
         $price = $product->getTierPrice();
         $this->assertNotEmpty($price);
-        $this->assertEquals(2, count($price));
+        $this->assertEquals(3, count($price));
     }
 
     /**
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceTest.php b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceTest.php
index e50cb153a33c8ae9d807cba39a6ec6de88d85f7c..1b75531f4a9052dca8224eb9e1da7941edc34bd7 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceTest.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/Model/Product/Type/PriceTest.php
@@ -111,7 +111,7 @@ class PriceTest extends \PHPUnit_Framework_TestCase
         );
         $product->load(1);
         // fixture
-        $this->assertEquals(2, $this->_model->getTierPriceCount($product));
+        $this->assertEquals(3, $this->_model->getTierPriceCount($product));
     }
 
     public function testGetFormatedTierPrice()
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/attribute_set_with_image_attribute.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/attribute_set_with_image_attribute.php
new file mode 100644
index 0000000000000000000000000000000000000000..8cdc42ac3ff53de82faec3a913cc17e9c5a31c21
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/attribute_set_with_image_attribute.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/** @var $product \Magento\Catalog\Model\Product */
+$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+
+/** @var \Magento\Eav\Model\Entity\Attribute\Set $attributeSet */
+$attributeSet = $objectManager->create('\Magento\Eav\Model\Entity\Attribute\Set');
+
+$entityType = $objectManager->create('Magento\Eav\Model\Entity\Type')->loadByCode('catalog_product');
+$defaultSetId = $objectManager->create('\Magento\Catalog\Model\Product')->getDefaultAttributeSetid();
+
+$data = [
+    'attribute_set_name' => 'custom attribute set 531',
+    'entity_type_id' => $entityType->getId(),
+    'sort_order' => 200,
+];
+
+$attributeSet->setData($data);
+$attributeSet->validate();
+$attributeSet->save();
+$attributeSet->initFromSkeleton($defaultSetId);
+$attributeSet->save();
+
+$attributeData = array(
+    'entity_type_id' => $entityType->getId(),
+    'attribute_code' => 'funny_image',
+    'frontend_input' => 'media_image',
+    'frontend_label' => 'Funny image',
+    'backend_type' => 'varchar',
+    'is_required' => 0,
+    'is_user_defined' => 1,
+    'attribute_set_id' => $attributeSet->getId(),
+    'attribute_group_id' => $attributeSet->getDefaultGroupId(),
+);
+
+/** @var \Magento\Catalog\Model\Entity\Attribute $attribute */
+$attribute = $objectManager->create('\Magento\Catalog\Model\Entity\Attribute');
+$attribute->setData($attributeData);
+$attribute->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/attribute_set_with_image_attribute_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/attribute_set_with_image_attribute_rollback.php
new file mode 100644
index 0000000000000000000000000000000000000000..fcf22a8366a62ce3c5c03a6660e7f3afbf5d1ce0
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/attribute_set_with_image_attribute_rollback.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/** @var $product \Magento\Catalog\Model\Product */
+$objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
+
+$entityType = $objectManager->create('Magento\Eav\Model\Entity\Type')->loadByCode('catalog_product');
+
+// remove attribute
+
+/** @var \Magento\Catalog\Model\Resource\Product\Attribute\Collection $attributeCollection */
+$attributeCollection = $objectManager->create('\Magento\Catalog\Model\Resource\Product\Attribute\Collection');
+$attributeCollection->setFrontendInputTypeFilter('media_image');
+$attributeCollection->setCodeFilter('funny_image');
+$attributeCollection->setEntityTypeFilter($entityType->getId());
+$attributeCollection->setPageSize(1);
+$attributeCollection->load();
+$attribute = $attributeCollection->fetchItem();
+$attribute->delete();
+
+// remove attribute set
+
+/** @var \Magento\Eav\Model\Resource\Entity\Attribute\Set\Collection $attributeSetCollection */
+$attributeSetCollection = $objectManager->create('\Magento\Eav\Model\Resource\Entity\Attribute\Set\Collection');
+$attributeSetCollection->addFilter('attribute_set_name', 'custom attribute set 531');
+$attributeSetCollection->addFilter('entity_type_id', $entityType->getId());
+$attributeSetCollection->setOrder('attribute_set_id'); // descending is default value
+$attributeSetCollection->setPageSize(1);
+$attributeSetCollection->load();
+
+/** @var \Magento\Eav\Model\Entity\Attribute\Set $attributeSet */
+$attributeSet = $attributeSetCollection->fetchItem();
+$attributeSet->delete();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_group_prices.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_group_prices.php
new file mode 100644
index 0000000000000000000000000000000000000000..f87b3b5af2c4e69ff81a97b23793b649de0fdfd6
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_group_prices.php
@@ -0,0 +1,68 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/** @var $product \Magento\Catalog\Model\Product */
+$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
+    ->create('Magento\Catalog\Model\Product');
+$product->isObjectNew(true);
+$product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
+    ->setId(1)
+    ->setAttributeSetId(4)
+    ->setWebsiteIds(array(1))
+    ->setName('Simple Product Group Price')
+    ->setSku('simple_with_group_price')
+    ->setPrice(10)
+    ->setWeight(1)
+    ->setShortDescription("Short description")
+    ->setTaxClassId(0)
+    ->setGroupPrice(
+        array(
+            array(
+                'website_id' => 0,
+                'cust_group' => \Magento\Customer\Service\V1\CustomerGroupServiceInterface::NOT_LOGGED_IN_ID,
+                'price'      => 9,
+            ),
+            array(
+                'website_id' => 0,
+                'cust_group' => \Magento\Customer\Service\V1\CustomerGroupServiceInterface::CUST_GROUP_ALL,
+                'price'      => 7,
+            ),
+        )
+    )
+    ->setDescription('Description with <b>html tag</b>')
+    ->setMetaTitle('meta title')
+    ->setMetaKeyword('meta keyword')
+    ->setMetaDescription('meta description')
+    ->setVisibility(\Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH)
+    ->setStatus(\Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED)
+    ->setCategoryIds(array(2))
+    ->setStockData(
+        array(
+            'use_config_manage_stock'   => 1,
+            'qty'                       => 100,
+            'is_qty_decimal'            => 0,
+            'is_in_stock'               => 1,
+        )
+    )
+    ->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_group_prices_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_group_prices_rollback.php
new file mode 100644
index 0000000000000000000000000000000000000000..6ffb72acf9bb123fe18604ce907ad2648eb8c84e
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_group_prices_rollback.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/** @var \Magento\Framework\Registry $registry */
+$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry');
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var $product \Magento\Catalog\Model\Product */
+$product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
+$product->load(1);
+if ($product->getId()) {
+    $product->delete();
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_image.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_image.php
index a4ba42c127bf99ab352f19d3e4ed423cdcd791e3..a433616ce8041fd594fa0eae0678066ee6115cd5 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_image.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_image.php
@@ -23,11 +23,18 @@
  */
 
 $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
-$mediaPath = $objectManager->get('Magento\Framework\App\Filesystem')
-    ->getPath(\Magento\Framework\App\Filesystem::MEDIA_DIR);
-$additionalPath = $objectManager->get('Magento\Catalog\Model\Product\Media\Config')->getBaseMediaPath();
-$dir = $mediaPath . '/' . $additionalPath . '/m/a';
-if (!is_dir($dir)) {
-    mkdir($dir, 0777, true);
-}
-copy(__DIR__ . '/magento_image.jpg', $dir . '/magento_image.jpg');
+/** @var $mediaConfig \Magento\Catalog\Model\Product\Media\Config */
+$mediaConfig = $objectManager->get('Magento\Catalog\Model\Product\Media\Config');
+
+/** @var $mediaDirectory \Magento\Framework\Filesystem\Directory\WriteInterface */
+$mediaDirectory = $objectManager->get('Magento\Framework\App\Filesystem')
+    ->getDirectoryWrite(\Magento\Framework\App\Filesystem::MEDIA_DIR);
+$targetDirPath = $mediaConfig->getBaseMediaPath() . str_replace('/', DIRECTORY_SEPARATOR, '/m/a/');
+$targetTmpDirPath = $mediaConfig->getBaseTmpMediaPath() . str_replace('/', DIRECTORY_SEPARATOR, '/m/a/');
+$mediaDirectory->create($targetDirPath);
+$mediaDirectory->create($targetTmpDirPath);
+
+$targetTmpFilePath = $mediaDirectory->getAbsolutePath() . DIRECTORY_SEPARATOR . $targetTmpDirPath
+    . DIRECTORY_SEPARATOR . 'magento_image.jpg';
+copy(__DIR__ . '/magento_image.jpg', $targetTmpFilePath);
+// Copying the image to target dir is not necessary because during product save, it will be moved there from tmp dir
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php
index d9cd3b8ea96ab884b113c179a1f044c632a0fb22..ab660709210bc8d248a0103a7692cce21637af05 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_simple.php
@@ -50,6 +50,12 @@ $product->setTypeId(\Magento\Catalog\Model\Product\Type::TYPE_SIMPLE)
                 'price_qty'  => 5,
                 'price'      => 5,
             ),
+            array(
+                'website_id' => 0,
+                'cust_group' => \Magento\Customer\Service\V1\CustomerGroupServiceInterface::NOT_LOGGED_IN_ID,
+                'price_qty'  => 3,
+                'price'      => 5,
+            ),
         )
     )
     ->setDescription('Description with <b>html tag</b>')
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image.php
index 925440c9dd4c649ff15c0ee91c4a436c4f4bf99d..5e37963002baead68689a0efe878d5c5ea5d83d2 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image.php
@@ -23,33 +23,20 @@
  */
 
 require __DIR__ . '/product_image.php';
+require __DIR__ . '/product_simple.php';
 
 /** @var $product \Magento\Catalog\Model\Product */
 $product = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Catalog\Model\Product');
-$product->setTypeId(
-    \Magento\Catalog\Model\Product\Type::TYPE_SIMPLE
-)->setId(
-    1
-)->setAttributeSetId(
-    4
-)->setWebsiteIds(
-    array(1)
-)->setName(
-    'Simple Product'
-)->setSku(
-    'simple'
-)->setPrice(
-    10
-)->setDescription(
-    'Description with <b>html tag</b>'
-)->setImage(
-    '/m/a/magento_image.jpg'
-)->setSmallImage(
-    '/m/a/magento_image.jpg'
-)->setThumbnail(
-    '/m/a/magento_image.jpg'
-)->setVisibility(
-    \Magento\Catalog\Model\Product\Visibility::VISIBILITY_BOTH
-)->setStatus(
-    \Magento\Catalog\Model\Product\Attribute\Source\Status::STATUS_ENABLED
-)->save();
+$product->load(1)
+    ->setStoreId(0)
+    ->setImage('/m/a/magento_image.jpg')
+    ->setSmallImage('/m/a/magento_image.jpg')
+    ->setThumbnail('/m/a/magento_image.jpg')
+    ->setData('media_gallery', array('images' => array(
+        array(
+            'file' => '/m/a/magento_image.jpg',
+            'position' => 1,
+            'label' => 'Image Alt Text',
+            'disabled' => 0,
+        ),
+    )))->save();
diff --git a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image_rollback.php b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image_rollback.php
index 5d0c89be0cdacdfa9f3e3f8150b53c37758d2992..6419bc360aa41b4c5535a003cda86b2ab28932a0 100644
--- a/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image_rollback.php
+++ b/dev/tests/integration/testsuite/Magento/Catalog/_files/product_with_image_rollback.php
@@ -22,4 +22,5 @@
  * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
  */
 
+require __DIR__ . '/product_simple_rollback.php';
 require __DIR__ . '/product_image_rollback.php';
diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/website.php b/dev/tests/integration/testsuite/Magento/Store/_files/website.php
new file mode 100644
index 0000000000000000000000000000000000000000..b021dfbc3ca8ced9e62835be1cd7732ad24502e3
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Store/_files/website.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/** @var $website \Magento\Store\Model\Website */
+$website = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Store\Model\Website');
+$website->setData(array('code' => 'test', 'name' => 'Test Website', 'default_group_id' => '1', 'is_default' => '0'));
+$website->save();
diff --git a/dev/tests/integration/testsuite/Magento/Store/_files/website_rollback.php b/dev/tests/integration/testsuite/Magento/Store/_files/website_rollback.php
new file mode 100644
index 0000000000000000000000000000000000000000..16b7a94f7065f46f05ebfacd7d57c525c1f2b285
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Store/_files/website_rollback.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+/** @var \Magento\Framework\Registry $registry */
+$registry = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\Registry');
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', true);
+
+/** @var \Magento\Store\Model\Website $website */
+$website = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create('Magento\Store\Model\Website');
+$website->load('test');
+
+if ($website->getId()) {
+    $website->delete();
+}
+
+$registry->unregister('isSecureArea');
+$registry->register('isSecureArea', false);
+
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 30dca15ae97320a61aeb78a50d5f719359cd13c0..0b0247dbb6dda07963ad9adc286ebd8fcc53269e 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
@@ -46,6 +46,7 @@ class SetupUtil
     ];
 
     const TAX_RATE_TX = 'tax_rate_tx';
+    const TAX_RATE_AUSTIN = 'tax_rate_austin';
     const TAX_RATE_SHIPPING = 'tax_rate_shipping';
     const TAX_STORE_RATE = 'tax_store_rate';
     const REGION_TX = '57';
@@ -69,6 +70,16 @@ class SetupUtil
             ],
             'id' => null,
         ],
+        self::TAX_RATE_AUSTIN => [
+            'data' => [
+                'tax_country_id' => self::COUNTRY_US,
+                'tax_region_id' => self::REGION_TX,
+                'tax_postcode' => self::AUSTIN_POST_CODE,
+                'code' => self::TAX_RATE_AUSTIN,
+                'rate' => '5',
+            ],
+            'id' => null,
+        ],
         self::TAX_RATE_SHIPPING => [
             'data' => [
                 'tax_country_id' => self::COUNTRY_US,
@@ -301,14 +312,12 @@ class SetupUtil
      *
      * @return array
      */
-    protected function getTaxRateIds()
+    protected function getDefaultTaxRateIds()
     {
-        $taxRateIds = [];
-        foreach ($this->taxRates as $taxRateName => $taxRate) {
-            if ($taxRateName != self::TAX_RATE_SHIPPING) {
-                $taxRateIds[] = $taxRate['id'];
-            }
-        }
+        $taxRateIds = [
+            $this->taxRates[self::TAX_RATE_TX]['id'],
+            $this->taxRates[self::TAX_STORE_RATE]['id'],
+        ];
 
         return $taxRateIds;
     }
@@ -353,7 +362,7 @@ class SetupUtil
             'position' => '0',
             'tax_customer_class' => $customerClassIds,
             'tax_product_class' => $this->getProductTaxClassIds(),
-            'tax_rate' => $this->getTaxRateIds(),
+            'tax_rate' => $this->getDefaultTaxRateIds(),
         ];
 
         //Create tax rules
diff --git a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php
index 301e0d8d8190a3701e8b48e38985e0f2e6bf4bb9..478f2549796492b75965cca29bba44d9ae6e4ad3 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/Model/Sales/Total/Quote/TaxTest.php
@@ -51,6 +51,7 @@ class TaxTest extends \PHPUnit_Framework_TestCase
      * @magentoDataFixture Magento/Tax/_files/tax_classes.php
      * @magentoDataFixture Magento/Customer/_files/customer_group.php
      * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
      */
     public function testCollect()
     {
@@ -257,12 +258,12 @@ class TaxTest extends \PHPUnit_Framework_TestCase
      * @param array $quoteData
      * @param array $expectedResults
      * @magentoDbIsolation enabled
+     * @magentoAppIsolation enabled
      * @dataProvider taxDataProvider
      * @return void
      */
     public function testTaxCalculation($configData, $quoteData, $expectedResults)
     {
-        Bootstrap::getInstance()->reinitialize();
         /** @var  \Magento\Framework\ObjectManager $objectManager */
         $objectManager = Bootstrap::getObjectManager();
 
diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/excluding_tax_apply_tax_before_discount.php b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/excluding_tax_apply_tax_before_discount.php
index 9eaffb5eb7526cf2a2c3f9e46a4771153473de62..845791b66daef5fda469df55323cddd31a5c0cdd 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/excluding_tax_apply_tax_before_discount.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/excluding_tax_apply_tax_before_discount.php
@@ -28,6 +28,7 @@ use Magento\Tax\Model\Sales\Total\Quote\SetupUtil;
 $taxCalculationData['excluding_tax_apply_tax_before_discount'] = [
     'config_data' => [
         SetupUtil::CONFIG_OVERRIDES => [
+            Config::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT => 0,
             Config::CONFIG_XML_PATH_SHIPPING_TAX_CLASS => SetupUtil::PRODUCT_TAX_CLASS_1,
         ],
         SetupUtil::TAX_RATE_OVERRIDES => [
diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/including_tax_cross_border_trade_disabled.php b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/including_tax_cross_border_trade_disabled.php
new file mode 100644
index 0000000000000000000000000000000000000000..f79dafa544da808a520f4f4108b62d448fdcfc25
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/including_tax_cross_border_trade_disabled.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+use Magento\Tax\Model\Config;
+use Magento\Tax\Model\Sales\Total\Quote\SetupUtil;
+use Magento\Tax\Model\Calculation;
+
+$taxCalculationData['including_tax_cross_border_trade_disabled'] = [
+    'config_data' => [
+        SetupUtil::CONFIG_OVERRIDES => [
+            Config::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT => 1,
+            Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX => 1,
+            Config::CONFIG_XML_PATH_CROSS_BORDER_TRADE_ENABLED => 0,
+            Config::XML_PATH_ALGORITHM => Calculation::CALC_UNIT_BASE,
+        ],
+        SetupUtil::TAX_RATE_OVERRIDES => [
+            SetupUtil::TAX_RATE_TX => 20,
+            SetupUtil::TAX_STORE_RATE => 10,
+        ],
+        SetupUtil::TAX_RULE_OVERRIDES => [
+        ],
+    ],
+    'quote_data' => [
+        'billing_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+        ],
+        'shipping_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+        ],
+        'items' => [
+            [
+                'sku' => 'simple1',
+                'price' => 9.99,
+                'qty' => 2,
+            ],
+        ],
+    ],
+    'expected_results' => [
+        'address_data' => [
+            'subtotal' => 18.16,
+            'base_subtotal' => 18.16,
+            'subtotal_incl_tax' => 21.80,
+            'base_subtotal_incl_tax' => 21.80,
+            'tax_amount' => 3.64,
+            'base_tax_amount' => 3.64,
+            'shipping_amount' => 0,
+            'base_shipping_amount' => 0,
+            'shipping_incl_tax' => 0,
+            'base_shipping_incl_tax' => 0,
+            'shipping_taxable' => 0,
+            'base_shipping_taxable' => 0,
+            'shipping_tax_amount' => 0,
+            'base_shipping_tax_amount' => 0,
+            'discount_amount' => 0,
+            'base_discount_amount' => 0,
+            'hidden_tax_amount' => 0,
+            'base_hidden_tax_amount' => 0,
+            'shipping_hidden_tax_amount' => 0,
+            'base_shipping_hidden_tax_amount' => 0,
+            'grand_total' => 21.80,
+            'base_grand_total' => 21.80,
+        ],
+        'items_data' => [
+            'simple1' => [
+                'row_total' => 18.16,
+                'base_row_total' => 18.16,
+                'taxable_amount' => 10.90,
+                'base_taxable_amount' => 10.90,
+                'tax_percent' => 20,
+                'price' => 9.08,
+                'base_price' => 9.08,
+                'price_incl_tax' => 10.90,
+                'base_price_incl_tax' => 10.90,
+                'row_total_incl_tax' => 21.80,
+                'base_row_total_incl_tax' => 21.80,
+                'tax_amount' => 3.64,
+                'base_tax_amount' => 3.64,
+                'discount_amount' => 0,
+                'base_discount_amount' => 0,
+                'discount_percent' => 0,
+                'hidden_tax_amount' => 0,
+                'base_hidden_tax_amount' => 0,
+            ],
+        ],
+    ],
+];
\ No newline at end of file
diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/including_tax_cross_border_trade_enabled.php b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/including_tax_cross_border_trade_enabled.php
new file mode 100644
index 0000000000000000000000000000000000000000..c1875cec5a1b265439a56fef108f6bd493b87297
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/including_tax_cross_border_trade_enabled.php
@@ -0,0 +1,107 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+use Magento\Tax\Model\Config;
+use Magento\Tax\Model\Sales\Total\Quote\SetupUtil;
+use Magento\Tax\Model\Calculation;
+
+$taxCalculationData['including_tax_cross_border_trade_enabled'] = [
+    'config_data' => [
+        SetupUtil::CONFIG_OVERRIDES => [
+            Config::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT => 1,
+            Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX => 1,
+            Config::CONFIG_XML_PATH_CROSS_BORDER_TRADE_ENABLED => 1,
+            Config::XML_PATH_ALGORITHM => Calculation::CALC_UNIT_BASE,
+        ],
+        SetupUtil::TAX_RATE_OVERRIDES => [
+            SetupUtil::TAX_RATE_TX => 20,
+            SetupUtil::TAX_STORE_RATE => 10,
+        ],
+        SetupUtil::TAX_RULE_OVERRIDES => [
+        ],
+    ],
+    'quote_data' => [
+        'billing_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+        ],
+        'shipping_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+        ],
+        'items' => [
+            [
+                'sku' => 'simple1',
+                'price' => 9.99,
+                'qty' => 2,
+            ],
+        ],
+    ],
+    'expected_results' => [
+        'address_data' => [
+            'subtotal' => 16.64,
+            'base_subtotal' => 16.64,
+            'subtotal_incl_tax' => 19.98,
+            'base_subtotal_incl_tax' => 19.98,
+            'tax_amount' => 3.34,
+            'base_tax_amount' => 3.34,
+            'shipping_amount' => 0,
+            'base_shipping_amount' => 0,
+            'shipping_incl_tax' => 0,
+            'base_shipping_incl_tax' => 0,
+            'shipping_taxable' => 0,
+            'base_shipping_taxable' => 0,
+            'shipping_tax_amount' => 0,
+            'base_shipping_tax_amount' => 0,
+            'discount_amount' => 0,
+            'base_discount_amount' => 0,
+            'hidden_tax_amount' => 0,
+            'base_hidden_tax_amount' => 0,
+            'shipping_hidden_tax_amount' => 0,
+            'base_shipping_hidden_tax_amount' => 0,
+            'grand_total' => 19.98,
+            'base_grand_total' => 19.98,
+        ],
+        'items_data' => [
+            'simple1' => [
+                'row_total' => 16.64,
+                'base_row_total' => 16.64,
+                'taxable_amount' => 9.99,
+                'base_taxable_amount' => 9.99,
+                'tax_percent' => 20,
+                'price' => 8.32,
+                'base_price' => 8.32,
+                'price_incl_tax' => 9.99,
+                'base_price_incl_tax' => 9.99,
+                'row_total_incl_tax' => 19.98,
+                'base_row_total_incl_tax' => 19.98,
+                'tax_amount' => 3.34,
+                'base_tax_amount' => 3.34,
+                'discount_amount' => 0,
+                'base_discount_amount' => 0,
+                'discount_percent' => 0,
+                'hidden_tax_amount' => 0,
+                'base_hidden_tax_amount' => 0,
+            ],
+        ],
+    ],
+];
\ No newline at end of file
diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_total_calculate_subtotal_no.php b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_total_calculate_subtotal_no.php
new file mode 100644
index 0000000000000000000000000000000000000000..6578ab2fdb1e7be7ba28bbd4c40e3e6c725465fa
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_total_calculate_subtotal_no.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+use Magento\Tax\Model\Config;
+use Magento\Tax\Model\Sales\Total\Quote\SetupUtil;
+use Magento\Tax\Model\Calculation;
+
+/**
+ * This test case test the scenario where there are two tax rules with different priority
+ * The calculate_subtotal field is off, the second tax rate will be applied on top of first
+ * tax rate. This testcases uses total based calculation.
+ */
+$taxCalculationData['multi_tax_rule_total_calculate_subtotal_no'] = [
+    'config_data' => [
+        SetupUtil::CONFIG_OVERRIDES => [
+            Config::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT => 1,
+            Config::XML_PATH_ALGORITHM => Calculation::CALC_TOTAL_BASE,
+        ],
+        SetupUtil::TAX_RATE_OVERRIDES => [
+            SetupUtil::TAX_RATE_TX => 7.5,
+            SetupUtil::TAX_RATE_AUSTIN => 5.5,
+        ],
+        SetupUtil::TAX_RULE_OVERRIDES => [
+            [
+                //tax rule 1 for product
+                'code' => 'Product Tax Rule TX',
+                'tax_product_class' => [SetupUtil::PRODUCT_TAX_CLASS_1],
+                'tax_rate' => [SetupUtil::TAX_RATE_TX],
+                'priority' => 1,
+            ],
+            [
+                //tax rule 2 for product
+                'code' => 'Product Tax Rule AUSTIN',
+                'tax_product_class' => [SetupUtil::PRODUCT_TAX_CLASS_1],
+                'tax_rate' => [SetupUtil::TAX_RATE_AUSTIN],
+                'priority' => 2,
+                'calculate_subtotal' => 0,
+            ],
+        ],
+    ],
+    'quote_data' => [
+        'billing_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+        ],
+        'shipping_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+            'tax_postcode' => SetupUtil::AUSTIN_POST_CODE,
+        ],
+        'items' => [
+            [
+                'sku' => 'simple1',
+                'price' => 1,
+                'qty' => 10,
+            ],
+        ],
+    ],
+    'expected_results' => [
+        'address_data' => [
+            'subtotal' => 10,
+            'base_subtotal' => 10,
+            'subtotal_incl_tax' => 11.34,
+            'base_subtotal_incl_tax' => 11.34,
+            'tax_amount' => 1.34,
+            'base_tax_amount' => 1.34,
+            'shipping_amount' => 0,
+            'base_shipping_amount' => 0,
+            'shipping_incl_tax' => 0,
+            'base_shipping_incl_tax' => 0,
+            'shipping_taxable' => 0,
+            'base_shipping_taxable' => 0,
+            'shipping_tax_amount' => 0,
+            'base_shipping_tax_amount' => 0,
+            'discount_amount' => 0,
+            'base_discount_amount' => 0,
+            'hidden_tax_amount' => 0,
+            'base_hidden_tax_amount' => 0,
+            'shipping_hidden_tax_amount' => 0,
+            'base_shipping_hidden_tax_amount' => 0,
+            'grand_total' => 11.34,
+            'base_grand_total' => 11.34,
+            'applied_taxes' => [
+                SetupUtil::TAX_RATE_TX => [
+                    'percent' => 7.5,
+                    'amount' => 0.75,
+                    'base_amount' => 0.75,
+                    'rates' => [
+                        [
+                            'code' => SetupUtil::TAX_RATE_TX,
+                            'title' => SetupUtil::TAX_RATE_TX,
+                            'percent' => 7.5,
+                        ],
+                    ],
+                ],
+                SetupUtil::TAX_RATE_AUSTIN => [
+                    'percent' => 5.9125,
+                    'amount' => 0.59,
+                    'base_amount' => 0.59,
+                    'rates' => [
+                        [
+                            'code' => SetupUtil::TAX_RATE_AUSTIN,
+                            'title' => SetupUtil::TAX_RATE_AUSTIN,
+                            'percent' => 5.5,
+                        ],
+                    ],
+                ],
+            ],
+        ],
+        'items_data' => [
+            'simple1' => [
+                'row_total' => 10,
+                'base_row_total' => 10,
+                'taxable_amount' => 10,
+                'base_taxable_amount' => 10,
+                'tax_percent' => 13.4125,
+                'price' => 1,
+                'base_price' => 1,
+                'price_incl_tax' => 1.13,
+                'base_price_incl_tax' => 1.13,
+                'row_total_incl_tax' => 11.34,
+                'base_row_total_incl_tax' => 11.34,
+                'tax_amount' => 1.34,
+                'base_tax_amount' => 1.34,
+                'discount_amount' => 0,
+                'base_discount_amount' => 0,
+                'discount_percent' => 0,
+                'hidden_tax_amount' => 0,
+                'base_hidden_tax_amount' => 0,
+            ],
+        ],
+    ],
+];
\ No newline at end of file
diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_total_calculate_subtotal_yes.php b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_total_calculate_subtotal_yes.php
new file mode 100644
index 0000000000000000000000000000000000000000..d88e3ddb026ad453330aa320704e99dd0ea9dbe9
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_total_calculate_subtotal_yes.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+use Magento\Tax\Model\Config;
+use Magento\Tax\Model\Sales\Total\Quote\SetupUtil;
+use Magento\Tax\Model\Calculation;
+
+/**
+ * This test case test the scenario where there are two tax rules with different priority
+ * The calculate_subtotal field is on, the second tax rate will be applied on subtotal only.
+ * This testcase uses total based calculation.
+ */
+$taxCalculationData['multi_tax_rule_total_calculate_subtotal_yes'] = [
+    'config_data' => [
+        SetupUtil::CONFIG_OVERRIDES => [
+            Config::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT => 1,
+            Config::XML_PATH_ALGORITHM => Calculation::CALC_TOTAL_BASE,
+        ],
+        SetupUtil::TAX_RATE_OVERRIDES => [
+            SetupUtil::TAX_RATE_TX => 7.5,
+            SetupUtil::TAX_RATE_AUSTIN => 5.5,
+        ],
+        SetupUtil::TAX_RULE_OVERRIDES => [
+            [
+                //tax rule 1 for product
+                'code' => 'Product Tax Rule TX',
+                'tax_product_class' => [SetupUtil::PRODUCT_TAX_CLASS_1],
+                'tax_rate' => [SetupUtil::TAX_RATE_TX],
+                'priority' => 1,
+            ],
+            [
+                //tax rule 2 for product
+                'code' => 'Product Tax Rule AUSTIN',
+                'tax_product_class' => [SetupUtil::PRODUCT_TAX_CLASS_1],
+                'tax_rate' => [SetupUtil::TAX_RATE_AUSTIN],
+                'priority' => 2,
+                'calculate_subtotal' => 1,
+            ],
+        ],
+    ],
+    'quote_data' => [
+        'billing_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+        ],
+        'shipping_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+            'tax_postcode' => SetupUtil::AUSTIN_POST_CODE,
+        ],
+        'items' => [
+            [
+                'sku' => 'simple1',
+                'price' => 1,
+                'qty' => 10,
+            ],
+        ],
+    ],
+    'expected_results' => [
+        'address_data' => [
+            'subtotal' => 10,
+            'base_subtotal' => 10,
+            'subtotal_incl_tax' => 11.3,
+            'base_subtotal_incl_tax' => 11.3,
+            'tax_amount' => 1.3,
+            'base_tax_amount' => 1.3,
+            'shipping_amount' => 0,
+            'base_shipping_amount' => 0,
+            'shipping_incl_tax' => 0,
+            'base_shipping_incl_tax' => 0,
+            'shipping_taxable' => 0,
+            'base_shipping_taxable' => 0,
+            'shipping_tax_amount' => 0,
+            'base_shipping_tax_amount' => 0,
+            'discount_amount' => 0,
+            'base_discount_amount' => 0,
+            'hidden_tax_amount' => 0,
+            'base_hidden_tax_amount' => 0,
+            'shipping_hidden_tax_amount' => 0,
+            'base_shipping_hidden_tax_amount' => 0,
+            'grand_total' => 11.3,
+            'base_grand_total' => 11.3,
+            'applied_taxes' => [
+                SetupUtil::TAX_RATE_TX => [
+                    'percent' => 7.5,
+                    'amount' => 0.75,
+                    'base_amount' => 0.75,
+                    'rates' => [
+                        [
+                            'code' => SetupUtil::TAX_RATE_TX,
+                            'title' => SetupUtil::TAX_RATE_TX,
+                            'percent' => 7.5,
+                        ],
+                    ],
+                ],
+                SetupUtil::TAX_RATE_AUSTIN => [
+                    'percent' => 5.5,
+                    'amount' => 0.55,
+                    'base_amount' => 0.55,
+                    'rates' => [
+                        [
+                            'code' => SetupUtil::TAX_RATE_AUSTIN,
+                            'title' => SetupUtil::TAX_RATE_AUSTIN,
+                            'percent' => 5.5,
+                        ],
+                    ],
+                ],
+            ],
+        ],
+        'items_data' => [
+            'simple1' => [
+                'row_total' => 10,
+                'base_row_total' => 10,
+                'taxable_amount' => 10,
+                'base_taxable_amount' => 10,
+                'tax_percent' => 13,
+                'price' => 1,
+                'base_price' => 1,
+                'price_incl_tax' => 1.13,
+                'base_price_incl_tax' => 1.13,
+                'row_total_incl_tax' => 11.3,
+                'base_row_total_incl_tax' => 11.3,
+                'tax_amount' => 1.3,
+                'base_tax_amount' => 1.3,
+                'discount_amount' => 0,
+                'base_discount_amount' => 0,
+                'discount_percent' => 0,
+                'hidden_tax_amount' => 0,
+                'base_hidden_tax_amount' => 0,
+            ],
+        ],
+    ],
+];
\ No newline at end of file
diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_unit_calculate_subtotal_no.php b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_unit_calculate_subtotal_no.php
new file mode 100644
index 0000000000000000000000000000000000000000..5e0701ea3869bf151ffb4994e1a3689c4398032a
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_unit_calculate_subtotal_no.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+use Magento\Tax\Model\Config;
+use Magento\Tax\Model\Sales\Total\Quote\SetupUtil;
+use Magento\Tax\Model\Calculation;
+
+/**
+ * This test case test the scenario where there are two tax rules with different priority
+ * The calculate_subtotal field is off, the second tax rate will be applied on top of first
+ * tax rate. This testcase uses unit based calculation.
+ */
+$taxCalculationData['multi_tax_rule_unit_calculate_subtotal_no'] = [
+    'config_data' => [
+        SetupUtil::CONFIG_OVERRIDES => [
+            Config::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT => 1,
+            Config::XML_PATH_ALGORITHM => Calculation::CALC_UNIT_BASE,
+        ],
+        SetupUtil::TAX_RATE_OVERRIDES => [
+            SetupUtil::TAX_RATE_TX => 7.5,
+            SetupUtil::TAX_RATE_AUSTIN => 5.5,
+        ],
+        SetupUtil::TAX_RULE_OVERRIDES => [
+            [
+                //tax rule 1 for product
+                'code' => 'Product Tax Rule TX',
+                'tax_product_class' => [SetupUtil::PRODUCT_TAX_CLASS_1],
+                'tax_rate' => [SetupUtil::TAX_RATE_TX],
+                'priority' => 1,
+            ],
+            [
+                //tax rule 2 for product
+                'code' => 'Product Tax Rule AUSTIN',
+                'tax_product_class' => [SetupUtil::PRODUCT_TAX_CLASS_1],
+                'tax_rate' => [SetupUtil::TAX_RATE_AUSTIN],
+                'priority' => 2,
+                'calculate_subtotal' => 0,
+            ],
+        ],
+    ],
+    'quote_data' => [
+        'billing_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+        ],
+        'shipping_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+            'tax_postcode' => SetupUtil::AUSTIN_POST_CODE,
+        ],
+        'items' => [
+            [
+                'sku' => 'simple1',
+                'price' => 1,
+                'qty' => 10,
+            ],
+        ],
+    ],
+    'expected_results' => [
+        'address_data' => [
+            'subtotal' => 10,
+            'base_subtotal' => 10,
+            'subtotal_incl_tax' => 11.4,
+            'base_subtotal_incl_tax' => 11.4,
+            'tax_amount' => 1.4,
+            'base_tax_amount' => 1.4,
+            'shipping_amount' => 0,
+            'base_shipping_amount' => 0,
+            'shipping_incl_tax' => 0,
+            'base_shipping_incl_tax' => 0,
+            'shipping_taxable' => 0,
+            'base_shipping_taxable' => 0,
+            'shipping_tax_amount' => 0,
+            'base_shipping_tax_amount' => 0,
+            'discount_amount' => 0,
+            'base_discount_amount' => 0,
+            'hidden_tax_amount' => 0,
+            'base_hidden_tax_amount' => 0,
+            'shipping_hidden_tax_amount' => 0,
+            'base_shipping_hidden_tax_amount' => 0,
+            'grand_total' => 11.4,
+            'base_grand_total' => 11.4,
+            'applied_taxes' => [
+                SetupUtil::TAX_RATE_TX => [
+                    'percent' => 7.5,
+                    'amount' => 0.8,
+                    'base_amount' => 0.8,
+                    'rates' => [
+                        [
+                            'code' => SetupUtil::TAX_RATE_TX,
+                            'title' => SetupUtil::TAX_RATE_TX,
+                            'percent' => 7.5,
+                        ],
+                    ],
+                ],
+                SetupUtil::TAX_RATE_AUSTIN => [
+                    'percent' => 5.9125,
+                    'amount' => 0.6,
+                    'base_amount' => 0.6,
+                    'rates' => [
+                        [
+                            'code' => SetupUtil::TAX_RATE_AUSTIN,
+                            'title' => SetupUtil::TAX_RATE_AUSTIN,
+                            'percent' => 5.5,
+                        ],
+                    ],
+                ],
+            ],
+        ],
+        'items_data' => [
+            'simple1' => [
+                'row_total' => 10,
+                'base_row_total' => 10,
+                'taxable_amount' => 1,
+                'base_taxable_amount' => 1,
+                'tax_percent' => 13.4125,
+                'price' => 1,
+                'base_price' => 1,
+                'price_incl_tax' => 1.14,
+                'base_price_incl_tax' => 1.14,
+                'row_total_incl_tax' => 11.4,
+                'base_row_total_incl_tax' => 11.4,
+                'tax_amount' => 1.4,
+                'base_tax_amount' => 1.4,
+                'discount_amount' => 0,
+                'base_discount_amount' => 0,
+                'discount_percent' => 0,
+                'hidden_tax_amount' => 0,
+                'base_hidden_tax_amount' => 0,
+            ],
+        ],
+    ],
+];
\ No newline at end of file
diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_unit_calculate_subtotal_yes.php b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_unit_calculate_subtotal_yes.php
new file mode 100644
index 0000000000000000000000000000000000000000..025ba3b402f1274151f8f6d797dff97e4b381fa4
--- /dev/null
+++ b/dev/tests/integration/testsuite/Magento/Tax/_files/scenarios/multi_tax_rule_unit_calculate_subtotal_yes.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+use Magento\Tax\Model\Config;
+use Magento\Tax\Model\Sales\Total\Quote\SetupUtil;
+use Magento\Tax\Model\Calculation;
+
+/**
+ * This test case test the scenario where there are two tax rules with different priority
+ * The calculate_subtotal field is on, the second tax rate will be applied on subtotal only.
+ * This testcase uses unit based calculation.
+ */
+$taxCalculationData['multi_tax_rule_unit_calculate_subtotal_yes'] = [
+    'config_data' => [
+        SetupUtil::CONFIG_OVERRIDES => [
+            Config::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT => 1,
+            Config::XML_PATH_ALGORITHM => Calculation::CALC_UNIT_BASE,
+        ],
+        SetupUtil::TAX_RATE_OVERRIDES => [
+            SetupUtil::TAX_RATE_TX => 7.5,
+            SetupUtil::TAX_RATE_AUSTIN => 5.5,
+        ],
+        SetupUtil::TAX_RULE_OVERRIDES => [
+            [
+                //tax rule 1 for product
+                'code' => 'Product Tax Rule TX',
+                'tax_product_class' => [SetupUtil::PRODUCT_TAX_CLASS_1],
+                'tax_rate' => [SetupUtil::TAX_RATE_TX],
+                'priority' => 1,
+            ],
+            [
+                //tax rule 2 for product
+                'code' => 'Product Tax Rule AUSTIN',
+                'tax_product_class' => [SetupUtil::PRODUCT_TAX_CLASS_1],
+                'tax_rate' => [SetupUtil::TAX_RATE_AUSTIN],
+                'priority' => 2,
+                'calculate_subtotal' => 1,
+            ],
+        ],
+    ],
+    'quote_data' => [
+        'billing_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+        ],
+        'shipping_address' => [
+            'region_id' => SetupUtil::REGION_TX,
+            'tax_postcode' => SetupUtil::AUSTIN_POST_CODE,
+        ],
+        'items' => [
+            [
+                'sku' => 'simple1',
+                'price' => 1,
+                'qty' => 10,
+            ],
+        ],
+    ],
+    'expected_results' => [
+        'address_data' => [
+            'subtotal' => 10,
+            'base_subtotal' => 10,
+            'subtotal_incl_tax' => 11.4,
+            'base_subtotal_incl_tax' => 11.4,
+            'tax_amount' => 1.4,
+            'base_tax_amount' => 1.4,
+            'shipping_amount' => 0,
+            'base_shipping_amount' => 0,
+            'shipping_incl_tax' => 0,
+            'base_shipping_incl_tax' => 0,
+            'shipping_taxable' => 0,
+            'base_shipping_taxable' => 0,
+            'shipping_tax_amount' => 0,
+            'base_shipping_tax_amount' => 0,
+            'discount_amount' => 0,
+            'base_discount_amount' => 0,
+            'hidden_tax_amount' => 0,
+            'base_hidden_tax_amount' => 0,
+            'shipping_hidden_tax_amount' => 0,
+            'base_shipping_hidden_tax_amount' => 0,
+            'grand_total' => 11.4,
+            'base_grand_total' => 11.4,
+            'applied_taxes' => [
+                SetupUtil::TAX_RATE_TX => [
+                    'percent' => 7.5,
+                    'amount' => 0.8,
+                    'base_amount' => 0.8,
+                    'rates' => [
+                        [
+                            'code' => SetupUtil::TAX_RATE_TX,
+                            'title' => SetupUtil::TAX_RATE_TX,
+                            'percent' => 7.5,
+                        ],
+                    ],
+                ],
+                SetupUtil::TAX_RATE_AUSTIN => [
+                    'percent' => 5.5,
+                    'amount' => 0.6,
+                    'base_amount' => 0.6,
+                    'rates' => [
+                        [
+                            'code' => SetupUtil::TAX_RATE_AUSTIN,
+                            'title' => SetupUtil::TAX_RATE_AUSTIN,
+                            'percent' => 5.5,
+                        ],
+                    ],
+                ],
+            ],
+        ],
+        'items_data' => [
+            'simple1' => [
+                'row_total' => 10,
+                'base_row_total' => 10,
+                'taxable_amount' => 1,
+                'base_taxable_amount' => 1,
+                'tax_percent' => 13,
+                'price' => 1,
+                'base_price' => 1,
+                'price_incl_tax' => 1.14,
+                'base_price_incl_tax' => 1.14,
+                'row_total_incl_tax' => 11.4,
+                'base_row_total_incl_tax' => 11.4,
+                'tax_amount' => 1.4,
+                'base_tax_amount' => 1.4,
+                'discount_amount' => 0,
+                'base_discount_amount' => 0,
+                'discount_percent' => 0,
+                'hidden_tax_amount' => 0,
+                'base_hidden_tax_amount' => 0,
+            ],
+        ],
+    ],
+];
\ No newline at end of file
diff --git a/dev/tests/integration/testsuite/Magento/Tax/_files/tax_calculation_data_aggregated.php b/dev/tests/integration/testsuite/Magento/Tax/_files/tax_calculation_data_aggregated.php
index 13097905b486d7e6b0a051628506ec3939b0bde3..b98287caeccba808e802f6a92b1c9fe92d390745 100644
--- a/dev/tests/integration/testsuite/Magento/Tax/_files/tax_calculation_data_aggregated.php
+++ b/dev/tests/integration/testsuite/Magento/Tax/_files/tax_calculation_data_aggregated.php
@@ -40,4 +40,9 @@ require_once __DIR__ . '/scenarios/including_tax_total.php';
 require_once __DIR__ . '/scenarios/excluding_tax_multi_item_unit.php';
 require_once __DIR__ . '/scenarios/excluding_tax_multi_item_row.php';
 require_once __DIR__ . '/scenarios/excluding_tax_multi_item_total.php';
-
+require_once __DIR__ . '/scenarios/including_tax_cross_border_trade_disabled.php';
+require_once __DIR__ . '/scenarios/including_tax_cross_border_trade_enabled.php';
+require_once __DIR__ . '/scenarios/multi_tax_rule_total_calculate_subtotal_no.php';
+require_once __DIR__ . '/scenarios/multi_tax_rule_unit_calculate_subtotal_no.php';
+require_once __DIR__ . '/scenarios/multi_tax_rule_total_calculate_subtotal_yes.php';
+require_once __DIR__ . '/scenarios/multi_tax_rule_unit_calculate_subtotal_yes.php';
diff --git a/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php b/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php
index aa286b773b37750dec11526ddce4b2d6f5cd8289..093a31ffad9883e6e6164243a7c3a30b57106ed3 100644
--- a/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php
+++ b/dev/tests/integration/testsuite/Magento/Widget/Model/Widget/InstanceTest.php
@@ -61,11 +61,6 @@ class InstanceTest extends \PHPUnit_Framework_TestCase
      */
     public function testGetWidgetConfigAsArray()
     {
-        $this->markTestIncomplete(
-            'Functionality is failed because widget' .
-            ' "app/design/frontend/Magento/iphone_html5/etc/widget.xml" replaces' .
-            ' "new_products" widget in Catalog module'
-        );
         $config = $this->_model->setType('Magento\Catalog\Block\Product\Widget\NewWidget')->getWidgetConfigAsArray();
         $this->assertTrue(is_array($config));
         $element = null;
@@ -96,11 +91,6 @@ class InstanceTest extends \PHPUnit_Framework_TestCase
      */
     public function testGetWidgetSupportedContainers()
     {
-        $this->markTestIncomplete(
-            'Functionality is failed because widget' .
-            ' "app/design/frontend/Magento/iphone_html5/etc/widget.xml" replaces' .
-            ' "new_products" widget in Catalog module'
-        );
         $this->_model->setType('Magento\Catalog\Block\Product\Widget\NewWidget');
         $containers = $this->_model->getWidgetSupportedContainers();
         $this->assertInternalType('array', $containers);
diff --git a/dev/tests/integration/testsuite/Magento/Widget/Model/WidgetTest.php b/dev/tests/integration/testsuite/Magento/Widget/Model/WidgetTest.php
index c5b4d41fd53d7f4cc4f02ff0fb3da256433af3c5..a6f8cbcc0fb798b1854f84e39855905c8f9505de 100644
--- a/dev/tests/integration/testsuite/Magento/Widget/Model/WidgetTest.php
+++ b/dev/tests/integration/testsuite/Magento/Widget/Model/WidgetTest.php
@@ -60,30 +60,14 @@ class WidgetTest extends \PHPUnit_Framework_TestCase
      */
     public function testGetPlaceholderImageUrl($type, $expectedFile)
     {
-        $this->markTestIncomplete(
-            'Functionality is failed because widget' .
-            ' "app/design/frontend/Magento/iphone_html5/etc/widget.xml" replaces' .
-            ' "new_products" widget in Catalog module'
-        );
         $objectManager = \Magento\TestFramework\Helper\Bootstrap::getObjectManager();
         \Magento\TestFramework\Helper\Bootstrap::getInstance()
             ->loadArea(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE);
         $objectManager->get('Magento\Framework\View\DesignInterface')->setDesignTheme('Magento/backend');
         $expectedFilePath = "/adminhtml/Magento/backend/en_US/{$expectedFile}";
-        $expectedPubFile = $objectManager->get(
-            'Magento\Framework\App\Filesystem'
-        )->getPath(
-            \Magento\Framework\App\Filesystem::STATIC_VIEW_DIR
-        ) . $expectedFilePath;
-
-        if (file_exists($expectedPubFile)) {
-            unlink($expectedPubFile);
-        }
 
         $url = $this->_model->getPlaceholderImageUrl($type);
-        $this->assertStringEndsWith($expectedFile, $url);
-        $this->assertFileExists($expectedPubFile);
-        return $expectedPubFile;
+        $this->assertStringEndsWith($expectedFilePath, $url);
     }
 
     /**
@@ -99,32 +83,4 @@ class WidgetTest extends \PHPUnit_Framework_TestCase
             'default image' => array('non_existing_widget_type', 'Magento_Widget/placeholder.gif')
         );
     }
-
-    /**
-     * Tests, that theme file is found anywhere in theme folders, not only in module directory.
-     *
-     * @magentoDataFixture Magento/Widget/_files/themes.php
-     * @magentoAppIsolation enabled
-     */
-    public function testGetPlaceholderImageUrlAtTheme()
-    {
-        \Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize(
-            array(
-                \Magento\Framework\App\Filesystem::PARAM_APP_DIRS => array(
-                    \Magento\Framework\App\Filesystem::THEMES_DIR => array(
-                        'path' => dirname(__DIR__) . '/_files/design'
-                    )
-                )
-            )
-        );
-        $actualFile = $this->testGetPlaceholderImageUrl(
-            'Magento\Catalog\Block\Product\Widget\NewWidget',
-            'Magento_Catalog/images/product_widget_new.gif'
-        );
-
-        $expectedFile = dirname(
-            __DIR__
-        ) . '/_files/design/adminhtml/Magento/backend/Magento_Catalog/web/images/product_widget_new.gif';
-        $this->assertFileEquals($expectedFile, $actualFile);
-    }
 }
diff --git a/dev/tests/integration/testsuite/Magento/Widget/_files/themes.php b/dev/tests/integration/testsuite/Magento/Widget/_files/themes.php
deleted file mode 100644
index c89104025486db21e0585ecc1118ae0de2e499cb..0000000000000000000000000000000000000000
--- a/dev/tests/integration/testsuite/Magento/Widget/_files/themes.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-/**
- * Magento
- *
- * NOTICE OF LICENSE
- *
- * This source file is subject to the Open Software License (OSL 3.0)
- * that is bundled with this package in the file LICENSE.txt.
- * It is also available through the world-wide-web at this URL:
- * http://opensource.org/licenses/osl-3.0.php
- * If you did not receive a copy of the license and are unable to
- * obtain it through the world-wide-web, please send an email
- * to license@magentocommerce.com so we can send you a copy immediately.
- *
- * DISCLAIMER
- *
- * Do not edit or add to this file if you wish to upgrade Magento to newer
- * versions in the future. If you wish to customize Magento for your
- * needs please refer to http://www.magentocommerce.com for more information.
- *
- * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
- * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
- */
-
-\Magento\TestFramework\Helper\Bootstrap::getInstance()->reinitialize(array(
-    \Magento\Framework\App\Filesystem::PARAM_APP_DIRS => array(
-        \Magento\Framework\App\Filesystem::THEMES_DIR => array('path' => __DIR__ . '/design')
-    )
-));
-
-\Magento\TestFramework\Helper\Bootstrap::getObjectManager()->get('Magento\Framework\App\AreaList')
-    ->getArea(\Magento\Backend\App\Area\FrontNameResolver::AREA_CODE)
-    ->load(\Magento\Framework\App\Area::PART_CONFIG);
-/** @var $registration \Magento\Core\Model\Theme\Registration */
-$registration = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(
-    'Magento\Core\Model\Theme\Registration'
-);
-$registration->register('*/*/theme.xml');
diff --git a/dev/tests/static/framework/Magento/TestFramework/Utility/ChangedFiles.php b/dev/tests/static/framework/Magento/TestFramework/Utility/ChangedFiles.php
new file mode 100644
index 0000000000000000000000000000000000000000..e7fb311d7c28fda24670be3da7ca6454cef958c1
--- /dev/null
+++ b/dev/tests/static/framework/Magento/TestFramework/Utility/ChangedFiles.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\TestFramework\Utility;
+
+/**
+ * A helper to gather various changed files
+ * if INCREMENTAL_BUILD env variable is set by CI build infrastructure, only files changed in the
+ * branch are gathered, otherwise all files
+ */
+class ChangedFiles
+{
+    /**
+     * Returns array of PHP-files, that use or declare Magento application classes and Magento libs
+     *
+     * @param string $changedFilesList
+     * @return array
+     */
+    public static function getPhpFiles($changedFilesList)
+    {
+        $fileHelper = \Magento\TestFramework\Utility\Files::init();
+        $allPhpFiles = $fileHelper->getPhpFiles();
+        if (isset($_ENV['INCREMENTAL_BUILD'])) {
+            $phpFiles = file($changedFilesList, FILE_IGNORE_NEW_LINES);
+            foreach ($phpFiles as $key => $phpFile) {
+                $phpFiles[$key] = $fileHelper->getPathToSource() . '/' . $phpFile;
+            }
+            $phpFiles = \Magento\TestFramework\Utility\Files::composeDataSets($phpFiles);
+            $phpFiles = array_intersect_key($phpFiles, $allPhpFiles);
+        } else {
+            $phpFiles = $allPhpFiles;
+        }
+
+        return $phpFiles;
+    }
+}
diff --git a/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php b/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php
index 7cf7a9155ef42867b0f1fb2f81de6982f69a56e8..18fcb1f839cd23490b63ceff0f7c6ab06b115782 100644
--- a/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php
+++ b/dev/tests/static/testsuite/Magento/Test/Legacy/ObsoleteCodeTest.php
@@ -148,7 +148,7 @@ class ObsoleteCodeTest extends \PHPUnit_Framework_TestCase
                 $this->_testObsoleteConstants($content);
                 $this->_testObsoletePropertySkipCalculate($content);
             },
-            \Magento\TestFramework\Utility\Files::init()->getPhpFiles()
+            \Magento\TestFramework\Utility\ChangedFiles::getPhpFiles(__DIR__ . '/_files/changed_files.txt')
         );
     }
 
diff --git a/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Adjustment/CalculatorTest.php b/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Adjustment/CalculatorTest.php
index 5f7cbfb1931f400c1c9d8971bf040da56426252a..8c8e61289a2c733ee3fcb9748e1d00988f50e353 100644
--- a/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Adjustment/CalculatorTest.php
+++ b/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Adjustment/CalculatorTest.php
@@ -61,6 +61,11 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase
      */
     protected $selectionFactory;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $taxData;
+
     /**
      * @var Calculator
      */
@@ -69,7 +74,7 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase
     protected function setUp()
     {
         $this->saleableItem = $this->getMockBuilder('Magento\Catalog\Model\Product')
-            ->setMethods(['getPriceInfo', 'getPriceType', '__wakeup'])
+            ->setMethods(['getPriceInfo', 'getPriceType', '__wakeup', 'getStore'])
             ->disableOriginalConstructor()
             ->getMock();
         $priceInfo = $this->getMock('Magento\Framework\Pricing\PriceInfo\Base', [], [], '', false);
@@ -81,6 +86,12 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase
         }));
         $this->saleableItem->expects($this->any())->method('getPriceInfo')->will($this->returnValue($priceInfo));
 
+        $store = $this->getMockBuilder('Magento\Store\Model\Store')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $store->expects($this->any())->method('roundPrice')->will($this->returnArgument(0));
+
+        $this->saleableItem->expects($this->any())->method('getStore')->will($this->returnValue($store));
 
         $this->baseCalculator = $this->getMock('Magento\Framework\Pricing\Adjustment\Calculator', [], [], '', false);
         $this->amountFactory = $this->getMock('Magento\Framework\Pricing\Amount\AmountFactory', [], [], '', false);
@@ -99,7 +110,17 @@ class CalculatorTest extends \PHPUnit_Framework_TestCase
             return $bundlePrice;
         });
         $this->selectionFactory->expects($this->any())->method('create')->will($factoryCallback);
-        $this->model = new Calculator($this->baseCalculator, $this->amountFactory, $this->selectionFactory);
+
+        $this->taxData = $this->getMockBuilder('Magento\Tax\Helper\Data')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $this->model = new Calculator(
+            $this->baseCalculator,
+            $this->amountFactory,
+            $this->selectionFactory,
+            $this->taxData
+        );
     }
 
     protected function tearDown()
diff --git a/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Price/BundleOptionPriceTest.php b/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Price/BundleOptionPriceTest.php
index b0c0d288b64b325253a9ab5a744547bf459a910e..629920fd72b0336466ff522d87080f113d981f1b 100644
--- a/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Price/BundleOptionPriceTest.php
+++ b/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Price/BundleOptionPriceTest.php
@@ -76,10 +76,20 @@ class BundleOptionPriceTest extends \PHPUnit_Framework_TestCase
             ->method('getPriceInfo')
             ->will($this->returnValue($this->priceInfoMock));
 
+        $store = $this->getMockBuilder('Magento\Store\Model\Store')
+            ->setMethods(['roundPrice', '__wakeup'])
+            ->disableOriginalConstructor()
+            ->getMock();
+        $store->expects($this->any())->method('roundPrice')->will($this->returnArgument(0));
+
         $this->saleableItemMock->expects($this->once())
             ->method('setQty')
             ->will($this->returnSelf());
 
+        $this->saleableItemMock->expects($this->any())
+            ->method('getStore')
+            ->will($this->returnValue($store));
+
         $this->selectionFactoryMock = $this->getMockBuilder('Magento\Bundle\Pricing\Price\BundleSelectionFactory')
             ->disableOriginalConstructor()
             ->getMock();
@@ -91,8 +101,13 @@ class BundleOptionPriceTest extends \PHPUnit_Framework_TestCase
         );
         $this->amountFactory->expects($this->any())->method('create')->will($factoryCallback);
         $this->baseCalculator = $this->getMock('Magento\Framework\Pricing\Adjustment\Calculator', [], [], '', false);
+
+        $taxData = $this->getMockBuilder('Magento\Tax\Helper\Data')
+            ->disableOriginalConstructor()
+            ->getMock();
+
         $this->bundleCalculatorMock = $this->getMockBuilder('Magento\Bundle\Pricing\Adjustment\Calculator')
-            ->setConstructorArgs([$this->baseCalculator, $this->amountFactory, $this->selectionFactoryMock])
+            ->setConstructorArgs([$this->baseCalculator, $this->amountFactory, $this->selectionFactoryMock, $taxData])
             ->setMethods(['getOptionsAmount'])
             ->getMock();
         $this->objectManagerHelper = new ObjectManagerHelper($this);
diff --git a/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Price/GroupPriceTest.php b/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Price/GroupPriceTest.php
index 0ec45ccb35d24b878394dae6c24104a300635acb..6039a1bf000b84fa291b4df2398b4da5754ea333 100644
--- a/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Price/GroupPriceTest.php
+++ b/dev/tests/unit/testsuite/Magento/Bundle/Pricing/Price/GroupPriceTest.php
@@ -26,88 +26,178 @@ namespace Magento\Bundle\Pricing\Price;
 class GroupPriceTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var GroupPrice
+     * @var \Magento\Bundle\Pricing\Price\GroupPrice
      */
-    protected $model;
+    protected $groupPrice;
 
     /**
-     * @var \Magento\Framework\Pricing\Object\SaleableInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $saleable;
+    protected $productMock;
 
     /**
-     * @var \Magento\Framework\Pricing\PriceInfo\Base |\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Catalog\Model\Resource\Product|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $priceInfo;
+    protected $productResourceMock;
 
-    public function setUp()
-    {
-        $this->saleable = $this->getMockBuilder('Magento\Catalog\Model\Product')
-            ->setMethods(['getPriceInfo', 'getCustomerGroupId', 'getData', '__wakeup'])
-            ->disableOriginalConstructor()
-            ->getMock();
-
-        $this->priceInfo = $this->getMock('Magento\Framework\Pricing\PriceInfo\Base', [], [], '', false);
-
-        $this->saleable->expects($this->once())
-            ->method('getPriceInfo')
-            ->will($this->returnValue($this->priceInfo));
+    /**
+     * @var \Magento\Framework\Pricing\Adjustment\Calculator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $calculatorMock;
 
-        $objectHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
-        $this->model = $objectHelper->getObject(
-            'Magento\Bundle\Pricing\Price\GroupPrice',
-            [
-                'saleableItem' => $this->saleable
-            ]
-        );
-    }
+    /**
+     * @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $customerSessionMock;
 
     /**
-     * @param $regularPrice
-     * @param $storedGroupPrice
-     * @param $value
-     * @param $percent
-     * @dataProvider getValueDataProvider
+     * @var \Magento\Customer\Model\Customer|\PHPUnit_Framework_MockObject_MockObject
      */
-    public function testGetValue($regularPrice, $storedGroupPrice, $value, $percent)
-    {
-        $customerGroupId = 234;
+    protected $customerMock;
 
-        $this->saleable->expects($this->atLeastOnce())
-            ->method('getCustomerGroupId')
-            ->will($this->returnValue($customerGroupId));
+    /**
+     * @var \Magento\Catalog\Model\Entity\Attribute|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $attributeMock;
 
-        $this->saleable->expects($this->once())
-            ->method('getData')
-            ->with('group_price')
-            ->will($this->returnValue($storedGroupPrice));
+    /**
+     * @var \Magento\Catalog\Model\Product\Attribute\Backend\Groupprice|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $backendMock;
 
-        if (!empty($storedGroupPrice)) {
-            $price = $this->getMock('Magento\Framework\Pricing\Price\PriceInterface');
-            $this->priceInfo->expects($this->once())
-                ->method('getPrice')
-                ->with(\Magento\Catalog\Pricing\Price\RegularPrice::PRICE_CODE)
-                ->will($this->returnValue($price));
-            $price->expects($this->once())
-                ->method('getValue')
-                ->will($this->returnValue($regularPrice));
-        }
-        $this->assertEquals($value, $this->model->getValue());
-        $this->assertEquals($percent, $this->model->getDiscountPercent());
-    }
+    /**
+     * @var \Magento\Framework\Pricing\PriceInfo\Base|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $priceInfoMock;
 
     /**
-     * @return array
+     * @var \Magento\Catalog\Pricing\Price\RegularPrice|\PHPUnit_Framework_MockObject_MockObject
      */
-    public function getValueDataProvider()
+    protected $regularPrice;
+    /**
+     * Set up test case
+     */
+    public function setUp()
     {
-        return array(
-            ['regularPrice' => 100, 'storedGroupPrice'
-                => [['cust_group' => 234, 'website_price' => 40]], 'value' => 60, 'percent' => 60],
-            ['regularPrice' => 75, 'storedGroupPrice'
-                => [['cust_group' => 234, 'website_price' => 40]], 'value' => 45, 'percent' => 60],
-            ['regularPrice' => 75, 'storedGroupPrice'
-                => [], 'value' => false, 'percent' => null],
+        $this->productMock = $this->getMock(
+            'Magento\Catalog\Model\Product',
+            ['__wakeup', 'getCustomerGroupId', 'getPriceInfo', 'getResource', 'getData'],
+            [],
+            '',
+            false
+        );
+        $this->productResourceMock = $this->getMock(
+            'Magento\Catalog\Model\Resource\Product',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->calculatorMock = $this->getMock(
+            'Magento\Framework\Pricing\Adjustment\Calculator',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->customerSessionMock = $this->getMock(
+            'Magento\Customer\Model\Session',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->customerMock = $this->getMock(
+            'Magento\Customer\Model\Customer',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->attributeMock = $this->getMock(
+            'Magento\Catalog\Model\Entity\Attribute',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->backendMock = $this->getMock(
+            'Magento\Catalog\Model\Product\Attribute\Backend\Groupprice',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->priceInfoMock = $this->getMock(
+            'Magento\Framework\Pricing\PriceInfo\Base',
+            ['getPrice'],
+            [],
+            '',
+            false
+        );
+        $this->regularPrice = $this->getMock(
+            'Magento\Catalog\Pricing\Price\RegularPrice',
+            [],
+            [],
+            '',
+            false
         );
+        $this->productMock->expects($this->once())
+            ->method('getPriceInfo')
+            ->will($this->returnValue($this->priceInfoMock));
+
+        $this->groupPrice = new \Magento\Bundle\Pricing\Price\GroupPrice(
+            $this->productMock,
+            1,
+            $this->calculatorMock,
+            $this->customerSessionMock
+        );
+    }
+
+    public function testGetValue()
+    {
+        $this->priceInfoMock->expects($this->once())
+            ->method('getPrice')
+            ->with($this->equalTo('regular_price'))
+            ->will($this->returnValue($this->regularPrice));
+        $this->regularPrice->expects($this->once())
+            ->method('getValue')
+            ->will($this->returnValue(100));
+        $this->productMock->expects($this->once())
+            ->method('getCustomerGroupId')
+            ->will($this->returnValue(null));
+        $this->customerSessionMock->expects($this->once())
+            ->method('getCustomerGroupId')
+            ->will($this->returnValue(3));
+        $this->productMock->expects($this->once())
+            ->method('getResource')
+            ->will($this->returnValue($this->productResourceMock));
+        $this->productResourceMock->expects($this->once())
+            ->method('getAttribute')
+            ->with($this->equalTo('group_price'))
+            ->will($this->returnValue($this->attributeMock));
+        $this->attributeMock->expects($this->once())
+            ->method('getBackend')
+            ->will($this->returnValue($this->backendMock));
+        $this->backendMock->expects($this->once())
+            ->method('afterLoad')
+            ->with($this->equalTo($this->productMock))
+            ->will($this->returnValue($this->backendMock));
+        $this->productMock->expects($this->once())
+            ->method('getData')
+            ->with(
+                $this->equalTo('group_price'),
+                $this->equalTo(null)
+            )
+            ->will($this->returnValue(
+                [
+                    [
+                        'cust_group' => 3,
+                        'website_price' => 80
+                    ]
+                ]
+
+            ));
+        $this->assertEquals(20, $this->groupPrice->getValue());
     }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/PriceModifierTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/PriceModifierTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..90db7848043e678feef0e4dc7e088710b6ac7a55
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/Product/PriceModifierTest.php
@@ -0,0 +1,161 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+namespace Magento\Catalog\Model\Product;
+
+class PriceModifierTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Catalog\Model\Product\PriceModifier
+     */
+    protected $priceModifier;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var array
+     */
+    protected $prices = array();
+
+    protected function setUp()
+    {
+        $this->productMock =
+            $this->getMock('Magento\Catalog\Model\Product',
+                array('getData', 'setData', '__wakeup'), array(), '', false);
+        $this->priceModifier = new \Magento\Catalog\Model\Product\PriceModifier();
+        $this->prices = array(
+            0 => array(
+                'all_groups' => 0,
+                'cust_group' => 1,
+                'price_qty' => 15,
+                'website_id' => 1
+            ),
+            1 => array(
+                'all_groups' => 1,
+                'cust_group' => 0,
+                'price_qty' => 10,
+                'website_id' => 1
+            )
+        );
+    }
+
+    public function testSuccessfullyRemoveGroupPriceSpecifiedForOneGroup()
+    {
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('group_price')
+            ->will($this->returnValue($this->prices));
+        $expectedPrices = array(1 => $this->prices[1]);
+        $this->productMock->expects($this->once())->method('setData')->with('group_price', $expectedPrices);
+        $this->priceModifier->removeGroupPrice($this->productMock, 1, 1);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedMessage This product doesn't have group price
+     */
+    public function testRemoveWhenGroupPricesNotExists()
+    {
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('group_price')
+            ->will($this->returnValue(array()));
+        $this->productMock->expects($this->never())->method('setData');
+        $this->priceModifier->removeGroupPrice($this->productMock, 1, 1);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedMessage For current  customerGroupId = '10' any group price exist'.
+     */
+    public function testRemoveGroupPriceForNonExistingCustomerGroup()
+    {
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('group_price')
+            ->will($this->returnValue($this->prices));
+        $this->productMock->expects($this->never())->method('setData');
+        $this->priceModifier->removeGroupPrice($this->productMock, 10, 1);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedMessage This product doesn't have tier price
+     */
+    public function testRemoveWhenTierPricesNotExists()
+    {
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('tier_price')
+            ->will($this->returnValue(array()));
+        $this->productMock->expects($this->never())->method('setData');
+        $this->priceModifier->removeTierPrice($this->productMock, 1, 3, 1);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @expectedMessage For current  customerGroupId = '10' with 'qty' = 15 any tier price exist'.
+     */
+    public function testRemoveTierPriceForNonExistingCustomerGroup()
+    {
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('tier_price')
+            ->will($this->returnValue($this->prices));
+        $this->productMock->expects($this->never())->method('setData');
+        $this->priceModifier->removeTierPrice($this->productMock, 10, 15, 1);
+    }
+
+    public function testSuccessfullyRemoveTierPriceSpecifiedForAllGroups()
+    {
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('tier_price')
+            ->will($this->returnValue($this->prices));
+        $expectedPrices = array($this->prices[0]);
+        $this->productMock->expects($this->once())->method('setData')->with('tier_price', $expectedPrices);
+        $this->priceModifier->removeTierPrice($this->productMock, 'all', 10, 1);
+    }
+
+    public function testSuccessfullyRemoveTierPriceSpecifiedForSpecificGroups()
+    {
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('tier_price')
+            ->will($this->returnValue($this->prices));
+        $expectedPrices = array(1 => $this->prices[1]);
+        $this->productMock->expects($this->once())->method('setData')->with('tier_price', $expectedPrices);
+        $this->priceModifier->removeTierPrice($this->productMock, 1, 15, 1);
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b73e577eff08f56a71d7faaa13e2887803c3b5d1
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Model/ProductRepositoryTest.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Model;
+
+class ProductRepositoryTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var \Magento\Catalog\Model\ProductRepository
+     */
+    protected $model;
+
+    protected function setUp()
+    {
+        $productFactoryMock = $this->getMock(
+            'Magento\Catalog\Model\ProductFactory', array('create'), array(), '', false
+        );
+        $this->productMock = $this->getMock('Magento\Catalog\Model\Product', array(), array(), '', false);
+        $productFactoryMock->expects($this->once())->method('create')->will($this->returnValue($this->productMock));
+        $this->model = new ProductRepository($productFactoryMock);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function testCreateThrowsExceptionIfNoSuchProduct()
+    {
+        $this->productMock->expects($this->once())->method('getIdBySku')->with('test_sku')
+            ->will($this->returnValue(null));
+        $this->model->get('test_sku');
+    }
+
+    public function testCreateCreatesProduct()
+    {
+        $this->productMock->expects($this->once())->method('getIdBySku')->with('test_sku')
+            ->will($this->returnValue('test_id'));
+        $this->productMock->expects($this->once())->method('load')->with('test_id');
+        $this->assertSame($this->productMock, $this->model->get('test_sku'));
+        $this->assertSame($this->productMock, $this->model->get('test_sku'));
+    }
+
+    public function testCreateCreatesProductInEditMode()
+    {
+        $this->productMock->expects($this->once())->method('getIdBySku')->with('test_sku')
+            ->will($this->returnValue('test_id'));
+        $this->productMock->expects($this->once())->method('setData')->with('_edit_mode', true);
+        $this->productMock->expects($this->once())->method('load')->with('test_id');
+        $this->assertSame($this->productMock, $this->model->get('test_sku', true));
+    }
+} 
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Pricing/Price/GroupPriceTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Pricing/Price/GroupPriceTest.php
index 36d889fbdeb1fdd4df8243275570538aec43fdce..395a35555c2b41a6201ada54c743a3ef750c5e32 100644
--- a/dev/tests/unit/testsuite/Magento/Catalog/Pricing/Price/GroupPriceTest.php
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Pricing/Price/GroupPriceTest.php
@@ -30,211 +30,206 @@ namespace Magento\Catalog\Pricing\Price;
 class GroupPriceTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\TestFramework\Helper\ObjectManager
+     * @var \Magento\Catalog\Pricing\Price\GroupPrice
      */
-    protected $objectManager;
-
-    public function setUp()
-    {
-        $this->objectManager = new \Magento\TestFramework\Helper\ObjectManager($this);
-    }
+    protected $groupPrice;
 
     /**
-     * @param array|null $groupPrice
-     * @param int $customerGroup
-     * @param float $expected
-     *
-     * @dataProvider groupPriceDataProvider
+     * @var \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject
      */
-    public function testGroupPrice($groupPrice, $customerGroup, $expected)
-    {
-        $saleableItemMock = $this->prepareSaleableItem($groupPrice);
-        $sessionMock = $this->prepareSession($saleableItemMock, $customerGroup);
-        $groupPriceModel = $this->objectManager->getObject(
-            'Magento\Catalog\Pricing\Price\GroupPrice',
-            [
-                'saleableItem'     => $saleableItemMock,
-                'customerSession' => $sessionMock
-            ]
-        );
-        $this->assertEquals($expected, $groupPriceModel->getValue());
-    }
+    protected $productMock;
 
     /**
-     * @param \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\Product $saleableItemMock
-     * @param int $customerGroup
-     * @return \PHPUnit_Framework_MockObject_MockObject|\Magento\Customer\Model\Session
+     * @var \Magento\Catalog\Model\Resource\Product|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected function prepareSession($saleableItemMock, $customerGroup)
-    {
-        $session = $this->getMock('Magento\Customer\Model\Session', ['getCustomerGroupId'], [], '', false);
-        $session->expects($this->any())
-            ->method('getCustomerGroupId')
-            ->will($this->returnValue($customerGroup));
+    protected $productResourceMock;
 
-        $saleableItemMock->expects($this->any())
-            ->method('getCustomerGroupId')
-            ->will($this->returnValue(false));
+    /**
+     * @var \Magento\Framework\Pricing\Adjustment\Calculator|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $calculatorMock;
 
-        return $session;
-    }
+    /**
+     * @var \Magento\Customer\Model\Session|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $customerSessionMock;
 
     /**
-     * @dataProvider groupPriceNonExistDataProvider
-     *
-     * @param array|null $groupPrice
-     * @param float $expected
+     * @var \Magento\Customer\Model\Customer|\PHPUnit_Framework_MockObject_MockObject
      */
-    public function testGroupPriceNonExist($groupPrice, $expected)
-    {
-        $groupPriceModel = $this->objectManager->getObject(
-            'Magento\Catalog\Pricing\Price\GroupPrice',
-            [
-                'saleableItem'     => $this->prepareSaleableItem($groupPrice),
-                'customerSession' => $this->getMock('Magento\Customer\Model\Session', [], [], '', false)
-            ]
-        );
+    protected $customerMock;
 
-        $this->assertEquals($expected, $groupPriceModel->getValue());
+    /**
+     * @var \Magento\Catalog\Model\Entity\Attribute|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $attributeMock;
 
-        //Verify that storedGroupPrice is cached
-        $this->assertEquals($expected, $groupPriceModel->getValue());
-    }
+    /**
+     * @var \Magento\Catalog\Model\Product\Attribute\Backend\Groupprice|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $backendMock;
 
     /**
-     * @param array|null $groupPrice
-     * @return \PHPUnit_Framework_MockObject_MockObject
+     * Set up test case
      */
-    protected function prepareSaleableItem($groupPrice)
+    public function setUp()
     {
-        $saleableItemMock = $this->getMock(
+        $this->productMock = $this->getMock(
             'Magento\Catalog\Model\Product',
-            ['getCustomerGroupId', 'getData', 'getPrice', 'getPriceInfo', 'getResource', '__wakeup'],
+            ['__wakeup', 'getCustomerGroupId', 'getPriceInfo', 'getResource', 'getData'],
+            [],
+            '',
+            false
+        );
+        $this->productResourceMock = $this->getMock(
+            'Magento\Catalog\Model\Resource\Product',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->calculatorMock = $this->getMock(
+            'Magento\Framework\Pricing\Adjustment\Calculator',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->customerSessionMock = $this->getMock(
+            'Magento\Customer\Model\Session',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->customerMock = $this->getMock(
+            'Magento\Customer\Model\Customer',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->attributeMock = $this->getMock(
+            'Magento\Catalog\Model\Entity\Attribute',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->backendMock = $this->getMock(
+            'Magento\Catalog\Model\Product\Attribute\Backend\Groupprice',
+            [],
             [],
             '',
             false
         );
 
-        $saleableItemMock->expects($this->at(1))
-            ->method('getData')
-            ->will($this->returnValue(null));
-
-        $saleableItemMock->expects($this->at(2))
-            ->method('getData')
-            ->will($this->returnValue($groupPrice));
-
-        $saleableItemMock->expects($this->any())
-            ->method('getResource')
-            ->will($this->returnValue($this->prepareSaleableItemResource()));
-
-        $priceInfo = $this->getMockBuilder(
-            'Magento\Framework\Pricing\PriceInfo\Base'
-        )->disableOriginalConstructor()->getMockForAbstractClass();
-
-        $priceInfo->expects($this->any())
-            ->method('getAdjustments')
-            ->will($this->returnValue([]));
-
-        $saleableItemMock->expects($this->any())
-            ->method('getPriceInfo')
-            ->will($this->returnValue($priceInfo));
-
-        return $saleableItemMock;
+        $this->groupPrice = new \Magento\Catalog\Pricing\Price\GroupPrice(
+            $this->productMock,
+            1,
+            $this->calculatorMock,
+            $this->customerSessionMock
+        );
     }
 
     /**
-     * @return \PHPUnit_Framework_MockObject_MockObject|\Magento\Catalog\Model\Resource\Product
+     * test get group price, customer group in session
      */
-    protected function prepareSaleableItemResource()
+    public function testGroupPriceCustomerGroupInSession()
     {
-        $resourceMock = $this->getMockBuilder(
-            'Magento\Catalog\Model\Resource\Product'
-        )->disableOriginalConstructor()->setMethods(['getAttribute', '__wakeup'])->getMock();
-
-        $attributeMock = $this->getMock(
-            'Magento\Framework\Object',
-            ['getBackend', 'afterLoad'],
-            [],
-            '',
-            false
-        );
-
-        $attributeMock->expects($this->any())
+        $this->productMock->expects($this->once())
+            ->method('getCustomerGroupId')
+            ->will($this->returnValue(null));
+        $this->customerSessionMock->expects($this->once())
+            ->method('getCustomerGroupId')
+            ->will($this->returnValue(3));
+        $this->productMock->expects($this->once())
+            ->method('getResource')
+            ->will($this->returnValue($this->productResourceMock));
+        $this->productResourceMock->expects($this->once())
+            ->method('getAttribute')
+            ->with($this->equalTo('group_price'))
+            ->will($this->returnValue($this->attributeMock));
+        $this->attributeMock->expects($this->once())
             ->method('getBackend')
-            ->will($this->returnValue($attributeMock));
-
-        $attributeMock->expects($this->any())
+            ->will($this->returnValue($this->backendMock));
+        $this->backendMock->expects($this->once())
             ->method('afterLoad')
-            ->will($this->returnValue($attributeMock));
-
-        $resourceMock->expects($this->any())
-            ->method('getAttribute')
-            ->will($this->returnValue($attributeMock));
+            ->with($this->equalTo($this->productMock))
+            ->will($this->returnValue($this->backendMock));
+        $this->productMock->expects($this->once())
+            ->method('getData')
+            ->with(
+                $this->equalTo('group_price'),
+                $this->equalTo(null)
+            )
+            ->will($this->returnValue(
+                [
+                    [
+                        'cust_group' => 3,
+                        'website_price' => 80
+                    ]
+                ]
 
-        return $resourceMock;
+            ));
+        $this->assertEquals(80, $this->groupPrice->getValue());
     }
 
     /**
-     * @return array
+     * test get group price, customer group in session
      */
-    public function groupPriceDataProvider()
+    public function testGroupPriceCustomerGroupInProduct()
     {
-        return [
-            [
-                'groupPrice' => [
-                    [
-                        'cust_group'    => 1,
-                        'website_price' => 90.9
-                    ],
-                    [
-                        'cust_group'    => 2,
-                        'website_price' => 80.8
-                    ],
+        $this->productMock->expects($this->exactly(2))
+            ->method('getCustomerGroupId')
+            ->will($this->returnValue(3));
+        $this->productMock->expects($this->once())
+            ->method('getResource')
+            ->will($this->returnValue($this->productResourceMock));
+        $this->productResourceMock->expects($this->once())
+            ->method('getAttribute')
+            ->with($this->equalTo('group_price'))
+            ->will($this->returnValue($this->attributeMock));
+        $this->attributeMock->expects($this->once())
+            ->method('getBackend')
+            ->will($this->returnValue($this->backendMock));
+        $this->backendMock->expects($this->once())
+            ->method('afterLoad')
+            ->with($this->equalTo($this->productMock))
+            ->will($this->returnValue($this->backendMock));
+        $this->productMock->expects($this->once())
+            ->method('getData')
+            ->with(
+                $this->equalTo('group_price'),
+                $this->equalTo(null)
+            )
+            ->will($this->returnValue(
+                [
                     [
-                        'cust_group'    => 1,
-                        'website_price' => 70.7
+                        'cust_group' => 3,
+                        'website_price' => 80
                     ]
-                ],
-                'customer_group'   => 1,
-                'expected'         => 90.9
-            ],
-            [
-                'groupPrice' => [
-                    [
-                        'cust_group'    => 2,
-                        'website_price' => 10.1
-                    ],
-                    [
-                        'cust_group'    => 1,
-                        'website_price' => 20.2
-                    ],
-                ],
-                'customer_group'   => 1,
-                'expected'         => 20.2
-            ],
-            [
-                'groupPrice' => [
-                    [
-                        'cust_group'    => 1,
-                        'website_price' => 90.9
-                    ],
-                ],
-                'customer_group'   => 2,
-                'expected'         => false
-            ]
-        ];
+                ]
+
+            ));
+        $this->assertEquals(80, $this->groupPrice->getValue());
     }
 
     /**
-     * @return array
+     * test get group price, attribut is noy srt
      */
-    public function groupPriceNonExistDataProvider()
+    public function testGroupPriceAttributeIsNotSet()
     {
-        return [
-            [
-                'groupPrice'       => null,
-                'expected'         => false
-            ]
-        ];
+        $this->productMock->expects($this->exactly(2))
+            ->method('getCustomerGroupId')
+            ->will($this->returnValue(3));
+        $this->productMock->expects($this->once())
+            ->method('getResource')
+            ->will($this->returnValue($this->productResourceMock));
+        $this->productResourceMock->expects($this->once())
+            ->method('getAttribute')
+            ->with($this->equalTo('group_price'))
+            ->will($this->returnValue(null));
+        $this->assertFalse($this->groupPrice->getValue());
     }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContentValidatorTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContentValidatorTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..4dc8ca67d7c8671a815d275db0803fbcf85d6263
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/GalleryEntryContentValidatorTest.php
@@ -0,0 +1,167 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media\Data;
+
+class GalleryEntryContentValidatorTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var GalleryEntryContentValidator
+     */
+    private $validator;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $entryContentMock;
+
+    /**
+     * @var string
+     */
+    private $testImagePath;
+
+    protected function setUp()
+    {
+        $this->validator = new GalleryEntryContentValidator();
+        $this->entryContentMock = $this->getMock(
+            '\Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntryContent',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->testImagePath = __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'magento_image.jpg';
+    }
+
+    public function testIsValid()
+    {
+        $this->entryContentMock->expects($this->any())->method('getData')->will($this->returnValue(
+            base64_encode(file_get_contents($this->testImagePath))
+        ));
+        $this->entryContentMock->expects($this->any())->method('getName')->will($this->returnValue(
+            'valid_name'
+        ));
+        $this->entryContentMock->expects($this->any())->method('getMimeType')->will($this->returnValue(
+            'image/jpeg'
+        ));
+        $this->assertTrue($this->validator->isValid($this->entryContentMock));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage The image content must be valid base64 encoded data.
+     */
+    public function testIsValidThrowsExceptionIfProvidedContentIsNotBase64Encoded()
+    {
+        $this->entryContentMock->expects($this->any())->method('getData')->will($this->returnValue(
+            'not_a_base64_encoded_content'
+        ));
+        $this->entryContentMock->expects($this->any())->method('getName')->will($this->returnValue(
+            'valid_name'
+        ));
+        $this->entryContentMock->expects($this->any())->method('getMimeType')->will($this->returnValue(
+            'image/jpeg'
+        ));
+        $this->assertTrue($this->validator->isValid($this->entryContentMock));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage The image content must be valid base64 encoded data.
+     */
+    public function testIsValidThrowsExceptionIfProvidedContentIsNotAnImage()
+    {
+        $this->entryContentMock->expects($this->any())->method('getData')->will($this->returnValue(
+            base64_encode('not_an_image_data')
+        ));
+        $this->entryContentMock->expects($this->any())->method('getName')->will($this->returnValue(
+            'valid_name'
+        ));
+        $this->entryContentMock->expects($this->any())->method('getMimeType')->will($this->returnValue(
+            'image/jpeg'
+        ));
+        $this->assertTrue($this->validator->isValid($this->entryContentMock));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage The image MIME type is not valid or not supported.
+     */
+    public function testIsValidThrowsExceptionIfProvidedImageHasWrongMimeType()
+    {
+        $this->entryContentMock->expects($this->any())->method('getData')->will($this->returnValue(
+            base64_encode(file_get_contents($this->testImagePath))
+        ));
+        $this->entryContentMock->expects($this->any())->method('getName')->will($this->returnValue(
+            'valid_name'
+        ));
+        $this->entryContentMock->expects($this->any())->method('getMimeType')->will($this->returnValue(
+            'wrong_mime_type'
+        ));
+        $this->assertTrue($this->validator->isValid($this->entryContentMock));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Provided image name contains forbidden characters.
+     * @dataProvider getInvalidImageNames
+     * @param string $imageName
+     */
+    public function testIsValidThrowsExceptionIfProvidedImageNameContainsForbiddenCharacters($imageName)
+    {
+        $this->entryContentMock->expects($this->any())->method('getData')->will($this->returnValue(
+            base64_encode(file_get_contents($this->testImagePath))
+        ));
+        $this->entryContentMock->expects($this->any())->method('getName')->will($this->returnValue(
+            $imageName
+        ));
+        $this->entryContentMock->expects($this->any())->method('getMimeType')->will($this->returnValue(
+            'image/jpeg'
+        ));
+        $this->assertTrue($this->validator->isValid($this->entryContentMock));
+    }
+
+    /**
+     * @return array
+     */
+    public function getInvalidImageNames()
+    {
+        return array(
+            array('test/test'),
+            array('test\test'),
+            array('test:test'),
+            array('test"test'),
+            array('test*test'),
+            array('test;test'),
+            array('test(test'),
+            array('test)test'),
+            array('test<test'),
+            array('test>test'),
+            array('test?test'),
+            array('test{test'),
+            array('test}test'),
+            array('test|test'),
+            array('test|test'),
+        );
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/_files/magento_image.jpg b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/_files/magento_image.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..bdda86b647e7f0cae331f3bdff83b07cf3b3dce6
Binary files /dev/null and b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/Data/_files/magento_image.jpg differ
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/GalleryEntryResolverTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/GalleryEntryResolverTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..99e49e46caf46d3427b57b4f310dbb62241fa07e
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/GalleryEntryResolverTest.php
@@ -0,0 +1,77 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media;
+
+use \Magento\Catalog\Model\Product;
+
+class GalleryEntryResolverTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var GalleryEntryResolver
+     */
+    private $entryResolver;
+
+    protected function setUp()
+    {
+        $this->entryResolver = new GalleryEntryResolver();
+    }
+
+    public function testGetEntryFilePathById()
+    {
+        $productMock = $this->getMock('Magento\Catalog\Model\Product', array(), array(), '', false);
+        $productMock->expects($this->any())->method('getData')->with('media_gallery')->will($this->returnValue(array(
+            'images' => array(
+                array(
+                    'file' => '/i/m/image.jpg',
+                    'value_id' => 1,
+                ),
+                array(
+                    'file' => '/i/m/image2.jpg',
+                    'value_id' => 2,
+                ),
+            ),
+        )));
+        $this->assertEquals('/i/m/image2.jpg', $this->entryResolver->getEntryFilePathById($productMock, 2));
+        $this->assertNull($this->entryResolver->getEntryFilePathById($productMock, 9999));
+    }
+
+    public function testGetEntryIdByFilePath()
+    {
+        $productMock = $this->getMock('Magento\Catalog\Model\Product', array(), array(), '', false);
+        $productMock->expects($this->any())->method('getData')->with('media_gallery')->will($this->returnValue(array(
+            'images' => array(
+                array(
+                    'file' => '/i/m/image2.jpg',
+                    'value_id' => 2,
+                ),
+                array(
+                    'file' => '/i/m/image.jpg',
+                    'value_id' => 1,
+                ),
+            ),
+        )));
+        $this->assertEquals(1, $this->entryResolver->getEntryIdByFilePath($productMock, '/i/m/image.jpg'));
+        $this->assertNull($this->entryResolver->getEntryIdByFilePath($productMock, '/i/m/non_existent_image.jpg'));
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/ReadServiceTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/ReadServiceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..48506b08ed76eb069349deeac681b4f2ae04c511
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/ReadServiceTest.php
@@ -0,0 +1,473 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media;
+
+class ReadServiceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Catalog\Service\V1\Product\Attribute\Media\ReadService
+     */
+    protected $service;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $collectionFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $setFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $eavConfigMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $setMock;
+
+    /**
+     * @var int attribute set id to use in tests
+     */
+    protected $attributeSetId = 100123;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $attributeCollectionMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productRepoMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $attributeFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $mediaGalleryMock;
+
+    /**
+     * @var \Magento\TestFramework\Helper\ObjectManager
+     */
+    protected $objectHelper;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $storeMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $storeManagerMock;
+
+    /**
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    protected function setUp()
+    {
+        $this->objectHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
+
+        $this->collectionFactoryMock = $this->getMock(
+            'Magento\Catalog\Model\Resource\Product\Attribute\CollectionFactory',
+            array('create', '__wakeup'),
+            array(),
+            '',
+            false
+        );
+
+        $this->attributeCollectionMock = $this->getMock(
+            'Magento\Catalog\Model\Resource\Product\Attribute\Collection',
+            array(),
+            array(),
+            '',
+            false
+        );
+
+        $mediaImageBuilder = $this->objectHelper->getObject(
+            '\Magento\Catalog\Service\V1\Product\Attribute\Media\Data\MediaImageBuilder'
+        );
+
+        $this->storeMock = $this->getMock('\Magento\Store\Model\Store', array(), array(), '', false);
+
+        $this->storeManagerMock = $this->getMock('\Magento\Store\Model\StoreManagerInterface');
+        $this->storeManagerMock->expects($this->any())->method('getStore')->will($this->returnValue($this->storeMock));
+
+        $this->setFactoryMock = $this->getMock(
+            'Magento\Eav\Model\Entity\Attribute\SetFactory',
+            array('create', '__wakeup'),
+            array(),
+            '',
+            false
+        );
+
+        $this->eavConfigMock = $this->getMock(
+            '\Magento\Eav\Model\Config', array('getEntityType', 'getId'), array(), '', false
+        );
+
+        $this->productRepoMock = $this->getMock(
+            'Magento\Catalog\Model\ProductRepository',
+            array(),
+            array(),
+            '',
+            false
+        );
+
+        $this->attributeFactoryMock = $this->getMock(
+            '\Magento\Catalog\Model\Resource\Eav\AttributeFactory',
+            array('create', '__wakeup'),
+            array(),
+            '',
+            false
+        );
+
+        $this->mediaGalleryMock = $this->getMock(
+            '\Magento\Catalog\Model\Resource\Product\Attribute\Backend\Media',
+            array(),
+            array(),
+            '',
+            false
+        );
+
+        $builder = $this->objectHelper->getObject(
+            '\Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntryBuilder'
+        );
+
+        $this->service = $this->objectHelper->getObject(
+            '\Magento\Catalog\Service\V1\Product\Attribute\Media\ReadService',
+            array(
+                'collectionFactory' => $this->collectionFactoryMock,
+                'setFactory' => $this->setFactoryMock,
+                'eavConfig' => $this->eavConfigMock,
+                'mediaImageBuilder' => $mediaImageBuilder,
+                'storeManager' => $this->storeManagerMock,
+                'productRepository' => $this->productRepoMock,
+                'attributeFactory' => $this->attributeFactoryMock,
+                'mediaGallery' => $this->mediaGalleryMock,
+                'galleryEntryBuilder' => $builder,
+            )
+        );
+
+        $this->setMock = $this->getMock(
+            '\Magento\Eav\Model\Entity\Attribute\Set',
+            array('getEntityTypeId', 'load', 'getId', '__wakeup'),
+            array(),
+            '',
+            false
+        );
+
+        $this->productMock = $this->getMock(
+            'Magento\Catalog\Model\Product',
+            array('getMediaGallery', 'getData', 'getMediaAttributes', 'getStoreId', '__wakeup'),
+            array(),
+            '',
+            false
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function testTypesForAbsentId()
+    {
+        $this->setFactoryMock->expects($this->once())->method('create')->will($this->returnValue($this->setMock));
+
+        $this->setMock->expects($this->once())
+            ->method('load')
+            ->with($this->attributeSetId)
+            ->will($this->returnSelf());
+
+        $this->setMock->expects($this->once())->method('getId')->will($this->returnValue(null));
+        $this->service->types($this->attributeSetId);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     */
+    public function testTypesForWrongEntityType()
+    {
+        $this->setFactoryMock->expects($this->once())->method('create')->will($this->returnValue($this->setMock));
+
+        $this->setMock->expects($this->once())
+            ->method('load')
+            ->with($this->attributeSetId)
+            ->will($this->returnSelf());
+
+        $this->setMock->expects($this->once())->method('getId')->will($this->returnValue(1));
+
+        $this->eavConfigMock->expects($this->once())
+            ->method('getEntityType')
+            ->with(\Magento\Catalog\Model\Product::ENTITY)
+            ->will($this->returnSelf());
+        $this->eavConfigMock->expects($this->once())->method('getId')->will($this->returnValue(1));
+        $this->setMock->expects($this->once())->method('getEntityTypeId')->will($this->returnValue(4));
+
+        $this->service->types($this->attributeSetId);
+    }
+
+    public function testTypesPositive()
+    {
+        $this->setFactoryMock->expects($this->once())->method('create')->will($this->returnValue($this->setMock));
+
+        $this->setMock->expects($this->once())
+            ->method('load')
+            ->with($this->attributeSetId)
+            ->will($this->returnSelf());
+
+        $this->setMock->expects($this->once())->method('getId')->will($this->returnValue(1));
+
+        $this->eavConfigMock->expects($this->once())
+            ->method('getEntityType')
+            ->with(\Magento\Catalog\Model\Product::ENTITY)
+            ->will($this->returnSelf());
+        $this->eavConfigMock->expects($this->once())->method('getId')->will($this->returnValue(4));
+        $this->setMock->expects($this->once())->method('getEntityTypeId')->will($this->returnValue(4));
+
+        $this->collectionFactoryMock->expects($this->once())
+            ->method('create')
+            ->will($this->returnValue($this->attributeCollectionMock));
+        $this->attributeCollectionMock->expects($this->once())->method('setAttributeSetFilter')
+            ->with($this->attributeSetId);
+        $this->attributeCollectionMock->expects($this->once())
+            ->method('setFrontendInputTypeFilter')
+            ->with('media_image');
+        $attributeMock = $this->getMock(
+            '\Magento\Catalog\Model\Resource\Eav\Attribute',
+            array('getStoreLabel', 'getData', 'getIsGlobal', 'isScopeWebsite', 'isScopeStore', '__wakeup'),
+            array(),
+            '',
+            false
+        );
+        $attributeMock->expects($this->once())->method('getStoreLabel')->will($this->returnValue('coolLabel'));
+        $attributeMock->expects($this->any())->method('getData')->will($this->returnArgument(0));
+        $attributeMock->expects($this->once())->method('getIsGlobal')->will($this->returnValue(false));
+        $attributeMock->expects($this->once())->method('isScopeWebsite')->will($this->returnValue(false));
+        $attributeMock->expects($this->once())->method('isScopeStore')->will($this->returnValue(true));
+
+        $items = array($attributeMock);
+        $this->attributeCollectionMock->expects($this->once())
+            ->method('getItems')
+            ->will($this->returnValue($items));
+
+        $attributes = $this->service->types($this->attributeSetId);
+        $this->assertEquals(1, count($attributes));
+        /** @var \Magento\Catalog\Service\V1\Product\Attribute\Media\Data\MediaImage $resultAttribute */
+        $resultAttribute = reset($attributes);
+        $this->assertEquals('coolLabel', $resultAttribute->getFrontendLabel());
+        $this->assertEquals('attribute_code', $resultAttribute->getCode());
+        $this->assertEquals(true, $resultAttribute->getIsUserDefined());
+        $this->assertEquals('Store View', $resultAttribute->getScope());
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function testGetListForAbsentSku()
+    {
+        $sku = 'absentSku';
+
+        $this->productRepoMock->expects($this->once())
+            ->method('get')
+            ->with($sku)
+            ->will($this->throwException(new \Magento\Framework\Exception\NoSuchEntityException()));
+
+        $this->service->getList($sku);
+    }
+
+    /**
+     * @dataProvider getListProvider
+     */
+    public function testGetList($gallery, $result, $productDataMap)
+    {
+        $sku = 'anyValidSku';
+        $productEntityCode = 4;
+        $attributes = [
+            'image' => 1,
+            'small_image'=> 2,
+            'thumbnail' => 3
+        ];
+
+        $this->productRepoMock->expects($this->once())
+            ->method('get')
+            ->with($sku)
+            ->will($this->returnValue($this->productMock));
+
+        $this->productMock->expects($this->any())
+            ->method('getData')->will($this->returnValueMap($productDataMap));
+
+        $attributeMock = $this->getMock(
+            '\Magento\Catalog\Model\Resource\Eav\Attribute',
+            array(),
+            array(),
+            '',
+            false
+        );
+
+        $this->attributeFactoryMock->expects($this->once())->method('create')->will($this->returnValue($attributeMock));
+        $this->eavConfigMock->expects($this->once())
+            ->method('getEntityType')
+            ->with(\Magento\Catalog\Model\Product::ENTITY)
+            ->will($this->returnValue($productEntityCode));
+        $attributeMock->expects($this->once())->method('loadByCode')->with($productEntityCode, 'media_gallery');
+        $this->mediaGalleryMock->expects($this->once())->method('loadGallery')->will($this->returnValue($gallery));
+        $this->productMock->expects($this->once())->method('getMediaAttributes')->will($this->returnValue($attributes));
+
+        $serviceOutput = $this->service->getList($sku);
+        $this->assertEquals($result, $serviceOutput);
+    }
+
+    public function getListProvider()
+    {
+        $objectHelper = new \Magento\TestFramework\Helper\ObjectManager($this);
+
+        $dataObject = $objectHelper->getObject(
+            '\Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntryBuilder');
+        $dataObject->populateWithArray(
+            array(
+                'id' => 26,
+                'label' => 'Image Alt Text',
+                'types' => array('image', 'small_image'),
+                'disabled' => 0,
+                'position' => 1,
+                'file' => '/m/a/magento_image.jpg',
+                'store_id' => null,
+            )
+        );
+
+        $productDataMap = [
+            ['image', null, '/m/a/magento_image.jpg'],
+            ['small_image', null, '/m/a/magento_image.jpg'],
+            ['thumbnail', null, null],
+        ];
+
+        return array(
+            'empty gallery' => [array(), array(), array()],
+            'one image' => [
+                array(
+                    0 =>
+                        array (
+                            'value_id' => '26',
+                            'file' => '/m/a/magento_image.jpg',
+                            'label_default' => 'Image Alt Text',
+                            'position_default' => '1',
+                            'disabled_default' => '0',
+                        ),
+                ),
+                array($dataObject->create()),
+                $productDataMap,
+            ],
+        );
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function testInfoAbsentSku()
+    {
+        $productSku = 'Sku absent';
+        $imageId = 123321;
+
+        $this->productRepoMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->will($this->throwException(new \Magento\Framework\Exception\NoSuchEntityException()));
+
+        $this->service->info($productSku, $imageId);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function testInfoEmptyGallery()
+    {
+        $productSku = 'Sku absent';
+        $imageId = 123321;
+
+        $this->productRepoMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->will($this->returnValue($this->productMock));
+
+
+        $this->productMock->expects($this->once())
+            ->method('getMediaAttributes')
+            ->will($this->returnValue(array()));
+        
+        $this->productMock->expects($this->once())
+            ->method('getMediaGallery')
+            ->with('images')
+            ->will($this->returnValue([]));
+        $this->service->info($productSku, $imageId);
+    }
+
+    public function testInfo()
+    {
+        $productSku = 'Sku absent';
+        $imageId = 123321;
+        $images = [
+            [
+                'value_id' => $imageId,
+                'file' => '/m/a/magento_image.jpg',
+                'label' => 'Image Alt Text',
+                'position' => '1',
+                'disabled' => '0',
+            ]
+        ];
+
+        $this->productRepoMock->expects($this->once())
+            ->method('get')
+            ->with($productSku)
+            ->will($this->returnValue($this->productMock));
+
+        $this->productMock->expects($this->once())
+            ->method('getMediaGallery')
+            ->with('images')
+            ->will($this->returnValue($images));
+
+        $this->productMock->expects($this->once())
+            ->method('getMediaAttributes')
+            ->will($this->returnValue(array()));
+
+        $result = $this->service->info($productSku, $imageId);
+
+        $resultImage = reset($images);
+        $this->assertEquals($resultImage['file'], $result->getFile());
+        $this->assertEquals($resultImage['label'], $result->getLabel());
+        $this->assertEquals($resultImage['position'], $result->getPosition());
+        $this->assertEquals($resultImage['disabled'], $result->isDisabled());
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/WriteServiceTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/WriteServiceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9db763c478002fd557b661158523436e74862c71
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/Attribute/Media/WriteServiceTest.php
@@ -0,0 +1,324 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product\Attribute\Media;
+
+use \Magento\Framework\App\Filesystem;
+
+class WriteServiceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $contentValidatorMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $filesystemMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $mediaConfigMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $productLoaderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $storeFactoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $entryResolverMock;
+
+    /**
+     * @var WriteService
+     */
+    private $service;
+
+    protected function setUp()
+    {
+        $this->contentValidatorMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntryContentValidator',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->filesystemMock = $this->getMock(
+            'Magento\Framework\App\Filesystem',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->mediaConfigMock = $this->getMock(
+            'Magento\Catalog\Model\Product\Media\Config',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->productLoaderMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Product\ProductLoader',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->storeFactoryMock = $this->getMock(
+            'Magento\Store\Model\StoreFactory',
+            array('create'),
+            array(),
+            '',
+            false
+        );
+        $this->entryResolverMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Product\Attribute\Media\GalleryEntryResolver',
+            array(),
+            array(),
+            '',
+            false
+        );
+
+        $this->service = new WriteService(
+            $this->contentValidatorMock,
+            $this->filesystemMock,
+            $this->productLoaderMock,
+            $this->mediaConfigMock,
+            $this->storeFactoryMock,
+            $this->entryResolverMock
+        );
+    }
+
+    public function testCreate()
+    {
+        $productSku = 'simple';
+        $storeId = 1;
+        $mediaTmpPath = 'tmp';
+        $entry = array(
+            'disabled' => true,
+            'types' => array('image'),
+            'label' => 'Image',
+            'position' => 100,
+        );
+        $entryContent = array(
+            'name' => 'image',
+            'mime_type' => 'image/jpg',
+            'data' => base64_encode('image_content'),
+        );
+
+        $storeMock = $this->getMock('Magento\Store\Model\Store', array(), array(), '', false);
+        $storeMock->expects($this->any())->method('getId')->will($this->returnValue($storeId));
+        $storeMock->expects($this->any())->method('load')->will($this->returnSelf());
+        $this->storeFactoryMock->expects($this->once())->method('create')->will($this->returnValue($storeMock));
+        $entryMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntry',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $entryContentMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntryContent',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->contentValidatorMock->expects($this->once())->method('isValid')->with($entryContentMock)
+            ->will($this->returnValue(true));
+        $productMock = $this->getMock('Magento\Catalog\Model\Product', array(), array(), '', false);
+        $this->productLoaderMock->expects($this->once())->method('load')->with($productSku)
+            ->will($this->returnValue($productMock));
+        $this->mediaConfigMock->expects($this->any())->method('getBaseTmpMediaPath')
+            ->will($this->returnValue($mediaTmpPath));
+        $mediaDirectoryMock = $this->getMock('Magento\Framework\Filesystem\Directory\WriteInterface');
+        $this->filesystemMock->expects($this->any())->method('getDirectoryWrite')->with(Filesystem::MEDIA_DIR)
+            ->will($this->returnValue($mediaDirectoryMock));
+
+        $mediaDirectoryMock->expects($this->once())->method('create')->with($mediaTmpPath);
+        $mediaDirectoryMock->expects($this->once())->method('delete')->with('tmp' . DIRECTORY_SEPARATOR . 'image.jpg');
+        $mediaDirectoryMock->expects($this->any())->method('getAbsolutePath')
+            ->with('tmp' . DIRECTORY_SEPARATOR . 'image.jpg')
+            ->will($this->returnValue('/i/m/image.jpg'));
+
+        $mediaDirectoryMock->expects($this->once())->method('writeFile')
+            ->with('tmp' . DIRECTORY_SEPARATOR . 'image.jpg', 'image_content');
+
+        $entryContentMock->expects($this->any())->method('getData')->will($this->returnValue($entryContent['data']));
+        $entryContentMock->expects($this->any())->method('getName')->will($this->returnValue($entryContent['name']));
+        $entryContentMock->expects($this->any())->method('getMimeType')->will($this->returnValue(
+            $entryContent['mime_type']
+        ));
+
+        $entryMock->expects($this->any())->method('isDisabled')->will($this->returnValue($entry['disabled']));
+        $entryMock->expects($this->any())->method('getTypes')->will($this->returnValue($entry['types']));
+        $entryMock->expects($this->any())->method('getLabel')->will($this->returnValue($entry['label']));
+        $entryMock->expects($this->any())->method('getPosition')->will($this->returnValue($entry['position']));
+
+        $galleryMock = $this->getGalleryAttributeBackendMock($productMock);
+        $testImageUri = '/i/m/image2.jpg';
+        $galleryMock->expects($this->once())->method('addImage')->with(
+            $productMock,
+            '/i/m/image.jpg',
+            $entry['types'],
+            true,
+            $entry['disabled']
+        )->will($this->returnValue($testImageUri));
+
+        $galleryMock->expects($this->once())->method('updateImage')->with(
+            $productMock,
+            $testImageUri,
+            array(
+                'label' => $entry['label'],
+                'position' => $entry['position'],
+                'disabled' => $entry['disabled'],
+            )
+        );
+        $productMock->expects($this->once())->method('save');
+        $galleryMock->expects($this->once())->method('getRenamedImage')->with($testImageUri)->will(
+            $this->returnValue($testImageUri)
+        );
+        $entryId = 1;
+        $this->entryResolverMock->expects($this->once())->method('getEntryIdByFilePath')
+            ->with($productMock, $testImageUri)
+            ->will($this->returnValue($entryId));
+        $this->assertEquals($entryId, $this->service->create($productSku, $entryMock, $entryContentMock, $storeId));
+    }
+
+    public function testUpdate()
+    {
+        $productSku = 'simple';
+        $storeId = 1;
+        $entry = array(
+            'id' => 1,
+            'disabled' => true,
+            'types' => array('image'),
+            'label' => 'Updated Image',
+            'position' => 100,
+        );
+        $storeMock = $this->getMock('Magento\Store\Model\Store', array(), array(), '', false);
+        $storeMock->expects($this->any())->method('getId')->will($this->returnValue($storeId));
+        $storeMock->expects($this->any())->method('load')->will($this->returnSelf());
+        $this->storeFactoryMock->expects($this->once())->method('create')->will($this->returnValue($storeMock));
+        $entryMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Product\Attribute\Media\Data\GalleryEntry',
+            array(),
+            array(),
+            '',
+            false
+        );
+
+        $productMock = $this->getMock('Magento\Catalog\Model\Product', array(), array(), '', false);
+        $this->productLoaderMock->expects($this->once())->method('load')->with($productSku)
+            ->will($this->returnValue($productMock));
+
+        $entryMock->expects($this->any())->method('getId')->will($this->returnValue($entry['id']));
+        $entryMock->expects($this->any())->method('isDisabled')->will($this->returnValue($entry['disabled']));
+        $entryMock->expects($this->any())->method('getTypes')->will($this->returnValue($entry['types']));
+        $entryMock->expects($this->any())->method('getLabel')->will($this->returnValue($entry['label']));
+        $entryMock->expects($this->any())->method('getPosition')->will($this->returnValue($entry['position']));
+        $galleryMock = $this->getGalleryAttributeBackendMock($productMock);
+
+        $testImageUri = '/i/m/image2.jpg';
+        $mediaAttributes = array('image' => 'image', 'small_image' => 'small_image', 'thumbnail' => 'thumbnail');
+        $productMock->expects($this->any())->method('getMediaAttributes')->will($this->returnValue($mediaAttributes));
+        $this->entryResolverMock->expects($this->once())->method('getEntryFilePathById')
+            ->with($productMock, $entry['id'])
+            ->will($this->returnValue($testImageUri));
+        $galleryMock->expects($this->once())->method('updateImage')->with(
+            $productMock,
+            $testImageUri,
+            array(
+                'label' => $entry['label'],
+                'position' => $entry['position'],
+                'disabled' => $entry['disabled'],
+            )
+        );
+        $galleryMock->expects($this->once())->method('clearMediaAttribute')
+            ->with($productMock, array('image', 'small_image', 'thumbnail'));
+        $galleryMock->expects($this->once())->method('setMediaAttribute')
+            ->with($productMock, $entry['types'], $testImageUri);
+        $productMock->expects($this->once())->method('save');
+
+        $this->assertTrue($this->service->update($productSku, $entryMock, $storeId));
+    }
+
+    public function testDelete()
+    {
+        $productSku = 'simple';
+        $storeId = 1;
+        $entryId = 1;
+        $productMock = $this->getMock('Magento\Catalog\Model\Product', array(), array(), '', false);
+        $this->productLoaderMock->expects($this->once())->method('load')->with($productSku)
+            ->will($this->returnValue($productMock));
+
+        $galleryMock = $this->getGalleryAttributeBackendMock($productMock);
+
+        $testImageUri = '/i/m/image2.jpg';
+
+        $this->entryResolverMock->expects($this->once())->method('getEntryFilePathById')
+            ->with($productMock, $entryId)
+            ->will($this->returnValue($testImageUri));
+        $galleryMock->expects($this->once())->method('removeImage')->with($productMock, $testImageUri);
+        $productMock->expects($this->once())->method('save');
+
+        $this->assertTrue($this->service->delete($productSku, $entryId, $storeId));
+    }
+
+    /**
+     * Create mock for media gallery attribute backend model
+     *
+     * @param \PHPUnit_Framework_MockObject_MockObject $productMock
+     * @return \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected function getGalleryAttributeBackendMock($productMock)
+    {
+        $typeInstanceMock = $this->getMock(
+            'Magento\Catalog\Model\Product\Type\Simple',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $attributeModelMock = $this->getMockForAbstractClass('Magento\Eav\Model\Entity\Attribute\AbstractAttribute',
+            array(), '', false, false, true, array('getBackend', '__wakeup'));
+        $productMock->expects($this->any())->method('getTypeInstance')->will($this->returnValue($typeInstanceMock));
+        $typeInstanceMock->expects($this->any())->method('getSetAttributes')->with($productMock)->will(
+            $this->returnValue(array(
+                'media_gallery' => $attributeModelMock,
+            ))
+        );
+        $backendModelMock = $this->getMock('Magento\Catalog\Model\Product\Attribute\Backend\Media', array(), array(),
+            '', false);
+        $attributeModelMock->expects($this->any())->method('getBackend')->will($this->returnValue($backendModelMock));
+        return $backendModelMock;
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadServiceTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadServiceTest.php
index d961bb8f274465024d73bd975b6f0271430e2230..a4128e4d975dd7cf7f371bc8b79fd8a486ed47a2 100644
--- a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadServiceTest.php
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/AttributeGroup/ReadServiceTest.php
@@ -36,6 +36,11 @@ class ReadServiceTest extends \PHPUnit_Framework_TestCase
      */
     protected $groupListFactory;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $setFactoryMock;
+
     protected function setUp()
     {
         $helper = new \Magento\TestFramework\Helper\ObjectManager($this);
@@ -46,8 +51,15 @@ class ReadServiceTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
+        $this->setFactoryMock = $this->getMock(
+            '\Magento\Eav\Model\Entity\Attribute\SetFactory',
+            array('create'),
+            array(),
+            '',
+            false
+        );
         $groupBuilder = $helper->getObject('\Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder');
-        $this->service = new ReadService($this->groupListFactory, $groupBuilder);
+        $this->service = new ReadService($this->groupListFactory, $this->setFactoryMock, $groupBuilder);
     }
 
     public function testListGroups()
@@ -60,6 +72,17 @@ class ReadServiceTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->groupListFactory->expects($this->once())->method('create')->will($this->returnValue($groupList));
+        $attributeSetMock = $this->getMock(
+            '\Magento\Eav\Model\Entity\Attribute\Set',
+            array(),
+            array(),
+            '',
+            false
+        );
+        $this->setFactoryMock->expects($this->once())->method('create')->will($this->returnValue($attributeSetMock));
+        $attributeSetMock->expects($this->once())->method('load')->with(1)->will($this->returnSelf());
+        $attributeSetMock->expects($this->once())->method('getId')->will($this->returnValue(1));
+
         $item1 = new \Magento\Framework\Object(array('id' => 1, 'attribute_group_name' => 'First'));
         $item2 = new \Magento\Framework\Object(array('id' => 2, 'attribute_group_name' => 'Second'));
         $groupList->expects($this->once())->method('getItems')->will($this->returnValue(array($item1, $item2)));
@@ -70,4 +93,17 @@ class ReadServiceTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals('First', $result[0]->getName());
         $this->assertEquals('Second', $result[1]->getName());
     }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function testListGroupsWrongAttributeSet()
+    {
+        $attributeSetMock = $this->getMock('\Magento\Eav\Model\Entity\Attribute\Set', [], [], '', false);
+        $this->setFactoryMock->expects($this->once())->method('create')->will($this->returnValue($attributeSetMock));
+        $attributeSetMock->expects($this->once())->method('load')->with(1)->will($this->returnSelf());
+        $attributeSetMock->expects($this->once())->method('getId')->will($this->returnValue(null));
+
+        $this->service->getList(1);
+    }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteServiceTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteServiceTest.php
index 9d8c7e507472e60b4f45fa6830acd2a54e12c2fd..95e658feb10f251db30db0cc2ed12ee985a10491 100644
--- a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteServiceTest.php
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/AttributeGroup/WriteServiceTest.php
@@ -43,6 +43,11 @@ class WriteServiceTest extends \PHPUnit_Framework_TestCase
      */
     protected $group;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $attributeSetMock;
+
     /**
      * @var \Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder
      */
@@ -67,7 +72,8 @@ class WriteServiceTest extends \PHPUnit_Framework_TestCase
         $this->group = $this->getMock(
             '\Magento\Catalog\Model\Product\Attribute\Group',
             array(
-                'getId', 'setId', 'setAttributeGroupName', '__wakeUp', 'save', 'load', 'delete', 'hasSystemAttributes'
+                'getId', 'setId', 'setAttributeGroupName', '__wakeUp', 'save', 'load', 'delete', 'hasSystemAttributes',
+                'getAttributeSetId'
             ),
             array(),
             '',
@@ -77,7 +83,17 @@ class WriteServiceTest extends \PHPUnit_Framework_TestCase
         $this->groupBuilder = $this->objectHelper->getObject(
             'Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder'
         );
-        $this->service = new WriteService($this->groupFactory, $this->groupBuilder);
+        $setFactoryMock = $this->getMock(
+            '\Magento\Eav\Model\Entity\Attribute\SetFactory',
+            array('create'),
+            array(),
+            '',
+            false
+        );
+        $this->attributeSetMock = $this->getMock('\Magento\Eav\Model\Entity\Attribute\Set', [], [], '', false);
+        $this->attributeSetMock->expects($this->any())->method('load')->will($this->returnSelf());
+        $setFactoryMock->expects($this->any())->method('create')->will($this->returnValue($this->attributeSetMock));
+        $this->service = new WriteService($this->groupFactory, $setFactoryMock, $this->groupBuilder);
     }
 
     /**
@@ -85,14 +101,26 @@ class WriteServiceTest extends \PHPUnit_Framework_TestCase
      */
     public function testCreateThrowsException()
     {
+        $this->attributeSetMock->expects($this->once())->method('getId')->will($this->returnValue(1));
         $this->group->expects($this->once())->method('save')->will($this->throwException(new \Exception()));
         $groupDataBuilder = $this->objectHelper->getObject('Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder');
         $groupDataBuilder->setName('testName');
         $this->service->create(1, $groupDataBuilder->create());
     }
 
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     */
+    public function testCreateThrowsExceptionIfNoSuchAttributeSetExists()
+    {
+        $this->attributeSetMock->expects($this->once())->method('getId')->will($this->returnValue(null));
+        $groupDataBuilder = $this->objectHelper->getObject('Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder');
+        $this->service->create(1, $groupDataBuilder->create());
+    }
+
     public function testCreateCreatesNewAttributeGroup()
     {
+        $this->attributeSetMock->expects($this->once())->method('getId')->will($this->returnValue(1));
         $this->group->expects($this->once())->method('setAttributeGroupName')->with('testName');
         $this->group->expects($this->once())->method('save');
         $groupDataBuilder = $this->objectHelper->getObject('Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder');
@@ -107,30 +135,46 @@ class WriteServiceTest extends \PHPUnit_Framework_TestCase
     {
         $groupDataBuilder = $this->objectHelper->getObject('Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder');
         $groupDataBuilder->setName('testName');
-        $this->service->update(1, $groupDataBuilder->create());
+        $this->service->update(1, 1, $groupDataBuilder->create());
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\StateException
+     * @expectedExceptionMessage Attribute group does not belong to provided attribute set
+     */
+    public function testUpdateThrowsExceptionIfTryToUpdateGroupFromWrongAttributeSet()
+    {
+        $this->group->expects($this->once())->method('getId')->will($this->returnValue(1));
+        $this->group->expects($this->once())->method('getAttributeSetId')->will($this->returnValue(2));
+        $groupDataBuilder = $this->objectHelper->getObject('Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder');
+        $groupDataBuilder->setName('testName');
+        $this->service->update(1, 1, $groupDataBuilder->create());
     }
 
     /**
      * @expectedException \Magento\Framework\Exception\CouldNotSaveException
+     * @expectedExceptionMessage Could not update attribute group
      */
     public function testUpdateThrowsExceptionIfEntityWasNotSaved()
     {
         $this->group->expects($this->once())->method('save')->will($this->throwException(new \Exception()));
         $this->group->expects($this->once())->method('getId')->will($this->returnValue(1));
+        $this->group->expects($this->once())->method('getAttributeSetId')->will($this->returnValue(1));
         $groupDataBuilder = $this->objectHelper->getObject('Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder');
         $groupDataBuilder->setName('testName');
-        $this->service->update(1, $groupDataBuilder->create());
+        $this->service->update(1, 1, $groupDataBuilder->create());
     }
 
     public function testUpdateSavesEntity()
     {
         $this->group->expects($this->once())->method('save');
         $this->group->expects($this->once())->method('getId')->will($this->returnValue(1));
-        $this->group->expects($this->once())->method('setId')->with(null);
+        $this->group->expects($this->once())->method('setId')->with(1);
+        $this->group->expects($this->once())->method('getAttributeSetId')->will($this->returnValue(1));
         $this->group->expects($this->once())->method('setAttributeGroupName')->with('testName');
         $groupDataBuilder = $this->objectHelper->getObject('Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder');
         $groupDataBuilder->setName('testName');
-        $this->service->update(1, $groupDataBuilder->create());
+        $this->service->update(1, 1, $groupDataBuilder->create());
     }
 
     /**
@@ -141,23 +185,39 @@ class WriteServiceTest extends \PHPUnit_Framework_TestCase
         $this->group->expects($this->once())->method('getId')->will($this->returnValue(null));
         $groupDataBuilder = $this->objectHelper->getObject('Magento\Catalog\Service\V1\Data\Eav\AttributeGroupBuilder');
         $groupDataBuilder->setName('testName');
-        $this->service->delete(1, $groupDataBuilder->create());
+        $this->service->delete(1, 1);
     }
 
     /**
      * @expectedException \Magento\Framework\Exception\StateException
+     * @expectedExceptionMessage Attribute group that contains system attributes can not be deleted
      */
     public function testDeleteThrowsStateExceptionIfTryToDeleteGroupWithSystemAttributes()
     {
+        $this->group->expects($this->once())->method('getId')->will($this->returnValue(1));
         $this->group->expects($this->once())->method('hasSystemAttributes')->will($this->returnValue(true));
         $this->group->expects($this->never())->method('delete');
-        $this->service->delete(1);
+        $this->service->delete(1, 1);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\StateException
+     * @expectedExceptionMessage Attribute group does not belong to provided attribute set
+     */
+    public function testDeleteThrowsStateExceptionIfTryToDeleteGroupFromWrongAttributeSet()
+    {
+        $this->group->expects($this->once())->method('getId')->will($this->returnValue(1));
+        $this->group->expects($this->once())->method('hasSystemAttributes')->will($this->returnValue(false));
+        $this->group->expects($this->once())->method('getAttributeSetId')->will($this->returnValue(0));
+        $this->group->expects($this->never())->method('delete');
+        $this->service->delete(1, 1);
     }
 
     public function testDeleteRemovesEntity()
     {
+        $this->group->expects($this->once())->method('getAttributeSetId')->will($this->returnValue(1));
         $this->group->expects($this->once())->method('getId')->will($this->returnValue(1));
         $this->group->expects($this->once())->method('delete');
-        $this->service->delete(1);
+        $this->service->delete(1, 1);
     }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/GroupPriceServiceTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/GroupPriceServiceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..20f35475e105b70b2e096b7b8e10abdc4d95d26c
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/GroupPriceServiceTest.php
@@ -0,0 +1,338 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+
+class GroupPriceServiceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var GroupPriceService
+     */
+    protected $service;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $repositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $priceBuilderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $storeManagerMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $groupServiceMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $priceModifierMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $websiteMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $configMock;
+
+    protected function setUp()
+    {
+        $this->repositoryMock = $this->getMock(
+            '\Magento\Catalog\Model\ProductRepository', array(), array(), '', false
+        );
+        $this->priceBuilderMock = $this->getMock(
+            'Magento\Catalog\Service\V1\Data\Product\GroupPriceBuilder', array(), array(), '', false
+        );
+        $this->storeManagerMock = $this->getMock('\Magento\Store\Model\StoreManagerInterface');
+        $this->groupServiceMock = $this->getMock('\Magento\Customer\Service\V1\CustomerGroupServiceInterface');
+
+        $this->priceModifierMock =
+            $this->getMock('Magento\Catalog\Model\Product\PriceModifier', array(), array(), '', false);
+        $this->websiteMock =
+            $this->getMock('Magento\Store\Model\Website', array('getId', '__wakeup'), array(), '', false);
+        $this->productMock = $this->getMock('Magento\Catalog\Model\Product',
+            array('getData', 'setData', 'validate', 'save', 'getIdBySku', 'load', '__wakeup'), array(), '', false);
+        $this->repositoryMock->expects($this->any())->method('get')->with('product_sku')
+            ->will($this->returnValue($this->productMock));
+        $this->configMock = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
+        $this->service = new GroupPriceService(
+            $this->repositoryMock,
+            $this->priceBuilderMock,
+            $this->storeManagerMock,
+            $this->groupServiceMock,
+            $this->priceModifierMock,
+            $this->configMock
+        );
+    }
+
+    /**
+     * @param string $configValue
+     * @param array  $groupData
+     * @param array $expected
+     * @dataProvider getListDataProvider
+     */
+    public function testGetList($configValue, $groupData, $expected)
+    {
+        $this->repositoryMock->expects($this->once())->method('get')->with('product_sku')
+            ->will($this->returnValue($this->productMock));
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('group_price')
+            ->will($this->returnValue(array($groupData)));
+        $this->configMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE)
+            ->will($this->returnValue($configValue));
+        $this->priceBuilderMock
+            ->expects($this->once())
+            ->method('populateWithArray')
+            ->with($expected);
+        $this->priceBuilderMock
+            ->expects($this->once())
+            ->method('create')
+            ->will($this->returnValue('data'));
+        $prices = $this->service->getList('product_sku');
+        $this->assertCount(1, $prices);
+        $this->assertEquals('data', $prices[0]);
+    }
+
+    public function getListDataProvider()
+    {
+        return array(
+            array(
+                1,
+                array('website_price' => 10, 'price' => 5, 'all_groups' => 1),
+                array('customer_group_id' => 'all', 'value' => 10)
+            ),
+            array(
+                0,
+                array('website_price' => 10, 'price' => 5, 'all_groups' => 0, 'cust_group' => 1),
+                array('customer_group_id' => 1, 'value' => 5)
+            )
+        );
+    }
+
+    public function testSuccessDeleteGroupPrice()
+    {
+        $this->storeManagerMock
+            ->expects($this->never())
+            ->method('getWebsite');
+        $this->configMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE)
+            ->will($this->returnValue(0));
+        $this->priceModifierMock->expects($this->once())->method('removeGroupPrice')->with($this->productMock, 4, 0);
+
+        $this->assertEquals(true, $this->service->delete('product_sku', 4));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @message Such product doesn't exist
+     */
+    public function testDeleteGroupPriceFromNonExistingProduct()
+    {
+        $this->repositoryMock->expects($this->once())->method('get')
+            ->will($this->throwException(new NoSuchEntityException()));
+        $this->priceModifierMock->expects($this->never())->method('removeGroupPrice');
+        $this->storeManagerMock
+            ->expects($this->never())
+            ->method('getWebsite');
+        $this->service->delete('product_sku', null, 10);
+    }
+
+    public function testSuccessDeleteGroupPriceFromWebsiteLevel()
+    {
+        $this->storeManagerMock
+            ->expects($this->once())
+            ->method('getWebsite')
+            ->will($this->returnValue($this->websiteMock));
+        $this->websiteMock->expects($this->once())->method('getId')->will($this->returnValue(1));
+        $this->configMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE)
+            ->will($this->returnValue(1));
+        $this->priceModifierMock->expects($this->once())->method('removeGroupPrice')->with($this->productMock, 4, 1);
+
+        $this->assertEquals(true, $this->service->delete('product_sku', 4));
+    }
+
+    public function testSetNewPriceWithGlobalPriceScope()
+    {
+        $priceBuilder = $this->getMock(
+            '\Magento\Catalog\Service\V1\Data\Product\GroupPriceBuilder', array(), array(), '', false
+        );
+        $priceBuilder->expects($this->any())->method('getData')->will($this->returnValue(array(
+            'customer_group_id' => 1,
+            'value' => 100
+        )));
+        $price = new \Magento\Catalog\Service\V1\Data\Product\GroupPrice($priceBuilder);
+        $groupBuilder = $this->getMock(
+            '\Magento\Customer\Service\V1\Data\CustomerGroupBuilder', array(), array(), '', false
+        );
+        $groupBuilder->expects($this->any())->method('getData')->will($this->returnValue(array('id' => 1)));
+        $group = new \Magento\Customer\Service\V1\Data\CustomerGroup($groupBuilder);
+        $this->groupServiceMock->expects($this->once())->method('getGroup')->will($this->returnValue($group));
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('group_price')
+            ->will($this->returnValue(array(array('cust_group' => 2, 'website_id' => 0, 'price' => 50))));
+        $this->configMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE)
+            ->will($this->returnValue(0));
+
+        $this->productMock->expects($this->once())->method('setData')->with(
+            'group_price',
+            array(
+                array('cust_group' => 2, 'website_id' => 0, 'price' => 50),
+                array('cust_group' => 1, 'website_id' => 0, 'price' => 100)
+            )
+        );
+        $this->productMock->expects($this->once())->method('save');
+        $this->service->set('product_sku', $price);
+    }
+
+    public function testSetUpdatedPriceWithGlobalPriceScope()
+    {
+        $priceBuilder = $this->getMock(
+            '\Magento\Catalog\Service\V1\Data\Product\GroupPriceBuilder', array(), array(), '', false
+        );
+        $priceBuilder->expects($this->any())->method('getData')->will($this->returnValue(array(
+            'customer_group_id' => 2,
+            'value' => 100
+        )));
+        $price = new \Magento\Catalog\Service\V1\Data\Product\GroupPrice($priceBuilder);
+        $groupBuilder = $this->getMock(
+            '\Magento\Customer\Service\V1\Data\CustomerGroupBuilder', array(), array(), '', false
+        );
+        $groupBuilder->expects($this->any())->method('getData')->will($this->returnValue(array('id' => 1)));
+        $group = new \Magento\Customer\Service\V1\Data\CustomerGroup($groupBuilder);
+        $this->groupServiceMock->expects($this->once())->method('getGroup')->will($this->returnValue($group));
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('group_price')
+            ->will($this->returnValue(array(array('cust_group' => 2, 'website_id' => 0, 'price' => 50))));
+        $this->configMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE)
+            ->will($this->returnValue(0));
+
+        $this->productMock->expects($this->once())->method('setData')->with(
+            'group_price',
+            array(
+                array('cust_group' => 2, 'website_id' => 0, 'price' => 100),
+            )
+        );
+        $this->productMock->expects($this->once())->method('save');
+        $this->service->set('product_sku', $price);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Values of following attributes are invalid: attr1, attr2
+     */
+    public function testSetThrowsExceptionIfDoesntValidate()
+    {
+        $priceBuilder = $this->getMock(
+            '\Magento\Catalog\Service\V1\Data\Product\GroupPriceBuilder', array(), array(), '', false
+        );
+        $priceBuilder->expects($this->any())->method('getData')->will($this->returnValue(array(
+                    'customer_group_id' => 2,
+                    'value' => 100
+                )));
+        $price = new \Magento\Catalog\Service\V1\Data\Product\GroupPrice($priceBuilder);
+        $groupBuilder = $this->getMock(
+            '\Magento\Customer\Service\V1\Data\CustomerGroupBuilder', array(), array(), '', false
+        );
+        $groupBuilder->expects($this->any())->method('getData')->will($this->returnValue(array('id' => 1)));
+        $group = new \Magento\Customer\Service\V1\Data\CustomerGroup($groupBuilder);
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('group_price')
+            ->will($this->returnValue(array()));
+
+        $this->groupServiceMock->expects($this->once())->method('getGroup')->will($this->returnValue($group));
+        $this->productMock->expects($this->once())->method('validate')->will($this->returnValue(
+            array('attr1' => '', 'attr2' => '')
+        ));
+        $this->productMock->expects($this->never())->method('save');
+        $this->service->set('product_sku', $price);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function testSetThrowsExceptionIfCantSave()
+    {
+        $priceBuilder = $this->getMock(
+            '\Magento\Catalog\Service\V1\Data\Product\GroupPriceBuilder', array(), array(), '', false
+        );
+        $priceBuilder->expects($this->any())->method('getData')->will($this->returnValue(array(
+            'customer_group_id' => 2,
+            'value' => 100
+        )));
+        $price = new \Magento\Catalog\Service\V1\Data\Product\GroupPrice($priceBuilder);
+        $groupBuilder = $this->getMock(
+            '\Magento\Customer\Service\V1\Data\CustomerGroupBuilder', array(), array(), '', false
+        );
+        $groupBuilder->expects($this->any())->method('getData')->will($this->returnValue(array('id' => 1)));
+        $group = new \Magento\Customer\Service\V1\Data\CustomerGroup($groupBuilder);
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('group_price')
+            ->will($this->returnValue(array()));
+
+        $this->groupServiceMock->expects($this->once())->method('getGroup')->will($this->returnValue($group));
+        $this->productMock->expects($this->once())->method('save')->will($this->throwException(new \Exception()));
+        $this->service->set('product_sku', $price);
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/TierPriceServiceTest.php b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/TierPriceServiceTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..476cc986eda16264b912a25c1bf2af1233e39a28
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Catalog/Service/V1/Product/TierPriceServiceTest.php
@@ -0,0 +1,357 @@
+<?php
+/**
+ *
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Catalog\Service\V1\Product;
+
+use Magento\Framework\Exception\NoSuchEntityException;
+
+class TierPriceServiceTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var TierPriceService
+     */
+    protected $service;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $repositoryMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $priceBuilderMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $storeManagerMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $groupServiceMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $priceModifierMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $websiteMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $configMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $productMock;
+
+    protected function setUp()
+    {
+        $this->repositoryMock = $this->getMock(
+            '\Magento\Catalog\Model\ProductRepository', array(), array(), '', false
+        );
+        $this->priceBuilderMock = $this->getMock(
+            '\Magento\Catalog\Service\V1\Data\Product\TierPriceBuilder', array(), array(), '', false
+        );
+        $this->storeManagerMock = $this->getMock('\Magento\Store\Model\StoreManagerInterface');
+        $this->groupServiceMock = $this->getMock('\Magento\Customer\Service\V1\CustomerGroupServiceInterface');
+        $this->websiteMock =
+            $this->getMock('Magento\Store\Model\Website', array('getId', '__wakeup'), array(), '', false);
+        $this->productMock = $this->getMock('Magento\Catalog\Model\Product',
+            array('getData', 'getIdBySku', 'load', '__wakeup', 'save', 'validate', 'setData'), array(), '', false);
+        $this->configMock = $this->getMock('Magento\Framework\App\Config\ScopeConfigInterface');
+        $this->priceModifierMock =
+            $this->getMock('Magento\Catalog\Model\Product\PriceModifier', array(), array(), '', false);
+        $this->repositoryMock->expects($this->any())->method('get')->with('product_sku')
+            ->will($this->returnValue($this->productMock));
+
+        $this->service = new TierPriceService(
+            $this->repositoryMock,
+            $this->priceBuilderMock,
+            $this->storeManagerMock,
+            $this->priceModifierMock,
+            $this->configMock,
+            $this->groupServiceMock
+        );
+    }
+
+    /**
+     * @param $configValue
+     * @param $customerGroupId
+     * @param $groupData
+     * @param $expected
+     * @dataProvider getListDataProvider
+     */
+    public function testGetList($configValue, $customerGroupId, $groupData, $expected)
+    {
+        $this->repositoryMock->expects($this->once())->method('get')->with('product_sku')
+            ->will($this->returnValue($this->productMock));
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('tier_price')
+            ->will($this->returnValue(array($groupData)));
+        $this->configMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE)
+            ->will($this->returnValue($configValue));
+        if ($expected) {
+            $this->priceBuilderMock
+                ->expects($this->once())
+                ->method('populateWithArray')
+                ->with($expected);
+            $this->priceBuilderMock
+                ->expects($this->once())
+                ->method('create')
+                ->will($this->returnValue('data'));
+        } else {
+            $this->priceBuilderMock->expects($this->never())->method('populateWithArray');
+        }
+        $prices = $this->service->getList('product_sku', $customerGroupId);
+        $this->assertCount($expected ? 1 : 0, $prices);
+        if ($expected) {
+            $this->assertEquals('data', $prices[0]);
+        }
+    }
+
+    public function getListDataProvider()
+    {
+        return array(
+            array(
+                1,
+                'all',
+                array('website_price' => 10, 'price' => 5, 'all_groups' => 1, 'price_qty' => 5),
+                array('value' => 10, 'qty' => 5)
+            ),
+            array(
+                0,
+                1,
+                array('website_price' => 10, 'price' => 5, 'all_groups' => 0, 'cust_group' => 1, 'price_qty' => 5),
+                array('value' => 5, 'qty' => 5)
+            ),
+            array(
+                0,
+                'all',
+                array('website_price' => 10, 'price' => 5, 'all_groups' => 0, 'cust_group' => 1, 'price_qty' => 5),
+                array()
+            )
+        );
+    }
+
+    public function testSuccessDeleteTierPrice()
+    {
+        $this->storeManagerMock
+            ->expects($this->never())
+            ->method('getWebsite');
+        $this->configMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE)
+            ->will($this->returnValue(0));
+        $this->priceModifierMock->expects($this->once())->method('removeTierPrice')->with($this->productMock, 4, 5, 0);
+
+        $this->assertEquals(true, $this->service->delete('product_sku', 4, 5, 0));
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\NoSuchEntityException
+     * @message Such product doesn't exist
+     */
+    public function testDeleteTierPriceFromNonExistingProduct()
+    {
+        $this->repositoryMock->expects($this->once())->method('get')
+            ->will($this->throwException(new NoSuchEntityException()));
+        $this->priceModifierMock->expects($this->never())->method('removeTierPrice');
+        $this->storeManagerMock
+            ->expects($this->never())
+            ->method('getWebsite');
+        $this->service->delete('product_sku', null, 10, 5);
+    }
+
+    public function testSuccessDeleteTierPriceFromWebsiteLevel()
+    {
+        $this->storeManagerMock
+            ->expects($this->once())
+            ->method('getWebsite')
+            ->will($this->returnValue($this->websiteMock));
+        $this->websiteMock->expects($this->once())->method('getId')->will($this->returnValue(1));
+        $this->configMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE)
+            ->will($this->returnValue(1));
+        $this->priceModifierMock->expects($this->once())->method('removeTierPrice')->with($this->productMock, 4, 5, 1);
+
+        $this->assertEquals(true, $this->service->delete('product_sku', 4, 5, 6));
+    }
+
+    public function testSetNewPriceWithGlobalPriceScope()
+    {
+        $priceBuilder = $this->getMock(
+            '\Magento\Catalog\Service\V1\Data\Product\TierPriceBuilder', array(), array(), '', false
+        );
+        $priceBuilder->expects($this->any())->method('getData')->will($this->returnValue(array(
+            'qty' => 3,
+            'value' => 100
+        )));
+        $price = new \Magento\Catalog\Service\V1\Data\Product\TierPrice($priceBuilder);
+        $groupBuilder = $this->getMock(
+            '\Magento\Customer\Service\V1\Data\CustomerGroupBuilder', array(), array(), '', false
+        );
+        $groupBuilder->expects($this->any())->method('getData')->will($this->returnValue(array('id' => 1)));
+        $group = new \Magento\Customer\Service\V1\Data\CustomerGroup($groupBuilder);
+        $this->groupServiceMock->expects($this->once())->method('getGroup')->will($this->returnValue($group));
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('tier_price')
+            ->will($this->returnValue(
+                array(array('cust_group' => 1, 'website_id' => 0, 'price_qty' => 4, 'price' => 50))
+            ));
+        $this->configMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE)
+            ->will($this->returnValue(0));
+
+        $this->productMock->expects($this->once())->method('setData')->with(
+            'tier_price',
+            array(
+                array('cust_group' => 1, 'website_id' => 0, 'price_qty' => 4, 'price' => 50),
+                array('cust_group' => 1, 'website_id' => 0, 'price_qty' => 3, 'price' => 100, 'website_price' => 100)
+            )
+        );
+        $this->productMock->expects($this->once())->method('save');
+        $this->service->set('product_sku', 1, $price);
+    }
+
+    public function testSetUpdatedPriceWithGlobalPriceScope()
+    {
+        $priceBuilder = $this->getMock(
+            '\Magento\Catalog\Service\V1\Data\Product\TierPriceBuilder', array(), array(), '', false
+        );
+        $priceBuilder->expects($this->any())->method('getData')->will($this->returnValue(array(
+            'qty' => 3,
+            'value' => 100
+        )));
+        $price = new \Magento\Catalog\Service\V1\Data\Product\TierPrice($priceBuilder);
+        $groupBuilder = $this->getMock(
+            '\Magento\Customer\Service\V1\Data\CustomerGroupBuilder', array(), array(), '', false
+        );
+        $groupBuilder->expects($this->any())->method('getData')->will($this->returnValue(array('id' => 1)));
+        $group = new \Magento\Customer\Service\V1\Data\CustomerGroup($groupBuilder);
+        $this->groupServiceMock->expects($this->once())->method('getGroup')->will($this->returnValue($group));
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('tier_price')
+            ->will($this->returnValue(
+                array(array('cust_group' => 1, 'website_id' => 0, 'price_qty' => 3, 'price' => 50)))
+            );
+        $this->configMock
+            ->expects($this->once())
+            ->method('getValue')
+            ->with('catalog/price/scope', \Magento\Store\Model\ScopeInterface::SCOPE_WEBSITE)
+            ->will($this->returnValue(0));
+
+        $this->productMock->expects($this->once())->method('setData')->with(
+            'tier_price',
+            array(
+                array('cust_group' => 1, 'website_id' => 0, 'price_qty' => 3, 'price' => 100)
+            )
+        );
+        $this->productMock->expects($this->once())->method('save');
+        $this->service->set('product_sku', 1, $price);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\InputException
+     * @expectedExceptionMessage Values of following attributes are invalid: attr1, attr2
+     */
+    public function testSetThrowsExceptionIfDoesntValidate()
+    {
+        $priceBuilder = $this->getMock(
+            '\Magento\Catalog\Service\V1\Data\Product\TierPriceBuilder', array(), array(), '', false
+        );
+        $priceBuilder->expects($this->any())->method('getData')->will($this->returnValue(array(
+            'qty' => 2,
+            'value' => 100
+        )));
+        $price = new \Magento\Catalog\Service\V1\Data\Product\TierPrice($priceBuilder);
+        $groupBuilder = $this->getMock(
+            '\Magento\Customer\Service\V1\Data\CustomerGroupBuilder', array(), array(), '', false
+        );
+        $groupBuilder->expects($this->any())->method('getData')->will($this->returnValue(array('id' => 1)));
+        $group = new \Magento\Customer\Service\V1\Data\CustomerGroup($groupBuilder);
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('tier_price')
+            ->will($this->returnValue(array()));
+
+        $this->groupServiceMock->expects($this->once())->method('getGroup')->will($this->returnValue($group));
+        $this->productMock->expects($this->once())->method('validate')->will($this->returnValue(
+                array('attr1' => '', 'attr2' => '')
+            ));
+        $this->productMock->expects($this->never())->method('save');
+        $this->service->set('product_sku', 1, $price);
+    }
+
+    /**
+     * @expectedException \Magento\Framework\Exception\CouldNotSaveException
+     */
+    public function testSetThrowsExceptionIfCantSave()
+    {
+        $priceBuilder = $this->getMock(
+            '\Magento\Catalog\Service\V1\Data\Product\TierPriceBuilder', array(), array(), '', false
+        );
+        $priceBuilder->expects($this->any())->method('getData')->will($this->returnValue(array(
+            'qty' => 2,
+            'value' => 100
+        )));
+        $price = new \Magento\Catalog\Service\V1\Data\Product\TierPrice($priceBuilder);
+        $groupBuilder = $this->getMock(
+            '\Magento\Customer\Service\V1\Data\CustomerGroupBuilder', array(), array(), '', false
+        );
+        $groupBuilder->expects($this->any())->method('getData')->will($this->returnValue(array('id' => 1)));
+        $group = new \Magento\Customer\Service\V1\Data\CustomerGroup($groupBuilder);
+        $this->productMock
+            ->expects($this->once())
+            ->method('getData')
+            ->with('tier_price')
+            ->will($this->returnValue(array()));
+
+        $this->groupServiceMock->expects($this->once())->method('getGroup')->will($this->returnValue($group));
+        $this->productMock->expects($this->once())->method('save')->will($this->throwException(new \Exception()));
+        $this->service->set('product_sku', 1, $price);
+    }
+} 
diff --git a/dev/tests/unit/testsuite/Magento/Eav/Model/Resource/Attribute/CollectionTest.php b/dev/tests/unit/testsuite/Magento/Eav/Model/Resource/Attribute/CollectionTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..056c44d6fc5279322ae8bba72bd9fcbb52ecd427
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Eav/Model/Resource/Attribute/CollectionTest.php
@@ -0,0 +1,230 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+namespace Magento\Eav\Model\Resource\Attribute;
+
+class CollectionTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Eav\Model\Resource\Attribute\Collection|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Core\Model\EntityFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $entityFactoryMock;
+
+    /**
+     * @var \Magento\Framework\Logger|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $loggerMock;
+
+    /**
+     * @var \Magento\Framework\Data\Collection\Db\FetchStrategyInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $fetchStrategyMock;
+
+    /**
+     * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $eventManagerMock;
+
+    /**
+     * @var \Magento\Eav\Model\Config|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $eavConfigMock;
+
+    /**
+     * @var \Magento\Eav\Model\Entity\Type
+     */
+    protected $entityTypeMock;
+
+    /**
+     * @var \Magento\Store\Model\StoreManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $storeManagerMock;
+
+    /**
+     * @var \Magento\Framework\DB\Adapter\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $connectionMock;
+
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\AbstractDb|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $resourceMock;
+
+    /**
+     * @var \Zend_Db_Select|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $selectMock;
+
+    protected function setUp()
+    {
+        $this->entityFactoryMock = $this->getMock('Magento\Core\Model\EntityFactory', array(), array(), '', false);
+        $this->loggerMock = $this->getMock('Magento\Framework\Logger', array(), array(), '', false);
+        $this->fetchStrategyMock = $this->getMock('Magento\Framework\Data\Collection\Db\FetchStrategyInterface');
+        $this->eventManagerMock = $this->getMock('Magento\Framework\Event\ManagerInterface');
+
+        $this->eavConfigMock = $this->getMock('Magento\Eav\Model\Config', array(), array(), '', false);
+        $this->entityTypeMock = $this->getMock('Magento\Eav\Model\Entity\Type', array('__wakeup'), array(), '', false);
+        $this->entityTypeMock->setAdditionalAttributeTable('some_extra_table');
+        $this->eavConfigMock->expects($this->any())
+            ->method('getEntityType')
+            ->will($this->returnValue($this->entityTypeMock));
+
+        $this->storeManagerMock = $this->getMock('Magento\Store\Model\StoreManagerInterface');
+        $this->storeManagerMock->expects($this->any())
+            ->method('getStore')
+            ->will($this->returnSelf());
+
+        $adapter = $this->getMockForAbstractClass('Zend_Db_Adapter_Abstract', array(), '', false);
+
+        $this->selectMock = $this->getMock('Zend_Db_Select', null, array($adapter));
+
+        $this->connectionMock = $this->getMock(
+            'Magento\Framework\DB\Adapter\Pdo\Mysql',
+            array('select','describeTable', 'quoteIdentifier', '_connect', '_quote'),
+            array(),
+            '',
+            false);
+
+        $this->resourceMock = $this->getMockForAbstractClass(
+            'Magento\Framework\Model\Resource\Db\AbstractDb',
+            array(),
+            '',
+            false,
+            true,
+            true,
+            array('__wakeup', 'getReadConnection', 'getMainTable', 'getTable')
+        );
+
+        $this->connectionMock->expects($this->any())
+            ->method('select')
+            ->will($this->returnValue($this->selectMock));
+        $this->connectionMock->expects($this->any())
+            ->method('quoteIdentifier')
+            ->will($this->returnArgument(0));
+        $this->connectionMock->expects($this->any())
+            ->method('describeTable')
+            ->will($this->returnvalueMap(
+                array(
+                    array(
+                        'some_main_table',
+                        null,
+                        array(
+                            'col1' => array(),
+                            'col2' => array(),
+                        )
+                    ),
+                    array(
+                        'some_extra_table',
+                        null,
+                        array(
+                            'col2' => array(),
+                            'col3' => array(),
+                        )
+                    ),
+                    array(
+                        null,
+                        null,
+                        array(
+                            'col2' => array(),
+                            'col3' => array(),
+                            'col4' => array(),
+                        )
+                    ),
+                )
+            ));
+        $this->connectionMock->expects($this->any())
+            ->method('_quote')
+            ->will($this->returnArgument(0));
+
+        $this->resourceMock->expects($this->any())
+            ->method('getReadConnection')
+            ->will($this->returnValue($this->connectionMock));
+        $this->resourceMock->expects($this->any())
+            ->method('getMainTable')
+            ->will($this->returnValue('some_main_table'));
+        $this->resourceMock->expects($this->any())
+            ->method('getTable')
+            ->will(
+                $this->returnValue('some_extra_table')
+            );
+    }
+
+    /**
+     * Test that Magento\Eav\Model\Resource\Attribute\Collection::_initSelect sets expressions
+     * that can be properly quoted by Zend_Db_Expr::quoteIdentifier
+     *
+     * @dataProvider initSelectDataProvider
+     */
+    public function testInitSelect($column, $value, $expected)
+    {
+        $helper = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $this->model = $helper->getObject('\Magento\Customer\Model\Resource\Attribute\Collection',
+            array(
+                'entityFactory' => $this->entityFactoryMock,
+                'logger' => $this->loggerMock,
+                'fetchStrategy' => $this->fetchStrategyMock,
+                'eventManager' => $this->eventManagerMock,
+                'eavConfig' => $this->eavConfigMock,
+                'storeManager' => $this->storeManagerMock,
+                'connection' => $this->connectionMock,
+                'resource' => $this->resourceMock
+            )
+        );
+
+        $this->model->addFieldToFilter($column, $value);
+        $this->assertEquals($expected, $this->model->getSelectCountSql()->assemble());
+    }
+
+    public function initSelectDataProvider()
+    {
+        return array(
+            'main_table_expression' => array(
+                'col2', '1',
+                'SELECT COUNT(*) FROM "some_main_table" AS "main_table"' . "\n"
+                . ' INNER JOIN "some_extra_table" AS "additional_table"'
+                . ' ON additional_table.attribute_id = main_table.attribute_id' . "\n"
+                . ' LEFT JOIN "some_extra_table" AS "scope_table"'
+                . ' ON scope_table.attribute_id = main_table.attribute_id'
+                . ' AND scope_table.website_id = :scope_website_id'
+                . ' WHERE (main_table.entity_type_id = :mt_entity_type_id)'
+                . ' AND (IF(main_table.col2 IS NULL, scope_table.col2, main_table.col2) = 1)'
+            ),
+            'additional_table_expression' => array(
+                'col3', '2',
+                'SELECT COUNT(*) FROM "some_main_table" AS "main_table"' . "\n"
+                . ' INNER JOIN "some_extra_table" AS "additional_table"'
+                . ' ON additional_table.attribute_id = main_table.attribute_id'. "\n"
+                . ' LEFT JOIN "some_extra_table" AS "scope_table"'
+                . ' ON scope_table.attribute_id = main_table.attribute_id'
+                . ' AND scope_table.website_id = :scope_website_id'
+                . ' WHERE (main_table.entity_type_id = :mt_entity_type_id)'
+                . ' AND (IF(additional_table.col3 IS NULL, scope_table.col3, additional_table.col3) = 2)'
+            )
+        );
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/SalesRule/Model/ValidatorTest.php b/dev/tests/unit/testsuite/Magento/SalesRule/Model/ValidatorTest.php
index dbd6d6b4e23ad6926830afcb10eec246e7099f60..3d8e21bf9d0b5d02ec85e3e9e4522c182fffe976 100644
--- a/dev/tests/unit/testsuite/Magento/SalesRule/Model/ValidatorTest.php
+++ b/dev/tests/unit/testsuite/Magento/SalesRule/Model/ValidatorTest.php
@@ -32,6 +32,7 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
 
     protected function setUp()
     {
+        // @TODO Re-write test according to standards of writing test (e.g do not mock tested class)
         $this->model = $this->getMock(
             'Magento\SalesRule\Model\Validator',
             array('_getRules', '_getItemOriginalPrice', '_getItemBaseOriginalPrice', '__wakeup'),
@@ -97,8 +98,6 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
         $quote->setVirtualItemsQty(2);
 
         $this->assertTrue($this->model->canApplyRules($item));
-
-        return true;
     }
 
     public function testProcess()
@@ -449,4 +448,47 @@ class ValidatorTest extends \PHPUnit_Framework_TestCase
 
         return $validator;
     }
+
+    public function testInit()
+    {
+        $websiteId = 1;
+        $customerGroupId = 2;
+        $couponCode = 'code';
+
+        $ruleCollection = $this->getMockBuilder('Magento\SalesRule\Model\Resource\Rule\Collection')
+            ->disableOriginalConstructor()
+            ->getMock();
+        $ruleCollection->expects($this->once())
+            ->method('setValidationFilter')
+            ->with($websiteId, $customerGroupId, $couponCode)
+            ->will($this->returnSelf());
+        $ruleCollection->expects($this->once())
+            ->method('addFieldToFilter')
+            ->with('is_active', 1)
+            ->will($this->returnSelf());
+        $ruleCollection->expects($this->once())
+            ->method('load')
+            ->will($this->returnSelf());
+
+        $ruleCollectionFactoryMock = $this->getMockBuilder('Magento\SalesRule\Model\Resource\Rule\CollectionFactory')
+            ->disableOriginalConstructor()
+            ->setMethods(['create'])
+            ->getMock();
+        $ruleCollectionFactoryMock->expects($this->once())
+            ->method('create')
+            ->will($this->returnValue($ruleCollection));
+
+        $helper = new \Magento\TestFramework\Helper\ObjectManager($this);
+        $model = $helper->getObject(
+            'Magento\SalesRule\Model\Validator',
+            [
+                'collectionFactory' => $ruleCollectionFactoryMock
+            ]
+        );
+
+        $this->assertInstanceOf(
+            'Magento\SalesRule\Model\Validator',
+            $model->init($websiteId, $customerGroupId, $couponCode)
+        );
+    }
 }
diff --git a/dev/tests/unit/testsuite/Magento/Tax/Model/ConfigTest.php b/dev/tests/unit/testsuite/Magento/Tax/Model/ConfigTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3502632adeb076bb3cb6a07574ff8523f59561dc
--- /dev/null
+++ b/dev/tests/unit/testsuite/Magento/Tax/Model/ConfigTest.php
@@ -0,0 +1,405 @@
+<?php
+/**
+ * Magento
+ *
+ * NOTICE OF LICENSE
+ *
+ * This source file is subject to the Open Software License (OSL 3.0)
+ * that is bundled with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://opensource.org/licenses/osl-3.0.php
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@magentocommerce.com so we can send you a copy immediately.
+ *
+ * DISCLAIMER
+ *
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
+ * versions in the future. If you wish to customize Magento for your
+ * needs please refer to http://www.magentocommerce.com for more information.
+ *
+ * @copyright   Copyright (c) 2014 X.commerce, Inc. (http://www.magentocommerce.com)
+ * @license     http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
+ */
+
+/**
+ * Test class for \Magento\Tax\Model\Config
+ */
+namespace Magento\Tax\Model;
+
+use Magento\Tax\Model\Config;
+
+class ConfigTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Tests the setter/getter methods that bypass the ScopeConfigInterface object
+     *
+     * @param string $setterMethod
+     * @param string $getterMethod
+     * @param bool $value
+     * @dataProvider dataProviderDirectSettersGettersMethods
+     */
+    public function testDirectSettersGettersMethods($setterMethod, $getterMethod, $value)
+    {
+        // Need a mocked object with only dummy methods.  It is just needed for construction.
+        // The setter/getter methods do not use this object (for this set of tests).
+        $scopeConfigMock = $this->getMockForAbstractClass('Magento\Framework\App\Config\ScopeConfigInterface');
+
+        /** @var \Magento\Tax\Model\Config */
+        $model = new Config($scopeConfigMock);
+        $model->{$setterMethod}($value);
+        $this->assertEquals($value, $model->{$getterMethod}());
+    }
+
+    /**
+     * Returns a set of 'true' and 'false' parameters for each of the setter/getter method pairs
+     *
+     * @return array
+     */
+    public function dataProviderDirectSettersGettersMethods()
+    {
+        return $this->_buildTrueFalsePairs(
+            [
+                [
+                    'setShippingPriceIncludeTax',
+                    'shippingPriceIncludesTax'
+                ],
+                [
+                    'setNeedUseShippingExcludeTax',
+                    'getNeedUseShippingExcludeTax'
+                ],
+                [
+                    'setPriceIncludesTax',
+                    'priceIncludesTax'
+                ]
+            ]
+        );
+    }
+
+    /**
+     * Returns an output array that is twice the size of the input array by adding 'true' and then 'false' to the
+     * set of parameters given
+     *
+     * @param array $arrayIn
+     * @return array
+     */
+    protected function _buildTrueFalsePairs($arrayIn)
+    {
+        $arrayOut = [];
+
+        foreach ($arrayIn as $paramArray) {
+            // replicate the paramArray, append 'true', and add the new array to the output array
+            $arrayT = $paramArray;
+            $arrayT[] = true;
+            $arrayOut[] = $arrayT;
+            // replicate the paramArray, append 'false', and add the new array to the output array
+            $arrayF = $paramArray;
+            $arrayF[] = false;
+            $arrayOut[] = $arrayF;
+        }
+
+        return $arrayOut;
+    }
+
+
+    /**
+     * Tests the getCalculationSequence method
+     *
+     * @param bool $applyTaxAfterDiscount
+     * @param bool $discountTaxIncl
+     * @param string $expectedValue
+     * @dataProvider dataProviderGetCalculationSequence
+     */
+    public function testGetCalculationSequence($applyTaxAfterDiscount, $discountTaxIncl, $expectedValue)
+    {
+        $scopeConfigMock = $this->getMockForAbstractClass('Magento\Framework\App\Config\ScopeConfigInterface');
+        $scopeConfigMock->expects(
+            $this->at(0))->method('getValue')->will($this->returnValue($applyTaxAfterDiscount));
+        $scopeConfigMock->expects(
+            $this->at(1))->method('getValue')->will($this->returnValue($discountTaxIncl));
+
+        /** @var \Magento\Tax\Model\Config */
+        $model = new Config($scopeConfigMock);
+        $this->assertEquals($expectedValue, $model->getCalculationSequence());
+    }
+
+    /**
+     * @return array
+     */
+    public function dataProviderGetCalculationSequence()
+    {
+        return [
+            [true,  true,  \Magento\Tax\Model\Calculation::CALC_TAX_AFTER_DISCOUNT_ON_INCL],
+            [true,  false, \Magento\Tax\Model\Calculation::CALC_TAX_AFTER_DISCOUNT_ON_EXCL],
+            [false, true,  \Magento\Tax\Model\Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_INCL],
+            [false, false, \Magento\Tax\Model\Calculation::CALC_TAX_BEFORE_DISCOUNT_ON_EXCL]
+        ];
+    }
+
+
+    /**
+     * Tests the methods that rely on the ScopeConfigInterface object to provide their return values
+     *
+     * @param string $method
+     * @param string $path
+     * @param bool|int $configValue
+     * @param bool $expectedValue
+     * @dataProvider dataProviderScopeConfigMethods
+     */
+    public function testScopeConfigMethods($method, $path, $configValue, $expectedValue)
+    {
+        $scopeConfigMock = $this->getMockForAbstractClass('Magento\Framework\App\Config\ScopeConfigInterface');
+        $scopeConfigMock->expects($this->once())
+            ->method('getValue')
+            ->with($path, \Magento\Store\Model\ScopeInterface::SCOPE_STORE, null)
+            ->will($this->returnValue($configValue));
+
+        /** @var \Magento\Tax\Model\Config */
+        $model = new Config($scopeConfigMock);
+        $this->assertEquals($expectedValue, $model->{$method}());
+    }
+
+    /**
+     * @return array
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     */
+    public function dataProviderScopeConfigMethods()
+    {
+        return [
+            [
+                'priceIncludesTax',
+                Config::CONFIG_XML_PATH_PRICE_INCLUDES_TAX,
+                true,
+                true
+            ],
+            [
+                'applyTaxAfterDiscount',
+                Config::CONFIG_XML_PATH_APPLY_AFTER_DISCOUNT,
+                true,
+                true
+            ],
+            [
+                'getPriceDisplayType',
+                Config::CONFIG_XML_PATH_PRICE_DISPLAY_TYPE,
+                true,
+                true
+            ],
+            [
+                'discountTax',
+                Config::CONFIG_XML_PATH_DISCOUNT_TAX,
+                1,
+                true
+            ],
+            [
+                'getAlgorithm',
+                Config::XML_PATH_ALGORITHM,
+                true,
+                true
+            ],
+            [
+                'getShippingTaxClass',
+                Config::CONFIG_XML_PATH_SHIPPING_TAX_CLASS,
+                true,
+                true
+            ],
+            [
+                'getShippingPriceDisplayType',
+                Config::CONFIG_XML_PATH_DISPLAY_SHIPPING,
+                true,
+                true
+            ],
+            [
+                'shippingPriceIncludesTax',
+                Config::CONFIG_XML_PATH_SHIPPING_INCLUDES_TAX,
+                true,
+                true
+            ],
+            [
+                'displayCartPricesInclTax',
+                Config::XML_PATH_DISPLAY_CART_PRICE,
+                Config::DISPLAY_TYPE_INCLUDING_TAX,
+                true
+            ],
+            [
+                'displayCartPricesExclTax',
+                Config::XML_PATH_DISPLAY_CART_PRICE,
+                Config::DISPLAY_TYPE_EXCLUDING_TAX,
+                true
+            ],
+            [
+                'displayCartPricesBoth',
+                Config::XML_PATH_DISPLAY_CART_PRICE,
+                Config::DISPLAY_TYPE_BOTH,
+                true
+            ],
+            [
+                'displayCartSubtotalInclTax',
+                Config::XML_PATH_DISPLAY_CART_SUBTOTAL,
+                Config::DISPLAY_TYPE_INCLUDING_TAX,
+                true
+            ],
+            [
+                'displayCartSubtotalExclTax',
+                Config::XML_PATH_DISPLAY_CART_SUBTOTAL,
+                Config::DISPLAY_TYPE_EXCLUDING_TAX,
+                true
+            ],
+            [
+                'displayCartSubtotalBoth',
+                Config::XML_PATH_DISPLAY_CART_SUBTOTAL,
+                Config::DISPLAY_TYPE_BOTH,
+                true
+            ],
+            [
+                'displayCartShippingInclTax',
+                Config::XML_PATH_DISPLAY_CART_SHIPPING,
+                Config::DISPLAY_TYPE_INCLUDING_TAX,
+                true
+            ],
+            [
+                'displayCartShippingExclTax',
+                Config::XML_PATH_DISPLAY_CART_SHIPPING,
+                Config::DISPLAY_TYPE_EXCLUDING_TAX,
+                true
+            ],
+            [
+                'displayCartShippingBoth',
+                Config::XML_PATH_DISPLAY_CART_SHIPPING,
+                Config::DISPLAY_TYPE_BOTH,
+                true
+            ],
+            [
+                'displayCartDiscountInclTax',
+                Config::XML_PATH_DISPLAY_CART_DISCOUNT,
+                Config::DISPLAY_TYPE_INCLUDING_TAX,
+                true
+            ],
+            [
+                'displayCartDiscountExclTax',
+                Config::XML_PATH_DISPLAY_CART_DISCOUNT,
+                Config::DISPLAY_TYPE_EXCLUDING_TAX,
+                true
+            ],
+            [
+                'displayCartDiscountBoth',
+                Config::XML_PATH_DISPLAY_CART_DISCOUNT,
+                Config::DISPLAY_TYPE_BOTH,
+                true
+            ],
+            [
+                'displayCartTaxWithGrandTotal',
+                Config::XML_PATH_DISPLAY_CART_GRANDTOTAL,
+                true,
+                true
+            ],
+            [
+                'displayCartFullSummary',
+                Config::XML_PATH_DISPLAY_CART_FULL_SUMMARY,
+                true,
+                true
+            ],
+            [
+                'displayCartZeroTax',
+                Config::XML_PATH_DISPLAY_CART_ZERO_TAX,
+                true,
+                true
+            ],
+            [
+                'displaySalesPricesInclTax',
+                Config::XML_PATH_DISPLAY_SALES_PRICE,
+                Config::DISPLAY_TYPE_INCLUDING_TAX,
+                true
+            ],
+            [
+                'displaySalesPricesExclTax',
+                Config::XML_PATH_DISPLAY_SALES_PRICE,
+                Config::DISPLAY_TYPE_EXCLUDING_TAX,
+                true
+            ],
+            [
+                'displaySalesPricesBoth',
+                Config::XML_PATH_DISPLAY_SALES_PRICE,
+                Config::DISPLAY_TYPE_BOTH,
+                true
+            ],
+            [
+                'displaySalesSubtotalInclTax',
+                Config::XML_PATH_DISPLAY_SALES_SUBTOTAL,
+                Config::DISPLAY_TYPE_INCLUDING_TAX,
+                true
+            ],
+            [
+                'displaySalesSubtotalExclTax',
+                Config::XML_PATH_DISPLAY_SALES_SUBTOTAL,
+                Config::DISPLAY_TYPE_EXCLUDING_TAX,
+                true
+            ],
+            [
+                'displaySalesSubtotalBoth',
+                Config::XML_PATH_DISPLAY_SALES_SUBTOTAL,
+                Config::DISPLAY_TYPE_BOTH,
+                true
+            ],
+            [
+                'displaySalesShippingInclTax',
+                Config::XML_PATH_DISPLAY_SALES_SHIPPING,
+                Config::DISPLAY_TYPE_INCLUDING_TAX,
+                true
+            ],
+            [
+                'displaySalesShippingExclTax',
+                Config::XML_PATH_DISPLAY_SALES_SHIPPING,
+                Config::DISPLAY_TYPE_EXCLUDING_TAX,
+                true
+            ],
+            [
+                'displaySalesShippingBoth',
+                Config::XML_PATH_DISPLAY_SALES_SHIPPING,
+                Config::DISPLAY_TYPE_BOTH,
+                true
+            ],
+            [
+                'displaySalesDiscountInclTax',
+                Config::XML_PATH_DISPLAY_SALES_DISCOUNT,
+                Config::DISPLAY_TYPE_INCLUDING_TAX,
+                true
+            ],
+            [
+                'displaySalesDiscountExclTax',
+                Config::XML_PATH_DISPLAY_SALES_DISCOUNT,
+                Config::DISPLAY_TYPE_EXCLUDING_TAX,
+                true
+            ],
+            [
+                'displaySalesDiscountBoth',
+                Config::XML_PATH_DISPLAY_SALES_DISCOUNT,
+                Config::DISPLAY_TYPE_BOTH,
+                true
+            ],
+            [
+                'displaySalesTaxWithGrandTotal',
+                Config::XML_PATH_DISPLAY_SALES_GRANDTOTAL,
+                true,
+                true
+            ],
+            [
+                'displaySalesFullSummary',
+                Config::XML_PATH_DISPLAY_SALES_FULL_SUMMARY,
+                true,
+                true
+            ],
+            [
+                'displaySalesZeroTax',
+                Config::XML_PATH_DISPLAY_SALES_ZERO_TAX,
+                true,
+                true
+            ],
+            [
+                'crossBorderTradeEnabled',
+                Config::CONFIG_XML_PATH_CROSS_BORDER_TRADE_ENABLED,
+                true,
+                true
+            ]
+        ];
+    }
+}
diff --git a/dev/tests/unit/testsuite/Magento/Tax/Pricing/AdjustmentTest.php b/dev/tests/unit/testsuite/Magento/Tax/Pricing/AdjustmentTest.php
index 74ea74b8a9059fd6e87fd0f067bd227b65908d10..ed4708b27ca52b1ad1eaeab53a2ff7c11b942c1b 100644
--- a/dev/tests/unit/testsuite/Magento/Tax/Pricing/AdjustmentTest.php
+++ b/dev/tests/unit/testsuite/Magento/Tax/Pricing/AdjustmentTest.php
@@ -119,6 +119,10 @@ class AdjustmentTest extends \PHPUnit_Framework_TestCase
             ->method('getPrice')
             ->with($object, $amount)
             ->will($this->returnValue($price));
+        $this->taxHelper->expects($this->any())
+            ->method('getPriceUnrounded')
+            ->with($object, $amount)
+            ->will($this->returnValue($price));
 
         $this->assertEquals($expectedResult, $this->adjustment->extractAdjustment($amount, $object));
     }
@@ -151,6 +155,10 @@ class AdjustmentTest extends \PHPUnit_Framework_TestCase
             ->method('getPrice')
             ->with($object, $amount, !$isPriceIncludesTax)
             ->will($this->returnValue($price));
+        $this->taxHelper->expects($this->any())
+            ->method('getPriceUnrounded')
+            ->with($object, $amount, !$isPriceIncludesTax)
+            ->will($this->returnValue($price));
 
         $this->assertEquals($expectedResult, $this->adjustment->applyAdjustment($amount, $object));
     }
diff --git a/lib/internal/Magento/Framework/AppInterface.php b/lib/internal/Magento/Framework/AppInterface.php
index 3800dabc2ff017e344791521dce2355ee4146945..0c82cf557f8ce0e2d685d0227a6dcfd64a8e65d4 100644
--- a/lib/internal/Magento/Framework/AppInterface.php
+++ b/lib/internal/Magento/Framework/AppInterface.php
@@ -35,7 +35,7 @@ interface AppInterface
     /**
      * Magento version
      */
-    const VERSION = '2.0.0.0-dev82';
+    const VERSION = '2.0.0.0-dev83';
 
     /**
      * Launch application