diff --git a/app/code/Magento/Bundle/Model/Product/Price.php b/app/code/Magento/Bundle/Model/Product/Price.php
index 83bfcbbabc2536ab0ee2f84525dcb4cca12aa883..d0aee24945f9d21df7c3d73350093206065b0429 100644
--- a/app/code/Magento/Bundle/Model/Product/Price.php
+++ b/app/code/Magento/Bundle/Model/Product/Price.php
@@ -533,6 +533,10 @@ class Price extends \Magento\Catalog\Model\Product\Type\Price
             $prevGroup = $allCustomersGroupId;
 
             foreach ($prices as $price) {
+                if (empty($price['percentage_value'])) {
+                    // can use only percentage tier price
+                    continue;
+                }
                 if ($price['cust_group'] != $custGroup && $price['cust_group'] != $allCustomersGroupId) {
                     // tier not for current customer group nor is for all groups
                     continue;
@@ -553,8 +557,8 @@ class Price extends \Magento\Catalog\Model\Product\Type\Price
                     continue;
                 }
 
-                if ($price['website_price'] > $prevPrice) {
-                    $prevPrice = $price['website_price'];
+                if ($price['percentage_value'] > $prevPrice) {
+                    $prevPrice = $price['percentage_value'];
                     $prevQty = $price['price_qty'];
                     $prevGroup = $price['cust_group'];
                 }
diff --git a/app/code/Magento/Bundle/Pricing/Price/TierPrice.php b/app/code/Magento/Bundle/Pricing/Price/TierPrice.php
index cbbf45e2dbb5f01187760b73f96c251fae49c1c5..fab49292d9bdea9f2ee02e1762385b979e15bdb0 100644
--- a/app/code/Magento/Bundle/Pricing/Price/TierPrice.php
+++ b/app/code/Magento/Bundle/Pricing/Price/TierPrice.php
@@ -8,6 +8,7 @@ namespace Magento\Bundle\Pricing\Price;
 
 use Magento\Catalog\Pricing\Price\RegularPrice;
 use Magento\Framework\Pricing\Amount\AmountInterface;
+use Magento\Framework\Pricing\PriceInfoInterface;
 
 /**
  * Bundle tier prices model
@@ -32,8 +33,25 @@ class TierPrice extends \Magento\Catalog\Pricing\Price\TierPrice implements Disc
     public function getDiscountPercent()
     {
         if ($this->percent === null) {
-            $percent = parent::getValue();
-            $this->percent = ($percent) ? max(0, min(100, 100 - $percent)) : null;
+            $prices = $this->getStoredTierPrices();
+            $prevQty = PriceInfoInterface::PRODUCT_QUANTITY_DEFAULT;
+            $this->value = $prevPrice = false;
+            $priceGroup = $this->groupManagement->getAllCustomersGroup()->getId();
+
+            foreach ($prices as $price) {
+                if (!$this->canApplyTierPrice($price, $priceGroup, $prevQty)
+                    || !isset($price['percentage_value'])
+                    || !is_numeric($price['percentage_value'])
+                ) {
+                    continue;
+                }
+                if (false === $prevPrice || $this->isFirstPriceBetter($price['website_price'], $prevPrice)) {
+                    $prevPrice = $price['website_price'];
+                    $prevQty = $price['price_qty'];
+                    $priceGroup = $price['cust_group'];
+                    $this->percent = max(0, min(100, 100 - $price['percentage_value']));
+                }
+            }
         }
         return $this->percent;
     }
@@ -90,13 +108,4 @@ class TierPrice extends \Magento\Catalog\Pricing\Price\TierPrice implements Disc
     {
         return true;
     }
-
-    /**
-     * @param AmountInterface $amount
-     * @return float
-     */
-    public function getSavePercent(AmountInterface $amount)
-    {
-        return round($amount->getBaseAmount());
-    }
 }
diff --git a/app/code/Magento/Bundle/Test/Unit/Model/Product/PriceTest.php b/app/code/Magento/Bundle/Test/Unit/Model/Product/PriceTest.php
index e97f0bbc1558dc3c63e02ef2c894b0d4423a61b2..9f7952e7ae8c882a5b747f9fd24855feea7c380e 100644
--- a/app/code/Magento/Bundle/Test/Unit/Model/Product/PriceTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Model/Product/PriceTest.php
@@ -90,7 +90,6 @@ class PriceTest extends \PHPUnit_Framework_TestCase
             false
         );
         $scopeConfig = $this->getMock(\Magento\Framework\App\Config\ScopeConfigInterface::class);
-
         $objectManagerHelper = new ObjectManagerHelper($this);
         $this->model = $objectManagerHelper->getObject(
             \Magento\Bundle\Model\Product\Price::class,
@@ -191,7 +190,6 @@ class PriceTest extends \PHPUnit_Framework_TestCase
         $dataObjectMock->expects($this->once())
             ->method('getValue')
             ->willReturn($value);
-
         $this->assertEquals(0, $this->model->getTotalBundleItemsPrice($productMock));
     }
 
@@ -245,7 +243,6 @@ class PriceTest extends \PHPUnit_Framework_TestCase
         $dataObjectMock->expects($this->once())
             ->method('getValue')
             ->willReturn('a:1:{i:0;s:1:"1";}');
-
         $productTypeMock->expects($this->once())
             ->method('getSelectionsByIds')
             ->with([1], $productMock)
diff --git a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/TierPriceTest.php b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/TierPriceTest.php
index 7b1f6181bb6f8ddc5951ce69e7564b7e2d1b1536..15bc06c2c6437d450ca480479b08a2cf1900d0de 100644
--- a/app/code/Magento/Bundle/Test/Unit/Pricing/Price/TierPriceTest.php
+++ b/app/code/Magento/Bundle/Test/Unit/Pricing/Price/TierPriceTest.php
@@ -188,9 +188,17 @@ class TierPriceTest extends \PHPUnit_Framework_TestCase
      */
     public function testGetSavePercent($baseAmount, $savePercent)
     {
+        $basePrice = 10.;
         $amount = $this->getMockForAbstractClass(\Magento\Framework\Pricing\Amount\AmountInterface::class);
         $amount->expects($this->once())->method('getBaseAmount')->willReturn($baseAmount);
+        $price = $this->getMock(\Magento\Framework\Pricing\Price\PriceInterface::class);
+        $price->expects($this->any())
+            ->method('getValue')
+            ->will($this->returnValue($basePrice));
 
+        $this->priceInfo->expects($this->any())
+            ->method('getPrice')
+            ->will($this->returnValue($price));
         $this->assertEquals($savePercent, $this->model->getSavePercent($amount));
     }
 
