diff --git a/.php_cs.dist b/.php_cs.dist
index 0f254c63283bd..84a5f88bf4355 100644
--- a/.php_cs.dist
+++ b/.php_cs.dist
@@ -5,9 +5,9 @@
*/
/**
- * Pre-commit hook installation:
- * vendor/bin/static-review.php hook:install dev/tools/Magento/Tools/StaticReview/pre-commit .git/hooks/pre-commit
+ * PHP Coding Standards fixer configuration
*/
+
$finder = PhpCsFixer\Finder::create()
->name('*.phtml')
->exclude('dev/tests/functional/generated')
diff --git a/app/code/Magento/Catalog/Block/Product/ImageBuilder.php b/app/code/Magento/Catalog/Block/Product/ImageBuilder.php
index 04d30270cbb62..b752000f5a19d 100644
--- a/app/code/Magento/Catalog/Block/Product/ImageBuilder.php
+++ b/app/code/Magento/Catalog/Block/Product/ImageBuilder.php
@@ -6,6 +6,7 @@
namespace Magento\Catalog\Block\Product;
use Magento\Catalog\Helper\ImageFactory as HelperFactory;
+use Magento\Catalog\Model\Product;
use Magento\Catalog\Model\Product\Image\NotLoadInfoImageException;
class ImageBuilder
@@ -21,7 +22,7 @@ class ImageBuilder
protected $helperFactory;
/**
- * @var \Magento\Catalog\Model\Product
+ * @var Product
*/
protected $product;
@@ -50,10 +51,10 @@ public function __construct(
/**
* Set product
*
- * @param \Magento\Catalog\Model\Product $product
+ * @param Product $product
* @return $this
*/
- public function setProduct(\Magento\Catalog\Model\Product $product)
+ public function setProduct(Product $product)
{
$this->product = $product;
return $this;
@@ -79,9 +80,7 @@ public function setImageId($imageId)
*/
public function setAttributes(array $attributes)
{
- if ($attributes) {
- $this->attributes = $attributes;
- }
+ $this->attributes = $attributes;
return $this;
}
diff --git a/app/code/Magento/Catalog/Test/Unit/Block/Product/ImageBuilderTest.php b/app/code/Magento/Catalog/Test/Unit/Block/Product/ImageBuilderTest.php
index e0b5d6ef3992a..dc152aaf05867 100644
--- a/app/code/Magento/Catalog/Test/Unit/Block/Product/ImageBuilderTest.php
+++ b/app/code/Magento/Catalog/Test/Unit/Block/Product/ImageBuilderTest.php
@@ -5,49 +5,43 @@
*/
namespace Magento\Catalog\Test\Unit\Block\Product;
+use Magento\Catalog\Block\Product\ImageBuilder;
+use Magento\Catalog\Block\Product\ImageFactory;
+use Magento\Catalog\Helper\Image;
+use Magento\Catalog\Model\Product;
+
class ImageBuilderTest extends \PHPUnit\Framework\TestCase
{
/**
- * @var \Magento\Catalog\Block\Product\ImageBuilder
+ * @var ImageBuilder
*/
- protected $model;
+ private $model;
/**
* @var \Magento\Catalog\Helper\ImageFactory|\PHPUnit_Framework_MockObject_MockObject
*/
- protected $helperFactory;
+ private $helperFactory;
/**
- * @var \Magento\Catalog\Block\Product\ImageFactory|\PHPUnit_Framework_MockObject_MockObject
+ * @var ImageFactory|\PHPUnit_Framework_MockObject_MockObject
*/
- protected $imageFactory;
+ private $imageFactory;
protected function setUp()
{
- $this->helperFactory = $this->getMockBuilder(\Magento\Catalog\Helper\ImageFactory::class)
- ->disableOriginalConstructor()
- ->setMethods(['create'])
- ->getMock();
-
- $this->imageFactory = $this->getMockBuilder(\Magento\Catalog\Block\Product\ImageFactory::class)
- ->disableOriginalConstructor()
- ->setMethods(['create'])
- ->getMock();
-
- $this->model = new \Magento\Catalog\Block\Product\ImageBuilder(
- $this->helperFactory,
- $this->imageFactory
- );
+ $this->helperFactory = $this->createPartialMock(\Magento\Catalog\Helper\ImageFactory::class, ['create']);
+
+ $this->imageFactory = $this->createPartialMock(ImageFactory::class, ['create']);
+
+ $this->model = new ImageBuilder($this->helperFactory, $this->imageFactory);
}
public function testSetProduct()
{
- $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
- ->disableOriginalConstructor()
- ->getMock();
+ $productMock = $this->createMock(Product::class);
$this->assertInstanceOf(
- \Magento\Catalog\Block\Product\ImageBuilder::class,
+ ImageBuilder::class,
$this->model->setProduct($productMock)
);
}
@@ -57,7 +51,7 @@ public function testSetImageId()
$imageId = 'test_image_id';
$this->assertInstanceOf(
- \Magento\Catalog\Block\Product\ImageBuilder::class,
+ ImageBuilder::class,
$this->model->setImageId($imageId)
);
}
@@ -68,7 +62,7 @@ public function testSetAttributes()
'name' => 'value',
];
$this->assertInstanceOf(
- \Magento\Catalog\Block\Product\ImageBuilder::class,
+ ImageBuilder::class,
$this->model->setAttributes($attributes)
);
}
@@ -81,13 +75,9 @@ public function testCreate($data, $expected)
{
$imageId = 'test_image_id';
- $productMock = $this->getMockBuilder(\Magento\Catalog\Model\Product::class)
- ->disableOriginalConstructor()
- ->getMock();
+ $productMock = $this->createMock(Product::class);
- $helperMock = $this->getMockBuilder(\Magento\Catalog\Helper\Image::class)
- ->disableOriginalConstructor()
- ->getMock();
+ $helperMock = $this->createMock(Image::class);
$helperMock->expects($this->once())
->method('init')
->with($productMock, $imageId)
@@ -116,9 +106,7 @@ public function testCreate($data, $expected)
->method('create')
->willReturn($helperMock);
- $imageMock = $this->getMockBuilder(\Magento\Catalog\Block\Product\Image::class)
- ->disableOriginalConstructor()
- ->getMock();
+ $imageMock = $this->createMock(\Magento\Catalog\Block\Product\Image::class);
$this->imageFactory->expects($this->once())
->method('create')
@@ -131,61 +119,173 @@ public function testCreate($data, $expected)
$this->assertInstanceOf(\Magento\Catalog\Block\Product\Image::class, $this->model->create());
}
+ /**
+ * Check if custom attributes will be overridden when builder used few times
+ * @param array $data
+ * @dataProvider createMultipleCallsDataProvider
+ */
+ public function testCreateMultipleCalls($data)
+ {
+ list ($firstCall, $secondCall) = array_values($data);
+
+ $imageId = 'test_image_id';
+
+ $productMock = $this->createMock(Product::class);
+
+ $helperMock = $this->createMock(Image::class);
+ $helperMock->expects($this->exactly(2))
+ ->method('init')
+ ->with($productMock, $imageId)
+ ->willReturnSelf();
+
+ $helperMock->expects($this->exactly(2))
+ ->method('getFrame')
+ ->willReturnOnConsecutiveCalls($firstCall['data']['frame'], $secondCall['data']['frame']);
+ $helperMock->expects($this->exactly(2))
+ ->method('getUrl')
+ ->willReturnOnConsecutiveCalls($firstCall['data']['url'], $secondCall['data']['url']);
+ $helperMock->expects($this->exactly(4))
+ ->method('getWidth')
+ ->willReturnOnConsecutiveCalls(
+ $firstCall['data']['width'],
+ $firstCall['data']['width'],
+ $secondCall['data']['width'],
+ $secondCall['data']['width']
+ );
+ $helperMock->expects($this->exactly(4))
+ ->method('getHeight')
+ ->willReturnOnConsecutiveCalls(
+ $firstCall['data']['height'],
+ $firstCall['data']['height'],
+ $secondCall['data']['height'],
+ $secondCall['data']['height']
+ );
+ $helperMock->expects($this->exactly(2))
+ ->method('getLabel')
+ ->willReturnOnConsecutiveCalls($firstCall['data']['label'], $secondCall['data']['label']);
+ $helperMock->expects($this->exactly(2))
+ ->method('getResizedImageInfo')
+ ->willReturnOnConsecutiveCalls($firstCall['data']['imagesize'], $secondCall['data']['imagesize']);
+ $this->helperFactory->expects($this->exactly(2))
+ ->method('create')
+ ->willReturn($helperMock);
+
+ $imageMock = $this->createMock(\Magento\Catalog\Block\Product\Image::class);
+
+ $this->imageFactory->expects($this->at(0))
+ ->method('create')
+ ->with($firstCall['expected'])
+ ->willReturn($imageMock);
+
+ $this->imageFactory->expects($this->at(1))
+ ->method('create')
+ ->with($secondCall['expected'])
+ ->willReturn($imageMock);
+
+ $this->model->setProduct($productMock);
+ $this->model->setImageId($imageId);
+ $this->model->setAttributes($firstCall['data']['custom_attributes']);
+
+ $this->assertInstanceOf(\Magento\Catalog\Block\Product\Image::class, $this->model->create());
+
+ $this->model->setProduct($productMock);
+ $this->model->setImageId($imageId);
+ $this->model->setAttributes($secondCall['data']['custom_attributes']);
+ $this->assertInstanceOf(\Magento\Catalog\Block\Product\Image::class, $this->model->create());
+ }
+
+ /**
+ * @return array
+ */
+ public function createDataProvider(): array
+ {
+ return [
+ $this->getTestDataWithoutAttributes(),
+ $this->getTestDataWithAttributes(),
+ ];
+ }
+
/**
* @return array
*/
- public function createDataProvider()
+ public function createMultipleCallsDataProvider(): array
{
return [
[
+ [
+ 'without_attributes' => $this->getTestDataWithoutAttributes(),
+ 'with_attributes' => $this->getTestDataWithAttributes(),
+ ],
+ ],
+ [
+ [
+ 'with_attributes' => $this->getTestDataWithAttributes(),
+ 'without_attributes' => $this->getTestDataWithoutAttributes(),
+ ],
+ ],
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ private function getTestDataWithoutAttributes(): array
+ {
+ return [
+ 'data' => [
+ 'frame' => 0,
+ 'url' => 'test_url_1',
+ 'width' => 100,
+ 'height' => 100,
+ 'label' => 'test_label',
+ 'custom_attributes' => [],
+ 'imagesize' => [100, 100],
+ ],
+ 'expected' => [
'data' => [
- 'frame' => 0,
- 'url' => 'test_url_1',
+ 'template' => 'Magento_Catalog::product/image_with_borders.phtml',
+ 'image_url' => 'test_url_1',
'width' => 100,
'height' => 100,
'label' => 'test_label',
- 'custom_attributes' => [],
- 'imagesize' => [100, 100],
+ 'ratio' => 1,
+ 'custom_attributes' => '',
+ 'resized_image_width' => 100,
+ 'resized_image_height' => 100,
],
- 'expected' => [
- 'data' => [
- 'template' => 'Magento_Catalog::product/image_with_borders.phtml',
- 'image_url' => 'test_url_1',
- 'width' => 100,
- 'height' => 100,
- 'label' => 'test_label',
- 'ratio' => 1,
- 'custom_attributes' => '',
- 'resized_image_width' => 100,
- 'resized_image_height' => 100,
- ],
+ ],
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ private function getTestDataWithAttributes(): array
+ {
+ return [
+ 'data' => [
+ 'frame' => 1,
+ 'url' => 'test_url_2',
+ 'width' => 100,
+ 'height' => 50,
+ 'label' => 'test_label_2',
+ 'custom_attributes' => [
+ 'name_1' => 'value_1',
+ 'name_2' => 'value_2',
],
+ 'imagesize' => [120, 70],
],
- [
+ 'expected' => [
'data' => [
- 'frame' => 1,
- 'url' => 'test_url_2',
+ 'template' => 'Magento_Catalog::product/image.phtml',
+ 'image_url' => 'test_url_2',
'width' => 100,
'height' => 50,
'label' => 'test_label_2',
- 'custom_attributes' => [
- 'name_1' => 'value_1',
- 'name_2' => 'value_2',
- ],
- 'imagesize' => [120, 70],
- ],
- 'expected' => [
- 'data' => [
- 'template' => 'Magento_Catalog::product/image.phtml',
- 'image_url' => 'test_url_2',
- 'width' => 100,
- 'height' => 50,
- 'label' => 'test_label_2',
- 'ratio' => 0.5,
- 'custom_attributes' => 'name_1="value_1" name_2="value_2"',
- 'resized_image_width' => 120,
- 'resized_image_height' => 70,
- ],
+ 'ratio' => 0.5,
+ 'custom_attributes' => 'name_1="value_1" name_2="value_2"',
+ 'resized_image_width' => 120,
+ 'resized_image_height' => 70,
],
],
];
diff --git a/app/code/Magento/Customer/etc/events.xml b/app/code/Magento/Customer/etc/events.xml
index 66c9a3813892c..d841d8faa9c38 100644
--- a/app/code/Magento/Customer/etc/events.xml
+++ b/app/code/Magento/Customer/etc/events.xml
@@ -10,7 +10,7 @@
-
+
diff --git a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js
index 71ca63f6750bb..be2e0aedfe4bb 100644
--- a/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js
+++ b/app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js
@@ -31,6 +31,8 @@ define([
this.options.cache.label = $(this.options.passwordStrengthMeterLabelSelector, this.element);
// We need to look outside the module for backward compatibility, since someone can already use the module.
+ // @todo Narrow this selector in 2.3 so it doesn't accidentally finds the the email field from the
+ // newsletter email field or any other "email" field.
this.options.cache.email = $(this.options.formSelector).find(this.options.emailSelector);
this._bind();
},
@@ -74,7 +76,9 @@ define([
'password-not-equal-to-user-name': this.options.cache.email.val()
});
- if (password.toLowerCase() === this.options.cache.email.val().toLowerCase()) {
+ // We should only perform this check in case there is an email field on screen
+ if (this.options.cache.email.length &&
+ password.toLowerCase() === this.options.cache.email.val().toLowerCase()) {
displayScore = 1;
} else {
isValid = $.validator.validateSingleElement(this.options.cache.input);
diff --git a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php
index 29e861cca891f..5575792c346d3 100644
--- a/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php
+++ b/app/code/Magento/Shipping/Model/Carrier/AbstractCarrier.php
@@ -453,7 +453,7 @@ protected function _updateFreeMethodQuote($request)
*/
public function getFinalPriceWithHandlingFee($cost)
{
- $handlingFee = $this->getConfigData('handling_fee');
+ $handlingFee = (float)$this->getConfigData('handling_fee');
$handlingType = $this->getConfigData('handling_type');
if (!$handlingType) {
$handlingType = self::HANDLING_TYPE_FIXED;
diff --git a/app/code/Magento/Store/etc/config.xml b/app/code/Magento/Store/etc/config.xml
index 470337a97dcd9..1011fe3051321 100644
--- a/app/code/Magento/Store/etc/config.xml
+++ b/app/code/Magento/Store/etc/config.xml
@@ -21,13 +21,13 @@
0
0
- /tiny_mce/
+ /tiny_mce/
0
- /tiny_mce/
+ /tiny_mce/
diff --git a/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml b/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml
index d16c4faeede28..fced077015f4e 100644
--- a/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml
+++ b/app/code/Magento/Tax/view/adminhtml/templates/rule/edit.phtml
@@ -111,6 +111,7 @@ require([
TaxRateEditableMultiselect.prototype.init = function () {
var options = {
+ mselectContainer: '#tax_rate + section.mselect-list',
toggleAddButton:false,
addText: '= /* @escapeNotVerified */ __('Add New Tax Rate') ?>',
parse: null,
diff --git a/app/code/Magento/Theme/Block/Html/Footer.php b/app/code/Magento/Theme/Block/Html/Footer.php
index 4cd63462ec754..cdb350336f38f 100644
--- a/app/code/Magento/Theme/Block/Html/Footer.php
+++ b/app/code/Magento/Theme/Block/Html/Footer.php
@@ -57,7 +57,6 @@ protected function _construct()
{
$this->addData(
[
- 'cache_lifetime' => false,
'cache_tags' => [\Magento\Store\Model\Store::CACHE_TAG, \Magento\Cms\Model\Block::CACHE_TAG],
]
);
@@ -123,4 +122,14 @@ public function getIdentities()
{
return [\Magento\Store\Model\Store::CACHE_TAG, \Magento\Cms\Model\Block::CACHE_TAG];
}
+
+ /**
+ * Get block cache life time
+ *
+ * @return int
+ */
+ protected function getCacheLifetime()
+ {
+ return parent::getCacheLifetime() ?: 3600;
+ }
}
diff --git a/app/code/Magento/Theme/Test/Unit/Block/Html/FooterTest.php b/app/code/Magento/Theme/Test/Unit/Block/Html/FooterTest.php
index 8451e9c5aee6a..52175cc669bbd 100644
--- a/app/code/Magento/Theme/Test/Unit/Block/Html/FooterTest.php
+++ b/app/code/Magento/Theme/Test/Unit/Block/Html/FooterTest.php
@@ -30,4 +30,18 @@ public function testGetIdentities()
$this->block->getIdentities()
);
}
+
+ /**
+ * Check Footer block has cache lifetime.
+ *
+ * @throws \ReflectionException
+ * @return void
+ */
+ public function testGetCacheLifetime()
+ {
+ $reflection = new \ReflectionClass($this->block);
+ $method = $reflection->getMethod('getCacheLifetime');
+ $method->setAccessible(true);
+ $this->assertEquals(3600, $method->invoke($this->block));
+ }
}
diff --git a/composer.json b/composer.json
index ea0f858f4d05f..62858294ae0e0 100644
--- a/composer.json
+++ b/composer.json
@@ -34,7 +34,7 @@
"colinmollenhour/cache-backend-file": "1.4",
"colinmollenhour/cache-backend-redis": "1.10.2",
"colinmollenhour/credis": "1.9.1",
- "colinmollenhour/php-redis-session-abstract": "~1.2.2",
+ "colinmollenhour/php-redis-session-abstract": "~1.3.8",
"composer/composer": "1.4.1",
"magento/composer": "~1.2.0",
"magento/magento-composer-installer": ">=0.1.11",
@@ -44,12 +44,12 @@
"pelago/emogrifier": "^2.0.0",
"phpseclib/phpseclib": "2.0.*",
"ramsey/uuid": "3.6.1",
- "sjparkinson/static-review": "~4.1",
"symfony/console": "~2.3, !=2.7.0",
"symfony/event-dispatcher": "~2.1",
"symfony/process": "~2.1",
"tedivm/jshrink": "~1.1.0",
"tubalmartin/cssmin": "4.1.0",
+ "webonyx/graphql-php": "^0.11.1",
"zendframework/zend-captcha": "^2.7.1",
"zendframework/zend-code": "^3.1.0",
"zendframework/zend-config": "^2.6.0",
diff --git a/dev/tools/Magento/Tools/StaticReview/PhpCsFixerReview.php b/dev/tools/Magento/Tools/StaticReview/PhpCsFixerReview.php
deleted file mode 100644
index 113b139555dfb..0000000000000
--- a/dev/tools/Magento/Tools/StaticReview/PhpCsFixerReview.php
+++ /dev/null
@@ -1,66 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- *
- * @see http://github.com/sjparkinson/static-review/blob/master/LICENSE.md
- */
-namespace Magento\Tools\StaticReview;
-
-use StaticReview\File\FileInterface;
-use StaticReview\Reporter\ReporterInterface;
-use StaticReview\Review\AbstractReview;
-
-class PhpCsFixerReview extends AbstractReview
-{
- /**
- * @var array
- */
- protected $options;
-
- /**
- * @param array $options
- */
- public function __construct($options = [])
- {
- $this->options = $options;
- }
-
- /**
- * Obtained from .php_cs configuration file.
- *
- * @param FileInterface $file
- * @return bool
- */
- public function canReview(FileInterface $file)
- {
- return in_array($file->getExtension(), ['php', 'phtml', 'xml', 'yml']);
- }
-
- /**
- * Checks and fixes PHP files using PHP Coding Standards Fixer.
- *
- * @param ReporterInterface $reporter
- * @param FileInterface $file
- * @return void
- * @SuppressWarnings(PHPMD.UnusedFormalParameter)
- */
- public function review(ReporterInterface $reporter, FileInterface $file)
- {
- $cmd = 'vendor/bin/php-cs-fixer -vvv ';
- foreach ($this->options as $key => $value) {
- $cmd .= ' --' . $key . '=' . escapeshellarg($value);
- }
- $cmd .= ' fix ' . escapeshellarg($file->getRelativePath());
-
- $process = $this->getProcess($cmd);
- $process->run();
-
- $process = $this->getProcess('git add ' . escapeshellarg($file->getRelativePath()));
- $process->run();
- }
-}
diff --git a/dev/tools/Magento/Tools/StaticReview/pre-commit b/dev/tools/Magento/Tools/StaticReview/pre-commit
deleted file mode 100755
index 0bbb62797f434..0000000000000
--- a/dev/tools/Magento/Tools/StaticReview/pre-commit
+++ /dev/null
@@ -1,71 +0,0 @@
-#!/usr/bin/env php
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- *
- * @see https://github.com/sjparkinson/static-review/blob/master/LICENSE
- */
-$included = include __DIR__ . '/../../../../../vendor/autoload.php';
-if (!$included) {
- echo 'You must set up the project dependencies, run the following commands:' . PHP_EOL
- . 'curl -sS https://getcomposer.org/installer | php' . PHP_EOL
- . 'php composer.phar install' . PHP_EOL;
-
- exit(1);
-}
-
-// Installation:
-// vendor/bin/static-review.php hook:install dev/tools/Magento/Tools/StaticReview/pre-commit .git/hooks/pre-commit
-
-// Reference the required classes and the reviews you want to use.
-use League\CLImate\CLImate;
-use StaticReview\Reporter\Reporter;
-use StaticReview\Review\Composer\ComposerLintReview;
-use StaticReview\Review\General\LineEndingsReview;
-use StaticReview\Review\General\NoCommitTagReview;
-use StaticReview\Review\PHP\PhpLeadingLineReview;
-use StaticReview\Review\PHP\PhpLintReview;
-use Magento\Tools\StaticReview\PhpCsFixerReview;
-use StaticReview\StaticReview;
-use StaticReview\VersionControl\GitVersionControl;
-
-$reporter = new Reporter();
-$climate = new CLImate();
-$git = new GitVersionControl();
-
-// Apply review which modifies staged files first
-$review = new StaticReview($reporter);
-$phpCsFixer = new PhpCsFixerReview();
-$review->addReview($phpCsFixer);
-$review->review($git->getStagedFiles());
-
-// Apply read-only review then
-$review = new StaticReview($reporter);
-$review->addReview(new LineEndingsReview())
- ->addReview(new PhpLeadingLineReview())
- ->addReview(new NoCommitTagReview())
- ->addReview(new PhpLintReview())
- ->addReview(new ComposerLintReview());
-$review->review($git->getStagedFiles());
-
-// Check if any matching issues were found.
-if ($reporter->hasIssues()) {
- $climate->out('')->out('');
-
- foreach ($reporter->getIssues() as $issue) {
- $climate->red($issue);
- }
-
- $climate->out('')->red('✘ Please fix the errors above.');
-
- exit(1);
-} else {
- $climate->out('')->green('✔ Looking good.')->white('Have you tested everything?');
-
- exit(0);
-}
diff --git a/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php b/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php
index 06a66a2b3f873..ff7077213c5c3 100644
--- a/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php
+++ b/lib/internal/Magento/Framework/App/DeploymentConfig/Reader.php
@@ -9,7 +9,9 @@
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Config\File\ConfigFilePool;
use Magento\Framework\Exception\FileSystemException;
+use Magento\Framework\Exception\RuntimeException;
use Magento\Framework\Filesystem\DriverPool;
+use Magento\Framework\Phrase;
/**
* Deployment configuration reader.
@@ -87,6 +89,7 @@ public function getFiles()
* @param string $fileKey The file key (deprecated)
* @return array
* @throws FileSystemException If file can not be read
+ * @throws RuntimeException If file is invalid
* @throws \Exception If file key is not correct
* @see FileReader
*/
@@ -99,6 +102,9 @@ public function load($fileKey = null)
$filePath = $path . '/' . $this->configFilePool->getPath($fileKey);
if ($fileDriver->isExists($filePath)) {
$result = include $filePath;
+ if (!is_array($result)) {
+ throw new RuntimeException(new Phrase("Invalid configuration file: '%1'", [$filePath]));
+ }
}
} else {
$configFiles = $this->configFilePool->getPaths();
@@ -108,11 +114,14 @@ public function load($fileKey = null)
$configFile = $path . '/' . $this->configFilePool->getPath($fileKey);
if ($fileDriver->isExists($configFile)) {
$fileData = include $configFile;
+ if (!is_array($fileData)) {
+ throw new RuntimeException(new Phrase("Invalid configuration file: '%1'", [$configFile]));
+ }
} else {
continue;
}
$allFilesData[$configFile] = $fileData;
- if (is_array($fileData) && count($fileData) > 0) {
+ if ($fileData) {
$result = array_replace_recursive($result, $fileData);
}
}
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php
index 3e3eea322cafd..8f8399263384c 100644
--- a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php
+++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/ReaderTest.php
@@ -8,26 +8,29 @@
use Magento\Framework\App\DeploymentConfig\Reader;
use Magento\Framework\App\Filesystem\DirectoryList;
+use Magento\Framework\Config\File\ConfigFilePool;
+use Magento\Framework\Filesystem\Driver\File;
+use Magento\Framework\Filesystem\DriverPool;
class ReaderTest extends \PHPUnit\Framework\TestCase
{
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var \Magento\Framework\App\Filesystem\DirectoryList|\PHPUnit_Framework_MockObject_MockObject
*/
private $dirList;
/**
- * @var \Magento\Framework\Filesystem\DriverPool|\PHPUnit_Framework_MockObject_MockObject
+ * @var DriverPool|\PHPUnit_Framework_MockObject_MockObject
*/
private $driverPool;
/**
- * @var \Magento\Framework\Filesystem\Driver\File|\PHPUnit_Framework_MockObject_MockObject
+ * @var File|\PHPUnit_Framework_MockObject_MockObject
*/
private $fileDriver;
/**
- * @var \PHPUnit_Framework_MockObject_MockObject
+ * @var ConfigFilePool|\PHPUnit_Framework_MockObject_MockObject
*/
private $configFilePool;
@@ -38,7 +41,7 @@ protected function setUp()
->method('getPath')
->with(DirectoryList::CONFIG)
->willReturn(__DIR__ . '/_files');
- $this->fileDriver = $this->createMock(\Magento\Framework\Filesystem\Driver\File::class);
+ $this->fileDriver = $this->createMock(File::class);
$this->fileDriver
->expects($this->any())
->method('isExists')
@@ -51,12 +54,12 @@ protected function setUp()
[__DIR__ . '/_files/mergeTwo.php', true],
[__DIR__ . '/_files/nonexistent.php', false]
]));
- $this->driverPool = $this->createMock(\Magento\Framework\Filesystem\DriverPool::class);
+ $this->driverPool = $this->createMock(DriverPool::class);
$this->driverPool
->expects($this->any())
->method('getDriver')
->willReturn($this->fileDriver);
- $this->configFilePool = $this->createMock(\Magento\Framework\Config\File\ConfigFilePool::class);
+ $this->configFilePool = $this->createMock(ConfigFilePool::class);
$this->configFilePool
->expects($this->any())
->method('getPaths')
@@ -100,13 +103,97 @@ public function testLoad()
*/
public function testCustomLoad($file, $expected)
{
- $configFilePool = $this->createMock(\Magento\Framework\Config\File\ConfigFilePool::class);
+ $configFilePool = $this->createMock(ConfigFilePool::class);
$configFilePool->expects($this->any())->method('getPaths')->willReturn([$file]);
$configFilePool->expects($this->any())->method('getPath')->willReturn($file);
$object = new Reader($this->dirList, $this->driverPool, $configFilePool, $file);
$this->assertSame($expected, $object->load($file));
}
+ /**
+ * Test Reader::load() will throw exception in case of invalid configuration file(single file).
+ *
+ * @expectedException \Magento\Framework\Exception\RuntimeException
+ * @expectedExceptionMessageRegExp /Invalid configuration file: \'.*\/\_files\/emptyConfig\.php\'/
+ * @return void
+ */
+ public function testLoadInvalidConfigurationFileWithFileKey()
+ {
+ $fileDriver = $this->getMockBuilder(File::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $fileDriver->expects($this->once())
+ ->method('isExists')
+ ->willReturn(true);
+ /** @var DriverPool|\PHPUnit_Framework_MockObject_MockObject $driverPool */
+ $driverPool = $this->getMockBuilder(DriverPool::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $driverPool
+ ->expects($this->once())
+ ->method('getDriver')
+ ->willReturn($fileDriver);
+ /** @var ConfigFilePool|\PHPUnit_Framework_MockObject_MockObject $configFilePool */
+ $configFilePool = $this->getMockBuilder(ConfigFilePool::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $configFilePool
+ ->expects($this->once())
+ ->method('getPath')
+ ->with($this->identicalTo('testConfig'))
+ ->willReturn('emptyConfig.php');
+ $object = new Reader($this->dirList, $driverPool, $configFilePool);
+ $object->load('testConfig');
+ }
+
+ /**
+ * Test Reader::load() will throw exception in case of invalid configuration file(multiple files).
+ *
+ * @expectedException \Magento\Framework\Exception\RuntimeException
+ * @expectedExceptionMessageRegExp /Invalid configuration file: \'.*\/\_files\/emptyConfig\.php\'/
+ * @return void
+ */
+ public function testLoadInvalidConfigurationFile()
+ {
+ $fileDriver = $this->getMockBuilder(File::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $fileDriver->expects($this->exactly(2))
+ ->method('isExists')
+ ->willReturn(true);
+ /** @var DriverPool|\PHPUnit_Framework_MockObject_MockObject $driverPool */
+ $driverPool = $this->getMockBuilder(DriverPool::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $driverPool
+ ->expects($this->once())
+ ->method('getDriver')
+ ->willReturn($fileDriver);
+ /** @var ConfigFilePool|\PHPUnit_Framework_MockObject_MockObject $configFilePool */
+ $configFilePool = $this->getMockBuilder(ConfigFilePool::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $configFilePool->expects($this->exactly(2))
+ ->method('getPaths')
+ ->willReturn(
+ [
+ 'configKeyOne' => 'config.php',
+ 'testConfig' => 'emptyConfig.php'
+ ]
+ );
+ $configFilePool->expects($this->exactly(2))
+ ->method('getPath')
+ ->withConsecutive(
+ [$this->identicalTo('configKeyOne')],
+ [$this->identicalTo('testConfig')]
+ )->willReturnOnConsecutiveCalls(
+ 'config.php',
+ 'emptyConfig.php'
+ );
+ $object = new Reader($this->dirList, $driverPool, $configFilePool);
+ $object->load();
+ }
+
/**
* @return array
*/
diff --git a/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/_files/emptyConfig.php b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/_files/emptyConfig.php
new file mode 100644
index 0000000000000..79549bf674aad
--- /dev/null
+++ b/lib/internal/Magento/Framework/App/Test/Unit/DeploymentConfig/_files/emptyConfig.php
@@ -0,0 +1,6 @@
+scopeConfig->getValue(self::XML_PATH_COOKIE_LIFETIME, StoreScopeInterface::SCOPE_STORE);
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSentinelServers()
+ {
+ return $this->deploymentConfig->get(self::PARAM_SENTINEL_SERVERS);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSentinelMaster()
+ {
+ return $this->deploymentConfig->get(self::PARAM_SENTINEL_MASTER);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSentinelVerifyMaster()
+ {
+ return $this->deploymentConfig->get(self::PARAM_SENTINEL_VERIFY_MASTER);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSentinelConnectRetries()
+ {
+ return $this->deploymentConfig->get(self::PARAM_SENTINEL_CONNECT_RETRIES);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFailAfter()
+ {
+ return self::DEFAULT_FAIL_AFTER;
+ }
}
diff --git a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php
index 26f3d4c4c4e89..2859b486ec7a1 100644
--- a/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php
+++ b/lib/internal/Magento/Framework/Session/Test/Unit/SaveHandler/Redis/ConfigTest.php
@@ -246,4 +246,49 @@ public function testGetLifetimeFrontend()
->willReturn($expectedLifetime);
$this->assertEquals($this->config->getLifetime(), $expectedLifetime);
}
+
+ public function testGetSentinelServers()
+ {
+ $expected = 'server-1,server-2';
+ $this->deploymentConfigMock->expects($this->once())
+ ->method('get')
+ ->with(Config::PARAM_SENTINEL_SERVERS)
+ ->willReturn($expected);
+ $this->assertEquals($expected, $this->config->getSentinelServers());
+ }
+
+ public function testGetSentinelMaster()
+ {
+ $expected = 'master';
+ $this->deploymentConfigMock->expects($this->once())
+ ->method('get')
+ ->with(Config::PARAM_SENTINEL_MASTER)
+ ->willReturn($expected);
+ $this->assertEquals($this->config->getSentinelMaster(), $expected);
+ }
+
+ public function testGetSentinelVerifyMaster()
+ {
+ $expected = '1';
+ $this->deploymentConfigMock->expects($this->once())
+ ->method('get')
+ ->with(Config::PARAM_SENTINEL_VERIFY_MASTER)
+ ->willReturn($expected);
+ $this->assertEquals($this->config->getSentinelVerifyMaster(), $expected);
+ }
+
+ public function testGetSentinelConnectRetries()
+ {
+ $expected = '10';
+ $this->deploymentConfigMock->expects($this->once())
+ ->method('get')
+ ->willReturn(Config::PARAM_SENTINEL_CONNECT_RETRIES)
+ ->willReturn($expected);
+ $this->assertEquals($this->config->getSentinelConnectRetries(), $expected);
+ }
+
+ public function testGetFailAfter()
+ {
+ $this->assertEquals($this->config->getFailAfter(), Config::DEFAULT_FAIL_AFTER);
+ }
}
diff --git a/lib/internal/Magento/Framework/View/Asset/Minification.php b/lib/internal/Magento/Framework/View/Asset/Minification.php
index 686f794d6318a..33c82a1810db6 100644
--- a/lib/internal/Magento/Framework/View/Asset/Minification.php
+++ b/lib/internal/Magento/Framework/View/Asset/Minification.php
@@ -143,7 +143,8 @@ public function getExcludes($contentType)
if (!isset($this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType])) {
$this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType] = [];
$key = sprintf(self::XML_PATH_MINIFICATION_EXCLUDES, $contentType);
- foreach (explode("\n", $this->scopeConfig->getValue($key, $this->scope)) as $exclude) {
+ $excludeValues = $this->getMinificationExcludeValues($key);
+ foreach ($excludeValues as $exclude) {
if (trim($exclude) != '') {
$this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType][] = trim($exclude);
}
@@ -151,4 +152,17 @@ public function getExcludes($contentType)
}
return $this->configCache[self::XML_PATH_MINIFICATION_EXCLUDES][$contentType];
}
+
+ /**
+ * Get minification exclude values from configuration
+ *
+ * @param string $key
+ * @return string[]
+ */
+ private function getMinificationExcludeValues($key)
+ {
+ $configValues = $this->scopeConfig->getValue($key, $this->scope) ?? [];
+
+ return array_values($configValues);
+ }
}
diff --git a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php
index 2f6305f1cc73c..1cc2a3dd7e2b7 100644
--- a/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php
+++ b/lib/internal/Magento/Framework/View/Test/Unit/Asset/MinificationTest.php
@@ -203,10 +203,10 @@ public function testGetExcludes()
->expects($this->once())
->method('getValue')
->with('dev/js/minify_exclude')
- ->willReturn(
- " /tiny_mce/ \n" .
- " /tiny_mce2/ "
- );
+ ->willReturn([
+ 'tiny_mce' => '/tiny_mce/',
+ 'some_other_unique_name' => '/tiny_mce2/'
+ ]);
$expected = ['/tiny_mce/', '/tiny_mce2/'];
$this->assertEquals($expected, $this->minification->getExcludes('js'));
diff --git a/lib/internal/Magento/Framework/composer.json b/lib/internal/Magento/Framework/composer.json
index 785ff07a60f39..b442effe5ffda 100644
--- a/lib/internal/Magento/Framework/composer.json
+++ b/lib/internal/Magento/Framework/composer.json
@@ -23,7 +23,7 @@
"ext-spl": "*",
"ext-xsl": "*",
"lib-libxml": "*",
- "colinmollenhour/php-redis-session-abstract": "~1.2.2",
+ "colinmollenhour/php-redis-session-abstract": "~1.3.8",
"composer/composer": "1.4.1",
"magento/zendframework1": "~1.13.0",
"monolog/monolog": "^1.17",
diff --git a/pub/static/.htaccess b/pub/static/.htaccess
index 21fe6a63e64ba..a10e234e07ff2 100644
--- a/pub/static/.htaccess
+++ b/pub/static/.htaccess
@@ -12,6 +12,9 @@ Options -MultiViews
RewriteEngine On
+ ## you can put here your pub/static folder path relative to web root
+ #RewriteBase /magento/pub/static/
+
# Remove signature of the static files that is used to overcome the browser cache
RewriteRule ^version.+?/(.+)$ $1 [L]
diff --git a/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php b/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php
index 5445bca8713e5..c2f4d6fce0d59 100644
--- a/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php
+++ b/setup/src/Magento/Setup/Console/Command/MaintenanceAllowIpsCommand.php
@@ -24,6 +24,7 @@ class MaintenanceAllowIpsCommand extends AbstractSetupCommand
*/
const INPUT_KEY_IP = 'ip';
const INPUT_KEY_NONE = 'none';
+ const INPUT_KEY_ADD = 'add';
/**
* @var MaintenanceMode
@@ -69,6 +70,12 @@ protected function configure()
InputOption::VALUE_NONE,
'Clear allowed IP addresses'
),
+ new InputOption(
+ self::INPUT_KEY_ADD,
+ null,
+ InputOption::VALUE_NONE,
+ 'Add the IP address to existing list'
+ ),
];
$this->setName('maintenance:allow-ips')
->setDescription('Sets maintenance mode exempt IPs')
@@ -91,6 +98,9 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
if (!empty($addresses)) {
+ if ($input->getOption(self::INPUT_KEY_ADD)) {
+ $addresses = array_unique(array_merge($this->maintenanceMode->getAddressInfo(), $addresses));
+ }
$this->maintenanceMode->setAddresses(implode(',', $addresses));
$output->writeln(
'Set exempt IP-addresses: ' . implode(' ', $this->maintenanceMode->getAddressInfo()) .
diff --git a/setup/src/Magento/Setup/Console/InputValidationException.php b/setup/src/Magento/Setup/Console/InputValidationException.php
new file mode 100755
index 0000000000000..efa8a03bcfe49
--- /dev/null
+++ b/setup/src/Magento/Setup/Console/InputValidationException.php
@@ -0,0 +1,14 @@
+input = $input;
+ $this->bufferedOutput = new BufferedOutput($output->getVerbosity(), false, clone $output->getFormatter());
+ // Windows cmd wraps lines as soon as the terminal width is reached, whether there are following chars or not.
+ $currentLength = $this->getTerminalWidth() - (int)(DIRECTORY_SEPARATOR === '\\');
+ $this->lineLength = min($currentLength, self::MAX_LINE_LENGTH);
+ parent::__construct($output);
+ }
+
+ /**
+ * Formats a message as a block of text.
+ *
+ * @param string|array $messages The message to write in the block
+ * @param string|null $type The block type (added in [] on first line)
+ * @param string|null $style The style to apply to the whole block
+ * @param string $prefix The prefix for the block
+ * @param bool $padding Whether to add vertical padding
+ * @return void
+ */
+ public function block(
+ $messages,
+ string $type = null,
+ string $style = null,
+ string $prefix = ' ',
+ bool $padding = false
+ ) {
+ $messages = is_array($messages) ? array_values($messages) : [$messages];
+ $this->autoPrependBlock();
+ $this->writeln($this->createBlock($messages, $type, $style, $prefix, $padding));
+ $this->newLine();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function title($message)
+ {
+ $this->autoPrependBlock();
+ $bar = str_repeat('=', Helper::strlenWithoutDecoration($this->getFormatter(), $message));
+ $this->writeln([
+ sprintf(' %s>', OutputFormatter::escapeTrailingBackslash($message)),
+ sprintf(' %s>', $bar),
+ ]);
+ $this->newLine();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function section($message)
+ {
+ $this->autoPrependBlock();
+ $bar = str_repeat('-', Helper::strlenWithoutDecoration($this->getFormatter(), $message));
+ $this->writeln([
+ sprintf(' %s>', OutputFormatter::escapeTrailingBackslash($message)),
+ sprintf(' %s>', $bar),
+ ]);
+ $this->newLine();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function listing(array $elements)
+ {
+ $this->autoPrependText();
+ $elements = array_map(function ($element) {
+ return sprintf(' * %s', $element);
+ }, $elements);
+
+ $this->writeln($elements);
+ $this->newLine();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function text($message)
+ {
+ $this->autoPrependText();
+ $messages = is_array($message) ? array_values($message) : [$message];
+ foreach ($messages as $singleMessage) {
+ $this->writeln(sprintf(' %s', $singleMessage));
+ }
+ }
+
+ /**
+ * Formats a command comment.
+ *
+ * @param string|array $message
+ * @param bool $padding
+ * @return void
+ */
+ public function comment($message, $padding = false)
+ {
+ $this->block($message, null, 'comment', ' ', $padding);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function success($message, $padding = true)
+ {
+ $this->block($message, 'SUCCESS', 'fg=black;bg=green', ' ', $padding);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function error($message, $padding = true)
+ {
+ $this->block($message, 'ERROR', 'fg=white;bg=red', ' ', $padding);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function warning($message, $padding = true)
+ {
+ $this->block($message, 'WARNING', 'fg=black;bg=yellow', ' ', $padding);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function note($message, $padding = false)
+ {
+ $this->block($message, 'NOTE', 'fg=yellow', ' ', $padding);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function caution($message, $padding = true)
+ {
+ $this->block($message, 'CAUTION', 'fg=black;bg=yellow', ' ! ', $padding);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function table(array $headers, array $rows)
+ {
+ $style = clone Table::getStyleDefinition('symfony-style-guide');
+ $style->setCellHeaderFormat('%s');
+
+ $table = new Table($this);
+ $table->setHeaders($headers);
+ $table->setRows($rows);
+ $table->setStyle($style);
+
+ $table->render();
+ $this->newLine();
+ }
+
+ /**
+ * {@inheritdoc}
+ * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
+ */
+ public function ask($question, $default = null, $validator = null, $maxAttempts = null)
+ {
+ $question = new Question($question, $default);
+ $question->setValidator($validator);
+ $question->setMaxAttempts($maxAttempts);
+
+ return $this->askQuestion($question);
+ }
+
+ /**
+ * {@inheritdoc}
+ * @throws \Symfony\Component\Console\Exception\LogicException
+ */
+ public function askHidden($question, $validator = null)
+ {
+ $question = new Question($question);
+
+ $question->setHidden(true);
+ $question->setValidator($validator);
+
+ return $this->askQuestion($question);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function confirm($question, $default = true)
+ {
+ return $this->askQuestion(new ConfirmationQuestion($question, $default));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function choice($question, array $choices, $default = null)
+ {
+ if (null !== $default) {
+ $values = array_flip($choices);
+ $default = $values[$default];
+ }
+
+ return $this->askQuestion(new ChoiceQuestion($question, $choices, $default));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function progressStart($max = 0)
+ {
+ $this->progressBar = $this->createProgressBar($max);
+ $this->progressBar->start();
+ }
+
+ /**
+ * {@inheritdoc}
+ * @throws \Symfony\Component\Console\Exception\LogicException
+ * @throws \Symfony\Component\Console\Exception\RuntimeException
+ */
+ public function progressAdvance($step = 1)
+ {
+ $this->getProgressBar()->advance($step);
+ }
+
+ /**
+ * {@inheritdoc}
+ * @throws \Symfony\Component\Console\Exception\RuntimeException
+ */
+ public function progressFinish()
+ {
+ $this->getProgressBar()->finish();
+ $this->newLine(2);
+ $this->progressBar = null;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createProgressBar($max = 0)
+ {
+ $progressBar = parent::createProgressBar($max);
+ $progressBar->setEmptyBarCharacter(' ');
+ $progressBar->setProgressCharacter('>');
+ $progressBar->setBarCharacter('=');
+
+ return $progressBar;
+ }
+
+ /**
+ * Ask user question.
+ *
+ * @param Question $question
+ *
+ * @return string
+ */
+ public function askQuestion(Question $question)
+ {
+ if ($this->input->isInteractive()) {
+ $this->autoPrependBlock();
+ }
+
+ if (!$this->questionHelper) {
+ $this->questionHelper = new SymfonyQuestionHelper();
+ }
+
+ $answer = $this->questionHelper->ask($this->input, $this, $question);
+
+ if ($this->input->isInteractive()) {
+ $this->newLine();
+ $this->bufferedOutput->write(PHP_EOL);
+ }
+
+ return $answer;
+ }
+
+ /**
+ * Ask for an missing argument.
+ *
+ * @param string $argument
+ * @param string $question
+ * @param string|null $default
+ * @param callable|null $validator
+ * @param int|null $maxAttempts
+ * @param bool $comment
+ * @param string $commentFormat
+ * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
+ */
+ public function askForMissingArgument(
+ string $argument,
+ string $question,
+ string $default = null,
+ callable $validator = null,
+ int $maxAttempts = null,
+ bool $comment = null,
+ string $commentFormat = 'Argument [%s] set to: %s'
+ ) {
+ try {
+ if ($this->input->getArgument($argument) === null) {
+ $this->input->setArgument($argument, $this->ask($question, $default, $validator, $maxAttempts));
+ }
+ $argumentValue = $this->input->getArgument($argument);
+ $validated = (is_callable($validator) ? $validator($argumentValue) : $argumentValue);
+ if ((bool)($comment ?? $this->isDebug())) {
+ $this->comment(sprintf($commentFormat, $argument, $validated));
+ }
+ } catch (InputValidationException $e) {
+ $this->error('Validation Error: ' . $e->getMessage());
+ $this->askForMissingArgument(
+ $argument,
+ $question,
+ $default,
+ $validator,
+ $maxAttempts,
+ $comment,
+ $commentFormat
+ );
+ }
+ }
+
+ /**
+ * Ask for an missing option.
+ *
+ * @param string $option
+ * @param string $question
+ * @param string|null $default
+ * @param callable|null $validator
+ * @param int|null $maxAttempts
+ * @param bool $comment
+ * @param string $commentFormat
+ * @throws \Symfony\Component\Console\Exception\InvalidArgumentException
+ */
+ public function askForMissingOption(
+ string $option,
+ string $question,
+ string $default = null,
+ callable $validator = null,
+ int $maxAttempts = null,
+ bool $comment = null,
+ string $commentFormat = 'Option [%s] set to: %s'
+ ) {
+ try {
+ if (null === $this->input->getOption($option)) {
+ $this->input->setOption($option, $this->ask($question, $default, $validator, $maxAttempts));
+ }
+ $optionValue = $this->input->getOption($option);
+ $validated = (is_callable($validator) ? $validator($optionValue) : $optionValue);
+ if ((bool)($comment ?? $this->isDebug())) {
+ $this->comment(sprintf($commentFormat, $option, $validated));
+ }
+ } catch (InputValidationException $e) {
+ $this->error('Validation Error: ' . $e->getMessage());
+ $this->askForMissingOption(
+ $option,
+ $question,
+ $default,
+ $validator,
+ $maxAttempts,
+ $comment,
+ $commentFormat
+ );
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeln($messages, $type = self::OUTPUT_NORMAL)
+ {
+ parent::writeln($messages, $type);
+ $this->bufferedOutput->writeln($this->reduceBuffer($messages), $type);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write($messages, $newline = false, $type = self::OUTPUT_NORMAL)
+ {
+ parent::write($messages, $newline, $type);
+ $this->bufferedOutput->write($this->reduceBuffer($messages), $newline, $type);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function newLine($count = 1)
+ {
+ parent::newLine($count);
+ $this->bufferedOutput->write(str_repeat(PHP_EOL, $count));
+ }
+
+ /**
+ * Get progress bar instance.
+ *
+ * @return ProgressBar
+ * @throws RuntimeException in case progress bar hasn't been instantiated yet.
+ */
+ private function getProgressBar()
+ {
+ if (!$this->progressBar) {
+ throw new RuntimeException('The ProgressBar is not started.');
+ }
+
+ return $this->progressBar;
+ }
+
+ /**
+ * @return int
+ */
+ private function getTerminalWidth()
+ {
+ $application = new Application();
+ $dimensions = $application->getTerminalDimensions();
+
+ return $dimensions[0] ?: self::MAX_LINE_LENGTH;
+ }
+
+ /**
+ * Add empty line before output element in case there were no empty lines before.
+ *
+ * @return void
+ */
+ private function autoPrependBlock()
+ {
+ $chars = substr($this->bufferedOutput->fetch(), -2);
+ if (!isset($chars[0])) {
+ $this->newLine(); //empty history, so we should start with a new line.
+ }
+ //Prepend new line for each non LF chars (This means no blank line was output before)
+ $this->newLine(2 - substr_count($chars, PHP_EOL));
+ }
+
+ /**
+ * Add empty line before text(listing) output element.
+ *
+ * @return void
+ */
+ private function autoPrependText()
+ {
+ $fetched = $this->bufferedOutput->fetch();
+ //Prepend new line if last char isn't EOL:
+ if (PHP_EOL !== substr($fetched, -1)) {
+ $this->newLine();
+ }
+ }
+
+ private function reduceBuffer($messages)
+ {
+ // We need to know if the two last chars are PHP_EOL
+ // Preserve the last 4 chars inserted (PHP_EOL on windows is two chars) in the history buffer
+ return array_map(function ($value) {
+ return substr($value, -4);
+ }, array_merge([$this->bufferedOutput->fetch()], (array)$messages));
+ }
+
+ /**
+ * Build output in block style.
+ *
+ * @param array $messages
+ * @param string|null $type
+ * @param string|null $style
+ * @param string $prefix
+ * @param bool $padding
+ * @return array
+ */
+ private function createBlock(
+ array $messages,
+ string $type = null,
+ string $style = null,
+ string $prefix = ' ',
+ bool $padding = false
+ ) {
+ $indentLength = 0;
+ $prefixLength = Helper::strlenWithoutDecoration($this->getFormatter(), $prefix);
+ if (null !== $type) {
+ $type = sprintf('[%s] ', $type);
+ $indentLength = strlen($type);
+ $lineIndentation = str_repeat(' ', $indentLength);
+ }
+ $lines = $this->getBlockLines($messages, $prefixLength, $indentLength);
+ $firstLineIndex = 0;
+ if ($padding && $this->isDecorated()) {
+ $firstLineIndex = 1;
+ array_unshift($lines, '');
+ $lines[] = '';
+ }
+ foreach ($lines as $i => &$line) {
+ if (null !== $type) {
+ $line = $firstLineIndex === $i ? $type . $line : $lineIndentation . $line;
+ }
+ $line = $prefix . $line;
+ $multiplier = $this->lineLength - Helper::strlenWithoutDecoration($this->getFormatter(), $line);
+ $line .= str_repeat(' ', $multiplier);
+ if ($style) {
+ $line = sprintf('<%s>%s>', $style, $line);
+ }
+ }
+
+ return $lines;
+ }
+
+ /**
+ * Wrap and add new lines for each element.
+ *
+ * @param array $messages
+ * @param int $prefixLength
+ * @param int $indentLength
+ * @return array
+ */
+ private function getBlockLines(
+ array $messages,
+ int $prefixLength,
+ int $indentLength
+ ) {
+ $lines = [[]];
+ foreach ($messages as $key => $message) {
+ $message = OutputFormatter::escape($message);
+ $wordwrap = wordwrap($message, $this->lineLength - $prefixLength - $indentLength, PHP_EOL, true);
+ $lines[] = explode(PHP_EOL, $wordwrap);
+ if (count($messages) > 1 && $key < count($messages) - 1) {
+ $lines[][] = '';
+ }
+ }
+ $lines = array_merge(...$lines);
+
+ return $lines;
+ }
+}
diff --git a/setup/src/Magento/Setup/Console/Style/MagentoStyleInterface.php b/setup/src/Magento/Setup/Console/Style/MagentoStyleInterface.php
new file mode 100755
index 0000000000000..a7aba31549699
--- /dev/null
+++ b/setup/src/Magento/Setup/Console/Style/MagentoStyleInterface.php
@@ -0,0 +1,17 @@
+ '7200',
self::INPUT_KEY_SESSION_REDIS_DISABLE_LOCKING => '0',
self::INPUT_KEY_SESSION_REDIS_MIN_LIFETIME => '60',
- self::INPUT_KEY_SESSION_REDIS_MAX_LIFETIME => '2592000'
+ self::INPUT_KEY_SESSION_REDIS_MAX_LIFETIME => '2592000',
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_VERIFY_MASTER => '0',
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_CONNECT_RETRIES => '5',
];
/**
@@ -121,6 +131,11 @@ class Session implements ConfigOptionsListInterface
self::INPUT_KEY_SESSION_REDIS_DISABLE_LOCKING => self::CONFIG_PATH_SESSION_REDIS_DISABLE_LOCKING,
self::INPUT_KEY_SESSION_REDIS_MIN_LIFETIME => self::CONFIG_PATH_SESSION_REDIS_MIN_LIFETIME,
self::INPUT_KEY_SESSION_REDIS_MAX_LIFETIME => self::CONFIG_PATH_SESSION_REDIS_MAX_LIFETIME,
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_MASTER => self::CONFIG_PATH_SESSION_REDIS_SENTINEL_MASTER,
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_SERVERS => self::CONFIG_PATH_SESSION_REDIS_SENTINEL_SERVERS,
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_CONNECT_RETRIES =>
+ self::CONFIG_PATH_SESSION_REDIS_SENTINEL_CONNECT_RETRIES,
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_VERIFY_MASTER => self::CONFIG_PATH_SESSION_REDIS_SENTINEL_VERIFY_MASTER,
];
/**
@@ -246,6 +261,30 @@ public function getOptions()
self::CONFIG_PATH_SESSION_REDIS_MAX_LIFETIME,
'Redis max session lifetime, in seconds'
),
+ new TextConfigOption(
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_MASTER,
+ TextConfigOption::FRONTEND_WIZARD_TEXT,
+ self::CONFIG_PATH_SESSION_REDIS_SENTINEL_MASTER,
+ 'Redis Sentinel master'
+ ),
+ new TextConfigOption(
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_SERVERS,
+ TextConfigOption::FRONTEND_WIZARD_TEXT,
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_SERVERS,
+ 'Redis Sentinel servers, comma separated'
+ ),
+ new TextConfigOption(
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_VERIFY_MASTER,
+ TextConfigOption::FRONTEND_WIZARD_TEXT,
+ self::CONFIG_PATH_SESSION_REDIS_SENTINEL_VERIFY_MASTER,
+ 'Redis Sentinel verify master. Values: false (default), true'
+ ),
+ new TextConfigOption(
+ self::INPUT_KEY_SESSION_REDIS_SENTINEL_CONNECT_RETRIES,
+ TextConfigOption::FRONTEND_WIZARD_TEXT,
+ self::CONFIG_PATH_SESSION_REDIS_SENTINEL_CONNECT_RETRIES,
+ 'Redis Sentinel connect retries.'
+ ),
];
}
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php
index 35af019436d71..cce7a2e39adfc 100644
--- a/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Command/MaintenanceAllowIpsCommandTest.php
@@ -66,6 +66,33 @@ public function testExecute(array $input, array $validatorMessages, $expectedMes
$this->assertEquals($expectedMessage, $tester->getDisplay());
}
+ /**
+ * @param array $addressInfo
+ * @param array $input
+ * @param array $validatorMessages
+ * @param string $expectedMessage
+ * @dataProvider executeWithAddDataProvider
+ */
+ public function testExecuteWithAdd(array $addressInfo, array $input, array $validatorMessages, $expectedMessage)
+ {
+ $newAddressInfo = array_unique(array_merge($addressInfo, $input['ip']));
+
+ $this->ipValidator->expects($this->once())->method('validateIps')->willReturn($validatorMessages);
+ $this->maintenanceMode
+ ->expects($this->once())
+ ->method('setAddresses')
+ ->with(implode(',', $newAddressInfo));
+
+ $this->maintenanceMode
+ ->expects($this->exactly(2))
+ ->method('getAddressInfo')
+ ->willReturnOnConsecutiveCalls($addressInfo, $newAddressInfo);
+
+ $tester = new CommandTester($this->command);
+ $tester->execute($input);
+ $this->assertEquals($expectedMessage, $tester->getDisplay());
+ }
+
/**
* return array
*/
@@ -99,4 +126,31 @@ public function executeDataProvider()
]
];
}
+
+ /**
+ * return array
+ */
+ public function executeWithAddDataProvider()
+ {
+ return [
+ [
+ [],
+ ['ip' => ['127.0.0.1'], '--add' => true],
+ [],
+ 'Set exempt IP-addresses: 127.0.0.1' . PHP_EOL,
+ ],
+ [
+ ['127.0.0.1'],
+ ['ip' => ['127.0.0.1'], '--add' => true],
+ [],
+ 'Set exempt IP-addresses: 127.0.0.1' . PHP_EOL,
+ ],
+ [
+ ['127.0.0.1'],
+ ['ip' => ['127.0.0.2'], '--add' => true],
+ [],
+ 'Set exempt IP-addresses: 127.0.0.1 127.0.0.2' . PHP_EOL,
+ ],
+ ];
+ }
}
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Style/MagentoStyleTest.php b/setup/src/Magento/Setup/Test/Unit/Console/Style/MagentoStyleTest.php
new file mode 100755
index 0000000000000..92aa43251ba26
--- /dev/null
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Style/MagentoStyleTest.php
@@ -0,0 +1,287 @@
+ 'foo'], new InputDefinition([new InputArgument('name')]));
+ $this->testOutput = new TestOutput();
+ $this->magentoStyle = new MagentoStyle($input, $this->testOutput);
+ }
+
+ /**
+ * Test style decorator will output block with correct style.
+ *
+ * @return void
+ */
+ public function testBlockStyle()
+ {
+ $this->magentoStyle->block(
+ ['test first message', 'test second message'],
+ 'testBlockType',
+ 'testBlockStyle',
+ 'testBlockPrefix'
+ );
+ // @codingStandardsIgnoreStart
+ $expected = PHP_EOL . PHP_EOL . PHP_EOL .
+ '\testBlockPrefix\[testBlockType\] test first message\s+'
+ . PHP_EOL . '\testBlockPrefix\s+'
+ . PHP_EOL . '\testBlockPrefix \s+ test second message\s+'
+ . PHP_EOL . PHP_EOL;
+ // @codingStandardsIgnoreEnd
+ $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Block does not match output');
+ }
+
+ /**
+ * Test style decorator will add title with correct style.
+ *
+ * @return void
+ */
+ public function testTitleStyle()
+ {
+ $this->magentoStyle->title('My Title');
+ $expected = PHP_EOL . PHP_EOL . PHP_EOL . ' My Title' . PHP_EOL . ' ========' . PHP_EOL . PHP_EOL;
+ $this->assertEquals($expected, $this->testOutput->output, 'Title does not match output');
+ }
+
+ /**
+ * Test style decorator will output section with correct style.
+ *
+ * @return void
+ */
+ public function testSectionStyle()
+ {
+ $this->magentoStyle->section('My Section');
+ $expected = PHP_EOL . PHP_EOL . PHP_EOL . ' My Section' . PHP_EOL . ' ----------' . PHP_EOL . PHP_EOL;
+ $this->assertEquals($expected, $this->testOutput->output, 'Section does not match output');
+ }
+
+ /**
+ * Test style decorator will output listing with proper style.
+ *
+ * @return void
+ */
+ public function testListingStyle()
+ {
+ $this->magentoStyle->listing(['test first element', 'test second element']);
+ $expected = PHP_EOL . ' * test first element' . PHP_EOL . ' * test second element' . PHP_EOL . PHP_EOL;
+ $this->assertEquals($expected, $this->testOutput->output, 'Listing does not match output');
+ }
+
+ /**
+ * Test style decorator will output text with proper style.
+ *
+ * @return void
+ */
+ public function testTextStyle()
+ {
+ $this->magentoStyle->text('test message');
+ $expected = PHP_EOL . ' test message' . PHP_EOL;
+
+ $this->assertEquals($expected, $this->testOutput->output, 'Text does not match output');
+ }
+
+ /**
+ * Test style decorator will output comment with proper style.
+ *
+ * @return void
+ */
+ public function testCommentStyle()
+ {
+ $this->magentoStyle->comment('test comment');
+ $expected = PHP_EOL . PHP_EOL . PHP_EOL . '\s+test comment\s+' . PHP_EOL . PHP_EOL;
+ $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Comment does not match output');
+ }
+
+ /**
+ * Test style decorator will output success message with proper style.
+ *
+ * @return void
+ */
+ public function testSuccessStyle()
+ {
+ $this->magentoStyle->success('test success message');
+ $expected = PHP_EOL . PHP_EOL . PHP_EOL . ' \[SUCCESS\] test success message\s+' . PHP_EOL . PHP_EOL;
+ $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Success message does not match output');
+ }
+
+ /**
+ * Test style decorator will output error message with proper style.
+ *
+ * @return void
+ */
+ public function testErrorStyle()
+ {
+ $this->magentoStyle->error('test error message');
+ $expected = PHP_EOL . PHP_EOL . PHP_EOL . '\s+\[ERROR\] test error message\s+' . PHP_EOL . PHP_EOL;
+ $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Error message does not match output');
+ }
+
+ /**
+ * Test style decorator will output warning message with proper style.
+ *
+ * @return void
+ */
+ public function testWarningStyle()
+ {
+ $this->magentoStyle->warning('test warning message');
+ $expected = PHP_EOL . PHP_EOL . PHP_EOL . '\s+\[WARNING\] test warning message\s+' . PHP_EOL . PHP_EOL;
+ $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Warning message does not match output');
+ }
+
+ /**
+ * Test style decorator will output note message with proper style.
+ *
+ * @return void
+ */
+ public function testNoteStyle()
+ {
+ $this->magentoStyle->note('test note message');
+ $expected = PHP_EOL . PHP_EOL . PHP_EOL . '\s+\[NOTE\] test note message\s+' . PHP_EOL . PHP_EOL;
+ $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Note message does not match output');
+ }
+
+ /**
+ * Test style decorator will output caution message with proper style.
+ *
+ * @return void
+ */
+ public function testCautionStyle()
+ {
+ $this->magentoStyle->caution('test caution message');
+ $expected = PHP_EOL . PHP_EOL . PHP_EOL . '\s+! \[CAUTION\] test caution message\s+' . PHP_EOL . PHP_EOL;
+ $this->assertRegExp('/' . $expected . '/', $this->testOutput->output, 'Caution message does not match output');
+ }
+
+ /**
+ * Test style decorator will output table with proper style.
+ *
+ * @return void
+ */
+ public function testTableStyle()
+ {
+ $headers = [
+ [new TableCell('Main table title', ['colspan' => 2])],
+ ['testHeader1', 'testHeader2', 'testHeader3'],
+ ];
+ $rows = [
+ [
+ 'testValue1',
+ 'testValue2',
+ new TableCell('testValue3', ['rowspan' => 2]),
+ ],
+ ['testValue4', 'testValue5'],
+ ];
+ $this->magentoStyle->table($headers, $rows);
+ $expected = ' ------------- ------------- ------------- ' . PHP_EOL .
+ ' Main table title ' . PHP_EOL .
+ ' ------------- ------------- ------------- ' . PHP_EOL .
+ ' testHeader1 testHeader2 testHeader3 ' . PHP_EOL .
+ ' ------------- ------------- ------------- ' . PHP_EOL .
+ ' testValue1 testValue2 testValue3 ' . PHP_EOL .
+ ' testValue4 testValue5 ' . PHP_EOL .
+ ' ------------- ------------- ------------- ' . PHP_EOL . PHP_EOL;
+
+ $this->assertEquals($expected, $this->testOutput->output, 'Table does not match output');
+ }
+
+ /**
+ * @return void
+ */
+ public function testAsk()
+ {
+ $objectManager = new ObjectManager($this);
+ $formatter = $this->getMockBuilder(OutputFormatter::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $input = $this->getMockBuilder(InputInterface::class)
+ ->setMethods(['isInteractive'])
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $input->expects($this->exactly(2))
+ ->method('isInteractive')
+ ->willReturn(false);
+ $output = $this->getMockBuilder(OutputInterface::class)
+ ->setMethods(['getVerbosity', 'getFormatter'])
+ ->disableOriginalConstructor()
+ ->getMockForAbstractClass();
+ $output->expects($this->once())
+ ->method('getVerbosity')
+ ->willReturn(32);
+ $output->expects($this->once())
+ ->method('getFormatter')
+ ->willReturn($formatter);
+ $magentoStyle = $objectManager->getObject(
+ MagentoStyle::class,
+ [
+ 'input' => $input,
+ 'output' => $output,
+ ]
+ );
+ $questionHelper = $this->getMockBuilder(SymfonyQuestionHelper::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $questionHelper->expects($this->once())
+ ->method('ask')
+ ->willReturn('test Answer');
+ $objectManager->setBackwardCompatibleProperty($magentoStyle, 'questionHelper', $questionHelper);
+
+ $this->assertEquals(
+ 'test Answer',
+ $magentoStyle->ask('test question?', 'test default')
+ );
+ }
+
+ /**
+ * Test style decorator will output progress with proper style.
+ *
+ * @return void
+ */
+ public function testProgress()
+ {
+ $this->magentoStyle->progressStart(2);
+ $this->magentoStyle->progressAdvance(3);
+ $this->magentoStyle->progressFinish();
+ $expected = ' 0/2 [> ] 0%' . PHP_EOL .
+ ' 3/3 [============================] 100%' . PHP_EOL . PHP_EOL;
+ $this->assertEquals($expected, $this->testOutput->output, 'Progress does not match output');
+ }
+}
diff --git a/setup/src/Magento/Setup/Test/Unit/Console/Style/TestOutput.php b/setup/src/Magento/Setup/Test/Unit/Console/Style/TestOutput.php
new file mode 100644
index 0000000000000..1407e5ed183e4
--- /dev/null
+++ b/setup/src/Magento/Setup/Test/Unit/Console/Style/TestOutput.php
@@ -0,0 +1,27 @@
+output = '';
+ }
+
+ protected function doWrite($message, $newline)
+ {
+ $this->output .= $message . ($newline ? "\n" : '');
+ }
+}
diff --git a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/SessionTest.php b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/SessionTest.php
index d37c07e715482..3b1d3e29e4e56 100644
--- a/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/SessionTest.php
+++ b/setup/src/Magento/Setup/Test/Unit/Model/ConfigOptionsList/SessionTest.php
@@ -32,7 +32,7 @@ protected function setUp()
public function testGetOptions()
{
$options = $this->configList->getOptions();
- $this->assertCount(19, $options);
+ $this->assertCount(23, $options);
$this->assertArrayHasKey(0, $options);
$this->assertInstanceOf(SelectConfigOption::class, $options[0]);
@@ -156,7 +156,11 @@ public function testCreateConfigWithSessionSaveRedis()
'bot_lifetime' => '',
'disable_locking' => '',
'min_lifetime' => '',
- 'max_lifetime' => ''
+ 'max_lifetime' => '',
+ 'sentinel_master' => '',
+ 'sentinel_servers' => '',
+ 'sentinel_connect_retries' => '',
+ 'sentinel_verify_master' => '',
]
]
@@ -209,7 +213,11 @@ public function testCreateConfigWithRedisInput()
'bot_lifetime' => '',
'disable_locking' => '',
'min_lifetime' => '60',
- 'max_lifetime' => '3600'
+ 'max_lifetime' => '3600',
+ 'sentinel_master' => '',
+ 'sentinel_servers' => '',
+ 'sentinel_connect_retries' => '',
+ 'sentinel_verify_master' => '',
]
],