Skip to content

Commit 7167c70

Browse files
committed
Merge remote-tracking branch 'origin/MC-20710' into MC-19282-web-setup
2 parents 562644f + 35a203a commit 7167c70

File tree

18 files changed

+995
-3
lines changed

18 files changed

+995
-3
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Elasticsearch\Setup;
9+
10+
use Magento\AdvancedSearch\Model\Client\ClientResolver;
11+
12+
/**
13+
* Validate Elasticsearch connection
14+
*/
15+
class ConnectionValidator
16+
{
17+
/**
18+
* @var ClientResolver
19+
*/
20+
private $clientResolver;
21+
22+
/**
23+
* @param ClientResolver $clientResolver
24+
*/
25+
public function __construct(ClientResolver $clientResolver)
26+
{
27+
$this->clientResolver = $clientResolver;
28+
}
29+
30+
/**
31+
* Checks Elasticsearch Connection
32+
*
33+
* @param string $searchEngine
34+
* @return bool true if the connection succeeded, false otherwise
35+
*/
36+
public function validate(string $searchEngine): bool
37+
{
38+
try {
39+
$client = $this->clientResolver->create($searchEngine);
40+
return $client->testConnection();
41+
} catch (\Exception $e) {
42+
return false;
43+
}
44+
}
45+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Elasticsearch\Setup;
9+
10+
use Magento\Framework\App\Config\Storage\WriterInterface;
11+
use Magento\Framework\Exception\InputException;
12+
use Magento\Setup\Model\SearchConfigOptionsList;
13+
use Magento\Search\Setup\InstallConfigInterface;
14+
15+
/**
16+
* Configure Elasticsearch search engine based on installation input
17+
*/
18+
class InstallConfig implements InstallConfigInterface
19+
{
20+
private const CATALOG_SEARCH = 'catalog/search/';
21+
22+
/**
23+
* @var array
24+
*/
25+
private $searchConfigMapping = [
26+
SearchConfigOptionsList::INPUT_KEY_SEARCH_ENGINE => 'engine'
27+
];
28+
29+
/**
30+
* @var ConnectionValidator
31+
*/
32+
private $validator;
33+
34+
/**
35+
* @var WriterInterface
36+
*/
37+
private $configWriter;
38+
39+
/**
40+
* @param WriterInterface $configWriter
41+
* @param ConnectionValidator $validator
42+
* @param array $searchConfigMapping
43+
*/
44+
public function __construct(
45+
WriterInterface $configWriter,
46+
ConnectionValidator $validator,
47+
array $searchConfigMapping = []
48+
) {
49+
$this->configWriter = $configWriter;
50+
$this->validator = $validator;
51+
$this->searchConfigMapping = array_merge($this->searchConfigMapping, $searchConfigMapping);
52+
}
53+
54+
/**
55+
* @inheritDoc
56+
*/
57+
public function configure(array $inputOptions)
58+
{
59+
foreach ($inputOptions as $inputKey => $inputValue) {
60+
if (null === $inputValue || !isset($this->searchConfigMapping[$inputKey])) {
61+
continue;
62+
}
63+
$configKey = $this->searchConfigMapping[$inputKey];
64+
$this->configWriter->save(self::CATALOG_SEARCH . $configKey, $inputValue);
65+
}
66+
67+
if ($this->doValidation($inputOptions)) {
68+
if (!$this->validator->validate($inputOptions[SearchConfigOptionsList::INPUT_KEY_SEARCH_ENGINE])) {
69+
throw new InputException(
70+
__(
71+
'Connection to Elasticsearch cannot be established. '
72+
. 'Please check the configuration and try again.'
73+
)
74+
);
75+
}
76+
}
77+
}
78+
79+
/**
80+
* Check if elasticsearch validation should be performed
81+
*
82+
* @param array $inputOptions
83+
* @return bool
84+
*/
85+
private function doValidation(array $inputOptions): bool
86+
{
87+
if (isset($inputOptions[SearchConfigOptionsList::INPUT_KEY_ELASTICSEARCH_SKIP_VALIDATION])) {
88+
return !$inputOptions[SearchConfigOptionsList::INPUT_KEY_ELASTICSEARCH_SKIP_VALIDATION];
89+
}
90+
return true;
91+
}
92+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Elasticsearch\Test\Unit\Setup;
9+
10+
use Magento\AdvancedSearch\Model\Client\ClientResolver;
11+
use Magento\Elasticsearch\Setup\ConnectionValidator;
12+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
13+
use Magento\Elasticsearch\Elasticsearch5\Model\Client\Elasticsearch;
14+
use PHPUnit\Framework\MockObject\MockObject;
15+
use PHPUnit\Framework\TestCase;
16+
17+
class ConnectionValidatorTest extends TestCase
18+
{
19+
/**
20+
* @var ConnectionValidator
21+
*/
22+
private $connectionValidator;
23+
24+
/**
25+
* @var ClientResolver|MockObject
26+
*/
27+
private $clientResolverMock;
28+
29+
/**
30+
* @var Elasticsearch|MockObject
31+
*/
32+
private $elasticsearchClientMock;
33+
34+
protected function setUp()
35+
{
36+
$this->clientResolverMock = $this->getMockBuilder(ClientResolver::class)
37+
->disableOriginalConstructor()
38+
->getMock();
39+
$this->elasticsearchClientMock = $this->getMockBuilder(Elasticsearch::class)
40+
->disableOriginalConstructor()
41+
->getMock();
42+
43+
$objectManager = new ObjectManager($this);
44+
$this->connectionValidator = $objectManager->getObject(
45+
ConnectionValidator::class,
46+
[
47+
'clientResolver' => $this->clientResolverMock
48+
]
49+
);
50+
}
51+
52+
public function testValidate()
53+
{
54+
$searchEngine = 'elasticsearch5';
55+
56+
$this->clientResolverMock
57+
->expects($this->once())
58+
->method('create')
59+
->with($searchEngine)
60+
->willReturn($this->elasticsearchClientMock);
61+
$this->elasticsearchClientMock->expects($this->once())->method('testConnection')->willReturn(true);
62+
63+
$this->assertTrue($this->connectionValidator->validate($searchEngine));
64+
}
65+
66+
public function testValidateFail()
67+
{
68+
$searchEngine = 'elasticsearch5';
69+
70+
$this->clientResolverMock
71+
->expects($this->once())
72+
->method('create')
73+
->with($searchEngine)
74+
->willReturn($this->elasticsearchClientMock);
75+
$this->elasticsearchClientMock->expects($this->once())->method('testConnection')->willReturn(false);
76+
77+
$this->assertFalse($this->connectionValidator->validate($searchEngine));
78+
}
79+
}
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Elasticsearch\Test\Unit\Setup;
9+
10+
use Magento\Elasticsearch\Setup\ConnectionValidator;
11+
use Magento\Elasticsearch\Setup\InstallConfig;
12+
use Magento\Framework\App\Config\Storage\WriterInterface;
13+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
14+
use PHPUnit\Framework\MockObject\MockObject;
15+
use PHPUnit\Framework\TestCase;
16+
17+
class InstallConfigTest extends TestCase
18+
{
19+
/**
20+
* @var InstallConfig
21+
*/
22+
private $installConfig;
23+
24+
/**
25+
* @var ConnectionValidator|MockObject
26+
*/
27+
private $validatorMock;
28+
29+
/**
30+
* @var WriterInterface|MockObject
31+
*/
32+
private $configWriterMock;
33+
34+
protected function setup()
35+
{
36+
$this->validatorMock = $this->getMockBuilder(ConnectionValidator::class)
37+
->disableOriginalConstructor()
38+
->getMock();
39+
$this->configWriterMock = $this->getMockBuilder(WriterInterface::class)->getMockForAbstractClass();
40+
41+
$objectManager = new ObjectManager($this);
42+
$this->installConfig = $objectManager->getObject(
43+
InstallConfig::class,
44+
[
45+
'configWriter' => $this->configWriterMock,
46+
'validator' => $this->validatorMock,
47+
'searchConfigMapping' => [
48+
'elasticsearch-host' => 'elasticsearch5_server_hostname',
49+
'elasticsearch-port' => 'elasticsearch5_server_port',
50+
'elasticsearch-timeout' => 'elasticsearch5_server_timeout',
51+
'elasticsearch-index-prefix' => 'elasticsearch5_index_prefix',
52+
'elasticsearch-enable-auth' => 'elasticsearch5_enable_auth',
53+
'elasticsearch-username' => 'elasticsearch5_username',
54+
'elasticsearch-password' => 'elasticsearch5_password',
55+
]
56+
]
57+
);
58+
}
59+
60+
public function testConfigure()
61+
{
62+
$inputOptions = [
63+
'search-engine' => 'elasticsearch5',
64+
'elasticsearch-host' => 'localhost',
65+
'elasticsearch-port' => '9200'
66+
];
67+
68+
$this->configWriterMock
69+
->expects($this->at(0))
70+
->method('save')
71+
->with('catalog/search/engine', 'elasticsearch5');
72+
$this->configWriterMock
73+
->expects($this->at(1))
74+
->method('save')
75+
->with('catalog/search/elasticsearch5_server_hostname', 'localhost');
76+
$this->configWriterMock
77+
->expects($this->at(2))
78+
->method('save')
79+
->with('catalog/search/elasticsearch5_server_port', '9200');
80+
81+
$this->validatorMock->expects($this->once())->method('validate')->with('elasticsearch5')->willReturn(true);
82+
83+
$this->installConfig->configure($inputOptions);
84+
}
85+
86+
/**
87+
* @expectedException \Magento\Framework\Exception\InputException
88+
* @expectedExceptionMessage Connection to Elasticsearch cannot be established.
89+
*/
90+
public function testConfigureValidateFail()
91+
{
92+
$inputOptions = [
93+
'search-engine' => 'elasticsearch5',
94+
'elasticsearch-host' => 'es.domain.com',
95+
'elasticsearch-port' => '9200'
96+
];
97+
98+
$this->configWriterMock
99+
->expects($this->at(0))
100+
->method('save')
101+
->with('catalog/search/engine', 'elasticsearch5');
102+
$this->configWriterMock
103+
->expects($this->at(1))
104+
->method('save')
105+
->with('catalog/search/elasticsearch5_server_hostname', 'es.domain.com');
106+
$this->configWriterMock
107+
->expects($this->at(2))
108+
->method('save')
109+
->with('catalog/search/elasticsearch5_server_port', '9200');
110+
111+
$this->validatorMock->expects($this->once())->method('validate')->with('elasticsearch5')->willReturn(false);
112+
113+
$this->installConfig->configure($inputOptions);
114+
}
115+
116+
public function testConfigureWithSkipValidation()
117+
{
118+
$inputOptions = [
119+
'search-engine' => 'elasticsearch5',
120+
'elasticsearch-host' => 'localhost',
121+
'elasticsearch-port' => '9200',
122+
'skip-elasticsearch-validation' => true
123+
];
124+
125+
$this->configWriterMock
126+
->expects($this->at(0))
127+
->method('save')
128+
->with('catalog/search/engine', 'elasticsearch5');
129+
$this->configWriterMock
130+
->expects($this->at(1))
131+
->method('save')
132+
->with('catalog/search/elasticsearch5_server_hostname', 'localhost');
133+
$this->configWriterMock
134+
->expects($this->at(2))
135+
->method('save')
136+
->with('catalog/search/elasticsearch5_server_port', '9200');
137+
$this->validatorMock->expects($this->never())->method('validate');
138+
139+
$this->installConfig->configure($inputOptions);
140+
}
141+
}

app/code/Magento/Elasticsearch/etc/di.xml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,4 +508,24 @@
508508
</argument>
509509
</arguments>
510510
</type>
511+
<type name="Magento\Elasticsearch\Setup\InstallConfig">
512+
<arguments>
513+
<argument name="searchConfigMapping" xsi:type="array">
514+
<item name="elasticsearch-host" xsi:type="string">elasticsearch5_server_hostname</item>
515+
<item name="elasticsearch-port" xsi:type="string">elasticsearch5_server_port</item>
516+
<item name="elasticsearch-timeout" xsi:type="string">elasticsearch5_server_timeout</item>
517+
<item name="elasticsearch-index-prefix" xsi:type="string">elasticsearch5_index_prefix</item>
518+
<item name="elasticsearch-enable-auth" xsi:type="string">elasticsearch5_enable_auth</item>
519+
<item name="elasticsearch-username" xsi:type="string">elasticsearch5_username</item>
520+
<item name="elasticsearch-password" xsi:type="string">elasticsearch5_password</item>
521+
</argument>
522+
</arguments>
523+
</type>
524+
<type name="Magento\Search\Setup\CompositeInstallConfig">
525+
<arguments>
526+
<argument name="installConfigList" xsi:type="array">
527+
<item name="elasticsearch5" xsi:type="object">Magento\Elasticsearch\Setup\InstallConfig</item>
528+
</argument>
529+
</arguments>
530+
</type>
511531
</config>

0 commit comments

Comments
 (0)