@@ -200,10 +208,8 @@ class TierPriceTest extends \PHPUnit_Framework_TestCase
     public function providerForTestGetSavePercent()
     {
         return [
-            'no fraction' => [10.0000, 10],
-            'lower half'  => [10.1234, 10],
-            'half way'    => [10.5000, 11],
-            'upper half'  => [10.6789, 11],
+            'no fraction' => [9.0000, 10],
+            'lower half'  => [9.1234, 9],
         ];
     }
 }
diff --git a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php
index 538c80d9b1cf27af4ba14c911b0d0a6913c403c7..4012af357e2c50e31c1052adae15ee1b1a4931bf 100644
--- a/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php
+++ b/app/code/Magento/Bundle/Ui/DataProvider/Product/Form/Modifier/BundlePanel.php
@@ -14,6 +14,8 @@ use Magento\Ui\Component\Container;
 use Magento\Ui\Component\DynamicRows;
 use Magento\Ui\Component\Form;
 use Magento\Ui\Component\Modal;
+use Magento\Catalog\Api\Data\ProductAttributeInterface;
+use Magento\Catalog\Model\Config\Source\ProductPriceOptionsInterface;
 
 /**
  * Create Ship Bundle Items and Affect Bundle Product Selections fields
@@ -73,6 +75,7 @@ class BundlePanel extends AbstractModifier
      */
     public function modifyMeta(array $meta)
     {
+        $meta = $this->removeFixedTierPrice($meta);
         $path = $this->arrayManager->findPath(static::CODE_BUNDLE_DATA, $meta, null, 'children');
 
         $meta = $this->arrayManager->merge(
@@ -178,6 +181,43 @@ class BundlePanel extends AbstractModifier
         return $meta;
     }
 
+    /**
+     * Remove option with fixed tier price from config.
+     *
+     * @param array $meta
+     * @return array
+     */
+    private function removeFixedTierPrice(array $meta)
+    {
+        $tierPricePath = $this->arrayManager->findPath(
+            ProductAttributeInterface::CODE_TIER_PRICE,
+            $meta,
+            null,
+            'children'
+        );
+        $pricePath =  $this->arrayManager->findPath(
+            ProductAttributeInterface::CODE_TIER_PRICE_FIELD_PRICE,
+            $meta,
+            $tierPricePath
+        );
+        $pricePath = $this->arrayManager->slicePath($pricePath, 0, -1) . '/value_type/arguments/data/options';
+
+        $price = $this->arrayManager->get($pricePath, $meta);
+        $meta = $this->arrayManager->remove($pricePath, $meta);
+        foreach ($price as $key => $item) {
+            if ($item['value'] == ProductPriceOptionsInterface::VALUE_FIXED) {
+                unset($price[$key]);
+            }
+        }
+        $meta = $this->arrayManager->merge(
+            $this->arrayManager->slicePath($pricePath, 0, -1),
+            $meta,
+            ['options' => $price]
+        );
+
+        return $meta;
+    }
+
     /**
      * {@inheritdoc}
      */
diff --git a/app/code/Magento/Bundle/etc/adminhtml/di.xml b/app/code/Magento/Bundle/etc/adminhtml/di.xml
index ca93dd5365160fd84372425a11fd5aff32972851..19b683027dfa14062883d4d80430f68a7c6ce49e 100644
--- a/app/code/Magento/Bundle/etc/adminhtml/di.xml
+++ b/app/code/Magento/Bundle/etc/adminhtml/di.xml
@@ -27,11 +27,11 @@
             <argument name="modifiers" xsi:type="array">
                 <item name="bundle" xsi:type="array">
                     <item name="class" xsi:type="string">Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\Composite</item>
-                    <item name="sortOrder" xsi:type="number">125</item>
+                    <item name="sortOrder" xsi:type="number">180</item>
                 </item>
                 <item name="bundle_stock_data" xsi:type="array">
                     <item name="class" xsi:type="string">Magento\Bundle\Ui\DataProvider\Product\Form\Modifier\StockData</item>
-                    <item name="sortOrder" xsi:type="number">126</item>
+                    <item name="sortOrder" xsi:type="number">190</item>
                 </item>
             </argument>
         </arguments>
diff --git a/app/code/Magento/Bundle/etc/di.xml b/app/code/Magento/Bundle/etc/di.xml
index 2d3913d72e579302ac9cd1f0e23d6b235f9c6b23..3425b9323ed4d4e18fd8be5342a4139be87291f3 100644
--- a/app/code/Magento/Bundle/etc/di.xml
+++ b/app/code/Magento/Bundle/etc/di.xml
@@ -130,4 +130,5 @@
             </argument>
         </arguments>
     </type>
+
 </config>
diff --git a/app/code/Magento/Bundle/view/base/templates/product/price/tier_prices.phtml b/app/code/Magento/Bundle/view/base/templates/product/price/tier_prices.phtml
index 3285603c431a219f76698b9e5e8d41571b285c11..63f090acf34dfb477521f992b2ee0f8d1eb6ff17 100644
--- a/app/code/Magento/Bundle/view/base/templates/product/price/tier_prices.phtml
+++ b/app/code/Magento/Bundle/view/base/templates/product/price/tier_prices.phtml
@@ -22,7 +22,7 @@ $tierPrices = $tierPriceModel->getTierPriceList();
                 <?php /* @escapeNotVerified */ echo __(
                     'Buy %1 with %2 discount each',
                     $price['price_qty'],
-                    '<strong class="benefit">' . $tierPriceModel->getSavePercent($price['price']) . '%</strong>'
+                    '<strong class="benefit">' . round($price['percentage_value']) . '%</strong>'
                 ); ?>
             </li>
         <?php endforeach; ?>
diff --git a/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Price.php b/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Price.php
index b994c787bee7aa76f8a4baa3648bcbb2c0e4ee27..5e518df37db1a574f25fe008510e75742cdffa9c 100644
--- a/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Price.php
+++ b/app/code/Magento/Catalog/Model/Config/Source/Product/Options/Price.php
@@ -23,7 +23,7 @@ class Price implements ProductPriceOptionsInterface
     {
         return [
             ['value' => self::VALUE_FIXED, 'label' => __('Fixed')],
-            ['value' => self::VALUE_PERCENT, 'label' => __('Percent')],
+            ['value' => self::VALUE_PERCENT, 'label' => __('Discount')],
         ];
     }
 }
