Completed
Push — 1.0 ( f45751...770e00 )
by Simonas
12:41 queued 10:12
created

AbstractElasticsearchTestCase::runTest()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
c 0
b 0
f 0
rs 8.7624
cc 6
eloc 12
nc 6
nop 0
1
<?php
2
3
/*
4
 * This file is part of the ONGR package.
5
 *
6
 * (c) NFQ Technologies UAB <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ONGR\ElasticsearchBundle\Test;
13
14
use Elasticsearch\Common\Exceptions\ElasticsearchException;
15
use ONGR\ElasticsearchBundle\Service\Manager;
16
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
17
use Symfony\Component\DependencyInjection\ContainerInterface;
18
19
/**
20
 * Base test which creates unique connection to test with.
21
 */
22
abstract class AbstractElasticsearchTestCase extends WebTestCase
23
{
24
    /**
25
     * @var Manager[] Holds used managers.
26
     */
27
    private $managers = [];
28
29
    /**
30
     * @var ContainerInterface
31
     */
32
    private $container;
33
34
    /**
35
     * {@inheritdoc}
36
     */
37
    public function runTest()
38
    {
39
        if ($this->getNumberOfRetries() < 1) {
40
            return parent::runTest();
41
        }
42
43
        foreach (range(1, $this->getNumberOfRetries()) as $try) {
44
            try {
45
                return parent::runTest();
46
            } catch (\Exception $e) {
47
                if (!($e instanceof ElasticsearchException)) {
48
                    throw $e;
49
                }
50
                // If error was from elasticsearch re-setup tests and retry.
51
                if ($try !== $this->getNumberOfRetries()) {
52
                    $this->tearDown();
53
                    $this->setUp();
54
                }
55
            }
56
        }
57
    }
58
59
    /**
60
     * {@inheritdoc}
61
     */
62
    protected function setUp()
63
    {
64
        foreach ($this->getDataArray() as $manager => $data) {
65
            // Create index and populate data
66
            $this->getManager($manager);
67
        }
68
    }
69
70
    /**
71
     * Returns number of retries tests should execute.
72
     *
73
     * @return int
74
     */
75
    protected function getNumberOfRetries()
76
    {
77
        return 3;
78
    }
79
80
    /**
81
     * Can be overwritten in child class to populate elasticsearch index with the data.
82
     *
83
     * Example:
84
     *      "manager_name" =>
85
     *      [
86
     *          'type_name' => [
87
     *              [
88
     *                  '_id' => 1,
89
     *                  'title' => 'foo',
90
     *              ],
91
     *              [
92
     *                  '_id' => 2,
93
     *                  'title' => 'bar',
94
     *              ]
95
     *          ]
96
     *      ]
97
     *
98
     * @return array
99
     */
100
    protected function getDataArray()
101
    {
102
        return [];
103
    }
104
105
    /**
106
     * Ignores versions specified.
107
     *
108
     * Returns two dimensional array, first item in sub array is version to ignore, second is comparator,
109
     * last test name. If no test name is provided it will be used on all test class.
110
     *
111
     * Comparator types can be found in `version_compare` documentation.
112
     *
113
     * Example: [
114
     *   ['1.2.7', '<='],
115
     *   ['1.2.9', '==', 'testSmth']
116
     * ]
117
     *
118
     * @return array
119
     */
120
    protected function getIgnoredVersions()
121
    {
122
        return [];
123
    }
124
125
    /**
126
     * Ignores version specified.
127
     *
128
     * @param Manager $manager
129
     */
130
    private function ignoreVersions(Manager $manager)
131
    {
132
        $currentVersion = $manager->getVersionNumber();
133
        $ignore = null;
134
135
        foreach ($this->getIgnoredVersions() as $ignoredVersion) {
136
            if (version_compare($currentVersion, $ignoredVersion[0], $ignoredVersion[1]) === true) {
137
                $ignore = true;
138
                if (isset($ignoredVersion[2])) {
139
                    if ($ignoredVersion[2] === $this->getName()) {
140
                        break;
141
                    }
142
                    $ignore = false;
143
                }
144
            }
145
        }
146
147
        if ($ignore === true) {
148
            $this->markTestSkipped("Elasticsearch version {$currentVersion} not supported by this test.");
149
        }
150
    }
151
152
    /**
153
     * Removes manager from local cache and drops its index.
154
     *
155
     * @param string $name
156
     */
157
    protected function removeManager($name)
158
    {
159
        if (isset($this->managers[$name])) {
160
            $this->managers[$name]->dropIndex();
161
            unset($this->managers[$name]);
162
        }
163
    }
164
165
    /**
166
     * Populates elasticsearch with data.
167
     *
168
     * @param Manager $manager
169
     * @param array   $data
170
     */
171
    private function populateElasticsearchWithData($manager, array $data)
172
    {
173
        if (!empty($data)) {
174
            foreach ($data as $type => $documents) {
175
                foreach ($documents as $document) {
176
                    $manager->bulk('index', $type, $document);
177
                }
178
            }
179
            $manager->commit();
180
            $manager->refresh();
181
        }
182
    }
183
184
    /**
185
     * {@inheritdoc}
186
     */
187
    protected function tearDown()
188
    {
189
        parent::tearDown();
190
191
        foreach ($this->managers as $name => $manager) {
192
            try {
193
                $manager->dropIndex();
194
            } catch (\Exception $e) {
195
                // Do nothing.
196
            }
197
        }
198
    }
199
200
    /**
201
     * Returns service container.
202
     *
203
     * @param bool  $reinitialize  Force kernel reinitialization.
204
     * @param array $kernelOptions Options used passed to kernel if it needs to be initialized.
205
     *
206
     * @return ContainerInterface
207
     */
208
    protected function getContainer($reinitialize = false, $kernelOptions = [])
209
    {
210
        if ($this->container === null || $reinitialize) {
211
            static::bootKernel($kernelOptions);
212
            $this->container = static::$kernel->getContainer();
213
        }
214
215
        return $this->container;
216
    }
217
218
    /**
219
     * Returns manager instance with injected connection if does not exist creates new one.
220
     *
221
     * @param string $name Manager name
222
     *
223
     * @return Manager
224
     *
225
     * @throws \LogicException
226
     */
227
    protected function getManager($name = 'default')
228
    {
229
        $serviceName = sprintf('es.manager.%s', $name);
230
231
        // Looks for cached manager.
232
        if (array_key_exists($name, $this->managers)) {
233
            $this->ignoreVersions($this->managers[$name]);
234
235
            return $this->managers[$name];
236
        } elseif ($this->getContainer()->has($serviceName)) {
237
            /** @var Manager $manager */
238
            $manager = $this->getContainer()->get($serviceName);
239
            $this->managers[$name] = $manager;
240
        } else {
241
            throw new \LogicException(sprintf("Manager '%s' does not exist", $name));
242
        }
243
244
        $this->ignoreVersions($manager);
245
        $manager->dropAndCreateIndex();
246
247
        // Populates elasticsearch index with data
248
        $data = $this->getDataArray();
249
        if (!empty($data[$name])) {
250
            $this->populateElasticsearchWithData($manager, $data[$name]);
251
        }
252
253
        return $manager;
254
    }
255
}
256