1<?php
2
3declare(strict_types = 1);
4
5namespace Elasticsearch\Tests;
6
7use Elasticsearch;
8use Elasticsearch\Client;
9use Elasticsearch\ClientBuilder;
10use Elasticsearch\Common\Exceptions\MaxRetriesException;
11use GuzzleHttp\Ring\Client\MockHandler;
12use GuzzleHttp\Ring\Future\FutureArray;
13use Mockery as m;
14
15/**
16 * Class ClientTest
17 *
18 * @category   Tests
19 * @package    Elasticsearch
20 * @subpackage Tests
21 * @author     Zachary Tong <zachary.tong@elasticsearch.com>
22 * @license    http://www.apache.org/licenses/LICENSE-2.0 Apache2
23 * @link       http://elasticsearch.org
24 */
25class ClientTest extends \PHPUnit\Framework\TestCase
26{
27    public function tearDown()
28    {
29        m::close();
30    }
31
32    public function testConstructorIllegalPort()
33    {
34        $this->expectException(\Elasticsearch\Common\Exceptions\InvalidArgumentException::class);
35        $this->expectExceptionMessage('Could not parse URI');
36
37        $client = Elasticsearch\ClientBuilder::create()->setHosts(['localhost:abc'])->build();
38    }
39
40    public function testFromConfig()
41    {
42        $params = [
43            'hosts' => [
44                'localhost:9200'
45            ],
46            'retries' => 2,
47            'handler' => ClientBuilder::multiHandler()
48        ];
49        $client = ClientBuilder::fromConfig($params);
50
51        $this->assertInstanceOf(Client::class, $client);
52    }
53
54    public function testFromConfigBadParam()
55    {
56        $params = [
57            'hosts' => [
58                'localhost:9200'
59            ],
60            'retries' => 2,
61            'imNotReal' => 5
62        ];
63
64        $this->expectException(\Elasticsearch\Common\Exceptions\RuntimeException::class);
65        $this->expectExceptionMessage('Unknown parameters provided: imNotReal');
66
67        $client = ClientBuilder::fromConfig($params);
68    }
69
70    public function testFromConfigBadParamQuiet()
71    {
72        $params = [
73            'hosts' => [
74                'localhost:9200'
75            ],
76            'retries' => 2,
77            'imNotReal' => 5
78        ];
79        $client = ClientBuilder::fromConfig($params, true);
80
81        $this->assertInstanceOf(Client::class, $client);
82    }
83
84    public function testIndexCannotBeNullForDelete()
85    {
86        $client = ClientBuilder::create()->build();
87
88        $this->expectException(Elasticsearch\Common\Exceptions\InvalidArgumentException::class);
89        $this->expectExceptionMessage('index cannot be null.');
90
91        $client->delete(
92            [
93            'index' => null,
94            'type' => 'test',
95            'id' => 'test'
96            ]
97        );
98    }
99
100    public function testTypeCanBeNullForDelete()
101    {
102        $client = ClientBuilder::create()->build();
103
104        $this->expectException(Elasticsearch\Common\Exceptions\Missing404Exception::class);
105
106        $client->delete(
107            [
108            'index' => 'test',
109            'type' => null,
110            'id' => 'test'
111            ]
112        );
113    }
114
115    public function testIdCannotBeNullForDelete()
116    {
117        $client = ClientBuilder::create()->build();
118
119        $this->expectException(Elasticsearch\Common\Exceptions\InvalidArgumentException::class);
120        $this->expectExceptionMessage('id cannot be null.');
121
122        $client->delete(
123            [
124            'index' => 'test',
125            'type' => 'test',
126            'id' => null
127            ]
128        );
129    }
130
131    public function testIndexCannotBeEmptyStringForDelete()
132    {
133        $client = ClientBuilder::create()->build();
134
135        $this->expectException(Elasticsearch\Common\Exceptions\InvalidArgumentException::class);
136        $this->expectExceptionMessage('index cannot be an empty string');
137
138        $client->delete(
139            [
140            'index' => '',
141            'type' => 'test',
142            'id' => 'test'
143            ]
144        );
145    }
146
147    public function testTypeCannotBeEmptyStringForDelete()
148    {
149        $client = ClientBuilder::create()->build();
150
151        $this->expectException(Elasticsearch\Common\Exceptions\BadRequest400Exception::class);
152
153        $client->delete(
154            [
155            'index' => 'test',
156            'type' => '',
157            'id' => 'test'
158            ]
159        );
160    }
161
162    public function testIdCannotBeEmptyStringForDelete()
163    {
164        $client = ClientBuilder::create()->build();
165
166        $this->expectException(Elasticsearch\Common\Exceptions\InvalidArgumentException::class);
167        $this->expectExceptionMessage('id cannot be an empty string');
168
169        $client->delete(
170            [
171            'index' => 'test',
172            'type' => 'test',
173            'id' => ''
174            ]
175        );
176    }
177
178    public function testIndexCannotBeArrayOfEmptyStringsForDelete()
179    {
180        $client = ClientBuilder::create()->build();
181
182        $this->expectException(Elasticsearch\Common\Exceptions\InvalidArgumentException::class);
183        $this->expectExceptionMessage('index cannot be an array of empty strings');
184
185        $client->delete(
186            [
187            'index' => ['', '', ''],
188            'type' => 'test',
189            'id' => 'test'
190            ]
191        );
192    }
193
194    public function testIndexCannotBeArrayOfNullsForDelete()
195    {
196        $client = ClientBuilder::create()->build();
197
198        $this->expectException(Elasticsearch\Common\Exceptions\InvalidArgumentException::class);
199        $this->expectExceptionMessage('index cannot be an array of empty strings');
200
201        $client->delete(
202            [
203            'index' => [null, null, null],
204            'type' => 'test',
205            'id' => 'test'
206            ]
207        );
208    }
209
210    public function testMaxRetriesException()
211    {
212        $client = Elasticsearch\ClientBuilder::create()
213            ->setHosts(["localhost:1"])
214            ->setRetries(0)
215            ->build();
216
217        $searchParams = [
218            'index' => 'test',
219            'type' => 'test',
220            'body' => [
221                'query' => [
222                    'match_all' => []
223                ]
224            ]
225        ];
226
227        $client = Elasticsearch\ClientBuilder::create()
228            ->setHosts(["localhost:1"])
229            ->setRetries(0)
230            ->build();
231
232        try {
233            $client->search($searchParams);
234            $this->fail("Should have thrown CouldNotConnectToHost");
235        } catch (Elasticsearch\Common\Exceptions\Curl\CouldNotConnectToHost $e) {
236            // All good
237            $previous = $e->getPrevious();
238            $this->assertInstanceOf(MaxRetriesException::class, $previous);
239        } catch (\Exception $e) {
240            throw $e;
241        }
242
243
244        $client = Elasticsearch\ClientBuilder::create()
245            ->setHosts(["localhost:1"])
246            ->setRetries(0)
247            ->build();
248
249        try {
250            $client->search($searchParams);
251            $this->fail("Should have thrown TransportException");
252        } catch (Elasticsearch\Common\Exceptions\TransportException $e) {
253            // All good
254            $previous = $e->getPrevious();
255            $this->assertInstanceOf(MaxRetriesException::class, $previous);
256        } catch (\Exception $e) {
257            throw $e;
258        }
259    }
260
261    public function testInlineHosts()
262    {
263        $client = Elasticsearch\ClientBuilder::create()->setHosts(
264            [
265            'localhost:9200'
266            ]
267        )->build();
268        $host = $client->transport->getConnection();
269        $this->assertSame("localhost", $host->getHost());
270        $this->assertSame(9200, $host->getPort());
271        $this->assertSame("http", $host->getTransportSchema());
272
273
274        $client = Elasticsearch\ClientBuilder::create()->setHosts(
275            [
276            'http://localhost:9200'
277            ]
278        )->build();
279        $host = $client->transport->getConnection();
280        $this->assertSame("localhost", $host->getHost());
281        $this->assertSame(9200, $host->getPort());
282        $this->assertSame("http", $host->getTransportSchema());
283
284        $client = Elasticsearch\ClientBuilder::create()->setHosts(
285            [
286            'http://foo.com:9200'
287            ]
288        )->build();
289        $host = $client->transport->getConnection();
290        $this->assertSame("foo.com", $host->getHost());
291        $this->assertSame(9200, $host->getPort());
292        $this->assertSame("http", $host->getTransportSchema());
293
294        $client = Elasticsearch\ClientBuilder::create()->setHosts(
295            [
296            'https://foo.com:9200'
297            ]
298        )->build();
299        $host = $client->transport->getConnection();
300        $this->assertSame("foo.com", $host->getHost());
301        $this->assertSame(9200, $host->getPort());
302        $this->assertSame("https", $host->getTransportSchema());
303
304
305        $client = Elasticsearch\ClientBuilder::create()->setHosts(
306            [
307            'https://user:pass@foo.com:9200'
308            ]
309        )->build();
310        $host = $client->transport->getConnection();
311        $this->assertSame("foo.com", $host->getHost());
312        $this->assertSame(9200, $host->getPort());
313        $this->assertSame("https", $host->getTransportSchema());
314        $this->assertSame("user:pass", $host->getUserPass());
315    }
316
317    public function testExtendedHosts()
318    {
319        $client = Elasticsearch\ClientBuilder::create()->setHosts(
320            [
321            [
322                'host' => 'localhost',
323                'port' => 9200,
324                'scheme' => 'http'
325            ]
326            ]
327        )->build();
328        $host = $client->transport->getConnection();
329        $this->assertSame("localhost", $host->getHost());
330        $this->assertSame(9200, $host->getPort());
331        $this->assertSame("http", $host->getTransportSchema());
332
333
334        $client = Elasticsearch\ClientBuilder::create()->setHosts(
335            [
336            [
337                'host' => 'foo.com',
338                'port' => 9200,
339                'scheme' => 'http'
340            ]
341            ]
342        )->build();
343        $host = $client->transport->getConnection();
344        $this->assertSame("foo.com", $host->getHost());
345        $this->assertSame(9200, $host->getPort());
346        $this->assertSame("http", $host->getTransportSchema());
347
348
349        $client = Elasticsearch\ClientBuilder::create()->setHosts(
350            [
351            [
352                'host' => 'foo.com',
353                'port' => 9200,
354                'scheme' => 'https'
355            ]
356            ]
357        )->build();
358        $host = $client->transport->getConnection();
359        $this->assertSame("foo.com", $host->getHost());
360        $this->assertSame(9200, $host->getPort());
361        $this->assertSame("https", $host->getTransportSchema());
362
363
364        $client = Elasticsearch\ClientBuilder::create()->setHosts(
365            [
366            [
367                'host' => 'foo.com',
368                'scheme' => 'http'
369            ]
370            ]
371        )->build();
372        $host = $client->transport->getConnection();
373        $this->assertSame("foo.com", $host->getHost());
374        $this->assertSame(9200, $host->getPort());
375        $this->assertSame("http", $host->getTransportSchema());
376
377
378        $client = Elasticsearch\ClientBuilder::create()->setHosts(
379            [
380            [
381                'host' => 'foo.com'
382            ]
383            ]
384        )->build();
385        $host = $client->transport->getConnection();
386        $this->assertSame("foo.com", $host->getHost());
387        $this->assertSame(9200, $host->getPort());
388        $this->assertSame("http", $host->getTransportSchema());
389
390
391        $client = Elasticsearch\ClientBuilder::create()->setHosts(
392            [
393            [
394                'host' => 'foo.com',
395                'port' => 9500,
396                'scheme' => 'https'
397            ]
398            ]
399        )->build();
400        $host = $client->transport->getConnection();
401        $this->assertSame("foo.com", $host->getHost());
402        $this->assertSame(9500, $host->getPort());
403        $this->assertSame("https", $host->getTransportSchema());
404
405
406        try {
407            $client = Elasticsearch\ClientBuilder::create()->setHosts(
408                [
409                [
410                    'port' => 9200,
411                    'scheme' => 'http'
412                ]
413                ]
414            )->build();
415            $this->fail("Expected RuntimeException from missing host, none thrown");
416        } catch (Elasticsearch\Common\Exceptions\RuntimeException $e) {
417            // good
418        }
419
420        // Underscore host, questionably legal, but inline method would break
421        $client = Elasticsearch\ClientBuilder::create()->setHosts(
422            [
423            [
424                'host' => 'the_foo.com'
425            ]
426            ]
427        )->build();
428        $host = $client->transport->getConnection();
429        $this->assertSame("the_foo.com", $host->getHost());
430        $this->assertSame(9200, $host->getPort());
431        $this->assertSame("http", $host->getTransportSchema());
432
433
434        // Special characters in user/pass, would break inline
435        $client = Elasticsearch\ClientBuilder::create()->setHosts(
436            [
437            [
438                'host' => 'foo.com',
439                'user' => 'user',
440                'pass' => 'abc#$@?%!abc'
441            ]
442            ]
443        )->build();
444        $host = $client->transport->getConnection();
445        $this->assertSame("foo.com", $host->getHost());
446        $this->assertSame(9200, $host->getPort());
447        $this->assertSame("http", $host->getTransportSchema());
448        $this->assertSame("user:abc#$@?%!abc", $host->getUserPass());
449    }
450
451    public function testClientLazy()
452    {
453        $handler = new MockHandler([
454          'status' => 200,
455          'transfer_stats' => [
456             'total_time' => 100
457          ],
458          'body' => '{test}',
459          'effective_url' => 'localhost'
460        ]);
461        $builder = ClientBuilder::create();
462        $builder->setHosts(['somehost']);
463        $builder->setHandler($handler);
464        $client = $builder->build();
465
466        $params = [
467            'client' => [
468                'future' => 'lazy',
469            ]
470        ];
471        $result = $client->info($params);
472        $this->assertInstanceOf(FutureArray::class, $result);
473    }
474}
475