diff --git a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php
index 480f8e8942e87f200ce3829641ea026d351b1967..460204a478d9d75ac86dbaa4e8d3684ea26b8812 100644
--- a/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php
+++ b/app/code/Magento/Catalog/Model/Product/Attribute/Backend/Tierprice.php
@@ -157,6 +157,7 @@ class Tierprice extends \Magento\Catalog\Model\Product\Attribute\Backend\GroupPr
         $data = parent::modifyPriceData($object, $data);
         foreach ($data as $key => $tierPrice) {
             if ($this->getPercentage($tierPrice)) {
+                $data[$key]['price'] = $object->getPrice() * (1 - $this->getPercentage($tierPrice) / 100);
                 $data[$key]['website_price'] = $object->getPrice() * (1 - $this->getPercentage($tierPrice) / 100);
             }
         }
diff --git a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php
index ac511edcf2e5338eba6b83c60cf38a749406cf89..9b382464e8e2392fb07d81c070bae66cce7c203f 100644
--- a/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php
+++ b/app/code/Magento/Catalog/Ui/DataProvider/Product/Form/Modifier/TierPrice.php
@@ -109,6 +109,7 @@ class TierPrice extends AbstractModifier
                             'label' => __('Price'),
                             'enableLabel' => true,
                             'dataScope' => '',
+                            'additionalClasses' => 'control-grouped',
                             'sortOrder' => isset($priceMeta['arguments']['data']['config']['sortOrder'])
                                 ? $priceMeta['arguments']['data']['config']['sortOrder'] : 40,
                         ],
diff --git a/app/code/Magento/Persistent/Model/Observer.php b/app/code/Magento/Persistent/Model/Observer.php
index 283d7bb45a5e832b0f4450a7633f6d27056d85ca..392d88a29a58137c04209a91107a4a4cc2f7001d 100644
--- a/app/code/Magento/Persistent/Model/Observer.php
+++ b/app/code/Magento/Persistent/Model/Observer.php
@@ -121,6 +121,13 @@ class Observer
     public function emulateTopLinks($block)
     {
         $this->_applyAccountLinksPersistentData();
-        $block->removeLinkByUrl($this->_url->getUrl('customer/account/login'));
+        /** @var \Magento\Framework\View\Element\Html\Link[] $links */
+        $links = $block->getLinks();
+        $removeLink = $this->_url->getUrl('customer/account/login');
+        foreach ($links as $link) {
+            if ($link->getHref() == $removeLink) {
+                $this->_layout->unsetChild($block->getNameInLayout(), $link->getNameInLayout());
+            }
+        }
     }
 }
diff --git a/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less b/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less
index 304f895a85b969dfe95acd4e3dddb0607940432f..77a769d8f5a36cc4788031b5efa4d57c85481106 100644
--- a/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less
+++ b/app/design/adminhtml/Magento/backend/Magento_Catalog/web/css/source/_module.less
@@ -78,3 +78,19 @@
         margin-top: -@indent__base;
     }
 }
