Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
MappingValidator
0.00% covered (danger)
0.00%
0 / 36
0.00% covered (danger)
0.00%
0 / 3
72
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
2
 validate
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
30
 compareMappingToActual
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3namespace CirrusSearch\Maintenance\Validators;
4
5use CirrusSearch\ElasticaErrorHandler;
6use CirrusSearch\Maintenance\Printer;
7use Elastica\Exception\ExceptionInterface;
8use Elastica\Index;
9use Elastica\Mapping;
10use MediaWiki\Language\RawMessage;
11use MediaWiki\Status\Status;
12use Wikimedia\Assert\Assert;
13
14class MappingValidator extends Validator {
15    /**
16     * @var Index
17     */
18    private $index;
19
20    /**
21     * @var string
22     */
23    private $masterTimeout;
24
25    /**
26     * @var bool
27     */
28    private $optimizeIndexForExperimentalHighlighter;
29
30    /**
31     * @var array
32     */
33    private $availablePlugins;
34
35    /**
36     * @var array
37     */
38    private $mappingConfig;
39
40    /**
41     * @todo this constructor takes way too much arguments - refactor
42     *
43     * @param Index $index
44     * @param string $masterTimeout
45     * @param bool $optimizeIndexForExperimentalHighlighter
46     * @param array $availablePlugins
47     * @param array $mappingConfig
48     * @param Printer|null $out
49     */
50    public function __construct(
51        Index $index,
52        $masterTimeout,
53        $optimizeIndexForExperimentalHighlighter,
54        array $availablePlugins,
55        array $mappingConfig,
56        Printer $out = null
57    ) {
58        parent::__construct( $out );
59
60        $this->index = $index;
61        $this->masterTimeout = $masterTimeout;
62        $this->optimizeIndexForExperimentalHighlighter = $optimizeIndexForExperimentalHighlighter;
63        $this->availablePlugins = $availablePlugins;
64        // Could be supported, but prefer consistency
65        Assert::parameter( isset( $mappingConfig['properties'] ), '$mappingConfig',
66            'Mapping types are no longer supported, properties must be top level' );
67        $this->mappingConfig = $mappingConfig;
68    }
69
70    /**
71     * @return Status
72     */
73    public function validate() {
74        $this->outputIndented( "Validating mappings..." );
75        if ( $this->optimizeIndexForExperimentalHighlighter &&
76            !in_array( 'experimental-highlighter', $this->availablePlugins ) ) {
77            $this->output( "impossible!\n" );
78            return Status::newFatal( new RawMessage(
79                "wgCirrusSearchOptimizeIndexForExperimentalHighlighter is set to true but the " .
80                "'experimental-highlighter' plugin is not installed on all hosts." ) );
81        }
82
83        if ( !$this->compareMappingToActual() ) {
84            $action = new Mapping( $this->mappingConfig['properties'] );
85            $action->setParam( "dynamic", false );
86
87            try {
88                $action->send( $this->index, [
89                    'master_timeout' => $this->masterTimeout,
90                ] );
91                $this->output( "corrected\n" );
92            } catch ( ExceptionInterface $e ) {
93                $this->output( "failed!\n" );
94                $message = ElasticaErrorHandler::extractMessage( $e );
95                return Status::newFatal( new RawMessage(
96                    "Couldn't update existing mappings. You may need to reindex.\nHere is elasticsearch's error message: $message\n" ) );
97            }
98        }
99
100        return Status::newGood();
101    }
102
103    /**
104     * Check that the mapping returned from Elasticsearch is as we want it.
105     *
106     * @return bool is the mapping good enough for us?
107     */
108    private function compareMappingToActual() {
109        $actualMappings = $this->index->getMapping();
110        $this->output( "\n" );
111        $this->outputIndented( "\tValidating mapping..." );
112        if ( $this->checkConfig( $actualMappings, $this->mappingConfig ) ) {
113            $this->output( "ok\n" );
114            return true;
115        } else {
116            $this->output( "different..." );
117            return false;
118        }
119    }
120}