+
+//
+//  Advanced Price panel
+//  ---------------------------------------------
+
+.admin__control-fields {
+    .control-grouped {
+        .lib-vendor-prefix-display(inline-flex);
+        .lib-vendor-prefix-flex-direction(row);
+
+        .admin__field + .admin__field {
+            margin-left: @indent__s;
+            margin-top: 0;
+        }
+    }
+}
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php
index 1bc689d8e1b1e3009bbf2f3fc563b3aa51ccc3c7..f8266026b3927798fa2a04128deb65a70254188e 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Constraint/AssertProductTierPriceInCart.php
@@ -110,7 +110,7 @@ class AssertProductTierPriceInCart extends AbstractConstraint
     {
         $tierPrice = $product->getDataFieldConfig('tier_price')['source']->getData()[0];
 
-        if ($tierPrice['value_type'] === "Percent") {
+        if ($tierPrice['value_type'] === "Discount") {
             $this->fixtureActualPrice = $this->fixturePrice * (1 - $tierPrice['percentage_value'] / 100);
         } else {
             $this->fixtureActualPrice = $tierPrice['price'];
diff --git a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/TierPrice.xml b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/TierPrice.xml
index 2f517f4d6cf3cc03020abc575d4e91cd7f7188da..9581427d16ec6f9e597e420dcee0329c2dddee32 100644
--- a/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/TierPrice.xml
+++ b/dev/tests/functional/tests/app/Magento/Catalog/Test/Repository/Product/TierPrice.xml
@@ -92,7 +92,7 @@
 
         <dataset name="custom_with_percentage_discount">
             <field name="0" xsi:type="array">
-                <item name="value_type" xsi:type="string">Percent</item>
+                <item name="value_type" xsi:type="string">Discount</item>
                 <item name="percentage_value" xsi:type="string">3</item>
                 <item name="website" xsi:type="string">All Websites [USD]</item>
                 <item name="price_qty" xsi:type="string">10</item>
diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithTierPriceCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithTierPriceCalculatorTest.php
index 0be5adcb304f772218e588795f3f6ef26ce0721c..c2c62aa2ce093e3b52502ec5c234d3932cdbe3b4 100644
--- a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithTierPriceCalculatorTest.php
+++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/DynamicBundleWithTierPriceCalculatorTest.php
@@ -201,7 +201,8 @@ class DynamicBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -239,7 +240,8 @@ class DynamicBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -281,7 +283,8 @@ class DynamicBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -323,7 +326,8 @@ class DynamicBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -365,7 +369,8 @@ class DynamicBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -422,7 +427,8 @@ class DynamicBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -479,7 +485,8 @@ class DynamicBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -536,7 +543,8 @@ class DynamicBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -578,7 +586,8 @@ class DynamicBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         $tierPriceSimpleProductData = [
diff --git a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithTierPriceCalculatorTest.php b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithTierPriceCalculatorTest.php
index bd148080631aea892cccb0fab6fd0321d08c231b..aa020fe1f5a2b89e6d1e1eb922c0dee8412f4de7 100644
--- a/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithTierPriceCalculatorTest.php
+++ b/dev/tests/integration/testsuite/Magento/Bundle/Model/Product/FixedBundleWithTierPriceCalculatorTest.php
@@ -495,7 +495,8 @@ class FixedBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -544,7 +545,8 @@ class FixedBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -601,7 +603,8 @@ class FixedBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -664,7 +667,8 @@ class FixedBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -727,7 +731,8 @@ class FixedBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -790,7 +795,8 @@ class FixedBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
@@ -872,7 +878,8 @@ class FixedBundleWithTierPriceCalculatorTest extends BundlePriceAbstract
         $tierPriceData = [
             'customer_group_id' => \Magento\Customer\Model\Group::NOT_LOGGED_IN_ID,
             'qty' => 1,
-            'value' => 50
+            'value' => 50,
+            'extension_attributes' => new \Magento\Framework\DataObject(['percentage_value' => 50])
         ];
 
         return [
diff --git a/dev/tests/integration/testsuite/Magento/Bundle/_files/product_with_tier_pricing.php b/dev/tests/integration/testsuite/Magento/Bundle/_files/product_with_tier_pricing.php
index 6d6d10ce4d220fc45047d140621a784ea44413c6..9574948dae900e292e38d55a306d4a7fe8706955 100644
--- a/dev/tests/integration/testsuite/Magento/Bundle/_files/product_with_tier_pricing.php
+++ b/dev/tests/integration/testsuite/Magento/Bundle/_files/product_with_tier_pricing.php
@@ -41,18 +41,21 @@ $product->setTypeId('bundle')
                'cust_group' => \Magento\Customer\Model\GroupManagement::CUST_GROUP_ALL,
                'price_qty'  => 2,
                'price'      => 8,
+               'percentage_value' => 8
            ],
             [
                 'website_id' => 0,
                 'cust_group' => \Magento\Customer\Model\GroupManagement::CUST_GROUP_ALL,
                 'price_qty'  => 5,
                 'price'      => 30,
+                'percentage_value' => 30
             ],
            [
                'website_id' => 0,
                'cust_group' => \Magento\Customer\Model\GroupManagement::NOT_LOGGED_IN_ID,
                'price_qty'  => 3,
                'price'      => 20,
+               'percentage_value' => 20
            ],
         ]
     )
diff --git a/setup/src/Magento/Setup/Fixtures/AttributeSetsFixture.php b/setup/src/Magento/Setup/Fixtures/AttributeSetsFixture.php
index 5617eca9a0e7e24694c151d508ed09a4cd547999..1bdffb253ae1f06f24647cf7efbc85d0801286f9 100644
--- a/setup/src/Magento/Setup/Fixtures/AttributeSetsFixture.php
+++ b/setup/src/Magento/Setup/Fixtures/AttributeSetsFixture.php
@@ -16,12 +16,27 @@ class AttributeSetsFixture extends Fixture
      */
     protected $priority = 25;
 
+    /**
+     * Cache for attribute IDs.
+     *
+     * @var array
+     */
+    private $attributeIdsCache = [];
+
+    /**
+     * Quantity of unique attributes to generate. Zero means infinity.
+     *
+     * @var int
+     */
+    protected $uniqueAttributesQuantity = 0;
+
     /**
      * {@inheritdoc}
      */
     public function execute()
     {
-        $attributeSets = $this->fixtureModel->getValue('attribute_sets', null);
+        $this->populateUniqueAttributesQuantity();
+        $attributeSets = $this->getAttributeSetsFixtureValue();
         if ($attributeSets === null) {
             return;
         }
@@ -71,37 +86,81 @@ class AttributeSetsFixture extends Fixture
             $attributesData = array_key_exists(0, $attributeSetData['attributes']['attribute'])
                 ? $attributeSetData['attributes']['attribute'] : [$attributeSetData['attributes']['attribute']];
             foreach ($attributesData as $attributeData) {
-                //Create Attribute
-                /** @var  \Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory $attributeFactory */
-                $attributeFactory = $this->fixtureModel->getObjectManager()->create(
-                    \Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory::class
-                );
-
-                $optionsData = array_key_exists(0, $attributeData['options']['option'])
-                    ? $attributeData['options']['option'] : [$attributeData['options']['option']];
-                $options = [];
-                foreach ($optionsData as $optionData) {
-                    /** @var \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory */
-                    $optionFactory = $this->fixtureModel->getObjectManager()->create(
-                        \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory::class
+                if ($this->uniqueAttributesQuantity === 0
+                    || (count($this->attributeIdsCache) < $this->uniqueAttributesQuantity)) {
+                    //Create Attribute
+                    /** @var  \Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory $attributeFactory */
+                    $attributeFactory = $this->fixtureModel->getObjectManager()->create(
+                        \Magento\Catalog\Api\Data\ProductAttributeInterfaceFactory::class
                     );
-                    $option = $optionFactory->create(['data' => $optionData]);
-                    $options[] = $option;
-                }
 
-                $attribute = $attributeFactory->create(['data' => $attributeData]);
-                $attribute->setOptions($options);
+                    $optionsData = array_key_exists(0, $attributeData['options']['option'])
+                        ? $attributeData['options']['option'] : [$attributeData['options']['option']];
+                    $options = [];
+                    foreach ($optionsData as $optionData) {
+                        /** @var \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory $optionFactory */
+                        $optionFactory = $this->fixtureModel->getObjectManager()->create(
+                            \Magento\Eav\Api\Data\AttributeOptionInterfaceFactory::class
+                        );
+                        $option = $optionFactory->create(['data' => $optionData]);
+                        $options[] = $option;
+                    }
 
-                $result = $attributeRepository->save($attribute);
-                $attributeId = $result->getAttributeId();
+                    $attribute = $attributeFactory->create(['data' => $attributeData]);
+                    $attribute->setOptions($options);
 
+                    $result = $attributeRepository->save($attribute);
+                    $attributeId = $result->getAttributeId();
+                    $this->fillAttributeIdsCache($attributeId);
+                } else {
+                    $attributeId = $this->getAttributeIdFromCache();
+                }
                 //Associate Attribute to Attribute Set
                 $sortOrder = 3;
+
                 $attributeManagement->assign($attributeSetId, $attributeGroupId, $attributeId, $sortOrder);
             }
         }
     }
 
+    /**
+     * Get attribute ID from cache.
+     *
+     * @return int
+     */
+    private function getAttributeIdFromCache()
+    {
+        $attributeId = next($this->attributeIdsCache);
+        if ($attributeId === false) {
+            $attributeId = reset($this->attributeIdsCache);
+        }
+
+        return $attributeId;
+    }
+
+    /**
+     * Fill attribute IDs cache.
+     *
+     * @param int $attributeId
+     * @return void
+     */
+    private function fillAttributeIdsCache($attributeId)
+    {
+        if ($this->uniqueAttributesQuantity !== 0) {
+            $this->attributeIdsCache[] = $attributeId;
+        }
+    }
+
+    /**
+     * Populate quantity of unique attributes to generate.
+     *
+     * @return void
+     */
+    protected function populateUniqueAttributesQuantity()
+    {
+        $this->uniqueAttributesQuantity = $this->fixtureModel->getValue('unique_attributes_quantity', 0);
+    }
+
     /**
      * {@inheritdoc}
      */
@@ -119,4 +178,14 @@ class AttributeSetsFixture extends Fixture
             'attribute_sets' => 'Attribute Sets'
         ];
     }
+
+    /**
+     * Get attribute sets fixture value.
+     *
+     * @return array|null
+     */
+    protected function getAttributeSetsFixtureValue()
+    {
+        return $this->fixtureModel->getValue('attribute_sets', null);
+    }
 }
diff --git a/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php b/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php
index 2340de71cf78363ed00fd9248577e7479b6dc012..9e84578281c5d65b8a84b384aab699b266c7286b 100644
--- a/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php
+++ b/setup/src/Magento/Setup/Fixtures/ConfigurableProductsFixture.php
@@ -25,6 +25,13 @@ class ConfigurableProductsFixture extends SimpleProductsFixture
      */
     protected $searchConfig;
 
+    /**
+     * Variations count.
+     *
+     * @var int
+     */
+    protected $variationsCount;
+
     //@codingStandardsIgnoreStart
     /**
      * Get CSV template headers
@@ -169,7 +176,7 @@ class ConfigurableProductsFixture extends SimpleProductsFixture
     )
     {
         return [
-            'sku' => 'Configurable Product %s' . $suffix,
+            'sku' => $this->getConfigurableProductSkuPattern() . $suffix,
             'store_view_code' => '',
             'attribute_set_code' => $attributeSetClosure,
             'additional_attributes' => $additionalAttributesClosure,
@@ -225,8 +232,8 @@ class ConfigurableProductsFixture extends SimpleProductsFixture
             'updated_at' => '2013-10-25 15:12:39',
             'upsell_tgtr_position_behavior' => '',
             'upsell_tgtr_position_limit' => '',
-            'url_key' => "configurable-product-%s{$suffix}",
-            'url_path' => "configurable-product-%s{$suffix}",
+            'url_key' => $this->getUrlKeyPrefix() . "{$suffix}",
+            'url_path' => $this->getUrlKeyPrefix() . "{$suffix}",
             'visibility' => 'Catalog, Search',
             'weight' => '',
             'qty' => 333,
@@ -305,7 +312,7 @@ class ConfigurableProductsFixture extends SimpleProductsFixture
         $data = [];
         for ($i = 1; $i <= $optionsNumber; $i++) {
             $productData = [
-                'sku' => "Configurable Product %s-option {$i}{$suffix}",
+                'sku' => $this->getConfigurableOptionSkuPattern() . "{$i}{$suffix}",
                 'store_view_code' => '',
                 'attribute_set_code' => $attributeSetClosure,
                 'additional_attributes' => $additionalAttributesClosure,
@@ -361,8 +368,8 @@ class ConfigurableProductsFixture extends SimpleProductsFixture
                 'updated_at' => '2013-10-25 15:12:32',
                 'upsell_tgtr_position_behavior' => '',
                 'upsell_tgtr_position_limit' => '',
-                'url_key' => "simple-of-configurable-product-{$suffix}-%s-option-{$i}",
-                'url_path' => "simple-of-configurable-product-{$suffix}-%s-option-{$i}",
+                'url_key' => $this->getOptionUrlKeyPrefix() . "-{$suffix}-%s-option-{$i}",
+                'url_path' => $this->getOptionUrlKeyPrefix() . "-{$suffix}-%s-option-{$i}",
                 'variations' => '',
                 'variations_1382710717' => '',
                 'variations_1382710773' => '',
@@ -431,7 +438,7 @@ class ConfigurableProductsFixture extends SimpleProductsFixture
      */
     public function execute()
     {
-        $configurableProductsCount = $this->fixtureModel->getValue('configurable_products', 0);
+        $configurableProductsCount = $this->getConfigurableProductsValue();
         if (!$configurableProductsCount) {
             return;
         }
@@ -440,170 +447,147 @@ class ConfigurableProductsFixture extends SimpleProductsFixture
         $maxAmountOfWordsShortDescription = $this->getSearchConfigValue('max_amount_of_words_short_description');
         $minAmountOfWordsDescription = $this->getSearchConfigValue('min_amount_of_words_description');
         $minAmountOfWordsShortDescription = $this->getSearchConfigValue('min_amount_of_words_short_description');
+        $configurableProductsWithAttributes = [];
 
-        $attributes = $this->getAttributes();
-        $searchTerms = $this->getSearchTerms();
-        $this->fixtureModel->resetObjectManager();
-        $result = $this->getCategoriesAndWebsites();
-        $variationCount = $this->fixtureModel->getValue('configurable_products_variation', 3);
-        $result = array_values($result);
-        $dataGenerator = new DataGenerator(realpath(__DIR__ . '/' . 'dictionary.csv'));
-
-        $productWebsiteClosure = function ($index) use ($result) {
-            return $result[$index % count($result)][0];
-        };
-        $productCategoryClosure = function ($index) use ($result) {
-            return $result[$index % count($result)][2] . '/' . $result[$index % count($result)][1];
-        };
-        $shortDescriptionClosure = function ($index)
-        use (
-            $searchTerms,
-            $simpleProductsCount,
-            $configurableProductsCount,
-            $dataGenerator,
-            $maxAmountOfWordsShortDescription,
-            $minAmountOfWordsShortDescription
-        )
-        {
-            $count = $searchTerms === null
-                ? 0
-                : round(
-                    $searchTerms[$index % count($searchTerms)]['count'] * (
-                        $configurableProductsCount / ($simpleProductsCount + $configurableProductsCount)
-                    )
-                );
-            mt_srand($index);
-            return $dataGenerator->generate(
-                $minAmountOfWordsShortDescription,
-                $maxAmountOfWordsShortDescription,
-                'shortDescription-' . $index
-            ) . ($index <= ($count * count($searchTerms)) ? ' '
-                . $searchTerms[$index % count($searchTerms)]['term'] : '');
-        };
-        $descriptionClosure = function ($index)
-        use (
-            $searchTerms,
-            $simpleProductsCount,
-            $configurableProductsCount,
-            $dataGenerator,
-            $maxAmountOfWordsDescription,
-            $minAmountOfWordsDescription
-        )
-        {
-            $count = $searchTerms === null
-                ? 0
-                : round(
-                    $searchTerms[$index % count($searchTerms)]['count'] * (
-                        $configurableProductsCount / ($simpleProductsCount + $configurableProductsCount)
-                    )
-                );
-            mt_srand($index);
-            return $dataGenerator->generate(
-                $minAmountOfWordsDescription,
-                $maxAmountOfWordsDescription,
-                'description-' . $index
-            ) . ($index <= ($count * count($searchTerms))
-                ? ' ' . $searchTerms[$index % count($searchTerms)]['term'] : '');
-        };
-        $priceClosure = function($index) {
-            mt_srand($index);
-            switch (mt_rand(0,3)) {
-                case 0: return 9.99;
-                case 1: return 5;
-                case 2: return 1;
-                case 3: return mt_rand(1,10000)/10;
-            }
-        };
-        $attributeSetClosure = function($index) use ($attributes, $result) {
-            mt_srand($index);
-            $attributeSet =  (count(array_keys($attributes)) > (($index - 1) % count($result))
-                ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default');
-            return $attributeSet;
-        };
-        $variationClosure = function($index, $variationIndex) use ($attributes, $result, $variationCount) {
-            mt_srand($index);
-            $attributeSetCode = (count(array_keys($attributes)) > (($index - 1) % count($result))
-                ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default');
-            $skus = [];
-            for ($i=1; $i <= $variationCount; $i++) {
-                $skus[] = 'sku=Configurable Product ' . $index . '-option ' . $i;
-            }
-            $values = [];
-            if ($attributeSetCode == 'Default') {
-                for ($i=1; $i <= $variationCount; $i++) {
-                    $values[] =  'configurable_variation=option ' . $i;
-                }
+        if ($this->getAdditionalConfigurableProductsVariations() === null) {
+            $configurableProductsWithAttributes[$configurableProductsCount]
+                = $this->getConfigurableProductsVariationsValue();
+        } else {
+            if (strpos($this->getAdditionalConfigurableProductsVariations(), ',')) {
+                $variations = explode(',', $this->getAdditionalConfigurableProductsVariations());
             } else {
-                for ($i=$variationCount; $i > 0; $i--) {
-                    $attributeValues = '';
-                    foreach ($attributes[$attributeSetCode] as $attribute) {
-                        $attributeValues = $attributeValues . $attribute['name'] . "=" .
-                            $attribute['values'][($variationIndex - $i) % count($attribute['values'])] . ",";
-                    }
-                    $values [] = $attributeValues;
-                }
+                $variations = [$this->getAdditionalConfigurableProductsVariations()];
             }
-            $variations = [];
-            for ($i=0; $i < $variationCount; $i++) {
-                $variations[] = trim(implode(",",[$skus[$i],$values[$i]]), ",");
+
+            foreach ($variations as $variation) {
+                $value = explode(':', $variation);
+                $configurableProductsWithAttributes[$value[0]] = $value[1];
             }
-            return implode("|",$variations);
-        };
-        $additionalAttributesClosure = function($index, $variationIndex) use ($attributes, $result) {
-            $attributeValues = '';
-            mt_srand($index);
-            $attributeSetCode = (count(array_keys($attributes)) > (($index - 1) % count($result))
-                ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default');
-            if ($attributeSetCode !== 'Default' ) {
-                foreach ($attributes[$attributeSetCode] as $attribute) {
-                    $attributeValues = $attributeValues . $attribute['name'] . "=" .
-                        $attribute['values'][$variationIndex %  count($attribute['values'])] . ",";
+        }
+
+        foreach ($configurableProductsWithAttributes as $productsCount => $variationsCount) {
+            $this->variationsCount = $variationsCount;
+            $configurableProductsCount = $productsCount;
+            $attributes = $this->getAttributes();
+            $searchTerms = $this->getSearchTerms();
+            $this->fixtureModel->resetObjectManager();
+            $result = $this->getCategoriesAndWebsites();
+            $result = array_values($result);
+            $dataGenerator = new DataGenerator(realpath(__DIR__ . '/' . 'dictionary.csv'));
+
+            $productWebsiteClosure = function ($index) use ($result) {
+                return $result[$index % count($result)][0];
+            };
+            $productCategoryClosure = function ($index) use ($result) {
+                return $result[$index % count($result)][2] . '/' . $result[$index % count($result)][1];
+            };
+            $shortDescriptionClosure = function ($index)
+            use (
+                $searchTerms,
+                $simpleProductsCount,
+                $configurableProductsCount,
+                $dataGenerator,
+                $maxAmountOfWordsShortDescription,
+                $minAmountOfWordsShortDescription
+            ) {
+                $count = $searchTerms === null
+                    ? 0
+                    : round(
+                        $searchTerms[$index % count($searchTerms)]['count'] * (
+                            $configurableProductsCount / ($simpleProductsCount + $configurableProductsCount)
+                        )
+                    );
+                mt_srand($index);
+                return $dataGenerator->generate(
+                    $minAmountOfWordsShortDescription,
+                    $maxAmountOfWordsShortDescription,
+                    'shortDescription-' . $index
+                ) . ($index <= ($count * count($searchTerms)) ? ' '
+                    . $searchTerms[$index % count($searchTerms)]['term'] : '');
+            };
+            $descriptionClosure = function ($index)
+            use (
+                $searchTerms,
+                $simpleProductsCount,
+                $configurableProductsCount,
+                $dataGenerator,
+                $maxAmountOfWordsDescription,
+                $minAmountOfWordsDescription
+            ) {
+                $count = $searchTerms === null
+                    ? 0
+                    : round(
+                        $searchTerms[$index % count($searchTerms)]['count'] * (
+                            $configurableProductsCount / ($simpleProductsCount + $configurableProductsCount)
+                        )
+                    );
+                mt_srand($index);
+                return $dataGenerator->generate(
+                    $minAmountOfWordsDescription,
+                    $maxAmountOfWordsDescription,
+                    'description-' . $index
+                ) . ($index <= ($count * count($searchTerms))
+                    ? ' ' . $searchTerms[$index % count($searchTerms)]['term'] : '');
+            };
+            $priceClosure = function ($index) {
+                mt_srand($index);
+                switch (mt_rand(0, 3)) {
+                    case 0:
+                        return 9.99;
+                    case 1:
+                        return 5;
+                    case 2:
+                        return 1;
+                    case 3:
+                        return mt_rand(1, 10000) / 10;
                 }
-            }
-            return trim($attributeValues, ",");
-        };
-        /**
-         * Create configurable products
-         */
-        $pattern = new Pattern();
-        $pattern->setHeaders($this->getHeaders());
-        $pattern->setRowsSet(
-            $this->getRows(
-                $productCategoryClosure,
-                $productWebsiteClosure,
-                $shortDescriptionClosure,
-                $descriptionClosure,
-                $priceClosure,
-                $attributeSetClosure,
-                $additionalAttributesClosure,
-                $variationClosure,
-                $variationCount
-            )
-        );
+            };
+            $attributeSetClosure = $this->getAttributeSetClosure($attributes, $result);
+            $variationClosure = $this->getVariationsClosure($attributes, $result, $variationsCount);
+            $additionalAttributesClosure = $this->getAdditionalAttributesClosure($attributes, $result);
+            /**
+             * Create configurable products
+             */
+            $pattern = new Pattern();
+            $pattern->setHeaders($this->getHeaders());
+            $pattern->setRowsSet(
+                $this->getRows(
+                    $productCategoryClosure,
+                    $productWebsiteClosure,
+                    $shortDescriptionClosure,
+                    $descriptionClosure,
+                    $priceClosure,
+                    $attributeSetClosure,
+                    $additionalAttributesClosure,
+                    $variationClosure,
+                    $variationsCount
+                )
+            );
 
-        /** @var \Magento\ImportExport\Model\Import $import */
-        $import = $this->fixtureModel->getObjectManager()->create(
-            \Magento\ImportExport\Model\Import::class,
-            [
-                'data' => [
-                    'entity' => 'catalog_product',
-                    'behavior' => 'append',
-                    'validation_strategy' => 'validation-stop-on-errors',
-                ],
-            ]
-        );
+            /** @var \Magento\ImportExport\Model\Import $import */
+            $import = $this->fixtureModel->getObjectManager()->create(
+                \Magento\ImportExport\Model\Import::class,
+                [
+                    'data' => [
+                        'entity' => 'catalog_product',
+                        'behavior' => 'append',
+                        'validation_strategy' => 'validation-stop-on-errors',
+                    ],
+                ]
+            );
 
-        $source = $this->fixtureModel->getObjectManager()->create(
-            Generator::class,
-            ['rowPattern' => $pattern, 'count' => $configurableProductsCount]
-        );
-        // it is not obvious, but the validateSource() will actually save import queue data to DB
-        if (!$import->validateSource($source)) {
-            throw new \Exception($import->getFormatedLogTrace());
-        }
-        // this converts import queue into actual entities
-        if (!$import->importSource()) {
-            throw new \Exception($import->getFormatedLogTrace());
+            $source = $this->fixtureModel->getObjectManager()->create(
+                Generator::class,
+                ['rowPattern' => $pattern, 'count' => $configurableProductsCount]
+            );
+            // it is not obvious, but the validateSource() will actually save import queue data to DB
+            if (!$import->validateSource($source)) {
+                throw new \Exception($import->getFormatedLogTrace());
+            }
+            // this converts import queue into actual entities
+            if (!$import->importSource()) {
+                throw new \Exception($import->getFormatedLogTrace());
+            }
         }
     }
     // @codingStandardsIgnoreEnd
@@ -674,4 +658,166 @@ class ConfigurableProductsFixture extends SimpleProductsFixture
         }
         return $result;
     }
+
+    /**
+     * Get configurable products value.
+     *
+     * @return int
+     */
+    protected function getConfigurableProductsValue()
+    {
+        return $this->fixtureModel->getValue('configurable_products', 0);
+    }
+
+    /**
+     * Get configurable products variations value.
+     *
+     * @return int
+     */
+    protected function getConfigurableProductsVariationsValue()
+    {
+        return $this->fixtureModel->getValue('configurable_products_variation', 3);
+    }
+
+    /**
+     * Get attribute set closure
+     *
+     * @param array $attributes
+     * @param array $result
+     * @return \Closure
+     */
+    protected function getAttributeSetClosure(array $attributes, array $result)
+    {
+        return function ($index) use ($attributes, $result) {
+            mt_srand($index);
+            $attributeSet =  (count(array_keys($attributes)) > (($index - 1) % count($result))
+                ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default');
+            return $attributeSet;
+        };
+    }
+
+    /**
+     * Get additional attributes closure.
+     *
+     * @param array $attributes
+     * @param array $result
+     * @return \Closure
+     */
+    protected function getAdditionalAttributesClosure(array $attributes, array $result)
+    {
+        return function ($index, $variationIndex) use ($attributes, $result) {
+            $attributeValues = '';
+            mt_srand($index);
+            $attributeSetCode = (count(array_keys($attributes)) > (($index - 1) % count($result))
+                ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default');
+            if ($attributeSetCode !== 'Default') {
+                foreach ($attributes[$attributeSetCode] as $attribute) {
+                    $attributeValues = $attributeValues . $attribute['name'] . "=" .
+                        $attribute['values'][$variationIndex %  count($attribute['values'])] . ",";
+                }
+            }
+            return trim($attributeValues, ",");
+        };
+    }
+
+    /**
+     * Get variations closure.
+     *
+     * @param array $attributes
+     * @param array $result
+     * @param int $variationCount
+     * @return \Closure
+     */
+    protected function getVariationsClosure(array $attributes, array $result, $variationCount)
+    {
+        return function ($index, $variationIndex) use ($attributes, $result, $variationCount) {
+            mt_srand($index);
+            $attributeSetCode = (count(array_keys($attributes)) > (($index - 1) % count($result))
+                ? array_keys($attributes)[mt_rand(0, count(array_keys($attributes)) - 1)] : 'Default');
+            $skus = [];
+            for ($i = 1; $i <= $variationCount; $i++) {
+                $skus[] = 'sku=' . sprintf($this->getConfigurableOptionSkuPattern(), $index) . $i;
+            }
+            $values = [];
+            if ($attributeSetCode == 'Default') {
+                for ($i = 1; $i <= $variationCount; $i++) {
+                    $values[] = 'configurable_variation=option ' . $i;
+                }
+            } else {
+                for ($i = $variationCount; $i > 0; $i--) {
+                    $attributeValues = '';
+                    foreach ($attributes[$attributeSetCode] as $attribute) {
+                        $attributeValues = $attributeValues . $attribute['name'] . "=" .
+                            $attribute['values'][($variationIndex - $i) % count($attribute['values'])] . ",";
+                    }
+                    $values [] = $attributeValues;
+                }
+            }
+            $variations = [];
+            for ($i = 0; $i < $variationCount; $i++) {
+                $variations[] = trim(implode(",", [$skus[$i], $values[$i]]), ",");
+            }
+            return implode("|", $variations);
+        };
+    }
+
+    /**
+     * Get configurable product sku pattern.
+     *
+     * @return string
+     */
+    private function getConfigurableProductSkuPattern()
+    {
+        return 'Configurable Product ' . $this->getConfigurableProductPrefix() . ' %s';
+    }
+
+    /**
+     * Get configurable option sku pattern.
+     *
+     * @return string
+     */
+    protected function getConfigurableOptionSkuPattern()
+    {
+        return 'Configurable Product ' . $this->getConfigurableProductPrefix() . '%s-option';
+    }
+
+    /**
+     * Get url key prefix.
+     *
+     * @return string
+     */
+    private function getUrlKeyPrefix()
+    {
+        return 'configurable-product' . $this->getConfigurableProductPrefix() . '-%s';
+    }
+
+    /**
+     * Get option url key prefix.
+     *
+     * @return string
+     */
+    private function getOptionUrlKeyPrefix()
+    {
+        return 'simple-of-configurable-product' . $this->getConfigurableProductPrefix();
+    }
+
+    /**
+     * Get additional configurations for configurable products.
+     *
+     * @return string|null
+     */
+    private function getAdditionalConfigurableProductsVariations()
+    {
+        return $this->fixtureModel->getValue('configurable_products_variations', null);
+    }
+
+    /**
+     * Get configurable product prefix.
+     *
+     * @return string
+     */
+    protected function getConfigurableProductPrefix()
+    {
+        return '';
+    }
 }
diff --git a/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php b/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php
index fbb28d35269b177762410e8da7560612dd64db9c..43270676cb94f0a16729d7c16dab4913247f105c 100644
--- a/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php
+++ b/setup/src/Magento/Setup/Fixtures/SimpleProductsFixture.php
@@ -235,7 +235,7 @@ class SimpleProductsFixture extends Fixture
      */
     protected function getAttributes()
     {
-        $attributeSets = $this->fixtureModel->getValue('attribute_sets', null);
+        $attributeSets = $this->getAttributeSets();
         $attributes = [];
 
         if ($attributeSets !== null && array_key_exists('attribute_set', $attributeSets)) {
@@ -337,4 +337,14 @@ class SimpleProductsFixture extends Fixture
         }
         return $searchTerms;
     }
+
+    /**
+     * Get attribute sets.
+     *
+     * @return array|null
+     */
+    private function getAttributeSets()
+    {
+        return $this->fixtureModel->getValue('attribute_sets', null);
+    }
 }
diff --git a/setup/src/Magento/Setup/Test/Unit/Fixtures/AttributeSetsFixtureTest.php b/setup/src/Magento/Setup/Test/Unit/Fixtures/AttributeSetsFixtureTest.php
index 674f444fbde10666b75aa5dadfef3719e3177152..2192f4e84e26e7d39e5fa09b2e5ee752eb659b10 100644
--- a/setup/src/Magento/Setup/Test/Unit/Fixtures/AttributeSetsFixtureTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Fixtures/AttributeSetsFixtureTest.php
@@ -202,7 +202,7 @@ class AttributeSetsFixtureTest extends \PHPUnit_Framework_TestCase
             ->willReturn($optionFactoryMock);
 
         $this->fixtureModelMock
-            ->expects($this->once())
+            ->expects($this->any())
             ->method('getValue')
             ->willReturn($attributeSets);
 
@@ -267,7 +267,7 @@ class AttributeSetsFixtureTest extends \PHPUnit_Framework_TestCase
             ->method('getObjectManager')
             ->will($this->returnValue($objectManagerMock));
         $this->fixtureModelMock
-            ->expects($this->once())
+            ->expects($this->any())
             ->method('getValue')
             ->willReturn(null);